2022-06-14 17:32:29 +00:00
package ctladdr
2020-08-19 20:08:04 +00:00
import (
"context"
2020-08-20 04:49:10 +00:00
2022-06-14 17:32:29 +00:00
logging "github.com/ipfs/go-log/v2"
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"
2021-07-07 17:12:03 +00:00
"github.com/filecoin-project/go-state-types/big"
2020-12-02 19:46:07 +00:00
"github.com/filecoin-project/lotus/api"
2020-08-19 20:08:04 +00:00
"github.com/filecoin-project/lotus/chain/types"
)
2022-06-14 17:32:29 +00:00
var log = logging . Logger ( "ctladdr" )
2022-08-09 10:57:20 +00:00
type NodeApi interface {
2020-08-19 20:08:04 +00:00
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
}
2022-08-09 10:57:20 +00:00
func ( as * AddressSelector ) AddressFor ( ctx context . Context , a NodeApi , mi api . MinerInfo , use api . AddrUse , goodFunds , minFunds abi . TokenAmount ) ( address . Address , abi . TokenAmount , error ) {
2021-07-07 17:12:03 +00:00
if as == nil {
// should only happen in some tests
log . Warnw ( "smart address selection disabled, using worker address" )
return mi . Worker , big . Zero ( ) , nil
}
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 ... )
2021-01-14 11:37:23 +00:00
case api . TerminateSectorsAddr :
addrs = append ( addrs , as . TerminateControl ... )
2021-07-07 16:00:54 +00:00
case api . DealPublishAddr :
addrs = append ( addrs , as . DealPublishControl ... )
2020-12-02 18:58:00 +00:00
default :
defaultCtl := map [ address . Address ] struct { } { }
for _ , a := range mi . ControlAddresses {
defaultCtl [ a ] = struct { } { }
}
delete ( defaultCtl , mi . Owner )
delete ( defaultCtl , mi . Worker )
2021-03-08 21:09:04 +00:00
configCtl := append ( [ ] address . Address { } , as . PreCommitControl ... )
configCtl = append ( configCtl , as . CommitControl ... )
configCtl = append ( configCtl , as . TerminateControl ... )
2021-07-07 16:00:54 +00:00
configCtl = append ( configCtl , as . DealPublishControl ... )
2021-03-08 21:09:04 +00:00
for _ , addr := range configCtl {
2020-12-02 18:58:00 +00:00
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
}
2021-02-17 15:56:32 +00:00
if len ( addrs ) == 0 || ! as . DisableWorkerFallback {
addrs = append ( addrs , mi . Worker )
}
if ! as . DisableOwnerFallback {
addrs = append ( addrs , mi . Owner )
}
2020-12-02 18:58:00 +00:00
2024-02-13 01:03:45 +00:00
return PickAddress ( ctx , a , mi , goodFunds , minFunds , addrs )
2020-12-02 18:58:00 +00:00
}
2020-08-19 20:08:04 +00:00
2024-02-13 01:03:45 +00:00
func PickAddress ( ctx context . Context , a NodeApi , mi api . 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 {
2020-12-04 16:02:23 +00:00
var err error
addr , err = a . StateLookupID ( ctx , addr , types . EmptyTSK )
2020-12-02 19:46:07 +00:00
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
2021-03-08 21:09:04 +00:00
log . Warnw ( "No address had enough funds to for full 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
}
2022-08-09 10:57:20 +00:00
func maybeUseAddress ( ctx context . Context , a NodeApi , addr address . Address , goodFunds abi . TokenAmount , leastBad * address . Address , bestAvail * abi . TokenAmount ) bool {
2020-10-26 15:28:39 +00:00
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
}
2021-01-19 01:36:35 +00:00
log . Warnw ( "address didn't have enough funds to send message" , "address" , addr , "required" , types . FIL ( goodFunds ) , "balance" , types . FIL ( b ) )
2020-10-26 15:28:39 +00:00
return false
2020-08-19 23:26:13 +00:00
}