Merge pull request #2756 from filecoin-project/feat/better-gas-price-est

Improve gas price estimator
This commit is contained in:
Jakub Sztandera 2020-08-01 22:04:42 +02:00 committed by GitHub
commit 113681fcc4
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
12 changed files with 178 additions and 86 deletions

View File

@ -27,13 +27,16 @@ func (ts *testSuite) testMining(t *testing.T) {
apis, sn := ts.makeNodes(t, 1, oneMiner)
api := apis[0]
h1, err := api.ChainHead(ctx)
require.NoError(t, err)
require.Equal(t, abi.ChainEpoch(1), h1.Height())
newHeads, err := api.ChainNotify(ctx)
require.NoError(t, err)
<-newHeads
initHead := (<-newHeads)[0]
if initHead.Val.Height() != 2 {
<-newHeads
}
h1, err := api.ChainHead(ctx)
require.NoError(t, err)
require.Equal(t, abi.ChainEpoch(2), h1.Height())
err = sn[0].MineOne(ctx, MineNext)
require.NoError(t, err)
@ -42,7 +45,7 @@ func (ts *testSuite) testMining(t *testing.T) {
h2, err := api.ChainHead(ctx)
require.NoError(t, err)
require.Equal(t, abi.ChainEpoch(2), h2.Height())
require.Equal(t, abi.ChainEpoch(3), h2.Height())
}
func (ts *testSuite) testMiningReal(t *testing.T) {
@ -55,13 +58,16 @@ func (ts *testSuite) testMiningReal(t *testing.T) {
apis, sn := ts.makeNodes(t, 1, oneMiner)
api := apis[0]
h1, err := api.ChainHead(ctx)
require.NoError(t, err)
require.Equal(t, abi.ChainEpoch(1), h1.Height())
newHeads, err := api.ChainNotify(ctx)
require.NoError(t, err)
<-newHeads
initHead := (<-newHeads)[0]
if initHead.Val.Height() != 2 {
<-newHeads
}
h1, err := api.ChainHead(ctx)
require.NoError(t, err)
require.Equal(t, abi.ChainEpoch(2), h1.Height())
err = sn[0].MineOne(ctx, MineNext)
require.NoError(t, err)
@ -70,7 +76,7 @@ func (ts *testSuite) testMiningReal(t *testing.T) {
h2, err := api.ChainHead(ctx)
require.NoError(t, err)
require.Equal(t, abi.ChainEpoch(2), h2.Height())
require.Equal(t, abi.ChainEpoch(3), h2.Height())
err = sn[0].MineOne(ctx, MineNext)
require.NoError(t, err)
@ -79,7 +85,7 @@ func (ts *testSuite) testMiningReal(t *testing.T) {
h2, err = api.ChainHead(ctx)
require.NoError(t, err)
require.Equal(t, abi.ChainEpoch(3), h2.Height())
require.Equal(t, abi.ChainEpoch(4), h2.Height())
}
func TestDealMining(t *testing.T, b APIBuilder, blocktime time.Duration, carExport bool) {

View File

@ -46,6 +46,7 @@ var chainCmd = &cli.Command{
chainBisectCmd,
chainExportCmd,
slashConsensusFault,
chainGasPriceCmd,
},
}
@ -931,13 +932,11 @@ var slashConsensusFault = &cli.Command{
}
msg := &types.Message{
To: maddr,
From: def,
Value: types.NewInt(0),
GasPrice: types.NewInt(1),
GasLimit: 0,
Method: builtin.MethodsMiner.ReportConsensusFault,
Params: enc,
To: maddr,
From: def,
Value: types.NewInt(0),
Method: builtin.MethodsMiner.ReportConsensusFault,
Params: enc,
}
smsg, err := api.MpoolPushMessage(ctx, msg)
@ -950,3 +949,30 @@ var slashConsensusFault = &cli.Command{
return nil
},
}
var chainGasPriceCmd = &cli.Command{
Name: "gas-price",
Usage: "Estimate gas prices",
Action: func(cctx *cli.Context) error {
api, closer, err := GetFullNodeAPI(cctx)
if err != nil {
return err
}
defer closer()
ctx := ReqContext(cctx)
nb := []int{1, 2, 3, 5, 10, 20, 50, 100, 300}
for _, nblocks := range nb {
addr := builtin.SystemActorAddr // TODO: make real when used in GasEstimateGasPrice
est, err := api.GasEstimateGasPrice(ctx, uint64(nblocks), addr, 10000, types.EmptyTSK)
if err != nil {
return err
}
fmt.Printf("%d blocks: %s (%s)\n", nblocks, est, types.FIL(est))
}
return nil
},
}

View File

@ -86,12 +86,10 @@ var noncefix = &cli.Command{
for i := start; i < end; i++ {
msg := &types.Message{
From: addr,
To: addr,
Value: types.NewInt(1),
GasLimit: 0,
GasPrice: types.NewInt(1),
Nonce: i,
From: addr,
To: addr,
Value: types.NewInt(1),
Nonce: i,
}
smsg, err := api.WalletSignMessage(ctx, addr, msg)
if err != nil {

View File

@ -69,12 +69,10 @@ var verifRegAddVerifierCmd = &cli.Command{
ctx := lcli.ReqContext(cctx)
msg := &types.Message{
To: builtin.VerifiedRegistryActorAddr,
From: fromk,
Method: builtin.MethodsVerifiedRegistry.AddVerifier,
GasPrice: types.NewInt(1),
GasLimit: 0,
Params: params,
To: builtin.VerifiedRegistryActorAddr,
From: fromk,
Method: builtin.MethodsVerifiedRegistry.AddVerifier,
Params: params,
}
smsg, err := api.MpoolPushMessage(ctx, msg)

View File

@ -78,7 +78,6 @@ var actorSetAddrsCmd = &cli.Command{
To: maddr,
From: minfo.Worker,
Value: types.NewInt(0),
GasPrice: types.NewInt(1),
GasLimit: gasLimit,
Method: 18,
Params: params,

6
go.sum
View File

@ -40,6 +40,7 @@ github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03
github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo=
github.com/DataDog/zstd v1.4.1 h1:3oxKN3wbHibqx897utPC2LTQU4J+IHWWJO+glkAkpFM=
github.com/DataDog/zstd v1.4.1/go.mod h1:1jcaCB/ufaK+sKp1NBhlGmpz41jOoPQ35bpF36t7BBo=
github.com/GeertJohan/go.incremental v1.0.0 h1:7AH+pY1XUgQE4Y1HcXYaMqAI0m9yrFqo/jt0CW30vsg=
github.com/GeertJohan/go.incremental v1.0.0/go.mod h1:6fAjUhbVuX1KcMD3c8TEgVUqmo4seqhv0i0kdATSkM0=
github.com/GeertJohan/go.rice v1.0.0 h1:KkI6O9uMaQU3VEKaj01ulavtF7o1fWT7+pk/4voiMLQ=
github.com/GeertJohan/go.rice v1.0.0/go.mod h1:eH6gbSOAUv07dQuZVnBmoDP8mgsM1rtixis4Tib9if0=
@ -59,6 +60,7 @@ github.com/Stebalien/go-bitfield v0.0.1/go.mod h1:GNjFpasyUVkHMsfEOk8EFLJ9syQ6SI
github.com/VividCortex/gohistogram v1.0.0/go.mod h1:Pf5mBqqDxYaXu3hDrrU+w6nw50o/4+TcAqDqk/vUH7g=
github.com/aead/siphash v1.0.1/go.mod h1:Nywa3cDsYNNK3gaciGTWPwHt0wlpNV15vwmswBAUSII=
github.com/afex/hystrix-go v0.0.0-20180502004556-fa1af6a1f4f5/go.mod h1:SkGFH1ia65gfNATL8TAiHDNxPzPdmEL5uirI2Uyuz6c=
github.com/akavel/rsrc v0.8.0 h1:zjWn7ukO9Kc5Q62DOJCcxGpXC18RawVtYAGdz2aLlfw=
github.com/akavel/rsrc v0.8.0/go.mod h1:uLoCtb9J+EyAqh+26kdrTgmzRBFPGOolLWKpdxkKq+c=
github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=
github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751 h1:JYp7IbQjafoB+tBA3gMyHYHrpOtNuDiK/uB5uXxq5wM=
@ -653,6 +655,7 @@ github.com/jbenet/goprocess v0.1.4 h1:DRGOFReOMqqDNXwW70QkacFW0YN9QnwLV0Vqk+3oU0
github.com/jbenet/goprocess v0.1.4/go.mod h1:5yspPrukOVuOLORacaBi858NqyClJPQxYZlqdZVfqY4=
github.com/jellevandenhooff/dkim v0.0.0-20150330215556-f50fe3d243e1/go.mod h1:E0B/fFc00Y+Rasa88328GlI/XbtyysCtTHZS8h7IrBU=
github.com/jessevdk/go-flags v0.0.0-20141203071132-1679536dcc89/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI=
github.com/jessevdk/go-flags v1.4.0 h1:4IU2WS7AumrZ/40jfhf4QVDMsQwqA7VEHozFRrGARJA=
github.com/jessevdk/go-flags v1.4.0/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI=
github.com/jmespath/go-jmespath v0.0.0-20180206201540-c2b33e8439af/go.mod h1:Nht3zPeWKUH0NzdCt2Blrr5ys8VGpn0CEB0cQHVjt7k=
github.com/jmespath/go-jmespath v0.3.0/go.mod h1:9QtRXoHjLGCJ5IBSaohpXITPlowMeeYCZ7fLUTSywik=
@ -1137,6 +1140,7 @@ github.com/neelance/astrewrite v0.0.0-20160511093645-99348263ae86/go.mod h1:kHJE
github.com/neelance/sourcemap v0.0.0-20151028013722-8c68805598ab/go.mod h1:Qr6/a/Q4r9LP1IltGz7tA7iOK1WonHEYhu1HRBA7ZiM=
github.com/nikkolasg/hexjson v0.0.0-20181101101858-78e39397e00c h1:5bFTChQxSKNwy8ALwOebjekYExl9HTT9urdawqC95tA=
github.com/nikkolasg/hexjson v0.0.0-20181101101858-78e39397e00c/go.mod h1:7qN3Y0BvzRUf4LofcoJplQL10lsFDb4PYlePTVwrP28=
github.com/nkovacs/streamquote v0.0.0-20170412213628-49af9bddb229 h1:E2B8qYyeSgv5MXpmzZXRNp8IAQ4vjxIjhpAf5hv/tAg=
github.com/nkovacs/streamquote v0.0.0-20170412213628-49af9bddb229/go.mod h1:0aYXnNPJ8l7uZxf45rWW1a/uME32OF0rhiYGNQ2oF2E=
github.com/nxadm/tail v1.4.4 h1:DQuhQpB1tVlglWS2hLQ5OV6B5r8aGxSrPc5Qo6uTN78=
github.com/nxadm/tail v1.4.4/go.mod h1:kenIhsEOeOJmVchQTgglprH7qJGnHDVpk1VPCcaMI8A=
@ -1346,7 +1350,9 @@ github.com/urfave/cli v1.22.1/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtX
github.com/urfave/cli/v2 v2.0.0/go.mod h1:SE9GqnLQmjVa0iPEY0f1w3ygNIYcIJ0OKPMoW2caLfQ=
github.com/urfave/cli/v2 v2.2.0 h1:JTTnM6wKzdA0Jqodd966MVj4vWbbquZykeX1sKbe2C4=
github.com/urfave/cli/v2 v2.2.0/go.mod h1:SE9GqnLQmjVa0iPEY0f1w3ygNIYcIJ0OKPMoW2caLfQ=
github.com/valyala/bytebufferpool v1.0.0 h1:GqA5TC/0021Y/b9FG4Oi9Mr3q7XYx6KllzawFIhcdPw=
github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc=
github.com/valyala/fasttemplate v1.0.1 h1:tY9CJiPnMXf1ERmG2EyK7gNUd+c6RKGD0IfU8WdUSz8=
github.com/valyala/fasttemplate v1.0.1/go.mod h1:UQGH1tvbgY+Nz5t2n7tXsz52dQxojPUpymEIMZ47gx8=
github.com/viant/assertly v0.4.8/go.mod h1:aGifi++jvCrUaklKEKT0BU95igDNaqkvz+49uaYMPRU=
github.com/viant/toolbox v0.24.0/go.mod h1:OxMCG57V0PXuIP2HNQrtJf2CjqdmbrOx5EkMILuUhzM=

View File

@ -70,7 +70,7 @@ type API struct {
Imports dtypes.ClientImportMgr
CombinedBstore dtypes.ClientBlockstore // TODO: try to remove
CombinedBstore dtypes.ClientBlockstore // TODO: try to remove
RetrievalStoreMgr dtypes.ClientRetrievalStoreManager
}

View File

@ -2,14 +2,18 @@ package full
import (
"context"
"sort"
"github.com/filecoin-project/go-address"
"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"
"github.com/filecoin-project/go-address"
"github.com/filecoin-project/specs-actors/actors/abi/big"
"github.com/filecoin-project/specs-actors/actors/runtime/exitcode"
"go.uber.org/fx"
"golang.org/x/xerrors"
)
@ -17,7 +21,7 @@ import (
type GasAPI struct {
fx.In
Stmgr *stmgr.StateManager
Cs *store.ChainStore
Chain *store.ChainStore
Mpool *messagepool.MessagePool
}
@ -26,11 +30,77 @@ const MinGasPrice = 1
func (a *GasAPI) GasEstimateGasPrice(ctx context.Context, nblocksincl uint64,
sender address.Address, gaslimit int64, tsk types.TipSetKey) (types.BigInt, error) {
// TODO: something smarter obviously
if nblocksincl == 0 {
nblocksincl = 1
}
type gasMeta struct {
price big.Int
used int64
}
var prices []gasMeta
var gasUsed int64
var blocks int
ts := a.Chain.GetHeaviestTipSet()
for i := uint64(0); i < nblocksincl*2; i++ {
if len(ts.Parents().Cids()) == 0 {
break // genesis
}
pts, err := a.Chain.LoadTipSet(ts.Parents())
if err != nil {
return types.BigInt{}, err
}
blocks += len(pts.Blocks())
msgs, err := a.Chain.MessagesForTipset(pts)
if err != nil {
return types.BigInt{}, xerrors.Errorf("loading messages: %w", err)
}
for i, msg := range msgs {
r, err := a.Chain.GetParentReceipt(ts.MinTicketBlock(), i)
if err != nil {
return types.BigInt{}, xerrors.Errorf("getting receipt: %w", err)
}
prices = append(prices, gasMeta{
price: msg.VMMessage().GasPrice,
used: r.GasUsed,
})
gasUsed += r.GasUsed
}
ts = pts
}
sort.Slice(prices, func(i, j int) bool {
// sort desc by price
return prices[i].price.GreaterThan(prices[j].price)
})
// todo: account for how full blocks are
at := gasUsed / 2
prev := big.Zero()
for _, price := range prices {
at -= price.used
if at > 0 {
prev = price.price
continue
}
return types.BigAdd(big.Div(types.BigAdd(price.price, prev), types.NewInt(2)), big.NewInt(1)), nil
}
switch nblocksincl {
case 0:
return types.NewInt(MinGasPrice + 2), nil
case 1:
return types.NewInt(MinGasPrice + 2), nil
case 2:
return types.NewInt(MinGasPrice + 1), nil
default:
return types.NewInt(MinGasPrice), nil
@ -43,7 +113,7 @@ func (a *GasAPI) GasEstimateGasLimit(ctx context.Context, msgIn *types.Message,
msg.GasLimit = build.BlockGasLimit
msg.GasPrice = types.NewInt(1)
currTs := a.Cs.GetHeaviestTipSet()
currTs := a.Chain.GetHeaviestTipSet()
fromA, err := a.Stmgr.ResolveToKeyAddress(ctx, msgIn.From, currTs)
if err != nil {
return -1, xerrors.Errorf("getting key address: %w", err)

View File

@ -87,7 +87,7 @@ func (a *MpoolAPI) MpoolPush(ctx context.Context, smsg *types.SignedMessage) (ci
return a.Mpool.Push(smsg)
}
// GasMargin sets by how much should gas limit be increased over test execution
// GasMargin sets by how much should gas used be increased over test execution
var GasMargin = 1.5
func (a *MpoolAPI) MpoolPushMessage(ctx context.Context, msg *types.Message) (*types.SignedMessage, error) {
@ -97,7 +97,7 @@ func (a *MpoolAPI) MpoolPushMessage(ctx context.Context, msg *types.Message) (*t
if msg.GasLimit == 0 {
gasLimit, err := a.GasEstimateGasLimit(ctx, msg, types.TipSetKey{})
if err != nil {
return nil, xerrors.Errorf("estimating gas limit: %w", err)
return nil, xerrors.Errorf("estimating gas used: %w", err)
}
msg.GasLimit = int64(float64(gasLimit) * GasMargin)
}

View File

@ -28,6 +28,7 @@ type MsigAPI struct {
MpoolAPI MpoolAPI
}
// TODO: remove gp (gasPrice) from arguemnts
func (a *MsigAPI) MsigCreate(ctx context.Context, req uint64, addrs []address.Address, duration abi.ChainEpoch, val types.BigInt, src address.Address, gp types.BigInt) (cid.Cid, error) {
lenAddrs := uint64(len(addrs))
@ -45,7 +46,7 @@ func (a *MsigAPI) MsigCreate(ctx context.Context, req uint64, addrs []address.Ad
}
if gp == types.EmptyInt {
gp = types.NewInt(1)
gp = types.NewInt(0)
}
// Set up constructor parameters for multisig
@ -77,9 +78,8 @@ func (a *MsigAPI) MsigCreate(ctx context.Context, req uint64, addrs []address.Ad
From: src,
Method: builtin.MethodsInit.Exec,
Params: enc,
GasPrice: gp,
GasLimit: 0,
Value: val,
GasPrice: gp,
}
// send the message out to the network
@ -120,13 +120,11 @@ func (a *MsigAPI) MsigPropose(ctx context.Context, msig address.Address, to addr
}
msg := &types.Message{
To: msig,
From: src,
Value: types.NewInt(0),
Method: builtin.MethodsMultisig.Propose,
Params: enc,
GasLimit: 0,
GasPrice: types.NewInt(1),
To: msig,
From: src,
Value: types.NewInt(0),
Method: builtin.MethodsMultisig.Propose,
Params: enc,
}
smsg, err := a.MpoolAPI.MpoolPushMessage(ctx, msg)
@ -236,13 +234,11 @@ func (a *MsigAPI) msigApproveOrCancel(ctx context.Context, operation api.MsigPro
}
msg := &types.Message{
To: msig,
From: src,
Value: types.NewInt(0),
Method: msigResponseMethod,
Params: enc,
GasLimit: 0,
GasPrice: types.NewInt(1),
To: msig,
From: src,
Value: types.NewInt(0),
Method: msigResponseMethod,
Params: enc,
}
smsg, err := a.MpoolAPI.MpoolPushMessage(ctx, msg)

View File

@ -122,13 +122,11 @@ func (s SealingAPIAdapter) StateComputeDataCommitment(ctx context.Context, maddr
}
ccmt := &types.Message{
To: builtin.StorageMarketActorAddr,
From: maddr,
Value: types.NewInt(0),
GasPrice: types.NewInt(0),
GasLimit: 0,
Method: builtin.MethodsMarket.ComputeDataCommitment,
Params: ccparams,
To: builtin.StorageMarketActorAddr,
From: maddr,
Value: types.NewInt(0),
Method: builtin.MethodsMarket.ComputeDataCommitment,
Params: ccparams,
}
r, err := s.delegate.StateCall(ctx, ccmt, tsk)
if err != nil {

View File

@ -171,13 +171,11 @@ func (s *WindowPoStScheduler) checkNextRecoveries(ctx context.Context, dlIdx uin
}
msg := &types.Message{
To: s.actor,
From: s.worker,
Method: builtin.MethodsMiner.DeclareFaultsRecovered,
Params: enc,
Value: types.NewInt(0),
GasLimit: 0,
GasPrice: types.NewInt(2),
To: s.actor,
From: s.worker,
Method: builtin.MethodsMiner.DeclareFaultsRecovered,
Params: enc,
Value: types.NewInt(0),
}
sm, err := s.api.MpoolPushMessage(ctx, msg)
@ -255,13 +253,11 @@ func (s *WindowPoStScheduler) checkNextFaults(ctx context.Context, dlIdx uint64,
}
msg := &types.Message{
To: s.actor,
From: s.worker,
Method: builtin.MethodsMiner.DeclareFaults,
Params: enc,
Value: types.NewInt(0), // TODO: Is there a fee?
GasLimit: 0,
GasPrice: types.NewInt(2),
To: s.actor,
From: s.worker,
Method: builtin.MethodsMiner.DeclareFaults,
Params: enc,
Value: types.NewInt(0), // TODO: Is there a fee?
}
sm, err := s.api.MpoolPushMessage(ctx, msg)
@ -457,12 +453,11 @@ func (s *WindowPoStScheduler) submitPost(ctx context.Context, proof *miner.Submi
}
msg := &types.Message{
To: s.actor,
From: s.worker,
Method: builtin.MethodsMiner.SubmitWindowedPoSt,
Params: enc,
Value: types.NewInt(1000), // currently hard-coded late fee in actor, returned if not late
GasPrice: types.NewInt(3),
To: s.actor,
From: s.worker,
Method: builtin.MethodsMiner.SubmitWindowedPoSt,
Params: enc,
Value: types.NewInt(1000), // currently hard-coded late fee in actor, returned if not late
}
// TODO: consider maybe caring about the output