implement compute state trace output

This commit is contained in:
whyrusleeping 2020-03-07 18:31:36 -08:00
parent 24bf720a9a
commit 4260cc38c9
7 changed files with 89 additions and 24 deletions

View File

@ -138,7 +138,7 @@ type FullNode interface {
StateGetReceipt(context.Context, cid.Cid, types.TipSetKey) (*types.MessageReceipt, error)
StateMinerSectorCount(context.Context, address.Address, types.TipSetKey) (MinerSectors, error)
StateListRewards(context.Context, address.Address, types.TipSetKey) ([]reward.Reward, error)
StateCompute(context.Context, abi.ChainEpoch, []*types.Message, types.TipSetKey) (cid.Cid, error)
StateCompute(context.Context, abi.ChainEpoch, []*types.Message, types.TipSetKey) (*ComputeStateOutput, error)
MsigGetAvailableBalance(context.Context, address.Address, types.TipSetKey) (types.BigInt, error)
@ -362,6 +362,11 @@ type MpoolUpdate struct {
Message *types.SignedMessage
}
type ComputeStateOutput struct {
Root cid.Cid
Trace []*InvocResult
}
func ProofTypeFromSectorSize(ssize abi.SectorSize) (abi.RegisteredProof, abi.RegisteredProof, error) {
switch ssize {
case 2 << 10:

View File

@ -131,7 +131,7 @@ type FullNodeStruct struct {
StateMinerSectorCount func(context.Context, address.Address, types.TipSetKey) (api.MinerSectors, error) `perm:"read"`
StateListMessages func(ctx context.Context, match *types.Message, tsk types.TipSetKey, toht abi.ChainEpoch) ([]cid.Cid, error) `perm:"read"`
StateListRewards func(context.Context, address.Address, types.TipSetKey) ([]reward.Reward, error) `perm:"read"`
StateCompute func(context.Context, abi.ChainEpoch, []*types.Message, types.TipSetKey) (cid.Cid, error) `perm:"read"`
StateCompute func(context.Context, abi.ChainEpoch, []*types.Message, types.TipSetKey) (*api.ComputeStateOutput, error) `perm:"read"`
MsigGetAvailableBalance func(context.Context, address.Address, types.TipSetKey) (types.BigInt, error) `perm:"read"`
@ -537,7 +537,7 @@ func (c *FullNodeStruct) StateListRewards(ctx context.Context, miner address.Add
return c.Internal.StateListRewards(ctx, miner, tsk)
}
func (c *FullNodeStruct) StateCompute(ctx context.Context, height abi.ChainEpoch, msgs []*types.Message, tsk types.TipSetKey) (cid.Cid, error) {
func (c *FullNodeStruct) StateCompute(ctx context.Context, height abi.ChainEpoch, msgs []*types.Message, tsk types.TipSetKey) (*api.ComputeStateOutput, error) {
return c.Internal.StateCompute(ctx, height, msgs, tsk)
}

View File

@ -117,6 +117,27 @@ func (sm *StateManager) TipSetState(ctx context.Context, ts *types.TipSet) (st c
return st, rec, nil
}
func (sm *StateManager) ExecutionTrace(ctx context.Context, ts *types.TipSet) (cid.Cid, []*api.InvocResult, error) {
var trace []*api.InvocResult
st, _, err := sm.computeTipSetState(ctx, ts.Blocks(), func(mcid cid.Cid, msg *types.Message, ret *vm.ApplyRet) error {
ir := &api.InvocResult{
Msg: msg,
MsgRct: &ret.MessageReceipt,
InternalExecutions: ret.InternalExecutions,
}
if ret.ActorErr != nil {
ir.Error = ret.ActorErr.Error()
}
trace = append(trace, ir)
return nil
})
if err != nil {
return cid.Undef, nil, err
}
return st, trace, nil
}
type BlockMessages struct {
Miner address.Address
BlsMessages []store.ChainMsg
@ -131,10 +152,6 @@ func (sm *StateManager) ApplyBlocks(ctx context.Context, pstate cid.Cid, bms []B
return cid.Undef, cid.Undef, xerrors.Errorf("instantiating VM failed: %w", err)
}
/*
}
*/
applied := make(map[address.Address]uint64)
balances := make(map[address.Address]types.BigInt)
@ -203,7 +220,7 @@ func (sm *StateManager) ApplyBlocks(ctx context.Context, pstate cid.Cid, bms []B
return cid.Undef, cid.Undef, xerrors.Errorf("failed to get system actor: %w", err)
}
ret, err := vmi.ApplyMessage(ctx, &types.Message{
rwMsg := &types.Message{
From: builtin.SystemActorAddr,
To: builtin.RewardActorAddr,
Nonce: sysAct.Nonce,
@ -212,10 +229,17 @@ func (sm *StateManager) ApplyBlocks(ctx context.Context, pstate cid.Cid, bms []B
GasLimit: types.NewInt(1 << 30),
Method: builtin.MethodsReward.AwardBlockReward,
Params: params,
})
}
ret, err := vmi.ApplyMessage(ctx, rwMsg)
if err != nil {
return cid.Undef, cid.Undef, xerrors.Errorf("failed to apply reward message for miner %s: %w", b.Miner, err)
}
if cb != nil {
if err := cb(rwMsg.Cid(), rwMsg, ret); err != nil {
return cid.Undef, cid.Undef, xerrors.Errorf("callback failed on reward message: %w", err)
}
}
if ret.ExitCode != 0 {
return cid.Undef, cid.Undef, xerrors.Errorf("reward application message failed (exit %d): %s", ret.ExitCode, ret.ActorErr)
}
@ -228,7 +252,7 @@ func (sm *StateManager) ApplyBlocks(ctx context.Context, pstate cid.Cid, bms []B
return cid.Undef, cid.Undef, err
}
ret, err := vmi.ApplyMessage(ctx, &types.Message{
cronMsg := &types.Message{
To: builtin.CronActorAddr,
From: builtin.SystemActorAddr,
Nonce: ca.Nonce,
@ -237,10 +261,16 @@ func (sm *StateManager) ApplyBlocks(ctx context.Context, pstate cid.Cid, bms []B
GasLimit: types.NewInt(1 << 30), // Make super sure this is never too little
Method: builtin.MethodsCron.EpochTick,
Params: nil,
})
}
ret, err := vmi.ApplyMessage(ctx, cronMsg)
if err != nil {
return cid.Undef, cid.Undef, err
}
if cb != nil {
if err := cb(cronMsg.Cid(), cronMsg, ret); err != nil {
return cid.Undef, cid.Undef, xerrors.Errorf("callback failed on cron message: %w", err)
}
}
if ret.ExitCode != 0 {
return cid.Undef, cid.Undef, xerrors.Errorf("CheckProofSubmissions exit was non-zero: %d", ret.ExitCode)
}

View File

@ -308,36 +308,41 @@ func LoadSectorsFromSet(ctx context.Context, bs blockstore.Blockstore, ssc cid.C
return sset, nil
}
func ComputeState(ctx context.Context, sm *StateManager, height abi.ChainEpoch, msgs []*types.Message, ts *types.TipSet) (cid.Cid, error) {
func ComputeState(ctx context.Context, sm *StateManager, height abi.ChainEpoch, msgs []*types.Message, ts *types.TipSet) (cid.Cid, []*api.InvocResult, error) {
if ts == nil {
ts = sm.cs.GetHeaviestTipSet()
}
base, _, err := sm.TipSetState(ctx, ts)
base, trace, err := sm.ExecutionTrace(ctx, ts)
if err != nil {
return cid.Undef, err
return cid.Undef, nil, err
}
fstate, err := sm.handleStateForks(ctx, base, height, ts.Height())
if err != nil {
return cid.Undef, err
return cid.Undef, nil, err
}
r := store.NewChainRand(sm.cs, ts.Cids(), height)
vmi, err := vm.NewVM(fstate, height, r, builtin.SystemActorAddr, sm.cs.Blockstore(), sm.cs.VMSys())
if err != nil {
return cid.Undef, err
return cid.Undef, nil, err
}
for i, msg := range msgs {
ret, err := vmi.ApplyMessage(ctx, msg)
if err != nil {
return cid.Undef, xerrors.Errorf("applying message %s: %w", msg.Cid(), err)
return cid.Undef, nil, xerrors.Errorf("applying message %s: %w", msg.Cid(), err)
}
if ret.ExitCode != 0 {
log.Infof("compute state apply message %d failed (exit: %d): %s", i, ret.ExitCode, ret.ActorErr)
}
}
return vmi.Flush(ctx)
root, err := vmi.Flush(ctx)
if err != nil {
return cid.Undef, nil, err
}
return root, trace, nil
}

View File

@ -4,6 +4,7 @@ import (
"context"
"github.com/filecoin-project/specs-actors/actors/abi"
"github.com/filecoin-project/specs-actors/actors/builtin"
"github.com/filecoin-project/specs-actors/actors/crypto"
"github.com/filecoin-project/specs-actors/actors/runtime/exitcode"
"github.com/ipfs/go-cid"
@ -83,6 +84,9 @@ func (a *Applier) ApplyTipSetMessages(state vstate.VMWrapper, blocks []vtypes.Bl
var receipts []vtypes.MessageReceipt
sroot, _, err := sm.ApplyBlocks(context.TODO(), state.Root(), bms, epoch, &randWrapper{rnd}, func(c cid.Cid, msg *types.Message, ret *vm.ApplyRet) error {
if msg.From == builtin.SystemActorAddr {
return nil // ignore reward and cron calls
}
receipts = append(receipts, vtypes.MessageReceipt{
ExitCode: exitcode.ExitCode(ret.ExitCode),
ReturnValue: ret.Return,

View File

@ -5,11 +5,12 @@ import (
"context"
"encoding/json"
"fmt"
"github.com/filecoin-project/specs-actors/actors/builtin"
"reflect"
"strconv"
"strings"
"github.com/filecoin-project/specs-actors/actors/builtin"
"github.com/filecoin-project/go-address"
"github.com/filecoin-project/specs-actors/actors/abi"
"github.com/filecoin-project/specs-actors/actors/builtin/market"
@ -741,6 +742,10 @@ var stateComputeStateCmd = &cli.Command{
Name: "apply-mpool-messages",
Usage: "apply messages from the mempool to the computed state",
},
&cli.BoolFlag{
Name: "show-trace",
Usage: "print out full execution trace for given tipset",
},
},
Action: func(cctx *cli.Context) error {
api, closer, err := GetFullNodeAPI(cctx)
@ -785,12 +790,20 @@ var stateComputeStateCmd = &cli.Command{
}
}
nstate, err := api.StateCompute(ctx, h, msgs, ts.Key())
stout, err := api.StateCompute(ctx, h, msgs, ts.Key())
if err != nil {
return err
}
fmt.Println("computed state cid: ", nstate)
fmt.Println("computed state cid: ", stout.Root)
if cctx.Bool("show-trace") {
for _, ir := range stout.Trace {
fmt.Printf("%s\t%s\t%s\t%d\t%x\t%d\t%x\n", ir.Msg.From, ir.Msg.To, ir.Msg.Value, ir.Msg.Method, ir.Msg.Params, ir.MsgRct.ExitCode, ir.MsgRct.Return)
for _, im := range ir.InternalExecutions {
fmt.Printf("\t%s\t%s\t%s\t%d\t%x\t%d\t%x\n", im.Msg.From, im.Msg.To, im.Msg.Value, im.Msg.Method, im.Msg.Params, im.MsgRct.ExitCode, im.MsgRct.Return)
}
}
}
return nil
},
}

View File

@ -541,12 +541,20 @@ func (a *StateAPI) StateListMessages(ctx context.Context, match *types.Message,
return out, nil
}
func (a *StateAPI) StateCompute(ctx context.Context, height abi.ChainEpoch, msgs []*types.Message, tsk types.TipSetKey) (cid.Cid, error) {
func (a *StateAPI) StateCompute(ctx context.Context, height abi.ChainEpoch, msgs []*types.Message, tsk types.TipSetKey) (*api.ComputeStateOutput, error) {
ts, err := a.Chain.GetTipSetFromKey(tsk)
if err != nil {
return cid.Undef, xerrors.Errorf("loading tipset %s: %w", tsk, err)
return nil, xerrors.Errorf("loading tipset %s: %w", tsk, err)
}
return stmgr.ComputeState(ctx, a.StateManager, height, msgs, ts)
st, t, err := stmgr.ComputeState(ctx, a.StateManager, height, msgs, ts)
if err != nil {
return nil, err
}
return &api.ComputeStateOutput{
Root: st,
Trace: t,
}, nil
}
func (a *StateAPI) MsigGetAvailableBalance(ctx context.Context, addr address.Address, tsk types.TipSetKey) (types.BigInt, error) {