diff --git a/cli/chain.go b/cli/chain.go index 8ae2c3c5e..dcd3b1ad4 100644 --- a/cli/chain.go +++ b/cli/chain.go @@ -46,6 +46,7 @@ var chainCmd = &cli.Command{ chainBisectCmd, chainExportCmd, slashConsensusFault, + chainGasPriceCmd, }, } @@ -950,3 +951,31 @@ 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 + }, +} + diff --git a/go.sum b/go.sum index 4cc5b32b8..6a2419eba 100644 --- a/go.sum +++ b/go.sum @@ -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= diff --git a/node/impl/full/gas.go b/node/impl/full/gas.go index 74b288640..3694de731 100644 --- a/node/impl/full/gas.go +++ b/node/impl/full/gas.go @@ -2,6 +2,8 @@ package full import ( "context" + "github.com/filecoin-project/specs-actors/actors/abi/big" + "sort" "github.com/filecoin-project/go-address" "github.com/filecoin-project/lotus/build" @@ -17,7 +19,7 @@ import ( type GasAPI struct { fx.In Stmgr *stmgr.StateManager - Cs *store.ChainStore + Chain *store.ChainStore Mpool *messagepool.MessagePool } @@ -26,11 +28,75 @@ 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 + + for _, price := range prices { + at -= price.used + if at > 0 { + continue + } + + return price.price, 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 +109,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) diff --git a/node/impl/full/mpool.go b/node/impl/full/mpool.go index 7979cec8e..a6fd4ba6b 100644 --- a/node/impl/full/mpool.go +++ b/node/impl/full/mpool.go @@ -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) }