Merge pull request #1354 from filecoin-project/feat/state-compute-trace
implement compute state trace output
This commit is contained in:
commit
3a94d9d176
@ -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:
|
||||||
|
@ -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)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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)
|
||||||
}
|
}
|
||||||
|
@ -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
|
||||||
}
|
}
|
||||||
|
@ -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,
|
||||||
|
19
cli/state.go
19
cli/state.go
@ -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
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
@ -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) {
|
||||||
|
Loading…
Reference in New Issue
Block a user