Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: cli: gas estimation tooling #9654

Merged
merged 4 commits into from
Nov 22, 2022
Merged
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Next Next commit
gas estimation shed command
  • Loading branch information
geoff-vball committed Nov 16, 2022

Verified

This commit was signed with the committer’s verified signature.
jkcdarunday Jan Keith Darunday
commit cde4b804e3e5b59795977ee409831cd1deff245b
4 changes: 4 additions & 0 deletions build/drand.go
Original file line number Diff line number Diff line change
@@ -69,6 +69,10 @@ var DrandConfigs = map[DrandEnum]dtypes.DrandConfig{
ChainInfoJSON: `{"public_key":"8cda589f88914aa728fd183f383980b35789ce81b274e5daee1f338b77d02566ef4d3fb0098af1f844f10f9c803c1827","period":25,"genesis_time":1595348225,"hash":"e73b7dc3c4f6a236378220c0dd6aa110eb16eed26c11259606e07ee122838d4f","groupHash":"567d4785122a5a3e75a9bc9911d7ea807dd85ff76b78dc4ff06b075712898607"}`,
},
DrandIncentinet: {
Servers: []string{
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What's going on here?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Due to some weird initialization stuff I do, the old beacon needs that. No idea why, that was the quickest fix for hacky code.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@geoff-vball Can you check if this is needed as part of this PR?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It is needed in the sense that if I remove it everything breaks. Whether or not its the best way to do things another question

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For the intrepid commit hunter, here's a summary of the underlying drand problem that needs to be resolved and an explanation for why this was needed here: #11802 (comment)

"https://dev1.drand.sh",
"https://dev2.drand.sh",
},
ChainInfoJSON: `{"public_key":"8cad0c72c606ab27d36ee06de1d5b2db1faf92e447025ca37575ab3a8aac2eaae83192f846fc9e158bc738423753d000","period":30,"genesis_time":1595873820,"hash":"80c8b872c714f4c00fdd3daa465d5514049f457f01f85a4caf68cdcd394ba039","groupHash":"d9406aaed487f7af71851b4399448e311f2328923d454e971536c05398ce2d9b"}`,
},
}
2 changes: 1 addition & 1 deletion chain/beacon/drand/drand.go
Original file line number Diff line number Diff line change
@@ -107,7 +107,7 @@ func NewDrandBeacon(genesisTs, interval uint64, ps *pubsub.PubSub, config dtypes

client, err := dclient.Wrap(clients, opts...)
if err != nil {
return nil, xerrors.Errorf("creating drand client")
return nil, xerrors.Errorf("creating drand client: %w", err)
}

lc, err := lru.New(1024)
77 changes: 77 additions & 0 deletions chain/stmgr/call.go
Original file line number Diff line number Diff line change
@@ -14,6 +14,7 @@ import (
"github.com/filecoin-project/go-state-types/abi"
"github.com/filecoin-project/go-state-types/big"
"github.com/filecoin-project/go-state-types/crypto"
"github.com/filecoin-project/go-state-types/network"

"github.com/filecoin-project/lotus/api"
"github.com/filecoin-project/lotus/blockstore"
@@ -153,6 +154,82 @@ func (sm *StateManager) Call(ctx context.Context, msg *types.Message, ts *types.
}, err
}

func (sm *StateManager) CallAtStateAndVersion(ctx context.Context, msg *types.Message, ts *types.TipSet, stateCid cid.Cid, v network.Version) (*api.InvocResult, error) {
r := rand.NewStateRand(sm.cs, ts.Cids(), sm.beacon, sm.GetNetworkVersion)

buffStore := blockstore.NewTieredBstore(sm.cs.StateBlockstore(), blockstore.NewMemorySync())
vmopt := &vm.VMOpts{
StateBase: stateCid,
Epoch: ts.Height() + 1,
Rand: r,
Bstore: buffStore,
Actors: sm.tsExec.NewActorRegistry(),
Syscalls: sm.Syscalls,
CircSupplyCalc: sm.GetVMCirculatingSupply,
NetworkVersion: v,
BaseFee: ts.Blocks()[0].ParentBaseFee,
LookbackState: LookbackStateGetterForTipset(sm, ts),
Tracing: true,
}

vmi, err := sm.newVM(ctx, vmopt)
if err != nil {
return nil, xerrors.Errorf("failed to set up vm: %w", err)
}

stTree, err := state.LoadStateTree(cbor.NewCborStore(buffStore), stateCid)
if err != nil {
return nil, xerrors.Errorf("loading state tree: %w", err)
}

fromActor, err := stTree.GetActor(msg.From)
if err != nil {
return nil, xerrors.Errorf("call raw get actor: %s", err)
}

msg.Nonce = fromActor.Nonce

fromKey, err := sm.ResolveToKeyAddress(ctx, msg.From, ts)
if err != nil {
return nil, xerrors.Errorf("could not resolve key: %w", err)
}

var msgApply types.ChainMsg

switch fromKey.Protocol() {
case address.BLS:
msgApply = msg
case address.SECP256K1:
msgApply = &types.SignedMessage{
Message: *msg,
Signature: crypto.Signature{
Type: crypto.SigTypeSecp256k1,
Data: make([]byte, 65),
},
}
}

ret, err := vmi.ApplyMessage(ctx, msgApply)
if err != nil {
return nil, xerrors.Errorf("gas estimation failed: %w", err)
}

var errs string
if ret.ActorErr != nil {
errs = ret.ActorErr.Error()
}

return &api.InvocResult{
MsgCid: msg.Cid(),
Msg: msg,
MsgRct: &ret.MessageReceipt,
GasCost: MakeMsgGasCost(msg, ret),
ExecutionTrace: ret.ExecutionTrace,
Error: errs,
Duration: ret.Duration,
}, nil
}

func (sm *StateManager) CallWithGas(ctx context.Context, msg *types.Message, priorMsgs []types.ChainMsg, ts *types.TipSet) (*api.InvocResult, error) {
ctx, span := trace.StartSpan(ctx, "statemanager.CallWithGas")
defer span.End()
153 changes: 153 additions & 0 deletions cmd/lotus-shed/gas-estimation.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,153 @@
package main

import (
"context"
"fmt"
"io"
"os"
"strconv"
"text/tabwriter"

"github.com/filecoin-project/go-state-types/abi"

"github.com/filecoin-project/go-state-types/network"

"github.com/ipfs/go-cid"
"github.com/urfave/cli/v2"
"golang.org/x/xerrors"

"github.com/filecoin-project/lotus/build"
"github.com/filecoin-project/lotus/chain/beacon"
"github.com/filecoin-project/lotus/chain/beacon/drand"
"github.com/filecoin-project/lotus/chain/consensus/filcns"
"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/lotus/chain/vm"
lcli "github.com/filecoin-project/lotus/cli"
"github.com/filecoin-project/lotus/node/repo"
"github.com/filecoin-project/lotus/storage/sealer/ffiwrapper"
)

var gasEstimationCmd = &cli.Command{
Name: "estimate-gas",
Description: "replay a message on the specified stateRoot and network version",
ArgsUsage: "[migratedStateRootCid migrationEpoch networkVersion messageHash]",
Flags: []cli.Flag{
&cli.StringFlag{
Name: "repo",
Value: "~/.lotus",
},
},
Action: func(cctx *cli.Context) error {
ctx := context.TODO()

if cctx.NArg() != 4 {
return lcli.IncorrectNumArgs(cctx)
}

stateRootCid, err := cid.Decode(cctx.Args().Get(0))
if err != nil {
return fmt.Errorf("failed to parse input: %w", err)
}

epoch, err := strconv.ParseInt(cctx.Args().Get(1), 10, 64)
if err != nil {
return fmt.Errorf("failed to parse input: %w", err)
}

nv, err := strconv.ParseInt(cctx.Args().Get(2), 10, 64)
if err != nil {
return fmt.Errorf("failed to parse input: %w", err)
}

messageCid, err := cid.Decode(cctx.Args().Get(3))
if err != nil {
return fmt.Errorf("failed to parse input: %w", err)
}

fsrepo, err := repo.NewFS(cctx.String("repo"))
if err != nil {
return err
}

lkrepo, err := fsrepo.Lock(repo.FullNode)
if err != nil {
return err
}

defer lkrepo.Close() //nolint:errcheck

bs, err := lkrepo.Blockstore(ctx, repo.UniversalBlockstore)
if err != nil {
return fmt.Errorf("failed to open blockstore: %w", err)
}

defer func() {
if c, ok := bs.(io.Closer); ok {
if err := c.Close(); err != nil {
log.Warnf("failed to close blockstore: %s", err)
}
}
}()

mds, err := lkrepo.Datastore(context.Background(), "/metadata")
if err != nil {
return err
}

dcs := build.DrandConfigSchedule()
shd := beacon.Schedule{}
for _, dc := range dcs {
bc, err := drand.NewDrandBeacon(1598306400, build.BlockDelaySecs, nil, dc.Config)
if err != nil {
return xerrors.Errorf("creating drand beacon: %w", err)
}
shd = append(shd, beacon.BeaconPoint{Start: dc.Start, Beacon: bc})
}
cs := store.NewChainStore(bs, bs, mds, filcns.Weight, nil)
defer cs.Close() //nolint:errcheck

sm, err := stmgr.NewStateManager(cs, filcns.NewTipSetExecutor(), vm.Syscalls(ffiwrapper.ProofVerifier), filcns.DefaultUpgradeSchedule(), shd)
if err != nil {
return err
}

msg, err := cs.GetMessage(ctx, messageCid)
if err != nil {
return err
}

// Set to block limit so message will not run out of gas
msg.GasLimit = 10_000_000_000

err = cs.Load(ctx)
if err != nil {
return err
}

executionTs, err := cs.GetTipsetByHeight(ctx, abi.ChainEpoch(epoch), nil, false)
if err != nil {
return err
}

tw := tabwriter.NewWriter(os.Stdout, 2, 2, 2, ' ', 0)
res, err := sm.CallAtStateAndVersion(ctx, msg, executionTs, stateRootCid, network.Version(nv))
if err != nil {
return err
}
printInternalExecutions(0, []types.ExecutionTrace{res.ExecutionTrace}, tw)

return tw.Flush()
},
}

func printInternalExecutions(depth int, trace []types.ExecutionTrace, tw *tabwriter.Writer) {
if depth == 0 {
_, _ = fmt.Fprintf(tw, "depth\tFrom\tTo\tValue\tMethod\tGasUsed\tExitCode\tReturn\n")
}
for _, im := range trace {
_, _ = fmt.Fprintf(tw, "%d\t%s\t%s\t%s\t%d\t%d\t%d\t%x\n", depth, im.Msg.From, im.Msg.To, im.Msg.Value, im.Msg.Method, im.MsgRct.GasUsed, im.MsgRct.ExitCode, im.MsgRct.Return)
printInternalExecutions(depth+1, im.Subcalls, tw)
}
}
1 change: 1 addition & 0 deletions cmd/lotus-shed/main.go
Original file line number Diff line number Diff line change
@@ -76,6 +76,7 @@ func main() {
msigCmd,
fip36PollCmd,
invariantsCmd,
gasEstimationCmd,
}

app := &cli.App{