2020-08-19 20:08:04 +00:00
package storage
import (
"context"
2020-08-20 04:49:10 +00:00
2020-08-19 20:08:04 +00:00
"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"
2020-10-07 17:41:07 +00:00
"github.com/filecoin-project/go-state-types/big"
2020-08-19 20:08:04 +00:00
2020-10-07 17:41:07 +00:00
"github.com/filecoin-project/lotus/chain/actors/builtin/miner"
2020-08-19 20:08:04 +00:00
"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 )
}
2020-10-07 17:41:07 +00:00
func AddressFor ( ctx context . Context , a addrSelectApi , mi miner . MinerInfo , use AddrUse , goodFunds , minFunds abi . TokenAmount ) ( address . Address , abi . TokenAmount , error ) {
2020-08-19 20:08:04 +00:00
switch use {
case PreCommitAddr , CommitAddr :
// always use worker, at least for now
2020-10-07 17:41:07 +00:00
return mi . Worker , big . Zero ( ) , nil
2020-08-19 20:08:04 +00:00
}
2020-10-07 17:41:07 +00:00
leastBad := address . Undef
bestAvail := minFunds
2020-08-19 20:08:04 +00:00
for _ , addr := range mi . ControlAddresses {
b , err := a . WalletBalance ( ctx , addr )
if err != nil {
2020-10-07 17:41:07 +00:00
return address . Undef , big . Zero ( ) , xerrors . Errorf ( "checking control address balance: %w" , err )
2020-08-19 20:08:04 +00:00
}
2020-10-07 17:41:07 +00:00
if b . GreaterThanEqual ( goodFunds ) {
2020-08-19 20:08:04 +00:00
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 {
2020-10-07 17:41:07 +00:00
return address . Undef , big . Zero ( ) , xerrors . Errorf ( "failed to check control address: %w" , err )
2020-08-19 20:08:04 +00:00
}
if ! have {
log . Errorw ( "don't have key" , "key" , k )
continue
}
2020-10-07 17:41:07 +00:00
return addr , b , nil
}
if b . GreaterThan ( bestAvail ) {
leastBad = addr
bestAvail = b
2020-08-19 20:08:04 +00:00
}
2020-10-07 17:41:07 +00:00
log . Warnw ( "control address didn't have enough funds for window post message" , "address" , addr , "required" , types . FIL ( goodFunds ) , "balance" , types . FIL ( b ) )
2020-08-19 20:08:04 +00:00
}
// Try to use the owner account if we can, fallback to worker if we can't
2020-10-07 17:41:07 +00:00
k , err := a . StateAccountKey ( ctx , mi . Owner , types . EmptyTSK )
2020-08-19 20:08:04 +00:00
if err != nil {
2020-10-07 17:41:07 +00:00
log . Errorw ( "getting owner account key" , "error" , err )
return mi . Worker , big . Zero ( ) , nil
2020-08-19 20:08:04 +00:00
}
2020-10-07 17:41:07 +00:00
haveOwner , err := a . WalletHas ( ctx , k )
if err != nil {
return address . Undef , big . Zero ( ) , xerrors . Errorf ( "failed to check owner address: %w" , err )
2020-08-19 20:08:04 +00:00
}
2020-10-07 17:41:07 +00:00
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
}
2020-08-19 20:08:04 +00:00
}
2020-10-07 17:41:07 +00:00
workerBalance , err := a . WalletBalance ( ctx , mi . Worker )
2020-08-19 20:08:04 +00:00
if err != nil {
2020-10-07 17:41:07 +00:00
return address . Undef , big . Zero ( ) , xerrors . Errorf ( "checking owner balance: %w" , err )
2020-08-19 20:08:04 +00:00
}
2020-10-07 17:41:07 +00:00
if workerBalance . GreaterThanEqual ( goodFunds ) {
return mi . Worker , goodFunds , nil
2020-08-19 20:08:04 +00:00
}
2020-10-07 17:41:07 +00:00
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
}