From 3be0c068b985add366d532a0fc166a6cc3075236 Mon Sep 17 00:00:00 2001 From: Aayush Rajasekaran Date: Wed, 3 Nov 2021 00:19:18 +0000 Subject: [PATCH] Shed: Add a util to create miners more easily --- chain/actors/builtin/miner/utils.go | 19 ++++ cmd/lotus-miner/init.go | 66 +++++++---- cmd/lotus-shed/miner.go | 163 ++++++++++++++++++++++++++++ 3 files changed, 229 insertions(+), 19 deletions(-) diff --git a/chain/actors/builtin/miner/utils.go b/chain/actors/builtin/miner/utils.go index 2f24e845401..5fafc31ef7f 100644 --- a/chain/actors/builtin/miner/utils.go +++ b/chain/actors/builtin/miner/utils.go @@ -67,3 +67,22 @@ func SealProofTypeFromSectorSize(ssize abi.SectorSize, nv network.Version) (abi. return 0, xerrors.Errorf("unsupported network version") } + +// WindowPoStProofTypeFromSectorSize returns preferred post proof type for creating +// new miner actors and new sectors +func WindowPoStProofTypeFromSectorSize(ssize abi.SectorSize) (abi.RegisteredPoStProof, error) { + switch ssize { + case 2 << 10: + return abi.RegisteredPoStProof_StackedDrgWindow2KiBV1, nil + case 8 << 20: + return abi.RegisteredPoStProof_StackedDrgWindow8MiBV1, nil + case 512 << 20: + return abi.RegisteredPoStProof_StackedDrgWindow512MiBV1, nil + case 32 << 30: + return abi.RegisteredPoStProof_StackedDrgWindow32GiBV1, nil + case 64 << 30: + return abi.RegisteredPoStProof_StackedDrgWindow64GiBV1, nil + default: + return 0, xerrors.Errorf("unsupported sector size for miner: %v", ssize) + } +} diff --git a/cmd/lotus-miner/init.go b/cmd/lotus-miner/init.go index a5e9710a9e0..b2199dd94a7 100644 --- a/cmd/lotus-miner/init.go +++ b/cmd/lotus-miner/init.go @@ -13,6 +13,8 @@ import ( "path/filepath" "strconv" + power6 "github.com/filecoin-project/specs-actors/v6/actors/builtin/power" + "github.com/docker/go-units" "github.com/google/uuid" "github.com/ipfs/go-datastore" @@ -644,11 +646,26 @@ func createStorageMiner(ctx context.Context, api v1api.FullNode, peerid peer.ID, return address.Address{}, err } + sender := owner + if fromstr := cctx.String("from"); fromstr != "" { + faddr, err := address.NewFromString(fromstr) + if err != nil { + return address.Undef, fmt.Errorf("could not parse from address: %w", err) + } + sender = faddr + } + + // make sure the sender account exists on chain + _, err = api.StateLookupID(ctx, owner, types.EmptyTSK) + if err != nil { + return address.Undef, xerrors.Errorf("sender must exist on chain: %w", err) + } + // make sure the worker account exists on chain _, err = api.StateLookupID(ctx, worker, types.EmptyTSK) if err != nil { signed, err := api.MpoolPushMessage(ctx, &types.Message{ - From: owner, + From: sender, To: worker, Value: types.NewInt(0), }, nil) @@ -668,35 +685,46 @@ func createStorageMiner(ctx context.Context, api v1api.FullNode, peerid peer.ID, } } - nv, err := api.StateNetworkVersion(ctx, types.EmptyTSK) + // make sure the owner account exists on chain + _, err = api.StateLookupID(ctx, owner, types.EmptyTSK) if err != nil { - return address.Undef, xerrors.Errorf("getting network version: %w", err) + signed, err := api.MpoolPushMessage(ctx, &types.Message{ + From: sender, + To: owner, + Value: types.NewInt(0), + }, nil) + if err != nil { + return address.Undef, xerrors.Errorf("push owner init: %w", err) + } + + log.Infof("Initializing owner account %s, message: %s", worker, signed.Cid()) + log.Infof("Waiting for confirmation") + + mw, err := api.StateWaitMsg(ctx, signed.Cid(), build.MessageConfidence, lapi.LookbackNoLimit, true) + if err != nil { + return address.Undef, xerrors.Errorf("waiting for owner init: %w", err) + } + if mw.Receipt.ExitCode != 0 { + return address.Undef, xerrors.Errorf("initializing owner account failed: exit code %d", mw.Receipt.ExitCode) + } } - spt, err := miner.SealProofTypeFromSectorSize(abi.SectorSize(ssize), nv) + // Note: the correct thing to do would be to call SealProofTypeFromSectorSize if actors version is v3 or later, but this still works + spt, err := miner.WindowPoStProofTypeFromSectorSize(abi.SectorSize(ssize)) if err != nil { - return address.Undef, xerrors.Errorf("getting seal proof type: %w", err) + return address.Undef, xerrors.Errorf("getting post proof type: %w", err) } - params, err := actors.SerializeParams(&power2.CreateMinerParams{ - Owner: owner, - Worker: worker, - SealProofType: spt, - Peer: abi.PeerID(peerid), + params, err := actors.SerializeParams(&power6.CreateMinerParams{ + Owner: owner, + Worker: worker, + WindowPoStProofType: spt, + Peer: abi.PeerID(peerid), }) if err != nil { return address.Undef, err } - sender := owner - if fromstr := cctx.String("from"); fromstr != "" { - faddr, err := address.NewFromString(fromstr) - if err != nil { - return address.Undef, fmt.Errorf("could not parse from address: %w", err) - } - sender = faddr - } - createStorageMinerMsg := &types.Message{ To: power.Address, From: sender, diff --git a/cmd/lotus-shed/miner.go b/cmd/lotus-shed/miner.go index ec5a445f94d..55838965553 100644 --- a/cmd/lotus-shed/miner.go +++ b/cmd/lotus-shed/miner.go @@ -2,11 +2,27 @@ package main import ( "bufio" + "bytes" + "fmt" "io" "os" "path/filepath" "strings" + power6 "github.com/filecoin-project/specs-actors/v6/actors/builtin/power" + + "github.com/docker/go-units" + "github.com/filecoin-project/go-state-types/abi" + "github.com/filecoin-project/go-state-types/big" + + "github.com/filecoin-project/go-address" + "github.com/filecoin-project/lotus/build" + "github.com/filecoin-project/lotus/chain/actors" + "github.com/filecoin-project/lotus/chain/actors/builtin/miner" + "github.com/filecoin-project/lotus/chain/actors/builtin/power" + "github.com/filecoin-project/lotus/chain/types" + lcli "github.com/filecoin-project/lotus/cli" + "github.com/mitchellh/go-homedir" "github.com/urfave/cli/v2" "golang.org/x/xerrors" @@ -17,6 +33,153 @@ var minerCmd = &cli.Command{ Usage: "miner-related utilities", Subcommands: []*cli.Command{ minerUnpackInfoCmd, + minerCreateCmd, + }, +} + +var minerCreateCmd = &cli.Command{ + Name: "create", + Usage: "sends a create miner msg", + ArgsUsage: "[sender] [owner] [worker] [sector size]", + Action: func(cctx *cli.Context) error { + wapi, closer, err := lcli.GetFullNodeAPI(cctx) + if err != nil { + return err + } + + defer closer() + ctx := lcli.ReqContext(cctx) + + if cctx.Args().Len() != 4 { + return xerrors.Errorf("expected 4 args (sender owner worker sectorSize)") + } + + sender, err := address.NewFromString(cctx.Args().First()) + if err != nil { + return err + } + + owner, err := address.NewFromString(cctx.Args().Get(1)) + if err != nil { + return err + } + + worker, err := address.NewFromString(cctx.Args().Get(2)) + if err != nil { + return err + } + + ssize, err := units.RAMInBytes(cctx.Args().Get(3)) + if err != nil { + return fmt.Errorf("failed to parse sector size: %w", err) + } + + // make sure the sender account exists on chain + _, err = wapi.StateLookupID(ctx, owner, types.EmptyTSK) + if err != nil { + return xerrors.Errorf("sender must exist on chain: %w", err) + } + + // make sure the worker account exists on chain + _, err = wapi.StateLookupID(ctx, worker, types.EmptyTSK) + if err != nil { + signed, err := wapi.MpoolPushMessage(ctx, &types.Message{ + From: sender, + To: worker, + Value: types.NewInt(0), + }, nil) + if err != nil { + return xerrors.Errorf("push worker init: %w", err) + } + + log.Infof("Initializing worker account %s, message: %s", worker, signed.Cid()) + log.Infof("Waiting for confirmation") + + mw, err := wapi.StateWaitMsg(ctx, signed.Cid(), build.MessageConfidence) + if err != nil { + return xerrors.Errorf("waiting for worker init: %w", err) + } + + if mw.Receipt.ExitCode != 0 { + return xerrors.Errorf("initializing worker account failed: exit code %d", mw.Receipt.ExitCode) + } + } + + // make sure the owner account exists on chain + _, err = wapi.StateLookupID(ctx, owner, types.EmptyTSK) + if err != nil { + signed, err := wapi.MpoolPushMessage(ctx, &types.Message{ + From: sender, + To: owner, + Value: types.NewInt(0), + }, nil) + if err != nil { + return xerrors.Errorf("push owner init: %w", err) + } + + log.Infof("Initializing owner account %s, message: %s", worker, signed.Cid()) + log.Infof("Wating for confirmation") + + mw, err := wapi.StateWaitMsg(ctx, signed.Cid(), build.MessageConfidence) + if err != nil { + return xerrors.Errorf("waiting for owner init: %w", err) + } + + if mw.Receipt.ExitCode != 0 { + return xerrors.Errorf("initializing owner account failed: exit code %d", mw.Receipt.ExitCode) + } + } + + // Note: the correct thing to do would be to call SealProofTypeFromSectorSize if actors version is v3 or later, but this still works + spt, err := miner.WindowPoStProofTypeFromSectorSize(abi.SectorSize(ssize)) + if err != nil { + return xerrors.Errorf("getting post proof type: %w", err) + } + + params, err := actors.SerializeParams(&power6.CreateMinerParams{ + Owner: owner, + Worker: worker, + WindowPoStProofType: spt, + }) + + if err != nil { + return err + } + + createStorageMinerMsg := &types.Message{ + To: power.Address, + From: sender, + Value: big.Zero(), + + Method: power.Methods.CreateMiner, + Params: params, + } + + signed, err := wapi.MpoolPushMessage(ctx, createStorageMinerMsg, nil) + if err != nil { + return xerrors.Errorf("pushing createMiner message: %w", err) + } + + log.Infof("Pushed CreateMiner message: %s", signed.Cid()) + log.Infof("Waiting for confirmation") + + mw, err := wapi.StateWaitMsg(ctx, signed.Cid(), build.MessageConfidence) + if err != nil { + return xerrors.Errorf("waiting for createMiner message: %w", err) + } + + if mw.Receipt.ExitCode != 0 { + return xerrors.Errorf("create miner failed: exit code %d", mw.Receipt.ExitCode) + } + + var retval power6.CreateMinerReturn + if err := retval.UnmarshalCBOR(bytes.NewReader(mw.Receipt.Return)); err != nil { + return err + } + + log.Infof("New miners address is: %s (%s)", retval.IDAddress, retval.RobustAddress) + + return nil }, }