diff --git a/api/api_full.go b/api/api_full.go index 784651466..09c69a1ba 100644 --- a/api/api_full.go +++ b/api/api_full.go @@ -378,7 +378,8 @@ type DealInfo struct { } type MsgLookup struct { - Receipt types.MessageReceipt + Receipt types.MessageReceipt + ReturnDec interface{} // TODO: This should probably a tipsetkey? TipSet *types.TipSet } diff --git a/chain/stmgr/utils.go b/chain/stmgr/utils.go index fd99deef1..8c9cfc792 100644 --- a/chain/stmgr/utils.go +++ b/chain/stmgr/utils.go @@ -4,6 +4,7 @@ import ( "bytes" "context" "os" + "reflect" cid "github.com/ipfs/go-cid" blockstore "github.com/ipfs/go-ipfs-blockstore" @@ -17,10 +18,16 @@ import ( "github.com/filecoin-project/sector-storage/ffiwrapper" "github.com/filecoin-project/specs-actors/actors/abi" "github.com/filecoin-project/specs-actors/actors/builtin" + "github.com/filecoin-project/specs-actors/actors/builtin/account" + "github.com/filecoin-project/specs-actors/actors/builtin/cron" init_ "github.com/filecoin-project/specs-actors/actors/builtin/init" "github.com/filecoin-project/specs-actors/actors/builtin/market" "github.com/filecoin-project/specs-actors/actors/builtin/miner" + "github.com/filecoin-project/specs-actors/actors/builtin/multisig" + "github.com/filecoin-project/specs-actors/actors/builtin/paych" "github.com/filecoin-project/specs-actors/actors/builtin/power" + "github.com/filecoin-project/specs-actors/actors/builtin/reward" + "github.com/filecoin-project/specs-actors/actors/builtin/verifreg" "github.com/filecoin-project/specs-actors/actors/crypto" "github.com/filecoin-project/specs-actors/actors/util/adt" @@ -578,3 +585,60 @@ func MinerGetBaseInfo(ctx context.Context, sm *StateManager, bcn beacon.RandomBe BeaconEntries: entries, }, nil } + +type methodMeta struct { + Name string + + Params reflect.Type + Ret reflect.Type +} + +var MethodsMap = map[cid.Cid][]methodMeta{} + +func init() { + cidToMethods := map[cid.Cid][2]interface{}{ + // builtin.SystemActorCodeID: {builtin.MethodsSystem, system.Actor{} }- apparently it doesn't have methods + builtin.InitActorCodeID: {builtin.MethodsInit, init_.Actor{}}, + builtin.CronActorCodeID: {builtin.MethodsCron, cron.Actor{}}, + builtin.AccountActorCodeID: {builtin.MethodsAccount, account.Actor{}}, + builtin.StoragePowerActorCodeID: {builtin.MethodsPower, power.Actor{}}, + builtin.StorageMinerActorCodeID: {builtin.MethodsMiner, miner.Actor{}}, + builtin.StorageMarketActorCodeID: {builtin.MethodsMarket, market.Actor{}}, + builtin.PaymentChannelActorCodeID: {builtin.MethodsPaych, paych.Actor{}}, + builtin.MultisigActorCodeID: {builtin.MethodsMultisig, multisig.Actor{}}, + builtin.RewardActorCodeID: {builtin.MethodsReward, reward.Actor{}}, + builtin.VerifiedRegistryActorCodeID: {builtin.MethodsVerifiedRegistry, verifreg.Actor{}}, + } + + for c, m := range cidToMethods { + rt := reflect.TypeOf(m[0]) + nf := rt.NumField() + + MethodsMap[c] = append(MethodsMap[c], methodMeta{ + Name: "Send", + Params: reflect.TypeOf(new(adt.EmptyValue)), + Ret: reflect.TypeOf(new(adt.EmptyValue)), + }) + + exports := m[1].(abi.Invokee).Exports() + for i := 0; i < nf; i++ { + export := reflect.TypeOf(exports[i+1]) + + MethodsMap[c] = append(MethodsMap[c], methodMeta{ + Name: rt.Field(i).Name, + Params: export.In(1), + Ret: export.Out(0), + }) + } + } +} + +func GetReturnType(ctx context.Context, sm *StateManager, to address.Address, method abi.MethodNum, ts *types.TipSet) (cbg.CBORUnmarshaler, error) { + act, err := sm.GetActor(to, ts) + if err != nil { + return nil, err + } + + m := MethodsMap[act.Code][method] + return reflect.New(m.Ret.Elem()).Interface().(cbg.CBORUnmarshaler), nil +} diff --git a/cli/state.go b/cli/state.go index a159f2272..dfe0118ca 100644 --- a/cli/state.go +++ b/cli/state.go @@ -23,72 +23,20 @@ import ( "github.com/filecoin-project/go-address" "github.com/filecoin-project/specs-actors/actors/abi" "github.com/filecoin-project/specs-actors/actors/builtin" - "github.com/filecoin-project/specs-actors/actors/builtin/account" - "github.com/filecoin-project/specs-actors/actors/builtin/cron" - init_ "github.com/filecoin-project/specs-actors/actors/builtin/init" "github.com/filecoin-project/specs-actors/actors/builtin/market" miner2 "github.com/filecoin-project/specs-actors/actors/builtin/miner" "github.com/filecoin-project/specs-actors/actors/builtin/multisig" "github.com/filecoin-project/specs-actors/actors/builtin/paych" "github.com/filecoin-project/specs-actors/actors/builtin/power" - "github.com/filecoin-project/specs-actors/actors/builtin/reward" - "github.com/filecoin-project/specs-actors/actors/builtin/verifreg" "github.com/filecoin-project/specs-actors/actors/runtime/exitcode" - "github.com/filecoin-project/specs-actors/actors/util/adt" "github.com/filecoin-project/lotus/api" "github.com/filecoin-project/lotus/build" + "github.com/filecoin-project/lotus/chain/stmgr" "github.com/filecoin-project/lotus/chain/types" "github.com/filecoin-project/lotus/miner" ) -type methodMeta struct { - Name string - - params reflect.Type - ret reflect.Type -} - -var methods = map[cid.Cid][]methodMeta{} - -func init() { - cidToMethods := map[cid.Cid][2]interface{}{ - // builtin.SystemActorCodeID: {builtin.MethodsSystem, system.Actor{} }- apparently it doesn't have methods - builtin.InitActorCodeID: {builtin.MethodsInit, init_.Actor{}}, - builtin.CronActorCodeID: {builtin.MethodsCron, cron.Actor{}}, - builtin.AccountActorCodeID: {builtin.MethodsAccount, account.Actor{}}, - builtin.StoragePowerActorCodeID: {builtin.MethodsPower, power.Actor{}}, - builtin.StorageMinerActorCodeID: {builtin.MethodsMiner, miner2.Actor{}}, - builtin.StorageMarketActorCodeID: {builtin.MethodsMarket, market.Actor{}}, - builtin.PaymentChannelActorCodeID: {builtin.MethodsPaych, paych.Actor{}}, - builtin.MultisigActorCodeID: {builtin.MethodsMultisig, multisig.Actor{}}, - builtin.RewardActorCodeID: {builtin.MethodsReward, reward.Actor{}}, - builtin.VerifiedRegistryActorCodeID: {builtin.MethodsVerifiedRegistry, verifreg.Actor{}}, - } - - for c, m := range cidToMethods { - rt := reflect.TypeOf(m[0]) - nf := rt.NumField() - - methods[c] = append(methods[c], methodMeta{ - Name: "Send", - params: reflect.TypeOf(new(adt.EmptyValue)), - ret: reflect.TypeOf(new(adt.EmptyValue)), - }) - - exports := m[1].(abi.Invokee).Exports() - for i := 0; i < nf; i++ { - export := reflect.TypeOf(exports[i+1]) - - methods[c] = append(methods[c], methodMeta{ - Name: rt.Field(i).Name, - params: export.In(1), - ret: export.Out(0), - }) - } - } -} - var stateCmd = &cli.Command{ Name: "state", Usage: "Interact with and query filecoin chain state", @@ -1191,7 +1139,7 @@ func codeStr(c cid.Cid) string { } func getMethod(code cid.Cid, method abi.MethodNum) string { - return methods[code][method].Name + return stmgr.MethodsMap[code][method].Name } func toFil(f types.BigInt) types.FIL { @@ -1222,7 +1170,7 @@ func sumGas(changes []*types.GasTrace) types.GasTrace { } func jsonParams(code cid.Cid, method abi.MethodNum, params []byte) (string, error) { - re := reflect.New(methods[code][method].params.Elem()) + re := reflect.New(stmgr.MethodsMap[code][method].Params.Elem()) p := re.Interface().(cbg.CBORUnmarshaler) if err := p.UnmarshalCBOR(bytes.NewReader(params)); err != nil { return "", err @@ -1233,7 +1181,7 @@ func jsonParams(code cid.Cid, method abi.MethodNum, params []byte) (string, erro } func jsonReturn(code cid.Cid, method abi.MethodNum, ret []byte) (string, error) { - re := reflect.New(methods[code][method].ret.Elem()) + re := reflect.New(stmgr.MethodsMap[code][method].Ret.Elem()) p := re.Interface().(cbg.CBORUnmarshaler) if err := p.UnmarshalCBOR(bytes.NewReader(ret)); err != nil { return "", err diff --git a/node/impl/full/state.go b/node/impl/full/state.go index e810cf1a4..179267944 100644 --- a/node/impl/full/state.go +++ b/node/impl/full/state.go @@ -361,9 +361,31 @@ func (a *StateAPI) StateWaitMsg(ctx context.Context, msg cid.Cid, confidence uin return nil, err } + var returndec interface{} + if recpt.ExitCode == 0 && len(recpt.Return) > 0 { + cmsg, err := a.Chain.GetCMessage(msg) + if err != nil { + return nil, xerrors.Errorf("failed to load message after successful receipt search: %w", err) + } + + vmsg := cmsg.VMMessage() + + t, err := stmgr.GetReturnType(ctx, a.StateManager, vmsg.To, vmsg.Method, ts) + if err != nil { + return nil, xerrors.Errorf("failed to get return type: %w", err) + } + + if err := t.UnmarshalCBOR(bytes.NewReader(recpt.Return)); err != nil { + return nil, err + } + + returndec = t + } + return &api.MsgLookup{ - Receipt: *recpt, - TipSet: ts, + Receipt: *recpt, + ReturnDec: returndec, + TipSet: ts, }, nil }