Merge pull request #1354 from filecoin-project/feat/state-compute-trace

implement compute state trace output
This commit is contained in:
Whyrusleeping 2020-03-08 21:22:40 -07:00 committed by GitHub
commit 3a94d9d176
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) StateGetReceipt(context.Context, cid.Cid, types.TipSetKey) (*types.MessageReceipt, error)
StateMinerSectorCount(context.Context, address.Address, types.TipSetKey) (MinerSectors, error) StateMinerSectorCount(context.Context, address.Address, types.TipSetKey) (MinerSectors, error)
StateListRewards(context.Context, address.Address, types.TipSetKey) ([]reward.Reward, 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) MsigGetAvailableBalance(context.Context, address.Address, types.TipSetKey) (types.BigInt, error)
@ -367,6 +367,11 @@ type MpoolUpdate struct {
Message *types.SignedMessage Message *types.SignedMessage
} }
type ComputeStateOutput struct {
Root cid.Cid
Trace []*InvocResult
}
func ProofTypeFromSectorSize(ssize abi.SectorSize) (abi.RegisteredProof, abi.RegisteredProof, error) { func ProofTypeFromSectorSize(ssize abi.SectorSize) (abi.RegisteredProof, abi.RegisteredProof, error) {
switch ssize { switch ssize {
case 2 << 10: 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"` 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"` 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"` 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"` 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) 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) 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 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 { type BlockMessages struct {
Miner address.Address Miner address.Address
BlsMessages []store.ChainMsg 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) return cid.Undef, cid.Undef, xerrors.Errorf("instantiating VM failed: %w", err)
} }
/*
}
*/
applied := make(map[address.Address]uint64) applied := make(map[address.Address]uint64)
balances := make(map[address.Address]types.BigInt) 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) 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, From: builtin.SystemActorAddr,
To: builtin.RewardActorAddr, To: builtin.RewardActorAddr,
Nonce: sysAct.Nonce, Nonce: sysAct.Nonce,
@ -212,10 +229,17 @@ func (sm *StateManager) ApplyBlocks(ctx context.Context, pstate cid.Cid, bms []B
GasLimit: types.NewInt(1 << 30), GasLimit: types.NewInt(1 << 30),
Method: builtin.MethodsReward.AwardBlockReward, Method: builtin.MethodsReward.AwardBlockReward,
Params: params, Params: params,
}) }
ret, err := vmi.ApplyMessage(ctx, rwMsg)
if err != nil { if err != nil {
return cid.Undef, cid.Undef, xerrors.Errorf("failed to apply reward message for miner %s: %w", b.Miner, err) 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 { if ret.ExitCode != 0 {
return cid.Undef, cid.Undef, xerrors.Errorf("reward application message failed (exit %d): %s", ret.ExitCode, ret.ActorErr) 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 return cid.Undef, cid.Undef, err
} }
ret, err := vmi.ApplyMessage(ctx, &types.Message{ cronMsg := &types.Message{
To: builtin.CronActorAddr, To: builtin.CronActorAddr,
From: builtin.SystemActorAddr, From: builtin.SystemActorAddr,
Nonce: ca.Nonce, 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 GasLimit: types.NewInt(1 << 30), // Make super sure this is never too little
Method: builtin.MethodsCron.EpochTick, Method: builtin.MethodsCron.EpochTick,
Params: nil, Params: nil,
}) }
ret, err := vmi.ApplyMessage(ctx, cronMsg)
if err != nil { if err != nil {
return cid.Undef, cid.Undef, err 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 { if ret.ExitCode != 0 {
return cid.Undef, cid.Undef, xerrors.Errorf("CheckProofSubmissions exit was non-zero: %d", ret.ExitCode) 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 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 { if ts == nil {
ts = sm.cs.GetHeaviestTipSet() ts = sm.cs.GetHeaviestTipSet()
} }
base, _, err := sm.TipSetState(ctx, ts) base, trace, err := sm.ExecutionTrace(ctx, ts)
if err != nil { if err != nil {
return cid.Undef, err return cid.Undef, nil, err
} }
fstate, err := sm.handleStateForks(ctx, base, height, ts.Height()) fstate, err := sm.handleStateForks(ctx, base, height, ts.Height())
if err != nil { if err != nil {
return cid.Undef, err return cid.Undef, nil, err
} }
r := store.NewChainRand(sm.cs, ts.Cids(), height) r := store.NewChainRand(sm.cs, ts.Cids(), height)
vmi, err := vm.NewVM(fstate, height, r, builtin.SystemActorAddr, sm.cs.Blockstore(), sm.cs.VMSys()) vmi, err := vm.NewVM(fstate, height, r, builtin.SystemActorAddr, sm.cs.Blockstore(), sm.cs.VMSys())
if err != nil { if err != nil {
return cid.Undef, err return cid.Undef, nil, err
} }
for i, msg := range msgs { for i, msg := range msgs {
ret, err := vmi.ApplyMessage(ctx, msg) ret, err := vmi.ApplyMessage(ctx, msg)
if err != nil { 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 { if ret.ExitCode != 0 {
log.Infof("compute state apply message %d failed (exit: %d): %s", i, ret.ExitCode, ret.ActorErr) 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" "context"
"github.com/filecoin-project/specs-actors/actors/abi" "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/crypto"
"github.com/filecoin-project/specs-actors/actors/runtime/exitcode" "github.com/filecoin-project/specs-actors/actors/runtime/exitcode"
"github.com/ipfs/go-cid" "github.com/ipfs/go-cid"
@ -83,6 +84,9 @@ func (a *Applier) ApplyTipSetMessages(state vstate.VMWrapper, blocks []vtypes.Bl
var receipts []vtypes.MessageReceipt 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 { 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{ receipts = append(receipts, vtypes.MessageReceipt{
ExitCode: exitcode.ExitCode(ret.ExitCode), ExitCode: exitcode.ExitCode(ret.ExitCode),
ReturnValue: ret.Return, ReturnValue: ret.Return,

View File

@ -5,11 +5,12 @@ import (
"context" "context"
"encoding/json" "encoding/json"
"fmt" "fmt"
"github.com/filecoin-project/specs-actors/actors/builtin"
"reflect" "reflect"
"strconv" "strconv"
"strings" "strings"
"github.com/filecoin-project/specs-actors/actors/builtin"
"github.com/filecoin-project/go-address" "github.com/filecoin-project/go-address"
"github.com/filecoin-project/specs-actors/actors/abi" "github.com/filecoin-project/specs-actors/actors/abi"
"github.com/filecoin-project/specs-actors/actors/builtin/market" "github.com/filecoin-project/specs-actors/actors/builtin/market"
@ -741,6 +742,10 @@ var stateComputeStateCmd = &cli.Command{
Name: "apply-mpool-messages", Name: "apply-mpool-messages",
Usage: "apply messages from the mempool to the computed state", 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 { Action: func(cctx *cli.Context) error {
api, closer, err := GetFullNodeAPI(cctx) 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 { if err != nil {
return err 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 return nil
}, },
} }

View File

@ -541,12 +541,20 @@ func (a *StateAPI) StateListMessages(ctx context.Context, match *types.Message,
return out, nil 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) ts, err := a.Chain.GetTipSetFromKey(tsk)
if err != nil { 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) { func (a *StateAPI) MsigGetAvailableBalance(ctx context.Context, addr address.Address, tsk types.TipSetKey) (types.BigInt, error) {