perf: add cache for gas permium estimation
Signed-off-by: Jakub Sztandera <kubuxu@protocol.ai>
This commit is contained in:
parent
897c5c7d82
commit
5f672c2ed0
@ -329,6 +329,8 @@ var ChainNode = Options(
|
|||||||
Override(new(storagemarket.StorageClientNode), storageadapter.NewClientNodeAdapter),
|
Override(new(storagemarket.StorageClientNode), storageadapter.NewClientNodeAdapter),
|
||||||
Override(HandleMigrateClientFundsKey, modules.HandleMigrateClientFunds),
|
Override(HandleMigrateClientFundsKey, modules.HandleMigrateClientFunds),
|
||||||
|
|
||||||
|
Override(new(*full.GasPriceCache), full.NewGasPriceCache),
|
||||||
|
|
||||||
// Lite node API
|
// Lite node API
|
||||||
ApplyIf(isLiteNode,
|
ApplyIf(isLiteNode,
|
||||||
Override(new(messagesigner.MpoolNonceAPI), From(new(modules.MpoolNonceAPI))),
|
Override(new(messagesigner.MpoolNonceAPI), From(new(modules.MpoolNonceAPI))),
|
||||||
|
@ -8,6 +8,7 @@ import (
|
|||||||
|
|
||||||
"github.com/filecoin-project/lotus/chain/actors/builtin"
|
"github.com/filecoin-project/lotus/chain/actors/builtin"
|
||||||
"github.com/filecoin-project/lotus/chain/actors/builtin/paych"
|
"github.com/filecoin-project/lotus/chain/actors/builtin/paych"
|
||||||
|
lru "github.com/hashicorp/golang-lru"
|
||||||
|
|
||||||
"go.uber.org/fx"
|
"go.uber.org/fx"
|
||||||
"golang.org/x/xerrors"
|
"golang.org/x/xerrors"
|
||||||
@ -39,6 +40,8 @@ type GasModule struct {
|
|||||||
Chain *store.ChainStore
|
Chain *store.ChainStore
|
||||||
Mpool *messagepool.MessagePool
|
Mpool *messagepool.MessagePool
|
||||||
GetMaxFee dtypes.DefaultMaxFeeFunc
|
GetMaxFee dtypes.DefaultMaxFeeFunc
|
||||||
|
|
||||||
|
PriceCache *GasPriceCache
|
||||||
}
|
}
|
||||||
|
|
||||||
var _ GasModuleAPI = (*GasModule)(nil)
|
var _ GasModuleAPI = (*GasModule)(nil)
|
||||||
@ -51,6 +54,53 @@ type GasAPI struct {
|
|||||||
Stmgr *stmgr.StateManager
|
Stmgr *stmgr.StateManager
|
||||||
Chain *store.ChainStore
|
Chain *store.ChainStore
|
||||||
Mpool *messagepool.MessagePool
|
Mpool *messagepool.MessagePool
|
||||||
|
|
||||||
|
PriceCache *GasPriceCache
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewGasPriceCache() *GasPriceCache {
|
||||||
|
// 50 because we usually won't access more than 40
|
||||||
|
c, err := lru.New2Q(50)
|
||||||
|
if err != nil {
|
||||||
|
// err only if parameter is bad
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return &GasPriceCache{
|
||||||
|
c: c,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
type GasPriceCache struct {
|
||||||
|
c *lru.TwoQueueCache
|
||||||
|
}
|
||||||
|
|
||||||
|
type GasMeta struct {
|
||||||
|
Price big.Int
|
||||||
|
Limit int64
|
||||||
|
}
|
||||||
|
|
||||||
|
func (g *GasPriceCache) GetTSGasStats(cstore *store.ChainStore, ts *types.TipSet) ([]GasMeta, error) {
|
||||||
|
i, has := g.c.Get(ts.Key())
|
||||||
|
if has {
|
||||||
|
return i.([]GasMeta), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
var prices []GasMeta
|
||||||
|
msgs, err := cstore.MessagesForTipset(ts)
|
||||||
|
if err != nil {
|
||||||
|
return nil, xerrors.Errorf("loading messages: %w", err)
|
||||||
|
}
|
||||||
|
for _, msg := range msgs {
|
||||||
|
prices = append(prices, GasMeta{
|
||||||
|
Price: msg.VMMessage().GasPremium,
|
||||||
|
Limit: msg.VMMessage().GasLimit,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
g.c.Add(ts.Key(), prices)
|
||||||
|
|
||||||
|
return prices, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
const MinGasPremium = 100e3
|
const MinGasPremium = 100e3
|
||||||
@ -88,24 +138,19 @@ func gasEstimateFeeCap(cstore *store.ChainStore, msg *types.Message, maxqueueblk
|
|||||||
return out, nil
|
return out, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
type gasMeta struct {
|
|
||||||
price big.Int
|
|
||||||
limit int64
|
|
||||||
}
|
|
||||||
|
|
||||||
// finds 55th percntile instead of median to put negative pressure on gas price
|
// finds 55th percntile instead of median to put negative pressure on gas price
|
||||||
func medianGasPremium(prices []gasMeta, blocks int) abi.TokenAmount {
|
func medianGasPremium(prices []GasMeta, blocks int) abi.TokenAmount {
|
||||||
sort.Slice(prices, func(i, j int) bool {
|
sort.Slice(prices, func(i, j int) bool {
|
||||||
// sort desc by price
|
// sort desc by price
|
||||||
return prices[i].price.GreaterThan(prices[j].price)
|
return prices[i].Price.GreaterThan(prices[j].Price)
|
||||||
})
|
})
|
||||||
|
|
||||||
at := build.BlockGasTarget * int64(blocks) / 2 // 50th
|
at := build.BlockGasTarget * int64(blocks) / 2 // 50th
|
||||||
at += build.BlockGasTarget * int64(blocks) / (2 * 20) // move 5% further
|
at += build.BlockGasTarget * int64(blocks) / (2 * 20) // move 5% further
|
||||||
prev1, prev2 := big.Zero(), big.Zero()
|
prev1, prev2 := big.Zero(), big.Zero()
|
||||||
for _, price := range prices {
|
for _, price := range prices {
|
||||||
prev1, prev2 = price.price, prev1
|
prev1, prev2 = price.Price, prev1
|
||||||
at -= price.limit
|
at -= price.Limit
|
||||||
if at < 0 {
|
if at < 0 {
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
@ -126,7 +171,7 @@ func (a *GasAPI) GasEstimateGasPremium(
|
|||||||
gaslimit int64,
|
gaslimit int64,
|
||||||
_ types.TipSetKey,
|
_ types.TipSetKey,
|
||||||
) (types.BigInt, error) {
|
) (types.BigInt, error) {
|
||||||
return gasEstimateGasPremium(a.Chain, nblocksincl)
|
return gasEstimateGasPremium(a.Chain, a.PriceCache, nblocksincl)
|
||||||
}
|
}
|
||||||
func (m *GasModule) GasEstimateGasPremium(
|
func (m *GasModule) GasEstimateGasPremium(
|
||||||
ctx context.Context,
|
ctx context.Context,
|
||||||
@ -135,14 +180,14 @@ func (m *GasModule) GasEstimateGasPremium(
|
|||||||
gaslimit int64,
|
gaslimit int64,
|
||||||
_ types.TipSetKey,
|
_ types.TipSetKey,
|
||||||
) (types.BigInt, error) {
|
) (types.BigInt, error) {
|
||||||
return gasEstimateGasPremium(m.Chain, nblocksincl)
|
return gasEstimateGasPremium(m.Chain, m.PriceCache, nblocksincl)
|
||||||
}
|
}
|
||||||
func gasEstimateGasPremium(cstore *store.ChainStore, nblocksincl uint64) (types.BigInt, error) {
|
func gasEstimateGasPremium(cstore *store.ChainStore, cache *GasPriceCache, nblocksincl uint64) (types.BigInt, error) {
|
||||||
if nblocksincl == 0 {
|
if nblocksincl == 0 {
|
||||||
nblocksincl = 1
|
nblocksincl = 1
|
||||||
}
|
}
|
||||||
|
|
||||||
var prices []gasMeta
|
var prices []GasMeta
|
||||||
var blocks int
|
var blocks int
|
||||||
|
|
||||||
ts := cstore.GetHeaviestTipSet()
|
ts := cstore.GetHeaviestTipSet()
|
||||||
@ -157,17 +202,11 @@ func gasEstimateGasPremium(cstore *store.ChainStore, nblocksincl uint64) (types.
|
|||||||
}
|
}
|
||||||
|
|
||||||
blocks += len(pts.Blocks())
|
blocks += len(pts.Blocks())
|
||||||
|
meta, err := cache.GetTSGasStats(cstore, pts)
|
||||||
msgs, err := cstore.MessagesForTipset(pts)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return types.BigInt{}, xerrors.Errorf("loading messages: %w", err)
|
return types.BigInt{}, err
|
||||||
}
|
|
||||||
for _, msg := range msgs {
|
|
||||||
prices = append(prices, gasMeta{
|
|
||||||
price: msg.VMMessage().GasPremium,
|
|
||||||
limit: msg.VMMessage().GasLimit,
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
prices = append(prices, meta...)
|
||||||
|
|
||||||
ts = pts
|
ts = pts
|
||||||
}
|
}
|
||||||
|
@ -12,27 +12,27 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
func TestMedian(t *testing.T) {
|
func TestMedian(t *testing.T) {
|
||||||
require.Equal(t, types.NewInt(5), medianGasPremium([]gasMeta{
|
require.Equal(t, types.NewInt(5), medianGasPremium([]GasMeta{
|
||||||
{big.NewInt(5), build.BlockGasTarget},
|
{big.NewInt(5), build.BlockGasTarget},
|
||||||
}, 1))
|
}, 1))
|
||||||
|
|
||||||
require.Equal(t, types.NewInt(10), medianGasPremium([]gasMeta{
|
require.Equal(t, types.NewInt(10), medianGasPremium([]GasMeta{
|
||||||
{big.NewInt(5), build.BlockGasTarget},
|
{big.NewInt(5), build.BlockGasTarget},
|
||||||
{big.NewInt(10), build.BlockGasTarget},
|
{big.NewInt(10), build.BlockGasTarget},
|
||||||
}, 1))
|
}, 1))
|
||||||
|
|
||||||
require.Equal(t, types.NewInt(15), medianGasPremium([]gasMeta{
|
require.Equal(t, types.NewInt(15), medianGasPremium([]GasMeta{
|
||||||
{big.NewInt(10), build.BlockGasTarget / 2},
|
{big.NewInt(10), build.BlockGasTarget / 2},
|
||||||
{big.NewInt(20), build.BlockGasTarget / 2},
|
{big.NewInt(20), build.BlockGasTarget / 2},
|
||||||
}, 1))
|
}, 1))
|
||||||
|
|
||||||
require.Equal(t, types.NewInt(25), medianGasPremium([]gasMeta{
|
require.Equal(t, types.NewInt(25), medianGasPremium([]GasMeta{
|
||||||
{big.NewInt(10), build.BlockGasTarget / 2},
|
{big.NewInt(10), build.BlockGasTarget / 2},
|
||||||
{big.NewInt(20), build.BlockGasTarget / 2},
|
{big.NewInt(20), build.BlockGasTarget / 2},
|
||||||
{big.NewInt(30), build.BlockGasTarget / 2},
|
{big.NewInt(30), build.BlockGasTarget / 2},
|
||||||
}, 1))
|
}, 1))
|
||||||
|
|
||||||
require.Equal(t, types.NewInt(15), medianGasPremium([]gasMeta{
|
require.Equal(t, types.NewInt(15), medianGasPremium([]GasMeta{
|
||||||
{big.NewInt(10), build.BlockGasTarget / 2},
|
{big.NewInt(10), build.BlockGasTarget / 2},
|
||||||
{big.NewInt(20), build.BlockGasTarget / 2},
|
{big.NewInt(20), build.BlockGasTarget / 2},
|
||||||
{big.NewInt(30), build.BlockGasTarget / 2},
|
{big.NewInt(30), build.BlockGasTarget / 2},
|
||||||
|
Loading…
Reference in New Issue
Block a user