diff --git a/cli/chain.go b/cli/chain.go index 4d296cf78..a174e75f2 100644 --- a/cli/chain.go +++ b/cli/chain.go @@ -442,7 +442,8 @@ var chainGetCmd = &cli.Command{ - /ipfs/[cid]/@Hi:123 - get varint elem 123 from hamt - /ipfs/[cid]/@Hu:123 - get uvarint elem 123 from hamt - /ipfs/[cid]/@Ha:t01 - get element under Addr(t01).Bytes - - /ipfs/[cid]/@A:10 - get 10th amt element + - /ipfs/[cid]/@A:10 - get 10th amt element + - .../@Ha:t01/@state - get pretty map-based actor state List of --as-type types: - raw diff --git a/node/impl/full/chain.go b/node/impl/full/chain.go index f6553fa54..d5c8f385b 100644 --- a/node/impl/full/chain.go +++ b/node/impl/full/chain.go @@ -1,7 +1,9 @@ package full import ( + "bytes" "context" + "encoding/json" "fmt" "io" "strconv" @@ -33,6 +35,7 @@ import ( "github.com/filecoin-project/lotus/api" "github.com/filecoin-project/lotus/chain/store" "github.com/filecoin-project/lotus/chain/types" + "github.com/filecoin-project/lotus/chain/vm" ) var log = logging.Logger("fullnode") @@ -377,6 +380,54 @@ func resolveOnce(bs blockstore.Blockstore) func(ctx context.Context, ds ipld.Nod return resolveOnce(bs)(ctx, ds, n, names[1:]) } + if names[0] == "@state" { + var act types.Actor + if err := act.UnmarshalCBOR(bytes.NewReader(nd.RawData())); err != nil { + return nil, nil, xerrors.Errorf("unmarshaling actor struct for @state: %w", err) + } + + head, err := ds.Get(ctx, act.Head) + if err != nil { + return nil, nil, xerrors.Errorf("getting actor head for @state: %w", err) + } + + m, err := vm.DumpActorState(act.Code, head.RawData()) + if err != nil { + return nil, nil, err + } + + // a hack to workaround struct aliasing in refmt + ms := map[string]interface{}{} + { + mstr, err := json.Marshal(m) + if err != nil { + return nil, nil, err + } + if err := json.Unmarshal(mstr, &ms); err != nil { + return nil, nil, err + } + } + + n, err := cbor.WrapObject(ms, mh.SHA2_256, 32) + if err != nil { + return nil, nil, err + } + + if err := bs.Put(n); err != nil { + return nil, nil, xerrors.Errorf("put amt val: %w", err) + } + + if len(names) == 1 { + return &ipld.Link{ + Name: "state", + Size: 0, + Cid: n.Cid(), + }, nil, nil + } + + return resolveOnce(bs)(ctx, ds, n, names[1:]) + } + return nd.ResolveLink(names) } }