From 236a21a9d7a42c430dcd3d3aa7e4937d9d3284d8 Mon Sep 17 00:00:00 2001 From: Jennifer Wang Date: Thu, 15 Sep 2022 03:34:24 -0400 Subject: [PATCH 1/4] add get all msig into lotus-shed --- cmd/lotus-shed/main.go | 1 + cmd/lotus-shed/msig.go | 184 +++++++++++++++++++++++++++++++++++++++++ 2 files changed, 185 insertions(+) create mode 100644 cmd/lotus-shed/msig.go diff --git a/cmd/lotus-shed/main.go b/cmd/lotus-shed/main.go index 0f10a617f2b..792d7296824 100644 --- a/cmd/lotus-shed/main.go +++ b/cmd/lotus-shed/main.go @@ -73,6 +73,7 @@ func main() { migrationsCmd, diffCmd, itestdCmd, + msigCmd, } app := &cli.App{ diff --git a/cmd/lotus-shed/msig.go b/cmd/lotus-shed/msig.go new file mode 100644 index 00000000000..dafa9a55b4e --- /dev/null +++ b/cmd/lotus-shed/msig.go @@ -0,0 +1,184 @@ +package main + +import ( + "context" + "encoding/json" + "fmt" + "strings" + + "github.com/ipfs/go-cid" + + "github.com/filecoin-project/lotus/api/v0api" + "github.com/filecoin-project/lotus/chain/types" + + "github.com/filecoin-project/go-address" + + "github.com/filecoin-project/go-state-types/network" + "github.com/filecoin-project/lotus/build" + + "github.com/filecoin-project/go-state-types/abi" + cliutil "github.com/filecoin-project/lotus/cli/util" + "github.com/urfave/cli/v2" + "golang.org/x/xerrors" +) + +var GetFullNodeAPI = cliutil.GetFullNodeAPI +var ReqContext = cliutil.ReqContext + +func LoadTipSet(ctx context.Context, cctx *cli.Context, api v0api.FullNode) (*types.TipSet, error) { + tss := cctx.String("tipset") + if tss == "" { + return api.ChainHead(ctx) + } + + return ParseTipSetRef(ctx, api, tss) +} + +func ParseTipSetRef(ctx context.Context, api v0api.FullNode, tss string) (*types.TipSet, error) { + if tss[0] == '@' { + if tss == "@head" { + return api.ChainHead(ctx) + } + + var h uint64 + if _, err := fmt.Sscanf(tss, "@%d", &h); err != nil { + return nil, xerrors.Errorf("parsing height tipset ref: %w", err) + } + + return api.ChainGetTipSetByHeight(ctx, abi.ChainEpoch(h), types.EmptyTSK) + } + + cids, err := ParseTipSetString(tss) + if err != nil { + return nil, err + } + + if len(cids) == 0 { + return nil, nil + } + + k := types.NewTipSetKey(cids...) + ts, err := api.ChainGetTipSet(ctx, k) + if err != nil { + return nil, err + } + + return ts, nil +} + +func ParseTipSetString(ts string) ([]cid.Cid, error) { + strs := strings.Split(ts, ",") + + var cids []cid.Cid + for _, s := range strs { + c, err := cid.Parse(strings.TrimSpace(s)) + if err != nil { + return nil, err + } + cids = append(cids, c) + } + + return cids, nil +} + +type msigBriefInfo struct { + ID address.Address + Signer interface{} + Balance abi.TokenAmount + Threshold float64 +} + +var msigCmd = &cli.Command{ + Name: "multisig", + Usage: "utils for multisig actors", + Flags: []cli.Flag{ + &cli.StringFlag{ + Name: "tipset", + Usage: "specify tipset to call method on (pass comma separated array of cids)", + }, + }, + Subcommands: []*cli.Command{ + multisigGetAllCmd, + }, +} + +var multisigGetAllCmd = &cli.Command{ + Name: "all", + Usage: "get all multisig actor on chain with id, siigners, threshold and balance", + Flags: []cli.Flag{ + &cli.UintFlag{ + Name: "network-version", + Value: uint(build.NewestNetworkVersion), + }, + }, + Action: func(cctx *cli.Context) error { + api, closer, err := GetFullNodeAPI(cctx) + if err != nil { + return err + } + defer closer() + + ctx := ReqContext(cctx) + + ts, err := LoadTipSet(ctx, cctx, api) + if err != nil { + return err + } + + actors, err := api.StateListActors(ctx, ts.Key()) + if err != nil { + return err + } + + nv := network.Version(cctx.Uint64("network-version")) + codeCids, err := api.StateActorCodeCIDs(ctx, nv) + if err != nil { + return err + } + + msigCid, exists := codeCids["multisig"] + if !exists { + return xerrors.Errorf("bad code cid key") + } + + var msigActorsInfo []msigBriefInfo + for _, actor := range actors { + + act, err := api.StateGetActor(ctx, actor, ts.Key()) + if err != nil { + return err + } + + if act.Code == msigCid { + + actorState, err := api.StateReadState(ctx, actor, ts.Key()) + if err != nil { + return err + } + + stateI, ok := actorState.State.(map[string]interface{}) + if !ok { + return xerrors.Errorf("fail to map msig state") + } + + signersI, _ := stateI["Signers"] + signers := signersI.([]interface{}) + thresholdI, _ := stateI["NumApprovalsThreshold"] + threshold := thresholdI.(float64) + info := msigBriefInfo{ + ID: actor, + Signer: signers, + Balance: actorState.Balance, + Threshold: threshold, + } + msigActorsInfo = append(msigActorsInfo, info) + } + } + out, err := json.MarshalIndent(msigActorsInfo, "", " ") + if err != nil { + return err + } + fmt.Println(string(out)) + return nil + }, +} From b87ade64022c4aa59125190aa11becb931c91321 Mon Sep 17 00:00:00 2001 From: Jennifer Wang Date: Thu, 15 Sep 2022 17:05:07 -0400 Subject: [PATCH 2/4] docsjen --- cmd/lotus-shed/msig.go | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) diff --git a/cmd/lotus-shed/msig.go b/cmd/lotus-shed/msig.go index dafa9a55b4e..d70634e7206 100644 --- a/cmd/lotus-shed/msig.go +++ b/cmd/lotus-shed/msig.go @@ -7,19 +7,17 @@ import ( "strings" "github.com/ipfs/go-cid" - - "github.com/filecoin-project/lotus/api/v0api" - "github.com/filecoin-project/lotus/chain/types" + "github.com/urfave/cli/v2" + "golang.org/x/xerrors" "github.com/filecoin-project/go-address" - + "github.com/filecoin-project/go-state-types/abi" "github.com/filecoin-project/go-state-types/network" - "github.com/filecoin-project/lotus/build" - "github.com/filecoin-project/go-state-types/abi" + "github.com/filecoin-project/lotus/api/v0api" + "github.com/filecoin-project/lotus/build" + "github.com/filecoin-project/lotus/chain/types" cliutil "github.com/filecoin-project/lotus/cli/util" - "github.com/urfave/cli/v2" - "golang.org/x/xerrors" ) var GetFullNodeAPI = cliutil.GetFullNodeAPI From 2ec4ac3c0fb9cd0d796e427daab2b586aed9d08a Mon Sep 17 00:00:00 2001 From: jennijuju Date: Thu, 22 Sep 2022 02:56:08 -0400 Subject: [PATCH 3/4] use offline mode instead --- cmd/lotus-shed/msig.go | 175 +++++++++++++++-------------------------- 1 file changed, 62 insertions(+), 113 deletions(-) diff --git a/cmd/lotus-shed/msig.go b/cmd/lotus-shed/msig.go index d70634e7206..b5cc9fea2a2 100644 --- a/cmd/lotus-shed/msig.go +++ b/cmd/lotus-shed/msig.go @@ -4,174 +4,123 @@ import ( "context" "encoding/json" "fmt" - "strings" + "io" + + "github.com/filecoin-project/lotus/chain/actors/builtin" + "github.com/filecoin-project/lotus/chain/actors/builtin/multisig" + + "github.com/filecoin-project/lotus/chain/actors/adt" + "github.com/filecoin-project/lotus/chain/consensus/filcns" + "github.com/filecoin-project/lotus/chain/state" + "github.com/filecoin-project/lotus/chain/store" + "github.com/filecoin-project/lotus/node/repo" + cbor "github.com/ipfs/go-ipld-cbor" "github.com/ipfs/go-cid" "github.com/urfave/cli/v2" - "golang.org/x/xerrors" "github.com/filecoin-project/go-address" "github.com/filecoin-project/go-state-types/abi" - "github.com/filecoin-project/go-state-types/network" - - "github.com/filecoin-project/lotus/api/v0api" - "github.com/filecoin-project/lotus/build" "github.com/filecoin-project/lotus/chain/types" - cliutil "github.com/filecoin-project/lotus/cli/util" ) -var GetFullNodeAPI = cliutil.GetFullNodeAPI -var ReqContext = cliutil.ReqContext - -func LoadTipSet(ctx context.Context, cctx *cli.Context, api v0api.FullNode) (*types.TipSet, error) { - tss := cctx.String("tipset") - if tss == "" { - return api.ChainHead(ctx) - } - - return ParseTipSetRef(ctx, api, tss) -} - -func ParseTipSetRef(ctx context.Context, api v0api.FullNode, tss string) (*types.TipSet, error) { - if tss[0] == '@' { - if tss == "@head" { - return api.ChainHead(ctx) - } - - var h uint64 - if _, err := fmt.Sscanf(tss, "@%d", &h); err != nil { - return nil, xerrors.Errorf("parsing height tipset ref: %w", err) - } - - return api.ChainGetTipSetByHeight(ctx, abi.ChainEpoch(h), types.EmptyTSK) - } - - cids, err := ParseTipSetString(tss) - if err != nil { - return nil, err - } - - if len(cids) == 0 { - return nil, nil - } - - k := types.NewTipSetKey(cids...) - ts, err := api.ChainGetTipSet(ctx, k) - if err != nil { - return nil, err - } - - return ts, nil -} - -func ParseTipSetString(ts string) ([]cid.Cid, error) { - strs := strings.Split(ts, ",") - - var cids []cid.Cid - for _, s := range strs { - c, err := cid.Parse(strings.TrimSpace(s)) - if err != nil { - return nil, err - } - cids = append(cids, c) - } - - return cids, nil -} - type msigBriefInfo struct { ID address.Address Signer interface{} Balance abi.TokenAmount - Threshold float64 + Threshold uint64 } var msigCmd = &cli.Command{ - Name: "multisig", - Usage: "utils for multisig actors", - Flags: []cli.Flag{ - &cli.StringFlag{ - Name: "tipset", - Usage: "specify tipset to call method on (pass comma separated array of cids)", - }, - }, + Name: "msig", Subcommands: []*cli.Command{ multisigGetAllCmd, }, } var multisigGetAllCmd = &cli.Command{ - Name: "all", - Usage: "get all multisig actor on chain with id, siigners, threshold and balance", + Name: "all", + Usage: "get all multisig actor on chain with id, siigners, threshold and balance at a tipset", + ArgsUsage: "[state root]", Flags: []cli.Flag{ - &cli.UintFlag{ - Name: "network-version", - Value: uint(build.NewestNetworkVersion), + &cli.StringFlag{ + Name: "repo", + Value: "~/.lotus", }, }, Action: func(cctx *cli.Context) error { - api, closer, err := GetFullNodeAPI(cctx) - if err != nil { - return err + ctx := context.TODO() + if !cctx.Args().Present() { + return fmt.Errorf("must pass state root") } - defer closer() - ctx := ReqContext(cctx) + sroot, err := cid.Decode(cctx.Args().First()) + if err != nil { + return fmt.Errorf("failed to parse input: %w", err) + } - ts, err := LoadTipSet(ctx, cctx, api) + fsrepo, err := repo.NewFS(cctx.String("repo")) if err != nil { return err } - actors, err := api.StateListActors(ctx, ts.Key()) + lkrepo, err := fsrepo.Lock(repo.FullNode) if err != nil { return err } - nv := network.Version(cctx.Uint64("network-version")) - codeCids, err := api.StateActorCodeCIDs(ctx, nv) + defer lkrepo.Close() //nolint:errcheck + + bs, err := lkrepo.Blockstore(ctx, repo.UniversalBlockstore) if err != nil { - return err + return fmt.Errorf("failed to open blockstore: %w", err) } - msigCid, exists := codeCids["multisig"] - if !exists { - return xerrors.Errorf("bad code cid key") + defer func() { + if c, ok := bs.(io.Closer); ok { + if err := c.Close(); err != nil { + log.Warnf("failed to close blockstore: %s", err) + } + } + }() + + mds, err := lkrepo.Datastore(context.Background(), "/metadata") + if err != nil { + return err } - var msigActorsInfo []msigBriefInfo - for _, actor := range actors { + cs := store.NewChainStore(bs, bs, mds, filcns.Weight, nil) + defer cs.Close() //nolint:errcheck - act, err := api.StateGetActor(ctx, actor, ts.Key()) - if err != nil { - return err - } + cst := cbor.NewCborStore(bs) + store := adt.WrapStore(ctx, cst) - if act.Code == msigCid { + tree, err := state.LoadStateTree(cst, sroot) + if err != nil { + return err + } - actorState, err := api.StateReadState(ctx, actor, ts.Key()) + var msigActorsInfo []msigBriefInfo + err = tree.ForEach(func(addr address.Address, act *types.Actor) error { + if builtin.IsMultisigActor(act.Code) { + ms, err := multisig.Load(store, act) if err != nil { return err } - stateI, ok := actorState.State.(map[string]interface{}) - if !ok { - return xerrors.Errorf("fail to map msig state") - } - - signersI, _ := stateI["Signers"] - signers := signersI.([]interface{}) - thresholdI, _ := stateI["NumApprovalsThreshold"] - threshold := thresholdI.(float64) + signers, _ := ms.Signers() + threshold, _ := ms.Threshold() info := msigBriefInfo{ - ID: actor, + ID: addr, Signer: signers, - Balance: actorState.Balance, + Balance: act.Balance, Threshold: threshold, } msigActorsInfo = append(msigActorsInfo, info) + } - } + return nil + }) out, err := json.MarshalIndent(msigActorsInfo, "", " ") if err != nil { return err From aea9c535e0e0980aaee79db6c6baac7b0df4cf3e Mon Sep 17 00:00:00 2001 From: Jennifer Wang Date: Thu, 22 Sep 2022 13:12:12 -0400 Subject: [PATCH 4/4] fix typo, add wrapper on error and make jen --- cmd/lotus-shed/msig.go | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/cmd/lotus-shed/msig.go b/cmd/lotus-shed/msig.go index b5cc9fea2a2..66e4885c37f 100644 --- a/cmd/lotus-shed/msig.go +++ b/cmd/lotus-shed/msig.go @@ -6,22 +6,21 @@ import ( "fmt" "io" - "github.com/filecoin-project/lotus/chain/actors/builtin" - "github.com/filecoin-project/lotus/chain/actors/builtin/multisig" - - "github.com/filecoin-project/lotus/chain/actors/adt" - "github.com/filecoin-project/lotus/chain/consensus/filcns" - "github.com/filecoin-project/lotus/chain/state" - "github.com/filecoin-project/lotus/chain/store" - "github.com/filecoin-project/lotus/node/repo" - cbor "github.com/ipfs/go-ipld-cbor" - "github.com/ipfs/go-cid" + cbor "github.com/ipfs/go-ipld-cbor" "github.com/urfave/cli/v2" "github.com/filecoin-project/go-address" "github.com/filecoin-project/go-state-types/abi" + + "github.com/filecoin-project/lotus/chain/actors/adt" + "github.com/filecoin-project/lotus/chain/actors/builtin" + "github.com/filecoin-project/lotus/chain/actors/builtin/multisig" + "github.com/filecoin-project/lotus/chain/consensus/filcns" + "github.com/filecoin-project/lotus/chain/state" + "github.com/filecoin-project/lotus/chain/store" "github.com/filecoin-project/lotus/chain/types" + "github.com/filecoin-project/lotus/node/repo" ) type msigBriefInfo struct { @@ -40,7 +39,7 @@ var msigCmd = &cli.Command{ var multisigGetAllCmd = &cli.Command{ Name: "all", - Usage: "get all multisig actor on chain with id, siigners, threshold and balance at a tipset", + Usage: "get all multisig actor on chain with id, signers, threshold and balance at a tipset", ArgsUsage: "[state root]", Flags: []cli.Flag{ &cli.StringFlag{ @@ -105,7 +104,8 @@ var multisigGetAllCmd = &cli.Command{ if builtin.IsMultisigActor(act.Code) { ms, err := multisig.Load(store, act) if err != nil { - return err + return fmt.Errorf("load msig failed %v", err) + } signers, _ := ms.Signers()