lotus/storage/addresses.go

129 lines
3.6 KiB
Go
Raw Normal View History

package storage
import (
"context"
"golang.org/x/xerrors"
"github.com/filecoin-project/go-address"
2020-09-07 03:49:10 +00:00
"github.com/filecoin-project/go-state-types/abi"
"github.com/filecoin-project/go-state-types/big"
"github.com/filecoin-project/lotus/chain/actors/builtin/miner"
"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 miner.MinerInfo, use AddrUse, goodFunds, minFunds abi.TokenAmount) (address.Address, abi.TokenAmount, error) {
switch use {
case PreCommitAddr, CommitAddr:
// always use worker, at least for now
return mi.Worker, big.Zero(), nil
}
leastBad := address.Undef
bestAvail := minFunds
for _, addr := range mi.ControlAddresses {
b, err := a.WalletBalance(ctx, addr)
if err != nil {
return address.Undef, big.Zero(), xerrors.Errorf("checking control address balance: %w", err)
}
if b.GreaterThanEqual(goodFunds) {
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, big.Zero(), xerrors.Errorf("failed to check control address: %w", err)
}
if !have {
log.Errorw("don't have key", "key", k)
continue
}
return addr, b, nil
}
if b.GreaterThan(bestAvail) {
leastBad = addr
bestAvail = b
}
log.Warnw("control address didn't have enough funds for window post message", "address", addr, "required", types.FIL(goodFunds), "balance", types.FIL(b))
}
// Try to use the owner account if we can, fallback to worker if we can't
k, err := a.StateAccountKey(ctx, mi.Owner, types.EmptyTSK)
if err != nil {
log.Errorw("getting owner account key", "error", err)
return mi.Worker, big.Zero(), nil
}
haveOwner, err := a.WalletHas(ctx, k)
if err != nil {
return address.Undef, big.Zero(), xerrors.Errorf("failed to check owner address: %w", err)
}
if haveOwner {
ownerBalance, err := a.WalletBalance(ctx, mi.Owner)
if err != nil {
return address.Undef, big.Zero(), xerrors.Errorf("checking owner balance: %w", err)
}
if ownerBalance.GreaterThanEqual(goodFunds) {
return mi.Owner, goodFunds, nil
}
if ownerBalance.GreaterThan(bestAvail) {
leastBad = mi.Owner
bestAvail = ownerBalance
}
}
workerBalance, err := a.WalletBalance(ctx, mi.Worker)
if err != nil {
return address.Undef, big.Zero(), xerrors.Errorf("checking owner balance: %w", err)
}
if workerBalance.GreaterThanEqual(goodFunds) {
return mi.Worker, goodFunds, nil
}
if workerBalance.GreaterThan(bestAvail) {
leastBad = mi.Worker
bestAvail = workerBalance
}
if bestAvail.GreaterThan(minFunds) {
log.Warnw("No address had enough funds to for full PoSt message Fee, selecting least bad address", "address", leastBad, "balance", types.FIL(bestAvail), "optimalFunds", types.FIL(goodFunds), "minFunds", types.FIL(minFunds))
return leastBad, bestAvail, nil
}
// This most likely won't work, but can't hurt to try
log.Warnw("No address had enough funds to for minimum PoSt message Fee, selecting worker address as a fallback", "address", mi.Worker, "balance", types.FIL(workerBalance), "optimalFunds", types.FIL(goodFunds), "minFunds", types.FIL(minFunds))
return mi.Worker, workerBalance, nil
2020-08-19 23:26:13 +00:00
}