Skip to content

Commit

Permalink
add cli commands for changing beneficiary
Browse files Browse the repository at this point in the history
  • Loading branch information
geoff-vball committed Sep 14, 2022
1 parent f567db6 commit 9e2fe56
Show file tree
Hide file tree
Showing 4 changed files with 525 additions and 30 deletions.
4 changes: 4 additions & 0 deletions cli/helper.go
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,10 @@ func ShowHelp(cctx *ufcli.Context, err error) error {
return &PrintHelpErr{Err: err, Ctx: cctx}
}

func IncorrectNumArgs(cctx *ufcli.Context) error {
return ShowHelp(cctx, fmt.Errorf("incorrect number of arguments, got %d", cctx.NArg()))
}

func RunApp(app *ufcli.App) {
if err := app.Run(os.Args); err != nil {
if os.Getenv("LOTUS_DEV") != "" {
Expand Down
268 changes: 263 additions & 5 deletions cmd/lotus-miner/actor.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import (
"bytes"
"fmt"
"os"
"strconv"
"strings"

"github.com/fatih/color"
Expand All @@ -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"
Expand Down Expand Up @@ -48,6 +49,8 @@ var actorCmd = &cli.Command{
actorProposeChangeWorker,
actorConfirmChangeWorker,
actorCompactAllocatedCmd,
actorProposeChangeBeneficiary,
actorConfirmChangeBeneficiary,
},
}

Expand Down Expand Up @@ -906,8 +909,7 @@ var actorProposeChangeWorker = &cli.Command{

// check it executed successfully
if wait.Receipt.ExitCode != 0 {
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)
Expand All @@ -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",
Expand Down Expand Up @@ -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
}

Expand All @@ -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)
Expand All @@ -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",
Expand Down
Loading

0 comments on commit 9e2fe56

Please sign in to comment.