diff --git a/node/impl/full/gas.go b/node/impl/full/gas.go index 2aa8a39ca..40ab88b6b 100644 --- a/node/impl/full/gas.go +++ b/node/impl/full/gas.go @@ -6,12 +6,8 @@ import ( "math/rand" "sort" - "github.com/filecoin-project/lotus/api" - "github.com/filecoin-project/lotus/build" - "github.com/filecoin-project/lotus/chain/messagepool" - "github.com/filecoin-project/lotus/chain/stmgr" - "github.com/filecoin-project/lotus/chain/store" - "github.com/filecoin-project/lotus/chain/types" + "go.uber.org/fx" + "golang.org/x/xerrors" "github.com/filecoin-project/go-address" "github.com/filecoin-project/go-state-types/abi" @@ -19,8 +15,12 @@ import ( "github.com/filecoin-project/go-state-types/exitcode" "github.com/filecoin-project/specs-actors/actors/builtin" - "go.uber.org/fx" - "golang.org/x/xerrors" + "github.com/filecoin-project/lotus/api" + "github.com/filecoin-project/lotus/build" + "github.com/filecoin-project/lotus/chain/messagepool" + "github.com/filecoin-project/lotus/chain/stmgr" + "github.com/filecoin-project/lotus/chain/store" + "github.com/filecoin-project/lotus/chain/types" ) type GasAPI struct { @@ -50,6 +50,35 @@ func (a *GasAPI) GasEstimateFeeCap(ctx context.Context, msg *types.Message, maxq return out, nil } +type gasMeta struct { + price big.Int + limit int64 +} + +func medianGasPremium(prices []gasMeta, blocks int) abi.TokenAmount { + sort.Slice(prices, func(i, j int) bool { + // sort desc by price + return prices[i].price.GreaterThan(prices[j].price) + }) + + at := build.BlockGasTarget * int64(blocks) / 2 + prev1, prev2 := big.Zero(), big.Zero() + for _, price := range prices { + prev1, prev2 = price.price, prev1 + at -= price.limit + if at < 0 { + break + } + } + + premium := prev1 + if prev2.Sign() != 0 { + premium = big.Div(types.BigAdd(prev1, prev2), types.NewInt(2)) + } + + return premium +} + func (a *GasAPI) GasEstimateGasPremium(ctx context.Context, nblocksincl uint64, sender address.Address, gaslimit int64, _ types.TipSetKey) (types.BigInt, error) { @@ -57,11 +86,6 @@ func (a *GasAPI) GasEstimateGasPremium(ctx context.Context, nblocksincl uint64, nblocksincl = 1 } - type gasMeta struct { - price big.Int - limit int64 - } - var prices []gasMeta var blocks int @@ -92,25 +116,7 @@ func (a *GasAPI) GasEstimateGasPremium(ctx context.Context, nblocksincl uint64, ts = pts } - sort.Slice(prices, func(i, j int) bool { - // sort desc by price - return prices[i].price.GreaterThan(prices[j].price) - }) - - at := build.BlockGasTarget * int64(blocks) / 2 - prev1, prev2 := big.Zero(), big.Zero() - for _, price := range prices { - prev1, prev2 = price.price, prev1 - at -= price.limit - if at > 0 { - continue - } - } - - premium := prev1 - if prev2.Sign() != 0 { - premium = big.Div(types.BigAdd(prev1, prev2), types.NewInt(2)) - } + premium := medianGasPremium(prices, blocks) if types.BigCmp(premium, types.NewInt(MinGasPremium)) < 0 { switch nblocksincl { diff --git a/node/impl/full/gas_test.go b/node/impl/full/gas_test.go new file mode 100644 index 000000000..2452ab807 --- /dev/null +++ b/node/impl/full/gas_test.go @@ -0,0 +1,40 @@ +package full + +import ( + "testing" + + "github.com/stretchr/testify/require" + + "github.com/filecoin-project/go-state-types/big" + + "github.com/filecoin-project/lotus/build" + "github.com/filecoin-project/lotus/chain/types" +) + +func TestMedian(t *testing.T) { + require.Equal(t, types.NewInt(5), medianGasPremium([]gasMeta{ + {big.NewInt(5), build.BlockGasTarget}, + }, 1)) + + require.Equal(t, types.NewInt(10), medianGasPremium([]gasMeta{ + {big.NewInt(5), build.BlockGasTarget}, + {big.NewInt(10), build.BlockGasTarget}, + }, 1)) + + require.Equal(t, types.NewInt(15), medianGasPremium([]gasMeta{ + {big.NewInt(10), build.BlockGasTarget / 2}, + {big.NewInt(20), build.BlockGasTarget / 2}, + }, 1)) + + require.Equal(t, types.NewInt(25), medianGasPremium([]gasMeta{ + {big.NewInt(10), build.BlockGasTarget / 2}, + {big.NewInt(20), build.BlockGasTarget / 2}, + {big.NewInt(30), build.BlockGasTarget / 2}, + }, 1)) + + require.Equal(t, types.NewInt(15), medianGasPremium([]gasMeta{ + {big.NewInt(10), build.BlockGasTarget / 2}, + {big.NewInt(20), build.BlockGasTarget / 2}, + {big.NewInt(30), build.BlockGasTarget / 2}, + }, 2)) +}