From 84fd51ff50f6d1f641fa8a5a061683184415fdfa Mon Sep 17 00:00:00 2001 From: Geoff Stuart Date: Wed, 14 Sep 2022 16:12:01 -0400 Subject: [PATCH 1/2] add cli commands for changing beneficiary --- cmd/lotus-miner/actor.go | 268 +++++++++++++++++++++++++++- cmd/lotus-shed/miner-multisig.go | 229 ++++++++++++++++++++++-- documentation/en/cli-lotus-miner.md | 52 ++++-- 3 files changed, 520 insertions(+), 29 deletions(-) diff --git a/cmd/lotus-miner/actor.go b/cmd/lotus-miner/actor.go index aad110414..b1f97d530 100644 --- a/cmd/lotus-miner/actor.go +++ b/cmd/lotus-miner/actor.go @@ -4,6 +4,7 @@ import ( "bytes" "fmt" "os" + "strconv" "strings" "github.com/fatih/color" @@ -20,7 +21,7 @@ import ( "github.com/filecoin-project/go-state-types/abi" "github.com/filecoin-project/go-state-types/big" "github.com/filecoin-project/go-state-types/builtin" - "github.com/filecoin-project/go-state-types/builtin/v8/miner" + "github.com/filecoin-project/go-state-types/builtin/v9/miner" "github.com/filecoin-project/go-state-types/network" "github.com/filecoin-project/lotus/api" @@ -48,6 +49,8 @@ var actorCmd = &cli.Command{ actorProposeChangeWorker, actorConfirmChangeWorker, actorCompactAllocatedCmd, + actorProposeChangeBeneficiary, + actorConfirmChangeBeneficiary, }, } @@ -906,8 +909,7 @@ var actorProposeChangeWorker = &cli.Command{ // check it executed successfully if wait.Receipt.ExitCode.IsError() { - fmt.Fprintln(cctx.App.Writer, "Propose worker change failed!") - return err + return fmt.Errorf("propose worker change failed") } mi, err = api.StateMinerInfo(ctx, maddr, wait.TipSet) @@ -925,6 +927,139 @@ var actorProposeChangeWorker = &cli.Command{ }, } +var actorProposeChangeBeneficiary = &cli.Command{ + Name: "propose-change-beneficiary", + Usage: "Propose a beneficiary address change", + ArgsUsage: "[beneficiaryAddress quota expiration]", + Flags: []cli.Flag{ + &cli.BoolFlag{ + Name: "really-do-it", + Usage: "Actually send transaction performing the action", + Value: false, + }, + &cli.BoolFlag{ + Name: "overwrite-pending-change", + Usage: "Overwrite the current beneficiary change proposal", + Value: false, + }, + &cli.StringFlag{ + Name: "actor", + Usage: "specify the address of miner actor", + }, + }, + Action: func(cctx *cli.Context) error { + if cctx.NArg() != 3 { + return lcli.IncorrectNumArgs(cctx) + } + + api, acloser, err := lcli.GetFullNodeAPI(cctx) + if err != nil { + return xerrors.Errorf("getting fullnode api: %w", err) + } + defer acloser() + + ctx := lcli.ReqContext(cctx) + + na, err := address.NewFromString(cctx.Args().Get(0)) + if err != nil { + return xerrors.Errorf("parsing beneficiary address: %w", err) + } + + newAddr, err := api.StateLookupID(ctx, na, types.EmptyTSK) + if err != nil { + return xerrors.Errorf("looking up new beneficiary address: %w", err) + } + + quota, err := types.ParseFIL(cctx.Args().Get(1)) + if err != nil { + return xerrors.Errorf("parsing quota: %w", err) + } + + expiration, err := strconv.ParseInt(cctx.Args().Get(2), 10, 64) + if err != nil { + return xerrors.Errorf("parsing expiration: %w", err) + } + + maddr, err := getActorAddress(ctx, cctx) + if err != nil { + return xerrors.Errorf("getting miner address: %w", err) + } + + mi, err := api.StateMinerInfo(ctx, maddr, types.EmptyTSK) + if err != nil { + return xerrors.Errorf("getting miner info: %w", err) + } + + if mi.Beneficiary == mi.Owner && newAddr == mi.Owner { + return fmt.Errorf("beneficiary %s already set to owner address", mi.Beneficiary) + } + + if mi.PendingBeneficiaryTerm != nil { + fmt.Println("WARNING: replacing Pending Beneficiary Term of:") + fmt.Println("Beneficiary: ", mi.PendingBeneficiaryTerm.NewBeneficiary) + fmt.Println("Quota:", mi.PendingBeneficiaryTerm.NewQuota) + fmt.Println("Expiration Epoch:", mi.PendingBeneficiaryTerm.NewExpiration) + + if !cctx.Bool("overwrite-pending-change") { + return fmt.Errorf("must pass --overwrite-pending-change to replace current pending beneficiary change. Please review CAREFULLY") + } + } + + if !cctx.Bool("really-do-it") { + fmt.Println("Pass --really-do-it to actually execute this action") + return nil + } + + params := &miner.ChangeBeneficiaryParams{ + NewBeneficiary: newAddr, + NewQuota: abi.TokenAmount(quota), + NewExpiration: abi.ChainEpoch(expiration), + } + + sp, err := actors.SerializeParams(params) + if err != nil { + return xerrors.Errorf("serializing params: %w", err) + } + + smsg, err := api.MpoolPushMessage(ctx, &types.Message{ + From: mi.Owner, + To: maddr, + Method: builtin.MethodsMiner.ChangeBeneficiary, + Value: big.Zero(), + Params: sp, + }, nil) + if err != nil { + return xerrors.Errorf("mpool push: %w", err) + } + + fmt.Println("Propose Message CID:", smsg.Cid()) + + // wait for it to get mined into a block + wait, err := api.StateWaitMsg(ctx, smsg.Cid(), build.MessageConfidence) + if err != nil { + return xerrors.Errorf("waiting for message to be included in block: %w", err) + } + + // check it executed successfully + if wait.Receipt.ExitCode.IsError() { + return fmt.Errorf("propose beneficiary change failed") + } + + updatedMinerInfo, err := api.StateMinerInfo(ctx, maddr, wait.TipSet) + if err != nil { + return xerrors.Errorf("getting miner info: %w", err) + } + + if updatedMinerInfo.PendingBeneficiaryTerm == nil { + fmt.Println("Beneficiary address successfully changed") + } else { + fmt.Println("Beneficiary address change awaiting additional confirmations") + } + + return nil + }, +} + var actorConfirmChangeWorker = &cli.Command{ Name: "confirm-change-worker", Usage: "Confirm a worker address change", @@ -988,7 +1123,7 @@ var actorConfirmChangeWorker = &cli.Command{ } if !cctx.Bool("really-do-it") { - fmt.Fprintln(cctx.App.Writer, "Pass --really-do-it to actually execute this action") + fmt.Println("Pass --really-do-it to actually execute this action") return nil } @@ -1002,7 +1137,7 @@ var actorConfirmChangeWorker = &cli.Command{ return xerrors.Errorf("mpool push: %w", err) } - fmt.Fprintln(cctx.App.Writer, "Confirm Message CID:", smsg.Cid()) + fmt.Println("Confirm Message CID:", smsg.Cid()) // wait for it to get mined into a block wait, err := api.StateWaitMsg(ctx, smsg.Cid(), build.MessageConfidence) @@ -1028,6 +1163,129 @@ var actorConfirmChangeWorker = &cli.Command{ }, } +var actorConfirmChangeBeneficiary = &cli.Command{ + Name: "confirm-change-beneficiary", + Usage: "Confirm a beneficiary address change", + ArgsUsage: "[minerAddress]", + Flags: []cli.Flag{ + &cli.BoolFlag{ + Name: "really-do-it", + Usage: "Actually send transaction performing the action", + Value: false, + }, + &cli.BoolFlag{ + Name: "existing-beneficiary", + Usage: "send confirmation from the existing beneficiary address", + }, + &cli.BoolFlag{ + Name: "new-beneficiary", + Usage: "send confirmation from the new beneficiary address", + }, + }, + Action: func(cctx *cli.Context) error { + if cctx.NArg() != 1 { + return lcli.IncorrectNumArgs(cctx) + } + + api, acloser, err := lcli.GetFullNodeAPI(cctx) + if err != nil { + return xerrors.Errorf("getting fullnode api: %w", err) + } + defer acloser() + + ctx := lcli.ReqContext(cctx) + + maddr, err := address.NewFromString(cctx.Args().First()) + if err != nil { + return xerrors.Errorf("parsing beneficiary address: %w", err) + } + + mi, err := api.StateMinerInfo(ctx, maddr, types.EmptyTSK) + if err != nil { + return xerrors.Errorf("getting miner info: %w", err) + } + + if mi.PendingBeneficiaryTerm == nil { + return fmt.Errorf("no pending beneficiary term found for miner %s", maddr) + } + + if (cctx.IsSet("existing-beneficiary") && cctx.IsSet("new-beneficiary")) || (!cctx.IsSet("existing-beneficiary") && !cctx.IsSet("new-beneficiary")) { + return lcli.ShowHelp(cctx, fmt.Errorf("must pass exactly one of --existing-beneficiary or --existing-beneficiary")) + } + + var fromAddr address.Address + if cctx.IsSet("existing-beneficiary") { + if mi.PendingBeneficiaryTerm.ApprovedByBeneficiary { + return fmt.Errorf("beneficiary change already approved by current beneficiary") + } + fromAddr = mi.Beneficiary + } else { + if mi.PendingBeneficiaryTerm.ApprovedByNominee { + return fmt.Errorf("beneficiary change already approved by new beneficiary") + } + fromAddr = mi.PendingBeneficiaryTerm.NewBeneficiary + } + + fmt.Println("Confirming Pending Beneficiary Term of:") + fmt.Println("Beneficiary: ", mi.PendingBeneficiaryTerm.NewBeneficiary) + fmt.Println("Quota:", mi.PendingBeneficiaryTerm.NewQuota) + fmt.Println("Expiration Epoch:", mi.PendingBeneficiaryTerm.NewExpiration) + + if !cctx.Bool("really-do-it") { + fmt.Println("Pass --really-do-it to actually execute this action") + return nil + } + + params := &miner.ChangeBeneficiaryParams{ + NewBeneficiary: mi.PendingBeneficiaryTerm.NewBeneficiary, + NewQuota: mi.PendingBeneficiaryTerm.NewQuota, + NewExpiration: mi.PendingBeneficiaryTerm.NewExpiration, + } + + sp, err := actors.SerializeParams(params) + if err != nil { + return xerrors.Errorf("serializing params: %w", err) + } + + smsg, err := api.MpoolPushMessage(ctx, &types.Message{ + From: fromAddr, + To: maddr, + Method: builtin.MethodsMiner.ChangeBeneficiary, + Value: big.Zero(), + Params: sp, + }, nil) + if err != nil { + return xerrors.Errorf("mpool push: %w", err) + } + + fmt.Println("Confirm Message CID:", smsg.Cid()) + + // wait for it to get mined into a block + wait, err := api.StateWaitMsg(ctx, smsg.Cid(), build.MessageConfidence) + if err != nil { + return xerrors.Errorf("waiting for message to be included in block: %w", err) + } + + // check it executed successfully + if wait.Receipt.ExitCode.IsError() { + return fmt.Errorf("confirm beneficiary change failed") + } + + updatedMinerInfo, err := api.StateMinerInfo(ctx, maddr, types.EmptyTSK) + if err != nil { + return err + } + + if updatedMinerInfo.PendingBeneficiaryTerm == nil { + fmt.Println("Beneficiary address successfully changed") + } else { + fmt.Println("Beneficiary address change awaiting additional confirmations") + } + + return nil + }, +} + var actorCompactAllocatedCmd = &cli.Command{ Name: "compact-allocated", Usage: "compact allocated sectors bitfield", diff --git a/cmd/lotus-shed/miner-multisig.go b/cmd/lotus-shed/miner-multisig.go index e4268a291..0ea29c50b 100644 --- a/cmd/lotus-shed/miner-multisig.go +++ b/cmd/lotus-shed/miner-multisig.go @@ -12,9 +12,8 @@ import ( "github.com/filecoin-project/go-state-types/abi" "github.com/filecoin-project/go-state-types/big" "github.com/filecoin-project/go-state-types/builtin" - miner2 "github.com/filecoin-project/specs-actors/v2/actors/builtin/miner" - miner5 "github.com/filecoin-project/specs-actors/v5/actors/builtin/miner" - msig5 "github.com/filecoin-project/specs-actors/v5/actors/builtin/multisig" + "github.com/filecoin-project/go-state-types/builtin/v9/miner" + "github.com/filecoin-project/go-state-types/builtin/v9/multisig" "github.com/filecoin-project/lotus/build" "github.com/filecoin-project/lotus/chain/actors" @@ -33,6 +32,8 @@ var minerMultisigsCmd = &cli.Command{ mmProposeChangeWorker, mmConfirmChangeWorker, mmProposeControlSet, + mmProposeChangeBeneficiary, + mmConfirmChangeBeneficiary, }, Flags: []cli.Flag{ &cli.StringFlag{ @@ -80,7 +81,7 @@ var mmProposeWithdrawBalance = &cli.Command{ return err } - sp, err := actors.SerializeParams(&miner5.WithdrawBalanceParams{ + sp, err := actors.SerializeParams(&miner.WithdrawBalanceParams{ AmountRequested: abi.TokenAmount(val), }) if err != nil { @@ -106,7 +107,7 @@ var mmProposeWithdrawBalance = &cli.Command{ return err } - var retval msig5.ProposeReturn + var retval multisig.ProposeReturn if err := retval.UnmarshalCBOR(bytes.NewReader(wait.Receipt.Return)); err != nil { return fmt.Errorf("failed to unmarshal propose return value: %w", err) } @@ -149,7 +150,7 @@ var mmApproveWithdrawBalance = &cli.Command{ return err } - sp, err := actors.SerializeParams(&miner5.WithdrawBalanceParams{ + sp, err := actors.SerializeParams(&miner.WithdrawBalanceParams{ AmountRequested: abi.TokenAmount(val), }) if err != nil { @@ -185,7 +186,7 @@ var mmApproveWithdrawBalance = &cli.Command{ return err } - var retval msig5.ApproveReturn + var retval multisig.ApproveReturn if err := retval.UnmarshalCBOR(bytes.NewReader(wait.Receipt.Return)); err != nil { return fmt.Errorf("failed to unmarshal approve return value: %w", err) } @@ -266,7 +267,7 @@ var mmProposeChangeOwner = &cli.Command{ return err } - var retval msig5.ProposeReturn + var retval multisig.ProposeReturn if err := retval.UnmarshalCBOR(bytes.NewReader(wait.Receipt.Return)); err != nil { return fmt.Errorf("failed to unmarshal propose return value: %w", err) } @@ -356,7 +357,7 @@ var mmApproveChangeOwner = &cli.Command{ return err } - var retval msig5.ApproveReturn + var retval multisig.ApproveReturn if err := retval.UnmarshalCBOR(bytes.NewReader(wait.Receipt.Return)); err != nil { return fmt.Errorf("failed to unmarshal approve return value: %w", err) } @@ -421,7 +422,7 @@ var mmProposeChangeWorker = &cli.Command{ } } - cwp := &miner2.ChangeWorkerAddressParams{ + cwp := &miner.ChangeWorkerAddressParams{ NewWorker: newAddr, NewControlAddrs: mi.ControlAddresses, } @@ -453,7 +454,7 @@ var mmProposeChangeWorker = &cli.Command{ return err } - var retval msig5.ProposeReturn + var retval multisig.ProposeReturn if err := retval.UnmarshalCBOR(bytes.NewReader(wait.Receipt.Return)); err != nil { return fmt.Errorf("failed to unmarshal propose return value: %w", err) } @@ -469,6 +470,114 @@ var mmProposeChangeWorker = &cli.Command{ }, } +var mmProposeChangeBeneficiary = &cli.Command{ + Name: "propose-change-beneficiary", + Usage: "Propose a beneficiary address change", + ArgsUsage: "[beneficiaryAddress quota expiration]", + Flags: []cli.Flag{ + &cli.BoolFlag{ + Name: "really-do-it", + Usage: "Actually send transaction performing the action", + Value: false, + }, + &cli.BoolFlag{ + Name: "overwrite-pending-change", + Usage: "Overwrite the current beneficiary change proposal", + Value: false, + }, + }, + Action: func(cctx *cli.Context) error { + if cctx.NArg() != 3 { + return lcli.IncorrectNumArgs(cctx) + } + + api, acloser, err := lcli.GetFullNodeAPI(cctx) + if err != nil { + return xerrors.Errorf("getting fullnode api: %w", err) + } + defer acloser() + + ctx := lcli.ReqContext(cctx) + + na, err := address.NewFromString(cctx.Args().Get(0)) + if err != nil { + return xerrors.Errorf("parsing beneficiary address: %w", err) + } + + newAddr, err := api.StateLookupID(ctx, na, types.EmptyTSK) + if err != nil { + return xerrors.Errorf("looking up new beneficiary address: %w", err) + } + + quota, err := types.ParseFIL(cctx.Args().Get(1)) + if err != nil { + return xerrors.Errorf("parsing quota: %w", err) + } + + expiration, err := types.BigFromString(cctx.Args().Get(2)) + if err != nil { + return xerrors.Errorf("parsing expiration: %w", err) + } + + multisigAddr, sender, minerAddr, err := getInputs(cctx) + if err != nil { + return err + } + + mi, err := api.StateMinerInfo(ctx, minerAddr, types.EmptyTSK) + if err != nil { + return err + } + + if mi.PendingBeneficiaryTerm != nil { + fmt.Println("WARNING: replacing Pending Beneficiary Term of:") + fmt.Println("Beneficiary: ", mi.PendingBeneficiaryTerm.NewBeneficiary) + fmt.Println("Quota:", mi.PendingBeneficiaryTerm.NewQuota) + fmt.Println("Expiration Epoch:", mi.PendingBeneficiaryTerm.NewExpiration) + + if !cctx.Bool("overwrite-pending-change") { + return fmt.Errorf("must pass --overwrite-pending-change to replace current pending beneficiary change. Please review CAREFULLY") + } + } + + if !cctx.Bool("really-do-it") { + fmt.Println("Pass --really-do-it to actually execute this action") + return nil + } + + params := &miner.ChangeBeneficiaryParams{ + NewBeneficiary: newAddr, + NewQuota: abi.TokenAmount(quota), + NewExpiration: abi.ChainEpoch(expiration.Int64()), + } + + sp, err := actors.SerializeParams(params) + if err != nil { + return xerrors.Errorf("serializing params: %w", err) + } + + pcid, err := api.MsigPropose(ctx, multisigAddr, minerAddr, big.Zero(), sender, uint64(builtin.MethodsMiner.ChangeBeneficiary), sp) + if err != nil { + return xerrors.Errorf("proposing message: %w", err) + } + + fmt.Println("Propose Message CID: ", pcid) + + // wait for it to get mined into a block + wait, err := api.StateWaitMsg(ctx, pcid, build.MessageConfidence) + if err != nil { + return xerrors.Errorf("waiting for message to be included in block: %w", err) + } + + // check it executed successfully + if wait.Receipt.ExitCode.IsError() { + return fmt.Errorf("propose beneficiary change failed") + } + + return nil + }, +} + var mmConfirmChangeWorker = &cli.Command{ Name: "confirm-change-worker", Usage: "Confirm an worker address change", @@ -537,7 +646,7 @@ var mmConfirmChangeWorker = &cli.Command{ return err } - var retval msig5.ProposeReturn + var retval multisig.ProposeReturn if err := retval.UnmarshalCBOR(bytes.NewReader(wait.Receipt.Return)); err != nil { return fmt.Errorf("failed to unmarshal propose return value: %w", err) } @@ -552,6 +661,98 @@ var mmConfirmChangeWorker = &cli.Command{ }, } +var mmConfirmChangeBeneficiary = &cli.Command{ + Name: "confirm-change-beneficiary", + Usage: "Confirm a beneficiary address change", + ArgsUsage: "[minerAddress]", + Flags: []cli.Flag{ + &cli.BoolFlag{ + Name: "really-do-it", + Usage: "Actually send transaction performing the action", + Value: false, + }, + }, + Action: func(cctx *cli.Context) error { + if cctx.NArg() != 1 { + return lcli.IncorrectNumArgs(cctx) + } + + api, acloser, err := lcli.GetFullNodeAPI(cctx) + if err != nil { + return xerrors.Errorf("getting fullnode api: %w", err) + } + defer acloser() + + ctx := lcli.ReqContext(cctx) + + multisigAddr, sender, minerAddr, err := getInputs(cctx) + if err != nil { + return err + } + + mi, err := api.StateMinerInfo(ctx, minerAddr, types.EmptyTSK) + if err != nil { + return err + } + + if mi.PendingBeneficiaryTerm == nil { + return fmt.Errorf("no pending beneficiary term found for miner %s", minerAddr) + } + + fmt.Println("Confirming Pending Beneficiary Term of:") + fmt.Println("Beneficiary: ", mi.PendingBeneficiaryTerm.NewBeneficiary) + fmt.Println("Quota:", mi.PendingBeneficiaryTerm.NewQuota) + fmt.Println("Expiration Epoch:", mi.PendingBeneficiaryTerm.NewExpiration) + + if !cctx.Bool("really-do-it") { + fmt.Println("Pass --really-do-it to actually execute this action") + return nil + } + + params := &miner.ChangeBeneficiaryParams{ + NewBeneficiary: mi.PendingBeneficiaryTerm.NewBeneficiary, + NewQuota: mi.PendingBeneficiaryTerm.NewQuota, + NewExpiration: mi.PendingBeneficiaryTerm.NewExpiration, + } + + sp, err := actors.SerializeParams(params) + if err != nil { + return xerrors.Errorf("serializing params: %w", err) + } + + pcid, err := api.MsigPropose(ctx, multisigAddr, minerAddr, big.Zero(), sender, uint64(builtin.MethodsMiner.ChangeBeneficiary), sp) + if err != nil { + return xerrors.Errorf("proposing message: %w", err) + } + + fmt.Println("Confirm Message CID:", pcid) + + // wait for it to get mined into a block + wait, err := api.StateWaitMsg(ctx, pcid, build.MessageConfidence) + if err != nil { + return xerrors.Errorf("waiting for message to be included in block: %w", err) + } + + // check it executed successfully + if wait.Receipt.ExitCode != 0 { + return fmt.Errorf("confirm beneficiary change failed") + } + + updatedMinerInfo, err := api.StateMinerInfo(ctx, minerAddr, types.EmptyTSK) + if err != nil { + return err + } + + if updatedMinerInfo.PendingBeneficiaryTerm == nil { + fmt.Println("Beneficiary address successfully changed") + } else { + fmt.Println("Beneficiary address change awaiting additional confirmations") + } + + return nil + }, +} + var mmProposeControlSet = &cli.Command{ Name: "propose-control-set", Usage: "Set control address(-es)", @@ -623,7 +824,7 @@ var mmProposeControlSet = &cli.Command{ } } - cwp := &miner2.ChangeWorkerAddressParams{ + cwp := &miner.ChangeWorkerAddressParams{ NewWorker: mi.Worker, NewControlAddrs: toSet, } @@ -652,7 +853,7 @@ var mmProposeControlSet = &cli.Command{ return err } - var retval msig5.ProposeReturn + var retval multisig.ProposeReturn if err := retval.UnmarshalCBOR(bytes.NewReader(wait.Receipt.Return)); err != nil { return fmt.Errorf("failed to unmarshal propose return value: %w", err) } diff --git a/documentation/en/cli-lotus-miner.md b/documentation/en/cli-lotus-miner.md index 235465aa2..322fe10de 100644 --- a/documentation/en/cli-lotus-miner.md +++ b/documentation/en/cli-lotus-miner.md @@ -231,16 +231,18 @@ USAGE: lotus-miner actor command [command options] [arguments...] COMMANDS: - set-addresses, set-addrs set addresses that your miner can be publicly dialed on - withdraw withdraw available balance to beneficiary - repay-debt pay down a miner's debt - set-peer-id set the peer id of your miner - set-owner Set owner address (this command should be invoked twice, first with the old owner as the senderAddress, and then with the new owner) - control Manage control addresses - propose-change-worker Propose a worker address change - confirm-change-worker Confirm a worker address change - compact-allocated compact allocated sectors bitfield - help, h Shows a list of commands or help for one command + set-addresses, set-addrs set addresses that your miner can be publicly dialed on + withdraw withdraw available balance to beneficiary + repay-debt pay down a miner's debt + set-peer-id set the peer id of your miner + set-owner Set owner address (this command should be invoked twice, first with the old owner as the senderAddress, and then with the new owner) + control Manage control addresses + propose-change-worker Propose a worker address change + confirm-change-worker Confirm a worker address change + compact-allocated compact allocated sectors bitfield + propose-change-beneficiary Propose a beneficiary address change + confirm-change-beneficiary Confirm a beneficiary address change + help, h Shows a list of commands or help for one command OPTIONS: --help, -h show help (default: false) @@ -390,6 +392,36 @@ OPTIONS: ``` +### lotus-miner actor propose-change-beneficiary +``` +NAME: + lotus-miner actor propose-change-beneficiary - Propose a beneficiary address change + +USAGE: + lotus-miner actor propose-change-beneficiary [command options] [beneficiaryAddress quota expiration] + +OPTIONS: + --actor value specify the address of miner actor + --overwrite-pending-change Overwrite the current beneficiary change proposal (default: false) + --really-do-it Actually send transaction performing the action (default: false) + +``` + +### lotus-miner actor confirm-change-beneficiary +``` +NAME: + lotus-miner actor confirm-change-beneficiary - Confirm a beneficiary address change + +USAGE: + lotus-miner actor confirm-change-beneficiary [command options] [minerAddress] + +OPTIONS: + --existing-beneficiary send confirmation from the existing beneficiary address (default: false) + --new-beneficiary send confirmation from the new beneficiary address (default: false) + --really-do-it Actually send transaction performing the action (default: false) + +``` + ## lotus-miner info ``` NAME: From 3c193287640eb9a9bb903e8541d4f7b474e0c277 Mon Sep 17 00:00:00 2001 From: Geoff Stuart Date: Wed, 14 Sep 2022 17:38:01 -0400 Subject: [PATCH 2/2] Review fixes --- cmd/lotus-miner/actor.go | 12 ++++++------ cmd/lotus-shed/miner-multisig.go | 10 +++++----- 2 files changed, 11 insertions(+), 11 deletions(-) diff --git a/cmd/lotus-miner/actor.go b/cmd/lotus-miner/actor.go index b1f97d530..7b0e81c3b 100644 --- a/cmd/lotus-miner/actor.go +++ b/cmd/lotus-miner/actor.go @@ -1006,7 +1006,7 @@ var actorProposeChangeBeneficiary = &cli.Command{ } if !cctx.Bool("really-do-it") { - fmt.Println("Pass --really-do-it to actually execute this action") + fmt.Println("Pass --really-do-it to actually execute this action. Review what you're about to approve CAREFULLY please") return nil } @@ -1050,7 +1050,7 @@ var actorProposeChangeBeneficiary = &cli.Command{ return xerrors.Errorf("getting miner info: %w", err) } - if updatedMinerInfo.PendingBeneficiaryTerm == nil { + if updatedMinerInfo.PendingBeneficiaryTerm == nil && updatedMinerInfo.Beneficiary == newAddr { fmt.Println("Beneficiary address successfully changed") } else { fmt.Println("Beneficiary address change awaiting additional confirmations") @@ -1210,7 +1210,7 @@ var actorConfirmChangeBeneficiary = &cli.Command{ } if (cctx.IsSet("existing-beneficiary") && cctx.IsSet("new-beneficiary")) || (!cctx.IsSet("existing-beneficiary") && !cctx.IsSet("new-beneficiary")) { - return lcli.ShowHelp(cctx, fmt.Errorf("must pass exactly one of --existing-beneficiary or --existing-beneficiary")) + return lcli.ShowHelp(cctx, fmt.Errorf("must pass exactly one of --existing-beneficiary or --new-beneficiary")) } var fromAddr address.Address @@ -1232,7 +1232,7 @@ var actorConfirmChangeBeneficiary = &cli.Command{ fmt.Println("Expiration Epoch:", mi.PendingBeneficiaryTerm.NewExpiration) if !cctx.Bool("really-do-it") { - fmt.Println("Pass --really-do-it to actually execute this action") + fmt.Println("Pass --really-do-it to actually execute this action. Review what you're about to approve CAREFULLY please") return nil } @@ -1268,7 +1268,7 @@ var actorConfirmChangeBeneficiary = &cli.Command{ // check it executed successfully if wait.Receipt.ExitCode.IsError() { - return fmt.Errorf("confirm beneficiary change failed") + return fmt.Errorf("confirm beneficiary change failed with code %d", wait.Receipt.ExitCode) } updatedMinerInfo, err := api.StateMinerInfo(ctx, maddr, types.EmptyTSK) @@ -1276,7 +1276,7 @@ var actorConfirmChangeBeneficiary = &cli.Command{ return err } - if updatedMinerInfo.PendingBeneficiaryTerm == nil { + if updatedMinerInfo.PendingBeneficiaryTerm == nil && updatedMinerInfo.Beneficiary == mi.PendingBeneficiaryTerm.NewBeneficiary { fmt.Println("Beneficiary address successfully changed") } else { fmt.Println("Beneficiary address change awaiting additional confirmations") diff --git a/cmd/lotus-shed/miner-multisig.go b/cmd/lotus-shed/miner-multisig.go index 0ea29c50b..080229a6a 100644 --- a/cmd/lotus-shed/miner-multisig.go +++ b/cmd/lotus-shed/miner-multisig.go @@ -541,7 +541,7 @@ var mmProposeChangeBeneficiary = &cli.Command{ } if !cctx.Bool("really-do-it") { - fmt.Println("Pass --really-do-it to actually execute this action") + fmt.Println("Pass --really-do-it to actually execute this action. Review what you're about to approve CAREFULLY please") return nil } @@ -705,7 +705,7 @@ var mmConfirmChangeBeneficiary = &cli.Command{ fmt.Println("Expiration Epoch:", mi.PendingBeneficiaryTerm.NewExpiration) if !cctx.Bool("really-do-it") { - fmt.Println("Pass --really-do-it to actually execute this action") + fmt.Println("Pass --really-do-it to actually execute this action. Review what you're about to approve CAREFULLY please") return nil } @@ -734,8 +734,8 @@ var mmConfirmChangeBeneficiary = &cli.Command{ } // check it executed successfully - if wait.Receipt.ExitCode != 0 { - return fmt.Errorf("confirm beneficiary change failed") + if wait.Receipt.ExitCode.IsError() { + return fmt.Errorf("confirm beneficiary change failed with code %d", wait.Receipt.ExitCode) } updatedMinerInfo, err := api.StateMinerInfo(ctx, minerAddr, types.EmptyTSK) @@ -743,7 +743,7 @@ var mmConfirmChangeBeneficiary = &cli.Command{ return err } - if updatedMinerInfo.PendingBeneficiaryTerm == nil { + if updatedMinerInfo.PendingBeneficiaryTerm == nil && updatedMinerInfo.Beneficiary == mi.PendingBeneficiaryTerm.NewBeneficiary { fmt.Println("Beneficiary address successfully changed") } else { fmt.Println("Beneficiary address change awaiting additional confirmations")