Merge pull request #4217 from filecoin-project/fix/post-smaller-feecap
Set lower feecap on PoSt messages with low balance
This commit is contained in:
commit
96f004032b
@ -414,7 +414,7 @@ var actorControlList = &cli.Command{
|
|||||||
tablewriter.Col("balance"),
|
tablewriter.Col("balance"),
|
||||||
)
|
)
|
||||||
|
|
||||||
postAddr, err := storage.AddressFor(ctx, api, mi, storage.PoStAddr, types.FromFil(1))
|
postAddr, _, err := storage.AddressFor(ctx, api, mi, storage.PoStAddr, types.FromFil(1), types.FromFil(1))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return xerrors.Errorf("getting address for post: %w", err)
|
return xerrors.Errorf("getting address for post: %w", err)
|
||||||
}
|
}
|
||||||
|
@ -3,13 +3,11 @@ package storage
|
|||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
|
||||||
"github.com/filecoin-project/lotus/chain/actors/builtin/miner"
|
|
||||||
|
|
||||||
"golang.org/x/xerrors"
|
|
||||||
|
|
||||||
"github.com/filecoin-project/go-address"
|
"github.com/filecoin-project/go-address"
|
||||||
"github.com/filecoin-project/go-state-types/abi"
|
"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"
|
"github.com/filecoin-project/lotus/chain/types"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -28,67 +26,62 @@ type addrSelectApi interface {
|
|||||||
StateAccountKey(context.Context, address.Address, types.TipSetKey) (address.Address, error)
|
StateAccountKey(context.Context, address.Address, types.TipSetKey) (address.Address, error)
|
||||||
}
|
}
|
||||||
|
|
||||||
func AddressFor(ctx context.Context, a addrSelectApi, mi miner.MinerInfo, use AddrUse, minFunds abi.TokenAmount) (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 {
|
switch use {
|
||||||
case PreCommitAddr, CommitAddr:
|
case PreCommitAddr, CommitAddr:
|
||||||
// always use worker, at least for now
|
// always use worker, at least for now
|
||||||
return mi.Worker, nil
|
return mi.Worker, big.Zero(), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, addr := range mi.ControlAddresses {
|
leastBad := mi.Worker
|
||||||
b, err := a.WalletBalance(ctx, addr)
|
bestAvail := minFunds
|
||||||
if err != nil {
|
|
||||||
return address.Undef, xerrors.Errorf("checking control address balance: %w", err)
|
for _, addr := range append(mi.ControlAddresses, mi.Owner, mi.Worker) {
|
||||||
|
if maybeUseAddress(ctx, a, addr, goodFunds, &leastBad, &bestAvail) {
|
||||||
|
return leastBad, bestAvail, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
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 window 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
|
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))
|
||||||
|
|
||||||
b, err := a.WalletBalance(ctx, mi.Owner)
|
return leastBad, bestAvail, nil
|
||||||
if err != nil {
|
}
|
||||||
return address.Undef, xerrors.Errorf("checking owner balance: %w", err)
|
|
||||||
}
|
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)
|
||||||
if !b.GreaterThanEqual(minFunds) {
|
if err != nil {
|
||||||
return mi.Worker, nil
|
log.Errorw("checking control address balance", "addr", addr, "error", err)
|
||||||
}
|
return false
|
||||||
|
}
|
||||||
k, err := a.StateAccountKey(ctx, mi.Owner, types.EmptyTSK)
|
|
||||||
if err != nil {
|
if b.GreaterThanEqual(goodFunds) {
|
||||||
log.Errorw("getting owner account key", "error", err)
|
k, err := a.StateAccountKey(ctx, addr, types.EmptyTSK)
|
||||||
return mi.Worker, nil
|
if err != nil {
|
||||||
}
|
log.Errorw("getting account key", "error", err)
|
||||||
|
return false
|
||||||
have, err := a.WalletHas(ctx, k)
|
}
|
||||||
if err != nil {
|
|
||||||
return address.Undef, xerrors.Errorf("failed to check owner address: %w", err)
|
have, err := a.WalletHas(ctx, k)
|
||||||
}
|
if err != nil {
|
||||||
|
log.Errorw("failed to check control address", "addr", addr, "error", err)
|
||||||
if !have {
|
return false
|
||||||
return mi.Worker, nil
|
}
|
||||||
}
|
|
||||||
|
if !have {
|
||||||
return mi.Owner, nil
|
log.Errorw("don't have key", "key", k)
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
*leastBad = addr
|
||||||
|
*bestAvail = b
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
if b.GreaterThan(*bestAvail) {
|
||||||
|
*leastBad = addr
|
||||||
|
*bestAvail = b
|
||||||
|
}
|
||||||
|
|
||||||
|
log.Warnw("address didn't have enough funds for window post message", "address", addr, "required", types.FIL(goodFunds), "balance", types.FIL(b))
|
||||||
|
return false
|
||||||
}
|
}
|
||||||
|
@ -95,6 +95,8 @@ type storageMinerApi interface {
|
|||||||
MpoolPushMessage(context.Context, *types.Message, *api.MessageSendSpec) (*types.SignedMessage, error)
|
MpoolPushMessage(context.Context, *types.Message, *api.MessageSendSpec) (*types.SignedMessage, error)
|
||||||
|
|
||||||
GasEstimateMessageGas(context.Context, *types.Message, *api.MessageSendSpec, types.TipSetKey) (*types.Message, error)
|
GasEstimateMessageGas(context.Context, *types.Message, *api.MessageSendSpec, types.TipSetKey) (*types.Message, error)
|
||||||
|
GasEstimateFeeCap(context.Context, *types.Message, int64, types.TipSetKey) (types.BigInt, error)
|
||||||
|
GasEstimateGasPremium(_ context.Context, nblocksincl uint64, sender address.Address, gaslimit int64, tsk types.TipSetKey) (types.BigInt, error)
|
||||||
|
|
||||||
ChainHead(context.Context) (*types.TipSet, error)
|
ChainHead(context.Context) (*types.TipSet, error)
|
||||||
ChainNotify(context.Context) (<-chan []*api.HeadChange, error)
|
ChainNotify(context.Context) (<-chan []*api.HeadChange, error)
|
||||||
|
@ -26,6 +26,7 @@ import (
|
|||||||
"github.com/filecoin-project/lotus/chain/actors"
|
"github.com/filecoin-project/lotus/chain/actors"
|
||||||
"github.com/filecoin-project/lotus/chain/actors/builtin/miner"
|
"github.com/filecoin-project/lotus/chain/actors/builtin/miner"
|
||||||
"github.com/filecoin-project/lotus/chain/actors/policy"
|
"github.com/filecoin-project/lotus/chain/actors/policy"
|
||||||
|
"github.com/filecoin-project/lotus/chain/messagepool"
|
||||||
"github.com/filecoin-project/lotus/chain/types"
|
"github.com/filecoin-project/lotus/chain/types"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -781,14 +782,38 @@ func (s *WindowPoStScheduler) setSender(ctx context.Context, msg *types.Message,
|
|||||||
}
|
}
|
||||||
*msg = *gm
|
*msg = *gm
|
||||||
|
|
||||||
minFunds := big.Add(msg.RequiredFunds(), msg.Value)
|
// estimate
|
||||||
|
minGasFeeMsg := *msg
|
||||||
|
|
||||||
pa, err := AddressFor(ctx, s.api, mi, PoStAddr, minFunds)
|
minGasFeeMsg.GasPremium, err = s.api.GasEstimateGasPremium(ctx, 5, msg.From, msg.GasLimit, types.TipSetKey{})
|
||||||
|
if err != nil {
|
||||||
|
log.Errorf("failed to estimate minimum gas premium: %+v", err)
|
||||||
|
minGasFeeMsg.GasPremium = msg.GasPremium
|
||||||
|
}
|
||||||
|
|
||||||
|
minGasFeeMsg.GasFeeCap, err = s.api.GasEstimateFeeCap(ctx, &minGasFeeMsg, 4, types.EmptyTSK)
|
||||||
|
if err != nil {
|
||||||
|
log.Errorf("failed to estimate minimum gas fee cap: %+v", err)
|
||||||
|
minGasFeeMsg.GasFeeCap = msg.GasFeeCap
|
||||||
|
}
|
||||||
|
|
||||||
|
goodFunds := big.Add(msg.RequiredFunds(), msg.Value)
|
||||||
|
minFunds := big.Min(big.Add(minGasFeeMsg.RequiredFunds(), minGasFeeMsg.Value), goodFunds)
|
||||||
|
|
||||||
|
pa, avail, err := AddressFor(ctx, s.api, mi, PoStAddr, goodFunds, minFunds)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Errorw("error selecting address for window post", "error", err)
|
log.Errorw("error selecting address for window post", "error", err)
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
msg.From = pa
|
msg.From = pa
|
||||||
|
bestReq := big.Add(msg.RequiredFunds(), msg.Value)
|
||||||
|
if avail.LessThan(bestReq) {
|
||||||
|
mff := func() (abi.TokenAmount, error) {
|
||||||
|
return msg.RequiredFunds(), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
messagepool.CapGasFee(mff, msg, big.Min(big.Sub(avail, msg.Value), msg.RequiredFunds()))
|
||||||
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
@ -49,6 +49,10 @@ func (m *mockStorageMinerAPI) StateMinerInfo(ctx context.Context, a address.Addr
|
|||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (m *mockStorageMinerAPI) StateNetworkVersion(ctx context.Context, key types.TipSetKey) (network.Version, error) {
|
||||||
|
return build.NewestNetworkVersion, nil
|
||||||
|
}
|
||||||
|
|
||||||
func (m *mockStorageMinerAPI) ChainGetRandomnessFromTickets(ctx context.Context, tsk types.TipSetKey, personalization crypto.DomainSeparationTag, randEpoch abi.ChainEpoch, entropy []byte) (abi.Randomness, error) {
|
func (m *mockStorageMinerAPI) ChainGetRandomnessFromTickets(ctx context.Context, tsk types.TipSetKey, personalization crypto.DomainSeparationTag, randEpoch abi.ChainEpoch, entropy []byte) (abi.Randomness, error) {
|
||||||
return abi.Randomness("ticket rand"), nil
|
return abi.Randomness("ticket rand"), nil
|
||||||
}
|
}
|
||||||
@ -94,8 +98,12 @@ func (m *mockStorageMinerAPI) StateWaitMsg(ctx context.Context, cid cid.Cid, con
|
|||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *mockStorageMinerAPI) StateNetworkVersion(context.Context, types.TipSetKey) (network.Version, error) {
|
func (m *mockStorageMinerAPI) GasEstimateGasPremium(_ context.Context, nblocksincl uint64, sender address.Address, gaslimit int64, tsk types.TipSetKey) (types.BigInt, error) {
|
||||||
return build.NewestNetworkVersion, nil
|
return big.Zero(), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *mockStorageMinerAPI) GasEstimateFeeCap(context.Context, *types.Message, int64, types.TipSetKey) (types.BigInt, error) {
|
||||||
|
return big.Zero(), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
type mockProver struct {
|
type mockProver struct {
|
||||||
|
Loading…
Reference in New Issue
Block a user