Skip to content

Commit

Permalink
[gasstation] Update gas station logic (#4035)
Browse files Browse the repository at this point in the history
  • Loading branch information
CoderZhi authored Jan 19, 2024
1 parent e7f8bb8 commit c413634
Show file tree
Hide file tree
Showing 2 changed files with 121 additions and 13 deletions.
22 changes: 16 additions & 6 deletions gasstation/gasstattion.go
Original file line number Diff line number Diff line change
Expand Up @@ -53,11 +53,13 @@ func (gs *GasStation) SuggestGasPrice() (uint64, error) {
if tip > uint64(gs.cfg.SuggestBlockWindow) {
endBlockHeight = tip - uint64(gs.cfg.SuggestBlockWindow)
}

maxGas := gs.bc.Genesis().BlockGasLimit * (tip - endBlockHeight)
defaultGasPrice := gs.cfg.DefaultGas
gasConsumed := uint64(0)
for height := tip; height > endBlockHeight; height-- {
blk, err := gs.dao.GetBlockByHeight(height)
if err != nil {
return gs.cfg.DefaultGas, err
return defaultGasPrice, err
}
if len(blk.Actions) == 0 {
continue
Expand All @@ -66,6 +68,9 @@ func (gs *GasStation) SuggestGasPrice() (uint64, error) {
continue
}
smallestPrice := blk.Actions[0].GasPrice()
for _, receipt := range blk.Receipts {
gasConsumed += receipt.GasConsumed
}
for _, act := range blk.Actions {
if action.IsSystemAction(act) {
continue
Expand All @@ -76,17 +81,22 @@ func (gs *GasStation) SuggestGasPrice() (uint64, error) {
}
smallestPrices = append(smallestPrices, smallestPrice)
}

if len(smallestPrices) == 0 {
// return default price
return gs.cfg.DefaultGas, nil
return defaultGasPrice, nil
}
sort.Slice(smallestPrices, func(i, j int) bool {
return smallestPrices[i].Cmp(smallestPrices[j]) < 0
})
gasPrice := smallestPrices[(len(smallestPrices)-1)*gs.cfg.Percentile/100].Uint64()
if gasPrice < gs.cfg.DefaultGas {
gasPrice = gs.cfg.DefaultGas
switch {
case gasConsumed > maxGas/2:
gasPrice += gasPrice / 10
case gasConsumed < maxGas/5:
gasPrice -= gasPrice / 10
}
if gasPrice < defaultGasPrice {
gasPrice = defaultGasPrice
}
return gasPrice, nil
}
112 changes: 105 additions & 7 deletions gasstation/gasstattion_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import (
"testing"
"time"

"github.com/golang/mock/gomock"
"github.com/stretchr/testify/require"

"github.com/iotexproject/iotex-core/action"
Expand All @@ -30,15 +31,28 @@ import (
"github.com/iotexproject/iotex-core/pkg/unit"
"github.com/iotexproject/iotex-core/state/factory"
"github.com/iotexproject/iotex-core/test/identityset"
"github.com/iotexproject/iotex-core/test/mock/mock_blockchain"
"github.com/iotexproject/iotex-core/test/mock/mock_blockdao"
"github.com/iotexproject/iotex-core/testutil"
)

type testConfig struct {
Genesis genesis.Genesis
Chain blockchain.Config
ActPool actpool.Config
GasStation Config
}
type (
testConfig struct {
Genesis genesis.Genesis
Chain blockchain.Config
ActPool actpool.Config
GasStation Config
}
testActionGas []struct {
gasPrice uint64
gasConsumed uint64
}
testCase struct {
name string
blocks []testActionGas
expectGasPrice uint64
}
)

func TestNewGasStation(t *testing.T) {
require := require.New(t)
Expand Down Expand Up @@ -131,7 +145,11 @@ func TestSuggestGasPriceForUserAction(t *testing.T) {
gp, err := gs.SuggestGasPrice()
require.NoError(t, err)
// i from 10 to 29,gasprice for 20 to 39,60%*20+20=31
require.Equal(t, big.NewInt(1).Mul(big.NewInt(int64(31)), big.NewInt(unit.Qev)).Uint64(), gp)
require.Equal(
t,
big.NewInt(1).Mul(big.NewInt(int64(31)), big.NewInt(unit.Qev)).Uint64()*9/10,
gp,
)
}

func TestSuggestGasPriceForSystemAction(t *testing.T) {
Expand Down Expand Up @@ -191,3 +209,83 @@ func TestSuggestGasPriceForSystemAction(t *testing.T) {
// i from 10 to 29,gasprice for 20 to 39,60%*20+20=31
require.Equal(t, gs.cfg.DefaultGas, gp)
}

func TestSuggestGasPrice_GasConsumed(t *testing.T) {
cases := []testCase{
{
name: "gas consumed > maxGas/2",
blocks: []testActionGas{
{{uint64(unit.Qev) * 2, 100000000}},
{{uint64(unit.Qev) * 2, 100000000}},
{{uint64(unit.Qev) * 2, 100000000}},
{{uint64(unit.Qev) * 2, 100000000}},
{{uint64(unit.Qev) * 2, 100000000}},
{{uint64(unit.Qev) * 2, 200000000}},
},
expectGasPrice: 2200000000000,
},
{
name: "gas consumed < maxGas/5",
blocks: []testActionGas{
{{uint64(unit.Qev) * 2, 1000000}},
{{uint64(unit.Qev) * 2, 1000000}},
{{uint64(unit.Qev) * 2, 1000000}},
{{uint64(unit.Qev) * 2, 1000000}},
{{uint64(unit.Qev) * 2, 1000000}},
{{uint64(unit.Qev) * 2, 2000000}},
},
expectGasPrice: 1800000000000,
},
{
name: "gas consumed between maxGas/5 - maxGas/2",
blocks: []testActionGas{
{{uint64(unit.Qev) * 2, 10000000}},
{{uint64(unit.Qev) * 2, 10000000}},
{{uint64(unit.Qev) * 2, 10000000}},
{{uint64(unit.Qev) * 2, 10000000}},
{{uint64(unit.Qev) * 2, 10000000}},
{{uint64(unit.Qev) * 2, 5000000}},
},
expectGasPrice: 2000000000000,
},
}
for _, c := range cases {
t.Run(c.name, func(t *testing.T) {
r := require.New(t)
blocks := prepareBlocks(r, c.blocks)
ctrl := gomock.NewController(t)
bc := mock_blockchain.NewMockBlockchain(ctrl)
dao := mock_blockdao.NewMockBlockDAO(ctrl)
gs := NewGasStation(bc, dao, DefaultConfig)
bc.EXPECT().TipHeight().Return(uint64(len(blocks) - 1)).Times(1)
bc.EXPECT().Genesis().Return(genesis.Default).Times(1)
dao.EXPECT().GetBlockByHeight(gomock.Any()).DoAndReturn(
func(height uint64) (*block.Block, error) {
return blocks[height], nil
},
).AnyTimes()
gp, err := gs.SuggestGasPrice()
r.NoError(err)
r.Equal(c.expectGasPrice, gp)
})
}
}

func prepareBlocks(r *require.Assertions, cases []testActionGas) map[uint64]*block.Block {
blocks := map[uint64]*block.Block{}
for i := range cases {
actions := []action.SealedEnvelope{}
receipts := []*action.Receipt{}
for _, gas := range cases[i] {
seale, err := action.SignedTransfer(identityset.Address(1).String(), identityset.PrivateKey(1), 1, big.NewInt(0), []byte{}, 1000, big.NewInt(int64(gas.gasPrice)))
r.NoError(err)
actions = append(actions, seale)
receipts = append(receipts, &action.Receipt{GasConsumed: gas.gasConsumed})
}
blocks[uint64(i)] = &block.Block{
Body: block.Body{Actions: actions},
Receipts: receipts,
}
}
return blocks
}

0 comments on commit c413634

Please sign in to comment.