package main import ( "fmt" "github.com/filecoin-project/specs-actors/actors/builtin" "github.com/libp2p/go-libp2p-core/peer" "golang.org/x/xerrors" ma "github.com/multiformats/go-multiaddr" "github.com/urfave/cli/v2" "github.com/filecoin-project/specs-actors/actors/abi" "github.com/filecoin-project/specs-actors/actors/builtin/miner" "github.com/filecoin-project/lotus/chain/actors" "github.com/filecoin-project/lotus/chain/types" lcli "github.com/filecoin-project/lotus/cli" ) var actorCmd = &cli.Command{ Name: "actor", Usage: "manipulate the miner actor", Subcommands: []*cli.Command{ actorSetAddrsCmd, actorWithdrawCmd, actorSetPeeridCmd, }, } var actorSetAddrsCmd = &cli.Command{ Name: "set-addrs", Usage: "set addresses that your miner can be publicly dialed on", Flags: []cli.Flag{ &cli.Int64Flag{ Name: "gas-limit", Usage: "set gas limit", Value: 0, }, }, Action: func(cctx *cli.Context) error { nodeAPI, 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 addrs []abi.Multiaddrs for _, a := range cctx.Args().Slice() { maddr, err := ma.NewMultiaddr(a) if err != nil { return fmt.Errorf("failed to parse %q as a multiaddr: %w", a, err) } maddrNop2p, strip := ma.SplitFunc(maddr, func(c ma.Component) bool { return c.Protocol().Code == ma.P_P2P }) if strip != nil { fmt.Println("Stripping peerid ", strip, " from ", maddr) } addrs = append(addrs, maddrNop2p.Bytes()) } maddr, err := nodeAPI.ActorAddress(ctx) if err != nil { return err } minfo, err := api.StateMinerInfo(ctx, maddr, types.EmptyTSK) if err != nil { return err } params, err := actors.SerializeParams(&miner.ChangeMultiaddrsParams{NewMultiaddrs: addrs}) if err != nil { return err } gasLimit := cctx.Int64("gas-limit") smsg, err := api.MpoolPushMessage(ctx, &types.Message{ To: maddr, From: minfo.Worker, Value: types.NewInt(0), GasLimit: gasLimit, Method: builtin.MethodsMiner.ChangeMultiaddrs, Params: params, }, nil) if err != nil { return err } fmt.Printf("Requested multiaddrs change in message %s\n", smsg.Cid()) return nil }, } var actorSetPeeridCmd = &cli.Command{ Name: "set-peer-id", Usage: "set the peer id of your miner", Flags: []cli.Flag{ &cli.Int64Flag{ Name: "gas-limit", Usage: "set gas limit", Value: 0, }, }, Action: func(cctx *cli.Context) error { nodeAPI, 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) pid, err := peer.IDFromString(cctx.Args().Get(0)) if err != nil { return fmt.Errorf("failed to parse input as a peerId: %w", err) } maddr, err := nodeAPI.ActorAddress(ctx) if err != nil { return err } minfo, err := api.StateMinerInfo(ctx, maddr, types.EmptyTSK) if err != nil { return err } params, err := actors.SerializeParams(&miner.ChangePeerIDParams{NewID: abi.PeerID(pid)}) if err != nil { return err } gasLimit := cctx.Int64("gas-limit") smsg, err := api.MpoolPushMessage(ctx, &types.Message{ To: maddr, From: minfo.Worker, Value: types.NewInt(0), GasLimit: gasLimit, Method: builtin.MethodsMiner.ChangePeerID, Params: params, }, nil) if err != nil { return err } fmt.Printf("Requested peerid change in message %s\n", smsg.Cid()) return nil }, } var actorWithdrawCmd = &cli.Command{ Name: "withdraw", Usage: "withdraw available balance", ArgsUsage: "[amount (FIL)]", Action: func(cctx *cli.Context) error { nodeApi, 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) maddr, err := nodeApi.ActorAddress(ctx) if err != nil { return err } mi, err := api.StateMinerInfo(ctx, maddr, types.EmptyTSK) if err != nil { return err } available, err := api.StateMinerAvailableBalance(ctx, maddr, types.EmptyTSK) if err != nil { return err } amount := available 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) if amount.GreaterThan(available) { return xerrors.Errorf("can't withdraw more funds than available; requested: %s; available: %s", amount, available) } } params, err := actors.SerializeParams(&miner.WithdrawBalanceParams{ AmountRequested: amount, // Default to attempting to withdraw all the extra funds in the miner actor }) if err != nil { return err } smsg, err := api.MpoolPushMessage(ctx, &types.Message{ To: maddr, From: mi.Owner, Value: types.NewInt(0), Method: builtin.MethodsMiner.WithdrawBalance, Params: params, }, nil) if err != nil { return err } fmt.Printf("Requested rewards withdrawal in message %s\n", smsg.Cid()) return nil }, }