2020-06-23 22:54:28 +00:00
package main
import (
2021-09-29 16:59:51 +00:00
"bytes"
2020-06-23 22:54:28 +00:00
"fmt"
2020-08-19 20:08:04 +00:00
"os"
2022-09-14 20:12:01 +00:00
"strconv"
2020-08-19 20:08:04 +00:00
"strings"
2020-06-23 22:54:28 +00:00
2020-08-19 20:08:04 +00:00
"github.com/fatih/color"
2022-09-14 04:19:47 +00:00
"github.com/ipfs/go-cid"
2022-06-14 15:00:51 +00:00
cbor "github.com/ipfs/go-ipld-cbor"
2022-08-25 18:20:41 +00:00
"github.com/libp2p/go-libp2p/core/peer"
2020-06-23 22:54:28 +00:00
ma "github.com/multiformats/go-multiaddr"
"github.com/urfave/cli/v2"
2020-08-19 20:08:04 +00:00
"golang.org/x/xerrors"
2020-06-23 22:54:28 +00:00
2020-08-19 20:08:04 +00:00
"github.com/filecoin-project/go-address"
2020-10-29 07:18:10 +00:00
"github.com/filecoin-project/go-bitfield"
2022-06-14 15:00:51 +00:00
rlepluslazy "github.com/filecoin-project/go-bitfield/rle"
2020-09-07 03:49:10 +00:00
"github.com/filecoin-project/go-state-types/abi"
"github.com/filecoin-project/go-state-types/big"
2022-04-20 21:34:28 +00:00
"github.com/filecoin-project/go-state-types/builtin"
2023-09-22 16:08:53 +00:00
minerV12 "github.com/filecoin-project/go-state-types/builtin/v12/miner"
2022-09-14 20:12:01 +00:00
"github.com/filecoin-project/go-state-types/builtin/v9/miner"
2022-06-14 15:00:51 +00:00
"github.com/filecoin-project/go-state-types/network"
2023-11-14 00:06:11 +00:00
2022-06-14 15:00:51 +00:00
"github.com/filecoin-project/lotus/api"
2021-01-29 20:01:00 +00:00
"github.com/filecoin-project/lotus/blockstore"
2020-10-08 20:32:54 +00:00
"github.com/filecoin-project/lotus/build"
2020-06-23 22:54:28 +00:00
"github.com/filecoin-project/lotus/chain/actors"
2020-10-08 20:32:54 +00:00
"github.com/filecoin-project/lotus/chain/actors/adt"
2022-07-21 06:14:52 +00:00
builtin2 "github.com/filecoin-project/lotus/chain/actors/builtin"
2022-06-14 15:00:51 +00:00
lminer "github.com/filecoin-project/lotus/chain/actors/builtin/miner"
2020-06-23 22:54:28 +00:00
"github.com/filecoin-project/lotus/chain/types"
lcli "github.com/filecoin-project/lotus/cli"
2020-08-19 20:08:04 +00:00
"github.com/filecoin-project/lotus/lib/tablewriter"
2020-06-23 22:54:28 +00:00
)
var actorCmd = & cli . Command {
2020-06-23 23:00:32 +00:00
Name : "actor" ,
2020-06-23 22:54:28 +00:00
Usage : "manipulate the miner actor" ,
Subcommands : [ ] * cli . Command {
actorSetAddrsCmd ,
2020-08-13 08:20:09 +00:00
actorWithdrawCmd ,
2020-10-11 23:49:57 +00:00
actorRepayDebtCmd ,
2020-08-18 00:53:02 +00:00
actorSetPeeridCmd ,
2020-10-06 09:05:39 +00:00
actorSetOwnerCmd ,
2020-08-19 20:08:04 +00:00
actorControl ,
2020-10-21 03:35:18 +00:00
actorProposeChangeWorker ,
actorConfirmChangeWorker ,
2021-07-22 14:18:55 +00:00
actorCompactAllocatedCmd ,
2023-09-22 16:08:53 +00:00
actorMovePartitionsCmd ,
2022-09-14 20:12:01 +00:00
actorProposeChangeBeneficiary ,
actorConfirmChangeBeneficiary ,
2020-06-23 22:54:28 +00:00
} ,
}
var actorSetAddrsCmd = & cli . Command {
2023-01-31 10:56:55 +00:00
Name : "set-addresses" ,
Aliases : [ ] string { "set-addrs" } ,
Usage : "set addresses that your miner can be publicly dialed on" ,
ArgsUsage : "<multiaddrs>" ,
2020-06-23 22:54:28 +00:00
Flags : [ ] cli . Flag {
2022-08-31 16:42:24 +00:00
& cli . StringFlag {
Name : "from" ,
Usage : "optionally specify the account to send the message from" ,
} ,
2020-06-23 22:54:28 +00:00
& cli . Int64Flag {
Name : "gas-limit" ,
Usage : "set gas limit" ,
2020-07-29 08:03:29 +00:00
Value : 0 ,
2020-06-23 22:54:28 +00:00
} ,
2021-04-06 03:24:32 +00:00
& cli . BoolFlag {
Name : "unset" ,
Usage : "unset address" ,
Value : false ,
} ,
2020-06-23 22:54:28 +00:00
} ,
Action : func ( cctx * cli . Context ) error {
2021-04-02 11:24:15 +00:00
args := cctx . Args ( ) . Slice ( )
2021-04-06 03:24:32 +00:00
unset := cctx . Bool ( "unset" )
if len ( args ) == 0 && ! unset {
2021-04-02 11:24:15 +00:00
return cli . ShowSubcommandHelp ( cctx )
}
2021-04-06 03:24:32 +00:00
if len ( args ) > 0 && unset {
2021-04-08 03:14:53 +00:00
return fmt . Errorf ( "unset can only be used with no arguments" )
2021-04-06 03:24:32 +00:00
}
2021-04-02 11:24:15 +00:00
2022-09-14 18:51:18 +00:00
minerApi , closer , err := lcli . GetStorageMinerAPI ( cctx )
2020-06-23 22:54:28 +00:00
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
2021-04-02 11:24:15 +00:00
for _ , a := range args {
2020-06-23 22:54:28 +00:00
maddr , err := ma . NewMultiaddr ( a )
if err != nil {
return fmt . Errorf ( "failed to parse %q as a multiaddr: %w" , a , err )
}
2020-08-18 01:18:11 +00:00
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 ( ) )
2020-06-23 22:54:28 +00:00
}
2022-09-14 18:51:18 +00:00
maddr , err := minerApi . ActorAddress ( ctx )
2020-06-23 22:54:28 +00:00
if err != nil {
return err
}
minfo , err := api . StateMinerInfo ( ctx , maddr , types . EmptyTSK )
if err != nil {
return err
}
2022-08-31 16:42:24 +00:00
fromAddr := minfo . Worker
if from := cctx . String ( "from" ) ; from != "" {
addr , err := address . NewFromString ( from )
if err != nil {
return err
}
fromAddr = addr
}
fromId , err := api . StateLookupID ( ctx , fromAddr , types . EmptyTSK )
if err != nil {
return err
}
if ! isController ( minfo , fromId ) {
return xerrors . Errorf ( "sender isn't a controller of miner: %s" , fromId )
}
2022-04-20 21:34:28 +00:00
params , err := actors . SerializeParams ( & miner . ChangeMultiaddrsParams { NewMultiaddrs : addrs } )
2020-06-23 22:54:28 +00:00
if err != nil {
return err
}
gasLimit := cctx . Int64 ( "gas-limit" )
smsg , err := api . MpoolPushMessage ( ctx , & types . Message {
To : maddr ,
2022-08-31 16:42:24 +00:00
From : fromId ,
2020-06-23 22:54:28 +00:00
Value : types . NewInt ( 0 ) ,
GasLimit : gasLimit ,
2022-04-20 21:34:28 +00:00
Method : builtin . MethodsMiner . ChangeMultiaddrs ,
2020-06-23 22:54:28 +00:00
Params : params ,
2020-08-12 20:17:21 +00:00
} , nil )
2020-06-23 23:00:32 +00:00
if err != nil {
return err
}
2020-06-23 22:54:28 +00:00
fmt . Printf ( "Requested multiaddrs change in message %s\n" , smsg . Cid ( ) )
return nil
} ,
}
2020-08-13 08:20:09 +00:00
2020-08-18 00:53:02 +00:00
var actorSetPeeridCmd = & cli . Command {
2023-01-31 10:56:55 +00:00
Name : "set-peer-id" ,
Usage : "set the peer id of your miner" ,
ArgsUsage : "<peer id>" ,
2020-08-18 00:53:02 +00:00
Flags : [ ] cli . Flag {
& cli . Int64Flag {
Name : "gas-limit" ,
Usage : "set gas limit" ,
Value : 0 ,
} ,
} ,
Action : func ( cctx * cli . Context ) error {
2022-09-14 18:51:18 +00:00
minerApi , closer , err := lcli . GetStorageMinerAPI ( cctx )
2020-08-18 00:53:02 +00:00
if err != nil {
return err
}
defer closer ( )
api , acloser , err := lcli . GetFullNodeAPI ( cctx )
if err != nil {
return err
}
defer acloser ( )
ctx := lcli . ReqContext ( cctx )
2023-01-31 10:56:55 +00:00
if cctx . NArg ( ) != 1 {
return lcli . IncorrectNumArgs ( cctx )
}
2020-08-26 00:10:06 +00:00
pid , err := peer . Decode ( cctx . Args ( ) . Get ( 0 ) )
2020-08-18 00:53:02 +00:00
if err != nil {
return fmt . Errorf ( "failed to parse input as a peerId: %w" , err )
}
2022-09-14 18:51:18 +00:00
maddr , err := minerApi . ActorAddress ( ctx )
2020-08-18 00:53:02 +00:00
if err != nil {
return err
}
minfo , err := api . StateMinerInfo ( ctx , maddr , types . EmptyTSK )
if err != nil {
return err
}
2022-04-20 21:34:28 +00:00
params , err := actors . SerializeParams ( & miner . ChangePeerIDParams { NewID : abi . PeerID ( pid ) } )
2020-08-18 00:53:02 +00:00
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 ,
2022-04-20 21:34:28 +00:00
Method : builtin . MethodsMiner . ChangePeerID ,
2020-08-18 00:53:02 +00:00
Params : params ,
} , nil )
if err != nil {
return err
}
fmt . Printf ( "Requested peerid change in message %s\n" , smsg . Cid ( ) )
return nil
} ,
}
2020-08-13 08:20:09 +00:00
var actorWithdrawCmd = & cli . Command {
2020-08-13 08:20:41 +00:00
Name : "withdraw" ,
2022-09-14 04:19:47 +00:00
Usage : "withdraw available balance to beneficiary" ,
2020-08-13 08:20:09 +00:00
ArgsUsage : "[amount (FIL)]" ,
2021-09-29 16:59:51 +00:00
Flags : [ ] cli . Flag {
& cli . IntFlag {
Name : "confidence" ,
Usage : "number of block confirmations to wait for" ,
Value : int ( build . MessageConfidence ) ,
} ,
2022-09-14 04:19:47 +00:00
& cli . BoolFlag {
Name : "beneficiary" ,
Usage : "send withdraw message from the beneficiary address" ,
} ,
2021-09-29 16:59:51 +00:00
} ,
2020-08-13 08:20:09 +00:00
Action : func ( cctx * cli . Context ) error {
2022-07-29 14:39:49 +00:00
amount := abi . NewTokenAmount ( 0 )
2020-08-13 08:20:09 +00:00
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 )
}
2022-09-14 18:51:18 +00:00
minerApi , closer , err := lcli . GetStorageMinerAPI ( cctx )
2020-08-13 08:20:09 +00:00
if err != nil {
return err
}
2022-07-29 14:39:49 +00:00
defer closer ( )
2020-08-13 08:20:09 +00:00
2022-07-29 14:39:49 +00:00
api , acloser , err := lcli . GetFullNodeAPI ( cctx )
2020-08-13 08:20:09 +00:00
if err != nil {
return err
}
2022-07-29 14:39:49 +00:00
defer acloser ( )
2020-08-13 08:20:09 +00:00
2022-07-29 14:39:49 +00:00
ctx := lcli . ReqContext ( cctx )
2021-10-11 18:35:45 +00:00
2022-09-14 04:19:47 +00:00
var res cid . Cid
if cctx . IsSet ( "beneficiary" ) {
2022-09-14 18:51:18 +00:00
res , err = minerApi . BeneficiaryWithdrawBalance ( ctx , amount )
2022-09-14 04:19:47 +00:00
} else {
2022-09-14 18:51:18 +00:00
res , err = minerApi . ActorWithdrawBalance ( ctx , amount )
2022-09-14 04:19:47 +00:00
}
2021-09-29 16:59:51 +00:00
if err != nil {
return err
}
2022-08-11 07:34:18 +00:00
fmt . Printf ( "Requested withdrawal in message %s\nwaiting for it to be included in a block..\n" , res )
2022-08-01 18:11:24 +00:00
// wait for it to get mined into a block
wait , err := api . StateWaitMsg ( ctx , res , uint64 ( cctx . Int ( "confidence" ) ) )
2022-07-29 14:39:49 +00:00
if err != nil {
2022-11-22 17:10:12 +00:00
return xerrors . Errorf ( "Timeout waiting for withdrawal message %s" , res )
2022-08-01 18:11:24 +00:00
}
2022-09-14 18:53:11 +00:00
if wait . Receipt . ExitCode . IsError ( ) {
2022-08-01 18:11:24 +00:00
return xerrors . Errorf ( "Failed to execute withdrawal message %s: %w" , wait . Message , wait . Receipt . ExitCode . Error ( ) )
2021-09-29 16:59:51 +00:00
}
2022-08-01 18:11:24 +00:00
nv , err := api . StateNetworkVersion ( ctx , wait . TipSet )
2021-10-10 00:11:49 +00:00
if err != nil {
2021-09-29 16:59:51 +00:00
return err
}
2021-10-10 00:11:49 +00:00
if nv >= network . Version14 {
var withdrawn abi . TokenAmount
2022-08-01 18:11:24 +00:00
if err := withdrawn . UnmarshalCBOR ( bytes . NewReader ( wait . Receipt . Return ) ) ; err != nil {
2021-10-10 00:11:49 +00:00
return err
}
2021-10-27 00:51:40 +00:00
fmt . Printf ( "Successfully withdrew %s \n" , types . FIL ( withdrawn ) )
2021-10-11 12:03:28 +00:00
if withdrawn . LessThan ( amount ) {
2021-10-27 00:51:40 +00:00
fmt . Printf ( "Note that this is less than the requested amount of %s\n" , types . FIL ( amount ) )
2021-10-10 00:11:49 +00:00
}
2021-09-29 16:59:51 +00:00
}
2020-08-13 08:20:09 +00:00
return nil
} ,
}
2020-08-19 20:08:04 +00:00
2020-10-11 23:49:57 +00:00
var actorRepayDebtCmd = & cli . Command {
Name : "repay-debt" ,
Usage : "pay down a miner's debt" ,
ArgsUsage : "[amount (FIL)]" ,
Flags : [ ] cli . Flag {
& cli . StringFlag {
Name : "from" ,
Usage : "optionally specify the account to send funds from" ,
} ,
} ,
Action : func ( cctx * cli . Context ) error {
2022-09-14 18:51:18 +00:00
minerApi , closer , err := lcli . GetStorageMinerAPI ( cctx )
2020-10-11 23:49:57 +00:00
if err != nil {
return err
}
defer closer ( )
api , acloser , err := lcli . GetFullNodeAPI ( cctx )
if err != nil {
return err
}
defer acloser ( )
ctx := lcli . ReqContext ( cctx )
2022-09-14 18:51:18 +00:00
maddr , err := minerApi . ActorAddress ( ctx )
2020-10-11 23:49:57 +00:00
if err != nil {
return err
}
mi , err := api . StateMinerInfo ( ctx , maddr , types . EmptyTSK )
if err != nil {
return err
}
var amount abi . TokenAmount
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 )
} else {
mact , err := api . StateGetActor ( ctx , maddr , types . EmptyTSK )
if err != nil {
return err
}
2021-01-29 20:01:00 +00:00
store := adt . WrapStore ( ctx , cbor . NewCborStore ( blockstore . NewAPIBlockstore ( api ) ) )
2020-10-11 23:49:57 +00:00
2022-04-20 21:34:28 +00:00
mst , err := lminer . Load ( store , mact )
2020-10-11 23:49:57 +00:00
if err != nil {
return err
}
amount , err = mst . FeeDebt ( )
if err != nil {
return err
}
}
fromAddr := mi . Worker
if from := cctx . String ( "from" ) ; from != "" {
addr , err := address . NewFromString ( from )
if err != nil {
return err
}
fromAddr = addr
}
fromId , err := api . StateLookupID ( ctx , fromAddr , types . EmptyTSK )
if err != nil {
return err
}
2022-04-20 21:34:28 +00:00
if ! isController ( mi , fromId ) {
2020-10-11 23:49:57 +00:00
return xerrors . Errorf ( "sender isn't a controller of miner: %s" , fromId )
}
smsg , err := api . MpoolPushMessage ( ctx , & types . Message {
To : maddr ,
From : fromId ,
Value : amount ,
2022-04-20 21:34:28 +00:00
Method : builtin . MethodsMiner . RepayDebt ,
2020-10-11 23:49:57 +00:00
Params : nil ,
} , nil )
if err != nil {
return err
}
fmt . Printf ( "Sent repay debt message %s\n" , smsg . Cid ( ) )
return nil
} ,
}
2020-08-19 20:08:04 +00:00
var actorControl = & cli . Command {
2020-08-19 23:26:13 +00:00
Name : "control" ,
Usage : "Manage control addresses" ,
2020-08-19 20:08:04 +00:00
Subcommands : [ ] * cli . Command {
actorControlList ,
actorControlSet ,
} ,
}
var actorControlList = & cli . Command {
2020-08-19 23:26:13 +00:00
Name : "list" ,
Usage : "Get currently set control addresses" ,
2020-08-19 20:08:04 +00:00
Flags : [ ] cli . Flag {
& cli . BoolFlag {
Name : "verbose" ,
} ,
} ,
Action : func ( cctx * cli . Context ) error {
2022-09-14 18:51:18 +00:00
minerApi , closer , err := lcli . GetStorageMinerAPI ( cctx )
2020-08-19 20:08:04 +00:00
if err != nil {
return err
}
defer closer ( )
2022-07-21 06:14:52 +00:00
api , acloser , err := lcli . GetFullNodeAPIV1 ( cctx )
2020-08-19 20:08:04 +00:00
if err != nil {
return err
}
defer acloser ( )
ctx := lcli . ReqContext ( cctx )
2021-08-11 11:23:37 +00:00
maddr , err := getActorAddress ( ctx , cctx )
2020-08-19 20:08:04 +00:00
if err != nil {
return err
}
mi , err := api . StateMinerInfo ( ctx , maddr , types . EmptyTSK )
if err != nil {
return err
}
tw := tablewriter . New (
tablewriter . Col ( "name" ) ,
tablewriter . Col ( "ID" ) ,
tablewriter . Col ( "key" ) ,
tablewriter . Col ( "use" ) ,
tablewriter . Col ( "balance" ) ,
)
2022-09-14 18:51:18 +00:00
ac , err := minerApi . ActorAddressConfig ( ctx )
2020-08-19 20:08:04 +00:00
if err != nil {
2020-12-02 19:46:07 +00:00
return err
}
commit := map [ address . Address ] struct { } { }
precommit := map [ address . Address ] struct { } { }
2021-02-17 15:56:32 +00:00
terminate := map [ address . Address ] struct { } { }
2021-07-07 16:00:54 +00:00
dealPublish := map [ address . Address ] struct { } { }
2020-12-02 19:46:07 +00:00
post := map [ address . Address ] struct { } { }
for _ , ca := range mi . ControlAddresses {
post [ ca ] = struct { } { }
}
for _ , ca := range ac . PreCommitControl {
ca , err := api . StateLookupID ( ctx , ca , types . EmptyTSK )
if err != nil {
return err
}
delete ( post , ca )
precommit [ ca ] = struct { } { }
}
for _ , ca := range ac . CommitControl {
ca , err := api . StateLookupID ( ctx , ca , types . EmptyTSK )
if err != nil {
return err
}
delete ( post , ca )
commit [ ca ] = struct { } { }
2020-08-19 20:08:04 +00:00
}
2021-02-17 15:56:32 +00:00
for _ , ca := range ac . TerminateControl {
ca , err := api . StateLookupID ( ctx , ca , types . EmptyTSK )
if err != nil {
return err
}
delete ( post , ca )
terminate [ ca ] = struct { } { }
}
2021-07-07 16:00:54 +00:00
for _ , ca := range ac . DealPublishControl {
ca , err := api . StateLookupID ( ctx , ca , types . EmptyTSK )
if err != nil {
return err
}
delete ( post , ca )
dealPublish [ ca ] = struct { } { }
2020-08-19 20:08:04 +00:00
}
printKey := func ( name string , a address . Address ) {
2022-07-21 06:14:52 +00:00
var actor * types . Actor
if actor , err = api . StateGetActor ( ctx , a , types . EmptyTSK ) ; err != nil {
fmt . Printf ( "%s\t%s: error getting actor: %s\n" , name , a , err )
2020-08-19 20:08:04 +00:00
return
}
2022-07-21 06:14:52 +00:00
b := actor . Balance
2022-08-04 08:14:56 +00:00
var k = a
2022-07-21 06:14:52 +00:00
// 'a' maybe a 'robust', in that case, 'StateAccountKey' returns an error.
if builtin2 . IsAccountActor ( actor . Code ) {
if k , err = api . StateAccountKey ( ctx , a , types . EmptyTSK ) ; err != nil {
fmt . Printf ( "%s\t%s: error getting account key: %s\n" , name , a , err )
return
}
2020-08-19 20:08:04 +00:00
}
kstr := k . String ( )
if ! cctx . Bool ( "verbose" ) {
2022-09-02 08:33:32 +00:00
if len ( kstr ) > 9 {
kstr = kstr [ : 6 ] + "..."
}
2020-08-19 20:08:04 +00:00
}
bstr := types . FIL ( b ) . String ( )
switch {
case b . LessThan ( types . FromFil ( 10 ) ) :
bstr = color . RedString ( bstr )
case b . LessThan ( types . FromFil ( 50 ) ) :
bstr = color . YellowString ( bstr )
default :
bstr = color . GreenString ( bstr )
}
var uses [ ] string
if a == mi . Worker {
uses = append ( uses , color . YellowString ( "other" ) )
}
2020-12-02 19:46:07 +00:00
if _ , ok := post [ a ] ; ok {
2020-08-19 20:08:04 +00:00
uses = append ( uses , color . GreenString ( "post" ) )
}
2020-12-02 19:46:07 +00:00
if _ , ok := precommit [ a ] ; ok {
uses = append ( uses , color . CyanString ( "precommit" ) )
}
if _ , ok := commit [ a ] ; ok {
uses = append ( uses , color . BlueString ( "commit" ) )
}
2021-02-17 15:56:32 +00:00
if _ , ok := terminate [ a ] ; ok {
uses = append ( uses , color . YellowString ( "terminate" ) )
}
2021-07-07 16:00:54 +00:00
if _ , ok := dealPublish [ a ] ; ok {
uses = append ( uses , color . MagentaString ( "deals" ) )
}
2020-08-19 20:08:04 +00:00
tw . Write ( map [ string ] interface { } {
2020-08-19 23:26:13 +00:00
"name" : name ,
"ID" : a ,
"key" : kstr ,
"use" : strings . Join ( uses , " " ) ,
2020-08-19 20:08:04 +00:00
"balance" : bstr ,
} )
}
printKey ( "owner" , mi . Owner )
printKey ( "worker" , mi . Worker )
2022-11-12 02:58:30 +00:00
printKey ( "beneficiary" , mi . Beneficiary )
2020-08-19 20:08:04 +00:00
for i , ca := range mi . ControlAddresses {
printKey ( fmt . Sprintf ( "control-%d" , i ) , ca )
}
return tw . Flush ( os . Stdout )
} ,
}
var actorControlSet = & cli . Command {
Name : "set" ,
Usage : "Set control address(-es)" ,
ArgsUsage : "[...address]" ,
Flags : [ ] cli . Flag {
& cli . BoolFlag {
2020-08-19 23:26:13 +00:00
Name : "really-do-it" ,
2020-08-19 20:08:04 +00:00
Usage : "Actually send transaction performing the action" ,
Value : false ,
} ,
} ,
Action : func ( cctx * cli . Context ) error {
2022-09-14 18:51:18 +00:00
minerApi , closer , err := lcli . GetStorageMinerAPI ( cctx )
2020-08-19 20:08:04 +00:00
if err != nil {
return err
}
defer closer ( )
api , acloser , err := lcli . GetFullNodeAPI ( cctx )
if err != nil {
return err
}
defer acloser ( )
ctx := lcli . ReqContext ( cctx )
2022-09-14 18:51:18 +00:00
maddr , err := minerApi . ActorAddress ( ctx )
2020-08-19 20:08:04 +00:00
if err != nil {
return err
}
mi , err := api . StateMinerInfo ( ctx , maddr , types . EmptyTSK )
if err != nil {
return err
}
del := map [ address . Address ] struct { } { }
existing := map [ address . Address ] struct { } { }
for _ , controlAddress := range mi . ControlAddresses {
ka , err := api . StateAccountKey ( ctx , controlAddress , types . EmptyTSK )
if err != nil {
return err
}
del [ ka ] = struct { } { }
existing [ ka ] = struct { } { }
}
var toSet [ ] address . Address
for i , as := range cctx . Args ( ) . Slice ( ) {
a , err := address . NewFromString ( as )
if err != nil {
return xerrors . Errorf ( "parsing address %d: %w" , i , err )
}
ka , err := api . StateAccountKey ( ctx , a , types . EmptyTSK )
if err != nil {
return err
}
// make sure the address exists on chain
_ , err = api . StateLookupID ( ctx , ka , types . EmptyTSK )
if err != nil {
return xerrors . Errorf ( "looking up %s: %w" , ka , err )
}
delete ( del , ka )
toSet = append ( toSet , ka )
}
for a := range del {
fmt . Println ( "Remove" , a )
}
for _ , a := range toSet {
if _ , exists := existing [ a ] ; ! exists {
fmt . Println ( "Add" , a )
}
}
if ! cctx . Bool ( "really-do-it" ) {
fmt . Println ( "Pass --really-do-it to actually execute this action" )
return nil
}
2022-04-20 21:34:28 +00:00
cwp := & miner . ChangeWorkerAddressParams {
2020-08-19 20:08:04 +00:00
NewWorker : mi . Worker ,
NewControlAddrs : toSet ,
}
sp , err := actors . SerializeParams ( cwp )
if err != nil {
return xerrors . Errorf ( "serializing params: %w" , err )
}
smsg , err := api . MpoolPushMessage ( ctx , & types . Message {
2020-08-19 23:26:13 +00:00
From : mi . Owner ,
To : maddr ,
2022-04-20 21:34:28 +00:00
Method : builtin . MethodsMiner . ChangeWorkerAddress ,
2020-08-19 20:08:04 +00:00
2020-08-19 23:26:13 +00:00
Value : big . Zero ( ) ,
2020-08-19 20:08:04 +00:00
Params : sp ,
} , nil )
if err != nil {
return xerrors . Errorf ( "mpool push: %w" , err )
}
fmt . Println ( "Message CID:" , smsg . Cid ( ) )
return nil
} ,
}
2020-10-06 09:05:39 +00:00
var actorSetOwnerCmd = & cli . Command {
Name : "set-owner" ,
2021-01-08 05:55:13 +00:00
Usage : "Set owner address (this command should be invoked twice, first with the old owner as the senderAddress, and then with the new owner)" ,
ArgsUsage : "[newOwnerAddress senderAddress]" ,
2020-10-06 09:05:39 +00:00
Flags : [ ] cli . Flag {
& cli . BoolFlag {
Name : "really-do-it" ,
Usage : "Actually send transaction performing the action" ,
Value : false ,
} ,
} ,
Action : func ( cctx * cli . Context ) error {
2023-01-31 10:56:55 +00:00
if cctx . NArg ( ) != 2 {
return lcli . IncorrectNumArgs ( cctx )
}
2020-10-06 09:05:39 +00:00
if ! cctx . Bool ( "really-do-it" ) {
fmt . Println ( "Pass --really-do-it to actually execute this action" )
return nil
}
api , acloser , err := lcli . GetFullNodeAPI ( cctx )
if err != nil {
return err
}
defer acloser ( )
ctx := lcli . ReqContext ( cctx )
na , err := address . NewFromString ( cctx . Args ( ) . First ( ) )
if err != nil {
return err
}
2021-01-08 05:55:13 +00:00
newAddrId , err := api . StateLookupID ( ctx , na , types . EmptyTSK )
2020-10-06 09:05:39 +00:00
if err != nil {
return err
}
2021-01-08 05:55:13 +00:00
fa , err := address . NewFromString ( cctx . Args ( ) . Get ( 1 ) )
2020-10-06 09:05:39 +00:00
if err != nil {
return err
}
2021-01-08 06:25:24 +00:00
fromAddrId , err := api . StateLookupID ( ctx , fa , types . EmptyTSK )
2020-10-06 09:05:39 +00:00
if err != nil {
return err
}
2021-09-14 09:29:58 +00:00
maddr , err := getActorAddress ( ctx , cctx )
2020-10-06 09:05:39 +00:00
if err != nil {
2021-01-08 05:55:13 +00:00
return err
2020-10-06 09:05:39 +00:00
}
2021-01-08 05:55:13 +00:00
mi , err := api . StateMinerInfo ( ctx , maddr , types . EmptyTSK )
2020-10-06 09:05:39 +00:00
if err != nil {
2021-01-08 05:55:13 +00:00
return err
2020-10-06 09:05:39 +00:00
}
2021-01-08 05:55:13 +00:00
if fromAddrId != mi . Owner && fromAddrId != newAddrId {
return xerrors . New ( "from address must either be the old owner or the new owner" )
2020-10-06 09:05:39 +00:00
}
2021-01-08 05:55:13 +00:00
sp , err := actors . SerializeParams ( & newAddrId )
if err != nil {
return xerrors . Errorf ( "serializing params: %w" , err )
2020-10-06 09:05:39 +00:00
}
2021-01-08 05:55:13 +00:00
smsg , err := api . MpoolPushMessage ( ctx , & types . Message {
From : fromAddrId ,
2020-10-06 09:05:39 +00:00
To : maddr ,
2022-04-20 21:34:28 +00:00
Method : builtin . MethodsMiner . ChangeOwnerAddress ,
2020-10-06 09:05:39 +00:00
Value : big . Zero ( ) ,
Params : sp ,
} , nil )
if err != nil {
return xerrors . Errorf ( "mpool push: %w" , err )
}
2021-01-08 05:55:13 +00:00
fmt . Println ( "Message CID:" , smsg . Cid ( ) )
2020-10-06 09:05:39 +00:00
// wait for it to get mined into a block
2021-01-08 05:55:13 +00:00
wait , err := api . StateWaitMsg ( ctx , smsg . Cid ( ) , build . MessageConfidence )
2020-10-06 09:05:39 +00:00
if err != nil {
return err
}
// check it executed successfully
2022-09-14 18:53:11 +00:00
if wait . Receipt . ExitCode . IsError ( ) {
2021-01-08 05:55:13 +00:00
fmt . Println ( "owner change failed!" )
2020-10-06 09:05:39 +00:00
return err
}
2021-01-13 08:03:19 +00:00
fmt . Println ( "message succeeded!" )
2020-10-06 09:05:39 +00:00
return nil
} ,
}
2020-10-21 03:35:18 +00:00
var actorProposeChangeWorker = & cli . Command {
Name : "propose-change-worker" ,
Usage : "Propose a worker address change" ,
ArgsUsage : "[address]" ,
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 . Args ( ) . Present ( ) {
return fmt . Errorf ( "must pass address of new worker address" )
}
2022-09-14 18:51:18 +00:00
minerApi , closer , err := lcli . GetStorageMinerAPI ( cctx )
2020-10-21 03:35:18 +00:00
if err != nil {
return err
}
defer closer ( )
api , acloser , err := lcli . GetFullNodeAPI ( cctx )
if err != nil {
return err
}
defer acloser ( )
ctx := lcli . ReqContext ( cctx )
na , err := address . NewFromString ( cctx . Args ( ) . First ( ) )
if err != nil {
return err
}
newAddr , err := api . StateLookupID ( ctx , na , types . EmptyTSK )
if err != nil {
return err
}
2022-09-14 18:51:18 +00:00
maddr , err := minerApi . ActorAddress ( ctx )
2020-10-21 03:35:18 +00:00
if err != nil {
return err
}
mi , err := api . StateMinerInfo ( ctx , maddr , types . EmptyTSK )
if err != nil {
return err
}
if mi . NewWorker . Empty ( ) {
if mi . Worker == newAddr {
return fmt . Errorf ( "worker address already set to %s" , na )
}
} else {
if mi . NewWorker == newAddr {
return fmt . Errorf ( "change to worker address %s already pending" , na )
}
}
if ! cctx . Bool ( "really-do-it" ) {
fmt . Fprintln ( cctx . App . Writer , "Pass --really-do-it to actually execute this action" )
return nil
}
2022-04-20 21:34:28 +00:00
cwp := & miner . ChangeWorkerAddressParams {
2020-10-21 03:35:18 +00:00
NewWorker : newAddr ,
NewControlAddrs : mi . ControlAddresses ,
}
sp , err := actors . SerializeParams ( cwp )
if err != nil {
return xerrors . Errorf ( "serializing params: %w" , err )
}
smsg , err := api . MpoolPushMessage ( ctx , & types . Message {
From : mi . Owner ,
To : maddr ,
2022-04-20 21:34:28 +00:00
Method : builtin . MethodsMiner . ChangeWorkerAddress ,
2020-10-21 03:35:18 +00:00
Value : big . Zero ( ) ,
Params : sp ,
} , nil )
if err != nil {
return xerrors . Errorf ( "mpool push: %w" , err )
}
fmt . Fprintln ( cctx . App . Writer , "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 err
}
// check it executed successfully
2022-09-14 18:53:11 +00:00
if wait . Receipt . ExitCode . IsError ( ) {
2022-09-14 20:12:01 +00:00
return fmt . Errorf ( "propose worker change failed" )
2020-10-21 03:35:18 +00:00
}
mi , err = api . StateMinerInfo ( ctx , maddr , wait . TipSet )
if err != nil {
return err
}
if mi . NewWorker != newAddr {
return fmt . Errorf ( "Proposed worker address change not reflected on chain: expected '%s', found '%s'" , na , mi . NewWorker )
}
2022-03-28 07:46:08 +00:00
fmt . Fprintf ( cctx . App . Writer , "Worker key change to %s successfully sent, change happens at height %d.\n" , na , mi . WorkerChangeEpoch )
2022-03-28 06:18:30 +00:00
fmt . Fprintf ( cctx . App . Writer , "If you have no active deadlines, call 'confirm-change-worker' at or after height %d to complete.\n" , mi . WorkerChangeEpoch )
2020-10-21 03:35:18 +00:00
return nil
} ,
}
2022-09-14 20:12:01 +00:00
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" ) {
2022-09-14 21:38:01 +00:00
fmt . Println ( "Pass --really-do-it to actually execute this action. Review what you're about to approve CAREFULLY please" )
2022-09-14 20:12:01 +00:00
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 )
}
2022-09-14 21:38:01 +00:00
if updatedMinerInfo . PendingBeneficiaryTerm == nil && updatedMinerInfo . Beneficiary == newAddr {
2022-09-14 20:12:01 +00:00
fmt . Println ( "Beneficiary address successfully changed" )
} else {
fmt . Println ( "Beneficiary address change awaiting additional confirmations" )
}
return nil
} ,
}
2020-10-21 03:35:18 +00:00
var actorConfirmChangeWorker = & cli . Command {
Name : "confirm-change-worker" ,
Usage : "Confirm a worker address change" ,
ArgsUsage : "[address]" ,
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 . Args ( ) . Present ( ) {
return fmt . Errorf ( "must pass address of new worker address" )
}
2022-09-14 18:51:18 +00:00
minerApi , closer , err := lcli . GetStorageMinerAPI ( cctx )
2020-10-21 03:35:18 +00:00
if err != nil {
return err
}
defer closer ( )
api , acloser , err := lcli . GetFullNodeAPI ( cctx )
if err != nil {
return err
}
defer acloser ( )
ctx := lcli . ReqContext ( cctx )
na , err := address . NewFromString ( cctx . Args ( ) . First ( ) )
if err != nil {
return err
}
newAddr , err := api . StateLookupID ( ctx , na , types . EmptyTSK )
if err != nil {
return err
}
2022-09-14 18:51:18 +00:00
maddr , err := minerApi . ActorAddress ( ctx )
2020-10-21 03:35:18 +00:00
if err != nil {
return err
}
mi , err := api . StateMinerInfo ( ctx , maddr , types . EmptyTSK )
if err != nil {
return err
}
if mi . NewWorker . Empty ( ) {
return xerrors . Errorf ( "no worker key change proposed" )
} else if mi . NewWorker != newAddr {
return xerrors . Errorf ( "worker key %s does not match current worker key proposal %s" , newAddr , mi . NewWorker )
}
if head , err := api . ChainHead ( ctx ) ; err != nil {
return xerrors . Errorf ( "failed to get the chain head: %w" , err )
} else if head . Height ( ) < mi . WorkerChangeEpoch {
return xerrors . Errorf ( "worker key change cannot be confirmed until %d, current height is %d" , mi . WorkerChangeEpoch , head . Height ( ) )
}
if ! cctx . Bool ( "really-do-it" ) {
2022-09-14 20:12:01 +00:00
fmt . Println ( "Pass --really-do-it to actually execute this action" )
2020-10-21 03:35:18 +00:00
return nil
}
smsg , err := api . MpoolPushMessage ( ctx , & types . Message {
From : mi . Owner ,
To : maddr ,
2022-12-15 00:02:43 +00:00
Method : builtin . MethodsMiner . ConfirmChangeWorkerAddress ,
2020-10-21 03:35:18 +00:00
Value : big . Zero ( ) ,
} , nil )
if err != nil {
return xerrors . Errorf ( "mpool push: %w" , err )
}
2022-09-14 20:12:01 +00:00
fmt . Println ( "Confirm Message CID:" , smsg . Cid ( ) )
2020-10-21 03:35:18 +00:00
// wait for it to get mined into a block
wait , err := api . StateWaitMsg ( ctx , smsg . Cid ( ) , build . MessageConfidence )
if err != nil {
return err
}
// check it executed successfully
2022-09-14 18:53:11 +00:00
if wait . Receipt . ExitCode . IsError ( ) {
2020-10-21 03:35:18 +00:00
fmt . Fprintln ( cctx . App . Writer , "Worker change failed!" )
return err
}
mi , err = api . StateMinerInfo ( ctx , maddr , wait . TipSet )
if err != nil {
return err
}
if mi . Worker != newAddr {
return fmt . Errorf ( "Confirmed worker address change not reflected on chain: expected '%s', found '%s'" , newAddr , mi . Worker )
}
return nil
} ,
}
2020-10-29 07:18:10 +00:00
2022-09-14 20:12:01 +00:00
var actorConfirmChangeBeneficiary = & cli . Command {
Name : "confirm-change-beneficiary" ,
Usage : "Confirm a beneficiary address change" ,
2023-05-04 13:21:05 +00:00
ArgsUsage : "[minerID]" ,
2022-09-14 20:12:01 +00:00
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" ) ) {
2022-09-14 21:38:01 +00:00
return lcli . ShowHelp ( cctx , fmt . Errorf ( "must pass exactly one of --existing-beneficiary or --new-beneficiary" ) )
2022-09-14 20:12:01 +00:00
}
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" ) {
2022-09-14 21:38:01 +00:00
fmt . Println ( "Pass --really-do-it to actually execute this action. Review what you're about to approve CAREFULLY please" )
2022-09-14 20:12:01 +00:00
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 ( ) {
2022-09-14 21:38:01 +00:00
return fmt . Errorf ( "confirm beneficiary change failed with code %d" , wait . Receipt . ExitCode )
2022-09-14 20:12:01 +00:00
}
updatedMinerInfo , err := api . StateMinerInfo ( ctx , maddr , types . EmptyTSK )
if err != nil {
return err
}
2022-09-14 21:38:01 +00:00
if updatedMinerInfo . PendingBeneficiaryTerm == nil && updatedMinerInfo . Beneficiary == mi . PendingBeneficiaryTerm . NewBeneficiary {
2022-09-14 20:12:01 +00:00
fmt . Println ( "Beneficiary address successfully changed" )
} else {
fmt . Println ( "Beneficiary address change awaiting additional confirmations" )
}
return nil
} ,
}
2023-09-22 16:08:53 +00:00
var actorMovePartitionsCmd = & cli . Command {
Name : "move-partitions" ,
Usage : "move deadline of specified partitions from one to another" ,
Flags : [ ] cli . Flag {
& cli . Int64SliceFlag {
Name : "partition-indices" ,
Usage : "Indices of partitions to update, separated by comma" ,
} ,
& cli . Uint64Flag {
Name : "orig-deadline" ,
Usage : "Deadline to move partition from" ,
} ,
& cli . Uint64Flag {
Name : "dest-deadline" ,
Usage : "Deadline to move partition to" ,
} ,
& cli . BoolFlag {
Name : "really-do-it" ,
Usage : "Actually send transaction performing the action" ,
Value : false ,
} ,
} ,
Action : func ( cctx * cli . Context ) error {
2023-09-26 20:56:16 +00:00
if ! cctx . Bool ( "really-do-it" ) {
fmt . Println ( "Pass --really-do-it to actually execute this action" )
return nil
}
2023-09-22 16:08:53 +00:00
if cctx . Args ( ) . Present ( ) {
return fmt . Errorf ( "please use flags to provide arguments" )
}
ctx := lcli . ReqContext ( cctx )
minerApi , closer , err := lcli . GetStorageMinerAPI ( cctx )
if err != nil {
return err
}
defer closer ( )
maddr , err := minerApi . ActorAddress ( ctx )
if err != nil {
return err
}
fmt . Printf ( "Miner: %s\n" , color . BlueString ( "%s" , maddr ) )
fullNodeApi , acloser , err := lcli . GetFullNodeAPI ( cctx )
if err != nil {
return err
}
defer acloser ( )
minfo , err := fullNodeApi . StateMinerInfo ( ctx , maddr , types . EmptyTSK )
if err != nil {
return err
}
origDeadline := cctx . Uint64 ( "orig-deadline" )
if origDeadline > miner . WPoStPeriodDeadlines {
return fmt . Errorf ( "orig-deadline %d out of range" , origDeadline )
}
destDeadline := cctx . Uint64 ( "dest-deadline" )
if destDeadline > miner . WPoStPeriodDeadlines {
return fmt . Errorf ( "dest-deadline %d out of range" , destDeadline )
}
if origDeadline == destDeadline {
return fmt . Errorf ( "dest-desdline cannot be the same as orig-deadline" )
}
partitions := cctx . Int64Slice ( "partition-indices" )
if len ( partitions ) == 0 {
return fmt . Errorf ( "must include at least one partition to move" )
}
curPartitions , err := fullNodeApi . StateMinerPartitions ( ctx , maddr , origDeadline , types . EmptyTSK )
if err != nil {
return fmt . Errorf ( "getting partitions for deadline %d: %w" , origDeadline , err )
}
if len ( partitions ) > len ( curPartitions ) {
return fmt . Errorf ( "partition size(%d) cannot be bigger than current partition size(%d) for deadline %d" , len ( partitions ) , len ( curPartitions ) , origDeadline )
}
fmt . Printf ( "Moving %d paritions\n" , len ( partitions ) )
partitionsBf := bitfield . New ( )
for _ , partition := range partitions {
if partition >= int64 ( len ( curPartitions ) ) {
return fmt . Errorf ( "partition index(%d) doesn't exist" , partition )
}
partitionsBf . Set ( uint64 ( partition ) )
}
params := minerV12 . MovePartitionsParams {
OrigDeadline : origDeadline ,
DestDeadline : destDeadline ,
Partitions : partitionsBf ,
}
serializedParams , err := actors . SerializeParams ( & params )
if err != nil {
return fmt . Errorf ( "serializing params: %w" , err )
}
smsg , err := fullNodeApi . MpoolPushMessage ( ctx , & types . Message {
From : minfo . Worker ,
To : maddr ,
Method : builtin . MethodsMiner . MovePartitions ,
Value : big . Zero ( ) ,
Params : serializedParams ,
} , nil )
if err != nil {
return fmt . Errorf ( "mpool push: %w" , err )
}
fmt . Println ( "MovePartitions Message CID:" , smsg . Cid ( ) )
// wait for it to get mined into a block
fmt . Println ( "Waiting for block confirmation..." )
wait , err := fullNodeApi . StateWaitMsg ( ctx , smsg . Cid ( ) , build . MessageConfidence )
if err != nil {
return err
}
// check it executed successfully
if wait . Receipt . ExitCode . IsError ( ) {
fmt . Println ( "Moving partitions failed!" )
return err
}
fmt . Println ( "Move partition confirmed" )
return nil
} ,
}
2020-10-29 07:18:10 +00:00
var actorCompactAllocatedCmd = & cli . Command {
Name : "compact-allocated" ,
Usage : "compact allocated sectors bitfield" ,
Flags : [ ] cli . Flag {
2020-10-29 19:58:09 +00:00
& cli . Uint64Flag {
Name : "mask-last-offset" ,
2023-09-22 16:08:53 +00:00
Usage : "Mask sector IDs from 0 to 'highest_allocated - offset'" ,
2020-10-29 19:58:09 +00:00
} ,
& cli . Uint64Flag {
Name : "mask-upto-n" ,
Usage : "Mask sector IDs from 0 to 'n'" ,
2020-10-29 07:18:10 +00:00
} ,
& cli . BoolFlag {
Name : "really-do-it" ,
Usage : "Actually send transaction performing the action" ,
Value : false ,
} ,
} ,
Action : func ( cctx * cli . Context ) error {
if ! cctx . Bool ( "really-do-it" ) {
fmt . Println ( "Pass --really-do-it to actually execute this action" )
return nil
}
if ! cctx . Args ( ) . Present ( ) {
return fmt . Errorf ( "must pass address of new owner address" )
}
2022-09-14 18:51:18 +00:00
minerApi , closer , err := lcli . GetStorageMinerAPI ( cctx )
2020-10-29 07:18:10 +00:00
if err != nil {
return err
}
defer closer ( )
api , acloser , err := lcli . GetFullNodeAPI ( cctx )
if err != nil {
return err
}
defer acloser ( )
ctx := lcli . ReqContext ( cctx )
2022-09-14 18:51:18 +00:00
maddr , err := minerApi . ActorAddress ( ctx )
2020-10-29 07:18:10 +00:00
if err != nil {
return err
}
mact , err := api . StateGetActor ( ctx , maddr , types . EmptyTSK )
if err != nil {
return err
}
2021-07-22 14:02:14 +00:00
store := adt . WrapStore ( ctx , cbor . NewCborStore ( blockstore . NewAPIBlockstore ( api ) ) )
2020-10-29 07:18:10 +00:00
2022-04-20 21:34:28 +00:00
mst , err := lminer . Load ( store , mact )
2020-10-29 07:18:10 +00:00
if err != nil {
return err
}
allocs , err := mst . GetAllocatedSectors ( )
if err != nil {
return err
}
2020-10-29 19:58:09 +00:00
var maskBf bitfield . BitField
{
exclusiveFlags := [ ] string { "mask-last-offset" , "mask-upto-n" }
hasFlag := false
for _ , f := range exclusiveFlags {
if hasFlag && cctx . IsSet ( f ) {
return xerrors . Errorf ( "more than one 'mask` flag set" )
}
hasFlag = hasFlag || cctx . IsSet ( f )
}
2020-10-29 07:18:10 +00:00
}
2020-10-29 19:58:09 +00:00
switch {
case cctx . IsSet ( "mask-last-offset" ) :
last , err := allocs . Last ( )
if err != nil {
return err
}
2020-10-29 07:18:10 +00:00
2020-10-29 19:58:09 +00:00
m := cctx . Uint64 ( "mask-last-offset" )
if last <= m + 1 {
2021-07-22 14:18:55 +00:00
return xerrors . Errorf ( "highest allocated sector lower than mask offset %d: %d" , m + 1 , last )
2020-10-29 19:58:09 +00:00
}
// securty to not brick a miner
if last > 1 << 60 {
return xerrors . Errorf ( "very high last sector number, refusing to mask: %d" , last )
}
maskBf , err = bitfield . NewFromIter ( & rlepluslazy . RunSliceIterator {
Runs : [ ] rlepluslazy . Run { { Val : true , Len : last - m } } } )
if err != nil {
return xerrors . Errorf ( "forming bitfield: %w" , err )
}
case cctx . IsSet ( "mask-upto-n" ) :
n := cctx . Uint64 ( "mask-upto-n" )
maskBf , err = bitfield . NewFromIter ( & rlepluslazy . RunSliceIterator {
Runs : [ ] rlepluslazy . Run { { Val : true , Len : n } } } )
if err != nil {
return xerrors . Errorf ( "forming bitfield: %w" , err )
}
default :
return xerrors . Errorf ( "no 'mask' flags set" )
}
2020-10-29 07:18:10 +00:00
mi , err := api . StateMinerInfo ( ctx , maddr , types . EmptyTSK )
if err != nil {
return err
}
2022-04-20 21:34:28 +00:00
params := & miner . CompactSectorNumbersParams {
2020-10-29 19:58:09 +00:00
MaskSectorNumbers : maskBf ,
}
2020-10-29 07:18:10 +00:00
sp , err := actors . SerializeParams ( params )
if err != nil {
return xerrors . Errorf ( "serializing params: %w" , err )
}
smsg , err := api . MpoolPushMessage ( ctx , & types . Message {
From : mi . Worker ,
To : maddr ,
2022-04-20 21:34:28 +00:00
Method : builtin . MethodsMiner . CompactSectorNumbers ,
2020-10-29 07:18:10 +00:00
Value : big . Zero ( ) ,
Params : sp ,
} , nil )
if err != nil {
return xerrors . Errorf ( "mpool push: %w" , err )
}
fmt . Println ( "CompactSectorNumbers 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 err
}
// check it executed successfully
2022-09-14 18:53:11 +00:00
if wait . Receipt . ExitCode . IsError ( ) {
2020-10-29 07:18:10 +00:00
fmt . Println ( "Propose owner change failed!" )
return err
}
return nil
} ,
}
2022-04-20 21:34:28 +00:00
func isController ( mi api . MinerInfo , addr address . Address ) bool {
if addr == mi . Owner || addr == mi . Worker {
return true
}
for _ , ca := range mi . ControlAddresses {
if addr == ca {
return true
}
}
return false
}