Merge pull request #9307 from filecoin-project/gstuart/change-beneficiary
feat: api/cli: change beneficiary propose and confirm for actors and multisigs.
This commit is contained in:
commit
305589e347
@ -4,6 +4,7 @@ import (
|
|||||||
"bytes"
|
"bytes"
|
||||||
"fmt"
|
"fmt"
|
||||||
"os"
|
"os"
|
||||||
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/fatih/color"
|
"github.com/fatih/color"
|
||||||
@ -20,7 +21,7 @@ import (
|
|||||||
"github.com/filecoin-project/go-state-types/abi"
|
"github.com/filecoin-project/go-state-types/abi"
|
||||||
"github.com/filecoin-project/go-state-types/big"
|
"github.com/filecoin-project/go-state-types/big"
|
||||||
"github.com/filecoin-project/go-state-types/builtin"
|
"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/go-state-types/network"
|
||||||
|
|
||||||
"github.com/filecoin-project/lotus/api"
|
"github.com/filecoin-project/lotus/api"
|
||||||
@ -48,6 +49,8 @@ var actorCmd = &cli.Command{
|
|||||||
actorProposeChangeWorker,
|
actorProposeChangeWorker,
|
||||||
actorConfirmChangeWorker,
|
actorConfirmChangeWorker,
|
||||||
actorCompactAllocatedCmd,
|
actorCompactAllocatedCmd,
|
||||||
|
actorProposeChangeBeneficiary,
|
||||||
|
actorConfirmChangeBeneficiary,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -906,8 +909,7 @@ var actorProposeChangeWorker = &cli.Command{
|
|||||||
|
|
||||||
// check it executed successfully
|
// check it executed successfully
|
||||||
if wait.Receipt.ExitCode.IsError() {
|
if wait.Receipt.ExitCode.IsError() {
|
||||||
fmt.Fprintln(cctx.App.Writer, "Propose worker change failed!")
|
return fmt.Errorf("propose worker change failed")
|
||||||
return err
|
|
||||||
}
|
}
|
||||||
|
|
||||||
mi, err = api.StateMinerInfo(ctx, maddr, wait.TipSet)
|
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. Review what you're about to approve CAREFULLY please")
|
||||||
|
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 && updatedMinerInfo.Beneficiary == newAddr {
|
||||||
|
fmt.Println("Beneficiary address successfully changed")
|
||||||
|
} else {
|
||||||
|
fmt.Println("Beneficiary address change awaiting additional confirmations")
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
var actorConfirmChangeWorker = &cli.Command{
|
var actorConfirmChangeWorker = &cli.Command{
|
||||||
Name: "confirm-change-worker",
|
Name: "confirm-change-worker",
|
||||||
Usage: "Confirm a worker address change",
|
Usage: "Confirm a worker address change",
|
||||||
@ -988,7 +1123,7 @@ var actorConfirmChangeWorker = &cli.Command{
|
|||||||
}
|
}
|
||||||
|
|
||||||
if !cctx.Bool("really-do-it") {
|
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
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1002,7 +1137,7 @@ var actorConfirmChangeWorker = &cli.Command{
|
|||||||
return xerrors.Errorf("mpool push: %w", err)
|
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 for it to get mined into a block
|
||||||
wait, err := api.StateWaitMsg(ctx, smsg.Cid(), build.MessageConfidence)
|
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 --new-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. Review what you're about to approve CAREFULLY please")
|
||||||
|
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 with code %d", wait.Receipt.ExitCode)
|
||||||
|
}
|
||||||
|
|
||||||
|
updatedMinerInfo, err := api.StateMinerInfo(ctx, maddr, types.EmptyTSK)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
if updatedMinerInfo.PendingBeneficiaryTerm == nil && updatedMinerInfo.Beneficiary == mi.PendingBeneficiaryTerm.NewBeneficiary {
|
||||||
|
fmt.Println("Beneficiary address successfully changed")
|
||||||
|
} else {
|
||||||
|
fmt.Println("Beneficiary address change awaiting additional confirmations")
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
var actorCompactAllocatedCmd = &cli.Command{
|
var actorCompactAllocatedCmd = &cli.Command{
|
||||||
Name: "compact-allocated",
|
Name: "compact-allocated",
|
||||||
Usage: "compact allocated sectors bitfield",
|
Usage: "compact allocated sectors bitfield",
|
||||||
|
@ -12,9 +12,8 @@ import (
|
|||||||
"github.com/filecoin-project/go-state-types/abi"
|
"github.com/filecoin-project/go-state-types/abi"
|
||||||
"github.com/filecoin-project/go-state-types/big"
|
"github.com/filecoin-project/go-state-types/big"
|
||||||
"github.com/filecoin-project/go-state-types/builtin"
|
"github.com/filecoin-project/go-state-types/builtin"
|
||||||
miner2 "github.com/filecoin-project/specs-actors/v2/actors/builtin/miner"
|
"github.com/filecoin-project/go-state-types/builtin/v9/miner"
|
||||||
miner5 "github.com/filecoin-project/specs-actors/v5/actors/builtin/miner"
|
"github.com/filecoin-project/go-state-types/builtin/v9/multisig"
|
||||||
msig5 "github.com/filecoin-project/specs-actors/v5/actors/builtin/multisig"
|
|
||||||
|
|
||||||
"github.com/filecoin-project/lotus/build"
|
"github.com/filecoin-project/lotus/build"
|
||||||
"github.com/filecoin-project/lotus/chain/actors"
|
"github.com/filecoin-project/lotus/chain/actors"
|
||||||
@ -33,6 +32,8 @@ var minerMultisigsCmd = &cli.Command{
|
|||||||
mmProposeChangeWorker,
|
mmProposeChangeWorker,
|
||||||
mmConfirmChangeWorker,
|
mmConfirmChangeWorker,
|
||||||
mmProposeControlSet,
|
mmProposeControlSet,
|
||||||
|
mmProposeChangeBeneficiary,
|
||||||
|
mmConfirmChangeBeneficiary,
|
||||||
},
|
},
|
||||||
Flags: []cli.Flag{
|
Flags: []cli.Flag{
|
||||||
&cli.StringFlag{
|
&cli.StringFlag{
|
||||||
@ -80,7 +81,7 @@ var mmProposeWithdrawBalance = &cli.Command{
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
sp, err := actors.SerializeParams(&miner5.WithdrawBalanceParams{
|
sp, err := actors.SerializeParams(&miner.WithdrawBalanceParams{
|
||||||
AmountRequested: abi.TokenAmount(val),
|
AmountRequested: abi.TokenAmount(val),
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -106,7 +107,7 @@ var mmProposeWithdrawBalance = &cli.Command{
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
var retval msig5.ProposeReturn
|
var retval multisig.ProposeReturn
|
||||||
if err := retval.UnmarshalCBOR(bytes.NewReader(wait.Receipt.Return)); err != nil {
|
if err := retval.UnmarshalCBOR(bytes.NewReader(wait.Receipt.Return)); err != nil {
|
||||||
return fmt.Errorf("failed to unmarshal propose return value: %w", err)
|
return fmt.Errorf("failed to unmarshal propose return value: %w", err)
|
||||||
}
|
}
|
||||||
@ -149,7 +150,7 @@ var mmApproveWithdrawBalance = &cli.Command{
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
sp, err := actors.SerializeParams(&miner5.WithdrawBalanceParams{
|
sp, err := actors.SerializeParams(&miner.WithdrawBalanceParams{
|
||||||
AmountRequested: abi.TokenAmount(val),
|
AmountRequested: abi.TokenAmount(val),
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -185,7 +186,7 @@ var mmApproveWithdrawBalance = &cli.Command{
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
var retval msig5.ApproveReturn
|
var retval multisig.ApproveReturn
|
||||||
if err := retval.UnmarshalCBOR(bytes.NewReader(wait.Receipt.Return)); err != nil {
|
if err := retval.UnmarshalCBOR(bytes.NewReader(wait.Receipt.Return)); err != nil {
|
||||||
return fmt.Errorf("failed to unmarshal approve return value: %w", err)
|
return fmt.Errorf("failed to unmarshal approve return value: %w", err)
|
||||||
}
|
}
|
||||||
@ -266,7 +267,7 @@ var mmProposeChangeOwner = &cli.Command{
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
var retval msig5.ProposeReturn
|
var retval multisig.ProposeReturn
|
||||||
if err := retval.UnmarshalCBOR(bytes.NewReader(wait.Receipt.Return)); err != nil {
|
if err := retval.UnmarshalCBOR(bytes.NewReader(wait.Receipt.Return)); err != nil {
|
||||||
return fmt.Errorf("failed to unmarshal propose return value: %w", err)
|
return fmt.Errorf("failed to unmarshal propose return value: %w", err)
|
||||||
}
|
}
|
||||||
@ -356,7 +357,7 @@ var mmApproveChangeOwner = &cli.Command{
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
var retval msig5.ApproveReturn
|
var retval multisig.ApproveReturn
|
||||||
if err := retval.UnmarshalCBOR(bytes.NewReader(wait.Receipt.Return)); err != nil {
|
if err := retval.UnmarshalCBOR(bytes.NewReader(wait.Receipt.Return)); err != nil {
|
||||||
return fmt.Errorf("failed to unmarshal approve return value: %w", err)
|
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,
|
NewWorker: newAddr,
|
||||||
NewControlAddrs: mi.ControlAddresses,
|
NewControlAddrs: mi.ControlAddresses,
|
||||||
}
|
}
|
||||||
@ -453,7 +454,7 @@ var mmProposeChangeWorker = &cli.Command{
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
var retval msig5.ProposeReturn
|
var retval multisig.ProposeReturn
|
||||||
if err := retval.UnmarshalCBOR(bytes.NewReader(wait.Receipt.Return)); err != nil {
|
if err := retval.UnmarshalCBOR(bytes.NewReader(wait.Receipt.Return)); err != nil {
|
||||||
return fmt.Errorf("failed to unmarshal propose return value: %w", err)
|
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. Review what you're about to approve CAREFULLY please")
|
||||||
|
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{
|
var mmConfirmChangeWorker = &cli.Command{
|
||||||
Name: "confirm-change-worker",
|
Name: "confirm-change-worker",
|
||||||
Usage: "Confirm an worker address change",
|
Usage: "Confirm an worker address change",
|
||||||
@ -537,7 +646,7 @@ var mmConfirmChangeWorker = &cli.Command{
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
var retval msig5.ProposeReturn
|
var retval multisig.ProposeReturn
|
||||||
if err := retval.UnmarshalCBOR(bytes.NewReader(wait.Receipt.Return)); err != nil {
|
if err := retval.UnmarshalCBOR(bytes.NewReader(wait.Receipt.Return)); err != nil {
|
||||||
return fmt.Errorf("failed to unmarshal propose return value: %w", err)
|
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. Review what you're about to approve CAREFULLY please")
|
||||||
|
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.IsError() {
|
||||||
|
return fmt.Errorf("confirm beneficiary change failed with code %d", wait.Receipt.ExitCode)
|
||||||
|
}
|
||||||
|
|
||||||
|
updatedMinerInfo, err := api.StateMinerInfo(ctx, minerAddr, types.EmptyTSK)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
if updatedMinerInfo.PendingBeneficiaryTerm == nil && updatedMinerInfo.Beneficiary == mi.PendingBeneficiaryTerm.NewBeneficiary {
|
||||||
|
fmt.Println("Beneficiary address successfully changed")
|
||||||
|
} else {
|
||||||
|
fmt.Println("Beneficiary address change awaiting additional confirmations")
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
var mmProposeControlSet = &cli.Command{
|
var mmProposeControlSet = &cli.Command{
|
||||||
Name: "propose-control-set",
|
Name: "propose-control-set",
|
||||||
Usage: "Set control address(-es)",
|
Usage: "Set control address(-es)",
|
||||||
@ -623,7 +824,7 @@ var mmProposeControlSet = &cli.Command{
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
cwp := &miner2.ChangeWorkerAddressParams{
|
cwp := &miner.ChangeWorkerAddressParams{
|
||||||
NewWorker: mi.Worker,
|
NewWorker: mi.Worker,
|
||||||
NewControlAddrs: toSet,
|
NewControlAddrs: toSet,
|
||||||
}
|
}
|
||||||
@ -652,7 +853,7 @@ var mmProposeControlSet = &cli.Command{
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
var retval msig5.ProposeReturn
|
var retval multisig.ProposeReturn
|
||||||
if err := retval.UnmarshalCBOR(bytes.NewReader(wait.Receipt.Return)); err != nil {
|
if err := retval.UnmarshalCBOR(bytes.NewReader(wait.Receipt.Return)); err != nil {
|
||||||
return fmt.Errorf("failed to unmarshal propose return value: %w", err)
|
return fmt.Errorf("failed to unmarshal propose return value: %w", err)
|
||||||
}
|
}
|
||||||
|
@ -240,6 +240,8 @@ COMMANDS:
|
|||||||
propose-change-worker Propose a worker address change
|
propose-change-worker Propose a worker address change
|
||||||
confirm-change-worker Confirm a worker address change
|
confirm-change-worker Confirm a worker address change
|
||||||
compact-allocated compact allocated sectors bitfield
|
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
|
help, h Shows a list of commands or help for one command
|
||||||
|
|
||||||
OPTIONS:
|
OPTIONS:
|
||||||
@ -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
|
## lotus-miner info
|
||||||
```
|
```
|
||||||
NAME:
|
NAME:
|
||||||
|
Loading…
Reference in New Issue
Block a user