diff --git a/cli/spcli/actor.go b/cli/spcli/actor.go new file mode 100644 index 00000000000..762b0d170fa --- /dev/null +++ b/cli/spcli/actor.go @@ -0,0 +1,98 @@ +package spcli + +import ( + "bytes" + "fmt" + + "github.com/urfave/cli/v2" + "golang.org/x/xerrors" + + "github.com/filecoin-project/go-state-types/abi" + "github.com/filecoin-project/go-state-types/network" + + lapi "github.com/filecoin-project/lotus/api" + "github.com/filecoin-project/lotus/build" + "github.com/filecoin-project/lotus/chain/types" + lcli "github.com/filecoin-project/lotus/cli" + "github.com/filecoin-project/lotus/node/impl" +) + +func ActorWithdrawCmd(getActor ActorAddressGetter) *cli.Command { + return &cli.Command{ + Name: "withdraw", + Usage: "withdraw available balance to beneficiary", + ArgsUsage: "[amount (FIL)]", + Flags: []cli.Flag{ + &cli.IntFlag{ + Name: "confidence", + Usage: "number of block confirmations to wait for", + Value: int(build.MessageConfidence), + }, + &cli.BoolFlag{ + Name: "beneficiary", + Usage: "send withdraw message from the beneficiary address", + }, + }, + Action: func(cctx *cli.Context) error { + amount := abi.NewTokenAmount(0) + + if cctx.Args().Present() { + f, err := types.ParseFIL(cctx.Args().First()) + if err != nil { + return xerrors.Errorf("parsing 'amount' argument: %w", err) + } + + amount = abi.TokenAmount(f) + } + + api, acloser, err := lcli.GetFullNodeAPIV1(cctx) + if err != nil { + return err + } + defer acloser() + + ctx := lcli.ReqContext(cctx) + + maddr, err := getActor(cctx) + if err != nil { + return err + } + + res, err := impl.WithdrawBalance(ctx, api, maddr, amount, !cctx.IsSet("beneficiary")) + if err != nil { + return err + } + + fmt.Printf("Requested withdrawal in message %s\nwaiting for it to be included in a block..\n", res) + + // wait for it to get mined into a block + wait, err := api.StateWaitMsg(ctx, res, uint64(cctx.Int("confidence")), lapi.LookbackNoLimit, true) + if err != nil { + return xerrors.Errorf("Timeout waiting for withdrawal message %s", res) + } + + if wait.Receipt.ExitCode.IsError() { + return xerrors.Errorf("Failed to execute withdrawal message %s: %w", wait.Message, wait.Receipt.ExitCode.Error()) + } + + nv, err := api.StateNetworkVersion(ctx, wait.TipSet) + if err != nil { + return err + } + + if nv >= network.Version14 { + var withdrawn abi.TokenAmount + if err := withdrawn.UnmarshalCBOR(bytes.NewReader(wait.Receipt.Return)); err != nil { + return err + } + + fmt.Printf("Successfully withdrew %s \n", types.FIL(withdrawn)) + if withdrawn.LessThan(amount) { + fmt.Printf("Note that this is less than the requested amount of %s\n", types.FIL(amount)) + } + } + + return nil + }, + } +} diff --git a/cli/spcli/util.go b/cli/spcli/util.go new file mode 100644 index 00000000000..71ac371fec7 --- /dev/null +++ b/cli/spcli/util.go @@ -0,0 +1,9 @@ +package spcli + +import ( + "github.com/urfave/cli/v2" + + "github.com/filecoin-project/go-address" +) + +type ActorAddressGetter func(cctx *cli.Context) (address address.Address, err error) diff --git a/cmd/lotus-miner/actor.go b/cmd/lotus-miner/actor.go index 6d76cc07fdc..a7b342f4c02 100644 --- a/cmd/lotus-miner/actor.go +++ b/cmd/lotus-miner/actor.go @@ -1,14 +1,12 @@ package main import ( - "bytes" "fmt" "os" "strconv" "strings" "github.com/fatih/color" - "github.com/ipfs/go-cid" cbor "github.com/ipfs/go-ipld-cbor" "github.com/libp2p/go-libp2p/core/peer" ma "github.com/multiformats/go-multiaddr" @@ -22,7 +20,6 @@ import ( "github.com/filecoin-project/go-state-types/big" "github.com/filecoin-project/go-state-types/builtin" "github.com/filecoin-project/go-state-types/builtin/v9/miner" - "github.com/filecoin-project/go-state-types/network" "github.com/filecoin-project/lotus/api" "github.com/filecoin-project/lotus/blockstore" @@ -33,6 +30,7 @@ import ( lminer "github.com/filecoin-project/lotus/chain/actors/builtin/miner" "github.com/filecoin-project/lotus/chain/types" lcli "github.com/filecoin-project/lotus/cli" + "github.com/filecoin-project/lotus/cli/spcli" "github.com/filecoin-project/lotus/lib/tablewriter" ) @@ -41,7 +39,7 @@ var actorCmd = &cli.Command{ Usage: "manipulate the miner actor", Subcommands: []*cli.Command{ actorSetAddrsCmd, - actorWithdrawCmd, + spcli.ActorWithdrawCmd(LMActorGetter), actorRepayDebtCmd, actorSetPeeridCmd, actorSetOwnerCmd, @@ -240,90 +238,6 @@ var actorSetPeeridCmd = &cli.Command{ }, } -var actorWithdrawCmd = &cli.Command{ - Name: "withdraw", - Usage: "withdraw available balance to beneficiary", - ArgsUsage: "[amount (FIL)]", - Flags: []cli.Flag{ - &cli.IntFlag{ - Name: "confidence", - Usage: "number of block confirmations to wait for", - Value: int(build.MessageConfidence), - }, - &cli.BoolFlag{ - Name: "beneficiary", - Usage: "send withdraw message from the beneficiary address", - }, - }, - Action: func(cctx *cli.Context) error { - amount := abi.NewTokenAmount(0) - - if cctx.Args().Present() { - f, err := types.ParseFIL(cctx.Args().First()) - if err != nil { - return xerrors.Errorf("parsing 'amount' argument: %w", err) - } - - amount = abi.TokenAmount(f) - } - - minerApi, closer, err := lcli.GetStorageMinerAPI(cctx) - if err != nil { - return err - } - defer closer() - - api, acloser, err := lcli.GetFullNodeAPI(cctx) - if err != nil { - return err - } - defer acloser() - - ctx := lcli.ReqContext(cctx) - - var res cid.Cid - if cctx.IsSet("beneficiary") { - res, err = minerApi.BeneficiaryWithdrawBalance(ctx, amount) - } else { - res, err = minerApi.ActorWithdrawBalance(ctx, amount) - } - if err != nil { - return err - } - - fmt.Printf("Requested withdrawal in message %s\nwaiting for it to be included in a block..\n", res) - - // wait for it to get mined into a block - wait, err := api.StateWaitMsg(ctx, res, uint64(cctx.Int("confidence"))) - if err != nil { - return xerrors.Errorf("Timeout waiting for withdrawal message %s", res) - } - - if wait.Receipt.ExitCode.IsError() { - return xerrors.Errorf("Failed to execute withdrawal message %s: %w", wait.Message, wait.Receipt.ExitCode.Error()) - } - - nv, err := api.StateNetworkVersion(ctx, wait.TipSet) - if err != nil { - return err - } - - if nv >= network.Version14 { - var withdrawn abi.TokenAmount - if err := withdrawn.UnmarshalCBOR(bytes.NewReader(wait.Receipt.Return)); err != nil { - return err - } - - fmt.Printf("Successfully withdrew %s \n", types.FIL(withdrawn)) - if withdrawn.LessThan(amount) { - fmt.Printf("Note that this is less than the requested amount of %s\n", types.FIL(amount)) - } - } - - return nil - }, -} - var actorRepayDebtCmd = &cli.Command{ Name: "repay-debt", Usage: "pay down a miner's debt", diff --git a/cmd/lotus-miner/main.go b/cmd/lotus-miner/main.go index 911e98e260a..b2c7f9ad19f 100644 --- a/cmd/lotus-miner/main.go +++ b/cmd/lotus-miner/main.go @@ -197,3 +197,13 @@ func setHidden(cmd *cli.Command) *cli.Command { cmd.Hidden = true return cmd } + +func LMActorGetter(cctx *cli.Context) (address.Address, error) { + minerApi, closer, err := lcli.GetStorageMinerAPI(cctx) + if err != nil { + return address.Undef, err + } + defer closer() + + return minerApi.ActorAddress(cctx.Context) +} diff --git a/cmd/sptool/actor.go b/cmd/sptool/actor.go index ee5f84fb779..d312e7c1980 100644 --- a/cmd/sptool/actor.go +++ b/cmd/sptool/actor.go @@ -1,9 +1,15 @@ package main -import "github.com/urfave/cli/v2" +import ( + "github.com/urfave/cli/v2" + + "github.com/filecoin-project/lotus/cli/spcli" +) var actorCmd = &cli.Command{ - Name: "actor", - Usage: "Manage Filecoin Miner Actor Metadata", - Subcommands: []*cli.Command{}, + Name: "actor", + Usage: "Manage Filecoin Miner Actor Metadata", + Subcommands: []*cli.Command{ + spcli.ActorWithdrawCmd(SPTActorGetter), + }, } diff --git a/cmd/sptool/main.go b/cmd/sptool/main.go index c917ed83404..702cbd2509b 100644 --- a/cmd/sptool/main.go +++ b/cmd/sptool/main.go @@ -3,17 +3,26 @@ package main import ( "context" "fmt" - "github.com/filecoin-project/lotus/build" - logging "github.com/ipfs/go-log/v2" - "github.com/urfave/cli/v2" "os" "os/signal" + + logging "github.com/ipfs/go-log/v2" + "github.com/urfave/cli/v2" + + "github.com/filecoin-project/go-address" + + "github.com/filecoin-project/lotus/build" ) var log = logging.Logger("sptool") func main() { - local := []*cli.Command{} + local := []*cli.Command{ + actorCmd, + //sectorsCmd, + //provingCmd, + //proposalsCmd, + } app := &cli.App{ Name: "sptool", @@ -31,6 +40,11 @@ func main() { Name: "log-level", Value: "info", }, + &cli.StringFlag{ + Name: "actor", + Required: true, + Usage: "miner actor to manage", + }, }, Before: func(cctx *cli.Context) error { return logging.SetLogLevel("sptool", cctx.String("sptool")) @@ -57,3 +71,11 @@ func main() { } } + +func SPTActorGetter(cctx *cli.Context) (address.Address, error) { + addr, err := address.NewFromString(cctx.String("actor")) + if err != nil { + return address.Undef, fmt.Errorf("parsing address: %w", err) + } + return addr, nil +} diff --git a/node/impl/storminer.go b/node/impl/storminer.go index 90248a355a4..bd482494017 100644 --- a/node/impl/storminer.go +++ b/node/impl/storminer.go @@ -1377,15 +1377,15 @@ func (sm *StorageMinerAPI) RuntimeSubsystems(context.Context) (res api.MinerSubs } func (sm *StorageMinerAPI) ActorWithdrawBalance(ctx context.Context, amount abi.TokenAmount) (cid.Cid, error) { - return sm.withdrawBalance(ctx, amount, true) + return WithdrawBalance(ctx, sm.Full, sm.Miner.Address(), amount, true) } func (sm *StorageMinerAPI) BeneficiaryWithdrawBalance(ctx context.Context, amount abi.TokenAmount) (cid.Cid, error) { - return sm.withdrawBalance(ctx, amount, false) + return WithdrawBalance(ctx, sm.Full, sm.Miner.Address(), amount, false) } -func (sm *StorageMinerAPI) withdrawBalance(ctx context.Context, amount abi.TokenAmount, fromOwner bool) (cid.Cid, error) { - available, err := sm.Full.StateMinerAvailableBalance(ctx, sm.Miner.Address(), types.EmptyTSK) +func WithdrawBalance(ctx context.Context, full api.FullNode, maddr address.Address, amount abi.TokenAmount, fromOwner bool) (cid.Cid, error) { + available, err := full.StateMinerAvailableBalance(ctx, maddr, types.EmptyTSK) if err != nil { return cid.Undef, xerrors.Errorf("Error getting miner balance: %w", err) } @@ -1405,7 +1405,7 @@ func (sm *StorageMinerAPI) withdrawBalance(ctx context.Context, amount abi.Token return cid.Undef, err } - mi, err := sm.Full.StateMinerInfo(ctx, sm.Miner.Address(), types.EmptyTSK) + mi, err := full.StateMinerInfo(ctx, maddr, types.EmptyTSK) if err != nil { return cid.Undef, xerrors.Errorf("Error getting miner's owner address: %w", err) } @@ -1417,8 +1417,8 @@ func (sm *StorageMinerAPI) withdrawBalance(ctx context.Context, amount abi.Token sender = mi.Beneficiary } - smsg, err := sm.Full.MpoolPushMessage(ctx, &types.Message{ - To: sm.Miner.Address(), + smsg, err := full.MpoolPushMessage(ctx, &types.Message{ + To: maddr, From: sender, Value: types.NewInt(0), Method: builtintypes.MethodsMiner.WithdrawBalance,