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
"github.com/filecoin-project/go-address"
2020-09-07 03:49:10 +00:00
"github.com/filecoin-project/go-state-types/abi"
2020-12-02 19:46:07 +00:00
"github.com/filecoin-project/lotus/api"
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 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-12-02 18:58:00 +00:00
StateLookupID ( context . Context , address . Address , types . TipSetKey ) ( address . Address , error )
}
type AddressSelector struct {
2020-12-02 19:46:07 +00:00
api . AddressConfig
2020-08-19 20:08:04 +00:00
}
2020-12-02 20:47:45 +00:00
func ( as * AddressSelector ) AddressFor ( ctx context . Context , a addrSelectApi , mi miner . MinerInfo , use api . AddrUse , goodFunds , minFunds abi . TokenAmount ) ( address . Address , abi . TokenAmount , error ) {
2020-12-02 18:58:00 +00:00
var addrs [ ] address . Address
2020-08-19 20:08:04 +00:00
switch use {
2020-12-02 20:47:45 +00:00
case api . PreCommitAddr :
2020-12-02 18:58:00 +00:00
addrs = append ( addrs , as . PreCommitControl ... )
2020-12-02 20:47:45 +00:00
case api . CommitAddr :
2020-12-02 18:58:00 +00:00
addrs = append ( addrs , as . CommitControl ... )
default :
defaultCtl := map [ address . Address ] struct { } { }
for _ , a := range mi . ControlAddresses {
defaultCtl [ a ] = struct { } { }
}
delete ( defaultCtl , mi . Owner )
delete ( defaultCtl , mi . Worker )
for _ , addr := range append ( append ( [ ] address . Address { } , as . PreCommitControl ... ) , as . CommitControl ... ) {
if addr . Protocol ( ) != address . ID {
var err error
addr , err = a . StateLookupID ( ctx , addr , types . EmptyTSK )
if err != nil {
log . Warnw ( "looking up control address" , "address" , addr , "error" , err )
continue
}
}
delete ( defaultCtl , addr )
}
for a := range defaultCtl {
addrs = append ( addrs , a )
}
2020-08-19 20:08:04 +00:00
}
2020-12-02 18:58:00 +00:00
addrs = append ( addrs , mi . Owner , mi . Worker )
return pickAddress ( ctx , a , mi , goodFunds , minFunds , addrs )
}
2020-08-19 20:08:04 +00:00
2020-12-02 18:58:00 +00:00
func pickAddress ( ctx context . Context , a addrSelectApi , mi miner . MinerInfo , goodFunds , minFunds abi . TokenAmount , addrs [ ] address . Address ) ( address . Address , abi . TokenAmount , error ) {
2020-10-26 15:28:39 +00:00
leastBad := mi . Worker
2020-10-07 17:41:07 +00:00
bestAvail := minFunds
2020-12-02 18:58:00 +00:00
ctl := map [ address . Address ] struct { } { }
for _ , a := range append ( mi . ControlAddresses , mi . Owner , mi . Worker ) {
ctl [ a ] = struct { } { }
}
for _ , addr := range addrs {
2020-12-02 19:46:07 +00:00
if addr . Protocol ( ) != address . ID {
addr , err := a . StateLookupID ( ctx , addr , types . EmptyTSK )
if err != nil {
log . Warnw ( "looking up control address" , "address" , addr , "error" , err )
continue
}
2020-12-02 18:58:00 +00:00
}
if _ , ok := ctl [ addr ] ; ! ok {
log . Warnw ( "non-control address configured for sending messages" , "address" , addr )
continue
}
2020-10-26 15:28:39 +00:00
if maybeUseAddress ( ctx , a , addr , goodFunds , & leastBad , & bestAvail ) {
return leastBad , bestAvail , nil
2020-10-07 17:41:07 +00:00
}
2020-10-26 15:28:39 +00:00
}
2020-10-07 17:41:07 +00:00
2020-11-19 19:37:00 +00:00
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 ) )
2020-08-19 20:08:04 +00:00
2020-11-19 19:37:00 +00:00
return leastBad , bestAvail , nil
2020-10-26 15:28:39 +00:00
}
func maybeUseAddress ( ctx context . Context , a addrSelectApi , addr address . Address , goodFunds abi . TokenAmount , leastBad * address . Address , bestAvail * abi . TokenAmount ) bool {
b , err := a . WalletBalance ( ctx , addr )
2020-10-07 17:41:07 +00:00
if err != nil {
2020-10-26 15:28:39 +00:00
log . Errorw ( "checking control address balance" , "addr" , addr , "error" , err )
return false
2020-08-19 20:08:04 +00:00
}
2020-10-26 15:28:39 +00:00
if b . GreaterThanEqual ( goodFunds ) {
k , err := a . StateAccountKey ( ctx , addr , types . EmptyTSK )
2020-10-07 17:41:07 +00:00
if err != nil {
2020-10-26 15:28:39 +00:00
log . Errorw ( "getting account key" , "error" , err )
return false
2020-10-07 17:41:07 +00:00
}
2020-10-26 15:28:39 +00:00
have , err := a . WalletHas ( ctx , k )
if err != nil {
log . Errorw ( "failed to check control address" , "addr" , addr , "error" , err )
return false
2020-10-07 17:41:07 +00:00
}
2020-10-26 15:28:39 +00:00
if ! have {
2020-12-02 18:58:00 +00:00
log . Errorw ( "don't have key" , "key" , k , "address" , addr )
2020-10-26 15:28:39 +00:00
return false
2020-10-07 17:41:07 +00:00
}
2020-08-19 20:08:04 +00:00
2020-10-26 15:28:39 +00:00
* leastBad = addr
* bestAvail = b
return true
2020-10-07 17:41:07 +00:00
}
2020-10-26 15:28:39 +00:00
if b . GreaterThan ( * bestAvail ) {
* leastBad = addr
* bestAvail = b
2020-10-07 17:41:07 +00:00
}
2020-10-26 15:28:39 +00:00
log . Warnw ( "address didn't have enough funds for window post message" , "address" , addr , "required" , types . FIL ( goodFunds ) , "balance" , types . FIL ( b ) )
return false
2020-08-19 23:26:13 +00:00
}