Merge pull request #3175 from filecoin-project/feat/control-addersses-control
Wire up miner control addresses, use for PoSt
This commit is contained in:
commit
885f357c59
@ -132,6 +132,9 @@ type FullNode interface {
|
||||
GasEstimateGasPremium(_ context.Context, nblocksincl uint64,
|
||||
sender address.Address, gaslimit int64, tsk types.TipSetKey) (types.BigInt, error)
|
||||
|
||||
// GasEstimateMessageGas estimates gas values for unset message gas fields
|
||||
GasEstimateMessageGas(context.Context, *types.Message, *MessageSendSpec, types.TipSetKey) (*types.Message, error)
|
||||
|
||||
// MethodGroup: Sync
|
||||
// The Sync method group contains methods for interacting with and
|
||||
// observing the lotus sync service.
|
||||
|
@ -90,9 +90,10 @@ type FullNodeStruct struct {
|
||||
|
||||
BeaconGetEntry func(ctx context.Context, epoch abi.ChainEpoch) (*types.BeaconEntry, error) `perm:"read"`
|
||||
|
||||
GasEstimateGasPremium func(context.Context, uint64, address.Address, int64, types.TipSetKey) (types.BigInt, error) `perm:"read"`
|
||||
GasEstimateGasLimit func(context.Context, *types.Message, types.TipSetKey) (int64, error) `perm:"read"`
|
||||
GasEstimateFeeCap func(context.Context, *types.Message, int64, types.TipSetKey) (types.BigInt, error) `perm:"read"`
|
||||
GasEstimateGasPremium func(context.Context, uint64, address.Address, int64, types.TipSetKey) (types.BigInt, error) `perm:"read"`
|
||||
GasEstimateGasLimit func(context.Context, *types.Message, types.TipSetKey) (int64, error) `perm:"read"`
|
||||
GasEstimateFeeCap func(context.Context, *types.Message, int64, types.TipSetKey) (types.BigInt, error) `perm:"read"`
|
||||
GasEstimateMessageGas func(context.Context, *types.Message, *api.MessageSendSpec, types.TipSetKey) (*types.Message, error) `perm:"read"`
|
||||
|
||||
SyncState func(context.Context) (*api.SyncState, error) `perm:"read"`
|
||||
SyncSubmitBlock func(ctx context.Context, blk *types.BlockMsg) error `perm:"write"`
|
||||
@ -459,17 +460,19 @@ func (c *FullNodeStruct) ClientDataTransferUpdates(ctx context.Context) (<-chan
|
||||
return c.Internal.ClientDataTransferUpdates(ctx)
|
||||
}
|
||||
|
||||
func (c *FullNodeStruct) GasEstimateGasPremium(ctx context.Context, nblocksincl uint64,
|
||||
sender address.Address, gaslimit int64, tsk types.TipSetKey) (types.BigInt, error) {
|
||||
func (c *FullNodeStruct) GasEstimateGasPremium(ctx context.Context, nblocksincl uint64, sender address.Address, gaslimit int64, tsk types.TipSetKey) (types.BigInt, error) {
|
||||
return c.Internal.GasEstimateGasPremium(ctx, nblocksincl, sender, gaslimit, tsk)
|
||||
}
|
||||
func (c *FullNodeStruct) GasEstimateFeeCap(ctx context.Context, msg *types.Message,
|
||||
maxqueueblks int64, tsk types.TipSetKey) (types.BigInt, error) {
|
||||
|
||||
func (c *FullNodeStruct) GasEstimateFeeCap(ctx context.Context, msg *types.Message, maxqueueblks int64, tsk types.TipSetKey) (types.BigInt, error) {
|
||||
return c.Internal.GasEstimateFeeCap(ctx, msg, maxqueueblks, tsk)
|
||||
}
|
||||
|
||||
func (c *FullNodeStruct) GasEstimateGasLimit(ctx context.Context, msg *types.Message,
|
||||
tsk types.TipSetKey) (int64, error) {
|
||||
func (c *FullNodeStruct) GasEstimateMessageGas(ctx context.Context, msg *types.Message, spec *api.MessageSendSpec, tsk types.TipSetKey) (*types.Message, error) {
|
||||
return c.Internal.GasEstimateMessageGas(ctx, msg, spec, tsk)
|
||||
}
|
||||
|
||||
func (c *FullNodeStruct) GasEstimateGasLimit(ctx context.Context, msg *types.Message, tsk types.TipSetKey) (int64, error) {
|
||||
return c.Internal.GasEstimateGasLimit(ctx, msg, tsk)
|
||||
}
|
||||
|
||||
|
18
api/types.go
18
api/types.go
@ -49,9 +49,10 @@ type PubsubScore struct {
|
||||
}
|
||||
|
||||
type MinerInfo struct {
|
||||
Owner address.Address // Must be an ID-address.
|
||||
Worker address.Address // Must be an ID-address.
|
||||
NewWorker address.Address // Must be an ID-address.
|
||||
Owner address.Address // Must be an ID-address.
|
||||
Worker address.Address // Must be an ID-address.
|
||||
NewWorker address.Address // Must be an ID-address.
|
||||
ControlAddresses []address.Address // Must be an ID-addresses.
|
||||
WorkerChangeEpoch abi.ChainEpoch
|
||||
PeerId *peer.ID
|
||||
Multiaddrs []abi.Multiaddrs
|
||||
@ -67,10 +68,13 @@ func NewApiMinerInfo(info *miner.MinerInfo) MinerInfo {
|
||||
}
|
||||
|
||||
mi := MinerInfo{
|
||||
Owner: info.Owner,
|
||||
Worker: info.Worker,
|
||||
NewWorker: address.Undef,
|
||||
WorkerChangeEpoch: -1,
|
||||
Owner: info.Owner,
|
||||
Worker: info.Worker,
|
||||
ControlAddresses: info.ControlAddresses,
|
||||
|
||||
NewWorker: address.Undef,
|
||||
WorkerChangeEpoch: -1,
|
||||
|
||||
PeerId: pid,
|
||||
Multiaddrs: info.Multiaddrs,
|
||||
SealProofType: info.SealProofType,
|
||||
|
@ -105,6 +105,9 @@ var stateMinerInfo = &cli.Command{
|
||||
|
||||
fmt.Printf("Owner:\t%s\n", mi.Owner)
|
||||
fmt.Printf("Worker:\t%s\n", mi.Worker)
|
||||
for i, controlAddress := range mi.ControlAddresses {
|
||||
fmt.Printf("Control %d: \t%s\n", i, controlAddress)
|
||||
}
|
||||
fmt.Printf("PeerID:\t%s\n", mi.PeerId)
|
||||
fmt.Printf("SectorSize:\t%s (%d)\n", types.SizeStr(types.NewInt(uint64(mi.SectorSize))), mi.SectorSize)
|
||||
fmt.Printf("Multiaddrs: \t")
|
||||
|
@ -2,19 +2,26 @@ package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/filecoin-project/specs-actors/actors/builtin"
|
||||
"github.com/libp2p/go-libp2p-core/peer"
|
||||
"golang.org/x/xerrors"
|
||||
"os"
|
||||
"strings"
|
||||
|
||||
"github.com/fatih/color"
|
||||
"github.com/libp2p/go-libp2p-core/peer"
|
||||
ma "github.com/multiformats/go-multiaddr"
|
||||
"github.com/urfave/cli/v2"
|
||||
"golang.org/x/xerrors"
|
||||
|
||||
"github.com/filecoin-project/go-address"
|
||||
"github.com/filecoin-project/specs-actors/actors/abi"
|
||||
"github.com/filecoin-project/specs-actors/actors/abi/big"
|
||||
"github.com/filecoin-project/specs-actors/actors/builtin"
|
||||
"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"
|
||||
"github.com/filecoin-project/lotus/lib/tablewriter"
|
||||
"github.com/filecoin-project/lotus/storage"
|
||||
)
|
||||
|
||||
var actorCmd = &cli.Command{
|
||||
@ -24,6 +31,7 @@ var actorCmd = &cli.Command{
|
||||
actorSetAddrsCmd,
|
||||
actorWithdrawCmd,
|
||||
actorSetPeeridCmd,
|
||||
actorControl,
|
||||
},
|
||||
}
|
||||
|
||||
@ -240,3 +248,232 @@ var actorWithdrawCmd = &cli.Command{
|
||||
return nil
|
||||
},
|
||||
}
|
||||
|
||||
var actorControl = &cli.Command{
|
||||
Name: "control",
|
||||
Usage: "Manage control addresses",
|
||||
Subcommands: []*cli.Command{
|
||||
actorControlList,
|
||||
actorControlSet,
|
||||
},
|
||||
}
|
||||
|
||||
var actorControlList = &cli.Command{
|
||||
Name: "list",
|
||||
Usage: "Get currently set control addresses",
|
||||
Flags: []cli.Flag{
|
||||
&cli.BoolFlag{
|
||||
Name: "verbose",
|
||||
},
|
||||
&cli.BoolFlag{
|
||||
Name: "color",
|
||||
Value: true,
|
||||
},
|
||||
},
|
||||
Action: func(cctx *cli.Context) error {
|
||||
color.NoColor = !cctx.Bool("color")
|
||||
|
||||
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
|
||||
}
|
||||
|
||||
tw := tablewriter.New(
|
||||
tablewriter.Col("name"),
|
||||
tablewriter.Col("ID"),
|
||||
tablewriter.Col("key"),
|
||||
tablewriter.Col("use"),
|
||||
tablewriter.Col("balance"),
|
||||
)
|
||||
|
||||
postAddr, err := storage.AddressFor(ctx, api, mi, storage.PoStAddr, types.FromFil(1))
|
||||
if err != nil {
|
||||
return xerrors.Errorf("getting address for post: %w", err)
|
||||
}
|
||||
|
||||
printKey := func(name string, a address.Address) {
|
||||
b, err := api.WalletBalance(ctx, a)
|
||||
if err != nil {
|
||||
fmt.Printf("%s\t%s: error getting balance: %s\n", name, a, err)
|
||||
return
|
||||
}
|
||||
|
||||
k, err := api.StateAccountKey(ctx, a, types.EmptyTSK)
|
||||
if err != nil {
|
||||
fmt.Printf("%s\t%s: error getting account key: %s\n", name, a, err)
|
||||
return
|
||||
}
|
||||
|
||||
kstr := k.String()
|
||||
if !cctx.Bool("verbose") {
|
||||
kstr = kstr[:9] + "..."
|
||||
}
|
||||
|
||||
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"))
|
||||
}
|
||||
if a == postAddr {
|
||||
uses = append(uses, color.GreenString("post"))
|
||||
}
|
||||
|
||||
tw.Write(map[string]interface{}{
|
||||
"name": name,
|
||||
"ID": a,
|
||||
"key": kstr,
|
||||
"use": strings.Join(uses, " "),
|
||||
"balance": bstr,
|
||||
})
|
||||
}
|
||||
|
||||
printKey("owner", mi.Owner)
|
||||
printKey("worker", mi.Worker)
|
||||
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{
|
||||
Name: "really-do-it",
|
||||
Usage: "Actually send transaction performing the action",
|
||||
Value: false,
|
||||
},
|
||||
},
|
||||
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
|
||||
}
|
||||
|
||||
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
|
||||
}
|
||||
|
||||
cwp := &miner.ChangeWorkerAddressParams{
|
||||
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{
|
||||
From: mi.Owner,
|
||||
To: maddr,
|
||||
Method: builtin.MethodsMiner.ChangeWorkerAddress,
|
||||
|
||||
Value: big.Zero(),
|
||||
Params: sp,
|
||||
}, nil)
|
||||
if err != nil {
|
||||
return xerrors.Errorf("mpool push: %w", err)
|
||||
}
|
||||
|
||||
fmt.Println("Message CID:", smsg.Cid())
|
||||
|
||||
return nil
|
||||
},
|
||||
}
|
||||
|
@ -143,6 +143,7 @@ func infoCmdAct(cctx *cli.Context) error {
|
||||
|
||||
fmt.Printf("Miner Balance: %s\n", color.YellowString("%s", types.FIL(mact.Balance)))
|
||||
fmt.Printf("\tPreCommit: %s\n", types.FIL(mas.PreCommitDeposits))
|
||||
fmt.Printf("\tPledge: %s\n", types.FIL(mas.InitialPledgeRequirement))
|
||||
fmt.Printf("\tLocked: %s\n", types.FIL(mas.LockedFunds))
|
||||
color.Green("\tAvailable: %s", types.FIL(types.BigSub(mact.Balance, types.BigAdd(mas.LockedFunds, mas.PreCommitDeposits))))
|
||||
wb, err := api.WalletBalance(ctx, mi.Worker)
|
||||
|
@ -109,8 +109,8 @@ The addresses passed to `set-addrs` parameter in the commands below should be cu
|
||||
|
||||
Once the config file has been updated, set the on-chain record of the miner's listen addresses:
|
||||
|
||||
```
|
||||
lotus-miner actor set-addrs <multiaddr_1> <multiaddr_2> ... <multiaddr_n>
|
||||
```
|
||||
lotus-miner actor set-addrs <multiaddr_1> <multiaddr_2> ... <multiaddr_n>
|
||||
```
|
||||
|
||||
This updates the `MinerInfo` object in the miner's actor, which will be looked up
|
||||
@ -119,5 +119,50 @@ when a client attempts to make a deal. Any number of addresses can be provided.
|
||||
Example:
|
||||
|
||||
```
|
||||
lotus-miner actor set-addrs /ip4/123.123.73.123/tcp/12345 /ip4/223.223.83.223/tcp/23456
|
||||
lotus-miner actor set-addrs /ip4/123.123.73.123/tcp/12345 /ip4/223.223.83.223/tcp/23456
|
||||
```
|
||||
|
||||
# Separate address for windowPoSt messages
|
||||
|
||||
WindowPoSt is the mechanism through which storage is verified in Filecoin. It requires miners to submit proofs for all sectors every 24h, which require sending messages to the chain.
|
||||
|
||||
Because many other mining related actions require sending messages to the chain, and not all of those are "high value", it may be desirable to use a separate account to send PoSt messages from. This allows for setting lower GasFeeCaps on the lower value messages without creating head-of-line blocking problems for the PoSt messages in congested chain conditions
|
||||
|
||||
To set this up, first create a new account, and send it some funds for gas fees:
|
||||
```sh
|
||||
lotus wallet new bls
|
||||
t3defg...
|
||||
|
||||
lotus send t3defg... 100
|
||||
```
|
||||
|
||||
Next add the control address
|
||||
```sh
|
||||
lotus-miner actor control set t3defg...
|
||||
Add t3defg...
|
||||
Pass --really-do-it to actually execute this action
|
||||
```
|
||||
|
||||
Now actually set the addresses
|
||||
```sh
|
||||
lotus-miner actor control set --really-do-it t3defg...
|
||||
Add t3defg...
|
||||
Message CID: bafy2..
|
||||
```
|
||||
|
||||
Wait for the message to land on chain
|
||||
```sh
|
||||
lotus state wait-msg bafy2..
|
||||
...
|
||||
Exit Code: 0
|
||||
...
|
||||
```
|
||||
|
||||
Check miner control address list to make sure the address was correctly setup
|
||||
```sh
|
||||
lotus-miner actor control list
|
||||
name ID key use balance
|
||||
owner t01111 t3abcd... other 300 FIL
|
||||
worker t01111 t3abcd... other 300 FIL
|
||||
control-0 t02222 t3defg... post 100 FIL
|
||||
```
|
||||
|
@ -6,6 +6,7 @@ import (
|
||||
"math/rand"
|
||||
"sort"
|
||||
|
||||
"github.com/filecoin-project/lotus/api"
|
||||
"github.com/filecoin-project/lotus/build"
|
||||
"github.com/filecoin-project/lotus/chain/messagepool"
|
||||
"github.com/filecoin-project/lotus/chain/stmgr"
|
||||
@ -176,3 +177,33 @@ func (a *GasAPI) GasEstimateGasLimit(ctx context.Context, msgIn *types.Message,
|
||||
|
||||
return res.MsgRct.GasUsed, nil
|
||||
}
|
||||
|
||||
func (a *GasAPI) GasEstimateMessageGas(ctx context.Context, msg *types.Message, spec *api.MessageSendSpec, _ types.TipSetKey) (*types.Message, error) {
|
||||
if msg.GasLimit == 0 {
|
||||
gasLimit, err := a.GasEstimateGasLimit(ctx, msg, types.TipSetKey{})
|
||||
if err != nil {
|
||||
return nil, xerrors.Errorf("estimating gas used: %w", err)
|
||||
}
|
||||
msg.GasLimit = int64(float64(gasLimit) * a.Mpool.GetConfig().GasLimitOverestimation)
|
||||
}
|
||||
|
||||
if msg.GasPremium == types.EmptyInt || types.BigCmp(msg.GasPremium, types.NewInt(0)) == 0 {
|
||||
gasPremium, err := a.GasEstimateGasPremium(ctx, 2, msg.From, msg.GasLimit, types.TipSetKey{})
|
||||
if err != nil {
|
||||
return nil, xerrors.Errorf("estimating gas price: %w", err)
|
||||
}
|
||||
msg.GasPremium = gasPremium
|
||||
}
|
||||
|
||||
if msg.GasFeeCap == types.EmptyInt || types.BigCmp(msg.GasFeeCap, types.NewInt(0)) == 0 {
|
||||
feeCap, err := a.GasEstimateFeeCap(ctx, msg, 10, types.EmptyTSK)
|
||||
if err != nil {
|
||||
return nil, xerrors.Errorf("estimating fee cap: %w", err)
|
||||
}
|
||||
msg.GasFeeCap = big.Add(feeCap, msg.GasPremium)
|
||||
}
|
||||
|
||||
capGasFee(msg, spec.Get().MaxFee)
|
||||
|
||||
return msg, nil
|
||||
}
|
||||
|
@ -146,32 +146,12 @@ func (a *MpoolAPI) MpoolPushMessage(ctx context.Context, msg *types.Message, spe
|
||||
if msg.Nonce != 0 {
|
||||
return nil, xerrors.Errorf("MpoolPushMessage expects message nonce to be 0, was %d", msg.Nonce)
|
||||
}
|
||||
if msg.GasLimit == 0 {
|
||||
gasLimit, err := a.GasEstimateGasLimit(ctx, msg, types.TipSetKey{})
|
||||
if err != nil {
|
||||
return nil, xerrors.Errorf("estimating gas used: %w", err)
|
||||
}
|
||||
msg.GasLimit = int64(float64(gasLimit) * a.Mpool.GetConfig().GasLimitOverestimation)
|
||||
}
|
||||
|
||||
if msg.GasPremium == types.EmptyInt || types.BigCmp(msg.GasPremium, types.NewInt(0)) == 0 {
|
||||
gasPremium, err := a.GasEstimateGasPremium(ctx, 2, msg.From, msg.GasLimit, types.TipSetKey{})
|
||||
if err != nil {
|
||||
return nil, xerrors.Errorf("estimating gas price: %w", err)
|
||||
}
|
||||
msg.GasPremium = gasPremium
|
||||
msg, err := a.GasAPI.GasEstimateMessageGas(ctx, msg, spec, types.EmptyTSK)
|
||||
if err != nil {
|
||||
return nil, xerrors.Errorf("GasEstimateMessageGas error: %w", err)
|
||||
}
|
||||
|
||||
if msg.GasFeeCap == types.EmptyInt || types.BigCmp(msg.GasFeeCap, types.NewInt(0)) == 0 {
|
||||
feeCap, err := a.GasEstimateFeeCap(ctx, msg, 10, types.EmptyTSK)
|
||||
if err != nil {
|
||||
return nil, xerrors.Errorf("estimating fee cap: %w", err)
|
||||
}
|
||||
msg.GasFeeCap = big.Add(feeCap, msg.GasPremium)
|
||||
}
|
||||
|
||||
capGasFee(msg, spec.Get().MaxFee)
|
||||
|
||||
sign := func(from address.Address, nonce uint64) (*types.SignedMessage, error) {
|
||||
msg.Nonce = nonce
|
||||
if msg.From.Protocol() == address.ID {
|
||||
@ -192,7 +172,6 @@ func (a *MpoolAPI) MpoolPushMessage(ctx context.Context, msg *types.Message, spe
|
||||
}
|
||||
|
||||
var m *types.SignedMessage
|
||||
var err error
|
||||
again:
|
||||
m, err = a.Mpool.PushWithNonce(ctx, msg.From, sign)
|
||||
if err == messagepool.ErrTryAgain {
|
||||
|
92
storage/addresses.go
Normal file
92
storage/addresses.go
Normal file
@ -0,0 +1,92 @@
|
||||
package storage
|
||||
|
||||
import (
|
||||
"context"
|
||||
"golang.org/x/xerrors"
|
||||
|
||||
"github.com/filecoin-project/go-address"
|
||||
"github.com/filecoin-project/specs-actors/actors/abi"
|
||||
|
||||
"github.com/filecoin-project/lotus/api"
|
||||
"github.com/filecoin-project/lotus/chain/types"
|
||||
)
|
||||
|
||||
type AddrUse int
|
||||
|
||||
const (
|
||||
PreCommitAddr AddrUse = iota
|
||||
CommitAddr
|
||||
PoStAddr
|
||||
)
|
||||
|
||||
type addrSelectApi interface {
|
||||
WalletBalance(context.Context, address.Address) (types.BigInt, error)
|
||||
WalletHas(context.Context, address.Address) (bool, error)
|
||||
|
||||
StateAccountKey(context.Context, address.Address, types.TipSetKey) (address.Address, error)
|
||||
}
|
||||
|
||||
func AddressFor(ctx context.Context, a addrSelectApi, mi api.MinerInfo, use AddrUse, minFunds abi.TokenAmount) (address.Address, error) {
|
||||
switch use {
|
||||
case PreCommitAddr, CommitAddr:
|
||||
// always use worker, at least for now
|
||||
return mi.Worker, nil
|
||||
}
|
||||
|
||||
for _, addr := range mi.ControlAddresses {
|
||||
b, err := a.WalletBalance(ctx, addr)
|
||||
if err != nil {
|
||||
return address.Undef, xerrors.Errorf("checking control address balance: %w", err)
|
||||
}
|
||||
|
||||
if b.GreaterThanEqual(minFunds) {
|
||||
k, err := a.StateAccountKey(ctx, addr, types.EmptyTSK)
|
||||
if err != nil {
|
||||
log.Errorw("getting account key", "error", err)
|
||||
continue
|
||||
}
|
||||
|
||||
have, err := a.WalletHas(ctx, k)
|
||||
if err != nil {
|
||||
return address.Undef, xerrors.Errorf("failed to check control address: %w", err)
|
||||
}
|
||||
|
||||
if !have {
|
||||
log.Errorw("don't have key", "key", k)
|
||||
continue
|
||||
}
|
||||
|
||||
return addr, nil
|
||||
}
|
||||
|
||||
log.Warnw("control address didn't have enough funds for PoSt message", "address", addr, "required", types.FIL(minFunds), "balance", types.FIL(b))
|
||||
}
|
||||
|
||||
// Try to use the owner account if we can, fallback to worker if we can't
|
||||
|
||||
b, err := a.WalletBalance(ctx, mi.Owner)
|
||||
if err != nil {
|
||||
return address.Undef, xerrors.Errorf("checking owner balance: %w", err)
|
||||
}
|
||||
|
||||
if !b.GreaterThanEqual(minFunds) {
|
||||
return mi.Worker, nil
|
||||
}
|
||||
|
||||
k, err := a.StateAccountKey(ctx, mi.Owner, types.EmptyTSK)
|
||||
if err != nil {
|
||||
log.Errorw("getting owner account key", "error", err)
|
||||
return mi.Worker, nil
|
||||
}
|
||||
|
||||
have, err := a.WalletHas(ctx, k)
|
||||
if err != nil {
|
||||
return address.Undef, xerrors.Errorf("failed to check owner address: %w", err)
|
||||
}
|
||||
|
||||
if !have {
|
||||
return mi.Worker, nil
|
||||
}
|
||||
|
||||
return mi.Owner, nil
|
||||
}
|
@ -67,9 +67,12 @@ type storageMinerApi interface {
|
||||
StateMarketStorageDeal(context.Context, abi.DealID, types.TipSetKey) (*api.MarketDeal, error)
|
||||
StateMinerFaults(context.Context, address.Address, types.TipSetKey) (abi.BitField, error)
|
||||
StateMinerRecoveries(context.Context, address.Address, types.TipSetKey) (abi.BitField, error)
|
||||
StateAccountKey(context.Context, address.Address, types.TipSetKey) (address.Address, error)
|
||||
|
||||
MpoolPushMessage(context.Context, *types.Message, *api.MessageSendSpec) (*types.SignedMessage, error)
|
||||
|
||||
GasEstimateMessageGas(context.Context, *types.Message, *api.MessageSendSpec, types.TipSetKey) (*types.Message, error)
|
||||
|
||||
ChainHead(context.Context) (*types.TipSet, error)
|
||||
ChainNotify(context.Context) (<-chan []*api.HeadChange, error)
|
||||
ChainGetRandomnessFromTickets(ctx context.Context, tsk types.TipSetKey, personalization crypto.DomainSeparationTag, randEpoch abi.ChainEpoch, entropy []byte) (abi.Randomness, error)
|
||||
|
@ -4,6 +4,7 @@ import (
|
||||
"bytes"
|
||||
"context"
|
||||
"errors"
|
||||
"github.com/filecoin-project/specs-actors/actors/abi/big"
|
||||
"time"
|
||||
|
||||
"github.com/filecoin-project/go-bitfield"
|
||||
@ -177,6 +178,8 @@ func (s *WindowPoStScheduler) checkNextRecoveries(ctx context.Context, dlIdx uin
|
||||
Params: enc,
|
||||
Value: types.NewInt(0),
|
||||
}
|
||||
spec := &api.MessageSendSpec{MaxFee: abi.TokenAmount(s.feeCfg.MaxWindowPoStGasFee)}
|
||||
s.setSender(ctx, msg, spec)
|
||||
|
||||
sm, err := s.api.MpoolPushMessage(ctx, msg, &api.MessageSendSpec{MaxFee: abi.TokenAmount(s.feeCfg.MaxWindowPoStGasFee)})
|
||||
if err != nil {
|
||||
@ -259,8 +262,10 @@ func (s *WindowPoStScheduler) checkNextFaults(ctx context.Context, dlIdx uint64,
|
||||
Params: enc,
|
||||
Value: types.NewInt(0), // TODO: Is there a fee?
|
||||
}
|
||||
spec := &api.MessageSendSpec{MaxFee: abi.TokenAmount(s.feeCfg.MaxWindowPoStGasFee)}
|
||||
s.setSender(ctx, msg, spec)
|
||||
|
||||
sm, err := s.api.MpoolPushMessage(ctx, msg, &api.MessageSendSpec{MaxFee: abi.TokenAmount(s.feeCfg.MaxWindowPoStGasFee)})
|
||||
sm, err := s.api.MpoolPushMessage(ctx, msg, spec)
|
||||
if err != nil {
|
||||
return xerrors.Errorf("pushing message to mpool: %w", err)
|
||||
}
|
||||
@ -465,9 +470,11 @@ func (s *WindowPoStScheduler) submitPost(ctx context.Context, proof *miner.Submi
|
||||
Params: enc,
|
||||
Value: types.NewInt(1000), // currently hard-coded late fee in actor, returned if not late
|
||||
}
|
||||
spec := &api.MessageSendSpec{MaxFee: abi.TokenAmount(s.feeCfg.MaxWindowPoStGasFee)}
|
||||
s.setSender(ctx, msg, spec)
|
||||
|
||||
// TODO: consider maybe caring about the output
|
||||
sm, err := s.api.MpoolPushMessage(ctx, msg, &api.MessageSendSpec{MaxFee: abi.TokenAmount(s.feeCfg.MaxWindowPoStGasFee)})
|
||||
sm, err := s.api.MpoolPushMessage(ctx, msg, spec)
|
||||
if err != nil {
|
||||
return xerrors.Errorf("pushing message to mpool: %w", err)
|
||||
}
|
||||
@ -490,3 +497,33 @@ func (s *WindowPoStScheduler) submitPost(ctx context.Context, proof *miner.Submi
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *WindowPoStScheduler) setSender(ctx context.Context, msg *types.Message, spec *api.MessageSendSpec) {
|
||||
mi, err := s.api.StateMinerInfo(ctx, s.actor, types.EmptyTSK)
|
||||
if err != nil {
|
||||
log.Errorw("error getting miner info", "error", err)
|
||||
|
||||
// better than just failing
|
||||
msg.From = s.worker
|
||||
return
|
||||
}
|
||||
|
||||
gm, err := s.api.GasEstimateMessageGas(ctx, msg, spec, types.EmptyTSK)
|
||||
if err != nil {
|
||||
log.Errorw("estimating gas", "error", err)
|
||||
msg.From = s.worker
|
||||
return
|
||||
}
|
||||
*msg = *gm
|
||||
|
||||
minFunds := big.Add(msg.RequiredFunds(), msg.Value)
|
||||
|
||||
pa, err := AddressFor(ctx, s.api, mi, PoStAddr, minFunds)
|
||||
if err != nil {
|
||||
log.Errorw("error selecting address for post", "error", err)
|
||||
msg.From = s.worker
|
||||
return
|
||||
}
|
||||
|
||||
msg.From = pa
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user