Merge pull request #8991 from filecoin-project/fix/estimate-with-zero-base-fee
fix: gas: estimate gas with a zero base-fee
This commit is contained in:
commit
57e5aa667f
@ -858,6 +858,11 @@ workflows:
|
|||||||
suite: itest-deals
|
suite: itest-deals
|
||||||
target: "./itests/deals_test.go"
|
target: "./itests/deals_test.go"
|
||||||
|
|
||||||
|
- test:
|
||||||
|
name: test-itest-gas_estimation
|
||||||
|
suite: itest-gas_estimation
|
||||||
|
target: "./itests/gas_estimation_test.go"
|
||||||
|
|
||||||
- test:
|
- test:
|
||||||
name: test-itest-gateway
|
name: test-itest-gateway
|
||||||
suite: itest-gateway
|
suite: itest-gateway
|
||||||
|
@ -12,6 +12,7 @@ import (
|
|||||||
|
|
||||||
"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/go-state-types/crypto"
|
"github.com/filecoin-project/go-state-types/crypto"
|
||||||
|
|
||||||
"github.com/filecoin-project/lotus/api"
|
"github.com/filecoin-project/lotus/api"
|
||||||
@ -156,6 +157,10 @@ func (sm *StateManager) CallWithGas(ctx context.Context, msg *types.Message, pri
|
|||||||
ctx, span := trace.StartSpan(ctx, "statemanager.CallWithGas")
|
ctx, span := trace.StartSpan(ctx, "statemanager.CallWithGas")
|
||||||
defer span.End()
|
defer span.End()
|
||||||
|
|
||||||
|
// Copy the message as we'll be modifying the nonce.
|
||||||
|
msgCopy := *msg
|
||||||
|
msg = &msgCopy
|
||||||
|
|
||||||
if ts == nil {
|
if ts == nil {
|
||||||
ts = sm.cs.GetHeaviestTipSet()
|
ts = sm.cs.GetHeaviestTipSet()
|
||||||
|
|
||||||
@ -273,9 +278,21 @@ func (sm *StateManager) CallWithGas(ctx context.Context, msg *types.Message, pri
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// If the fee cap is set to zero, make gas free.
|
||||||
|
if msg.GasFeeCap.NilOrZero() {
|
||||||
|
// Now estimate with a new VM with no base fee.
|
||||||
|
vmopt.BaseFee = big.Zero()
|
||||||
|
vmopt.StateBase = stateCid
|
||||||
|
|
||||||
|
vmi, err = sm.newVM(ctx, vmopt)
|
||||||
|
if err != nil {
|
||||||
|
return nil, xerrors.Errorf("failed to set up estimation vm: %w", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
ret, err := vmi.ApplyMessage(ctx, msgApply)
|
ret, err := vmi.ApplyMessage(ctx, msgApply)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, xerrors.Errorf("apply message failed: %w", err)
|
return nil, xerrors.Errorf("gas estimation failed: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
var errs string
|
var errs string
|
||||||
|
@ -28,6 +28,15 @@ var (
|
|||||||
)
|
)
|
||||||
|
|
||||||
func TestDealsRetryLackOfFunds(t *testing.T) {
|
func TestDealsRetryLackOfFunds(t *testing.T) {
|
||||||
|
t.Run("cover-gas", func(t *testing.T) {
|
||||||
|
testDealsRetryLackOfFunds(t, types.NewInt(1020000000000))
|
||||||
|
})
|
||||||
|
t.Run("empty", func(t *testing.T) {
|
||||||
|
testDealsRetryLackOfFunds(t, types.NewInt(1))
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func testDealsRetryLackOfFunds(t *testing.T, publishStorageAccountFunds abi.TokenAmount) {
|
||||||
//stm: @CHAIN_SYNCER_LOAD_GENESIS_001, @CHAIN_SYNCER_FETCH_TIPSET_001,
|
//stm: @CHAIN_SYNCER_LOAD_GENESIS_001, @CHAIN_SYNCER_FETCH_TIPSET_001,
|
||||||
//stm: @CHAIN_SYNCER_START_001, @CHAIN_SYNCER_SYNC_001, @BLOCKCHAIN_BEACON_VALIDATE_BLOCK_VALUES_01
|
//stm: @CHAIN_SYNCER_START_001, @CHAIN_SYNCER_SYNC_001, @BLOCKCHAIN_BEACON_VALIDATE_BLOCK_VALUES_01
|
||||||
//stm: @CHAIN_SYNCER_COLLECT_CHAIN_001, @CHAIN_SYNCER_COLLECT_HEADERS_001, @CHAIN_SYNCER_VALIDATE_TIPSET_001
|
//stm: @CHAIN_SYNCER_COLLECT_CHAIN_001, @CHAIN_SYNCER_COLLECT_HEADERS_001, @CHAIN_SYNCER_VALIDATE_TIPSET_001
|
||||||
@ -61,7 +70,6 @@ func TestDealsRetryLackOfFunds(t *testing.T) {
|
|||||||
})),
|
})),
|
||||||
)
|
)
|
||||||
|
|
||||||
publishStorageAccountFunds := types.NewInt(1020000000000)
|
|
||||||
minerFullNode, clientFullNode, miner, ens := kit.EnsembleTwoOne(t, kit.Account(publishStorageDealKey, publishStorageAccountFunds), kit.ConstructorOpts(opts), kit.MockProofs(), eightMBSectorsOpt)
|
minerFullNode, clientFullNode, miner, ens := kit.EnsembleTwoOne(t, kit.Account(publishStorageDealKey, publishStorageAccountFunds), kit.ConstructorOpts(opts), kit.MockProofs(), eightMBSectorsOpt)
|
||||||
|
|
||||||
kit.QuietMiningLogs()
|
kit.QuietMiningLogs()
|
||||||
@ -178,69 +186,3 @@ func TestDealsRetryLackOfFunds_blockInPublishDeal(t *testing.T) {
|
|||||||
case <-time.After(time.Second * 15):
|
case <-time.After(time.Second * 15):
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestDealsRetryLackOfFunds_belowLimit(t *testing.T) {
|
|
||||||
//stm: @CHAIN_SYNCER_LOAD_GENESIS_001, @CHAIN_SYNCER_FETCH_TIPSET_001,
|
|
||||||
//stm: @CHAIN_SYNCER_START_001, @CHAIN_SYNCER_SYNC_001, @BLOCKCHAIN_BEACON_VALIDATE_BLOCK_VALUES_01
|
|
||||||
//stm: @CHAIN_SYNCER_COLLECT_CHAIN_001, @CHAIN_SYNCER_COLLECT_HEADERS_001, @CHAIN_SYNCER_VALIDATE_TIPSET_001
|
|
||||||
//stm: @CHAIN_SYNCER_NEW_PEER_HEAD_001, @CHAIN_SYNCER_VALIDATE_MESSAGE_META_001, @CHAIN_SYNCER_STOP_001
|
|
||||||
//stm: @CLIENT_STORAGE_DEALS_LIST_IMPORTS_001
|
|
||||||
ctx := context.Background()
|
|
||||||
kit.QuietMiningLogs()
|
|
||||||
|
|
||||||
// Allow 8MB sectors
|
|
||||||
eightMBSectorsOpt := kit.SectorSize(8 << 20)
|
|
||||||
|
|
||||||
publishStorageDealKey, err := key.GenerateKey(types.KTSecp256k1)
|
|
||||||
require.NoError(t, err)
|
|
||||||
|
|
||||||
opts := node.Options(
|
|
||||||
node.Override(new(*storageadapter.DealPublisher),
|
|
||||||
storageadapter.NewDealPublisher(nil, storageadapter.PublishMsgConfig{
|
|
||||||
Period: publishPeriod,
|
|
||||||
MaxDealsPerMsg: maxDealsPerMsg,
|
|
||||||
}),
|
|
||||||
),
|
|
||||||
node.Override(new(*ctladdr.AddressSelector), modules.AddressSelector(&config.MinerAddressConfig{
|
|
||||||
DealPublishControl: []string{
|
|
||||||
publishStorageDealKey.Address.String(),
|
|
||||||
},
|
|
||||||
DisableOwnerFallback: true,
|
|
||||||
DisableWorkerFallback: true,
|
|
||||||
})),
|
|
||||||
)
|
|
||||||
|
|
||||||
publishStorageAccountFunds := types.NewInt(1)
|
|
||||||
minerFullNode, clientFullNode, miner, ens := kit.EnsembleTwoOne(t, kit.Account(publishStorageDealKey, publishStorageAccountFunds), kit.ConstructorOpts(opts), kit.MockProofs(), eightMBSectorsOpt)
|
|
||||||
|
|
||||||
kit.QuietMiningLogs()
|
|
||||||
|
|
||||||
ens.
|
|
||||||
Start().
|
|
||||||
InterconnectAll().
|
|
||||||
BeginMining(blockTime)
|
|
||||||
|
|
||||||
_, err = minerFullNode.WalletImport(ctx, &publishStorageDealKey.KeyInfo)
|
|
||||||
require.NoError(t, err)
|
|
||||||
|
|
||||||
miner.SetControlAddresses(publishStorageDealKey.Address)
|
|
||||||
|
|
||||||
dh := kit.NewDealHarness(t, clientFullNode, miner, miner)
|
|
||||||
|
|
||||||
res, _ := clientFullNode.CreateImportFile(ctx, 0, 4<<20) // 4MiB file.
|
|
||||||
list, err := clientFullNode.ClientListImports(ctx)
|
|
||||||
require.NoError(t, err)
|
|
||||||
require.Len(t, list, 1)
|
|
||||||
require.Equal(t, res.Root, *list[0].Root)
|
|
||||||
|
|
||||||
dp := dh.DefaultStartDealParams()
|
|
||||||
dp.Data.Root = res.Root
|
|
||||||
dp.FastRetrieval = true
|
|
||||||
dp.EpochPrice = abi.NewTokenAmount(62500000) // minimum asking price.
|
|
||||||
deal := dh.StartDeal(ctx, dp)
|
|
||||||
|
|
||||||
err = dh.ExpectDealFailure(ctx, deal, "Actor balance less than needed")
|
|
||||||
if err != nil {
|
|
||||||
t.Fatal(err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
54
itests/gas_estimation_test.go
Normal file
54
itests/gas_estimation_test.go
Normal file
@ -0,0 +1,54 @@
|
|||||||
|
package itests
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"testing"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/stretchr/testify/require"
|
||||||
|
|
||||||
|
"github.com/filecoin-project/go-state-types/big"
|
||||||
|
|
||||||
|
"github.com/filecoin-project/lotus/api"
|
||||||
|
"github.com/filecoin-project/lotus/chain/actors/builtin/account"
|
||||||
|
"github.com/filecoin-project/lotus/chain/types"
|
||||||
|
"github.com/filecoin-project/lotus/itests/kit"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestEstimateGasNoFunds(t *testing.T) {
|
||||||
|
ctx := context.Background()
|
||||||
|
|
||||||
|
kit.QuietMiningLogs()
|
||||||
|
|
||||||
|
client, _, ens := kit.EnsembleMinimal(t, kit.MockProofs())
|
||||||
|
ens.InterconnectAll().BeginMining(10 * time.Millisecond)
|
||||||
|
|
||||||
|
// create a new address
|
||||||
|
addr, err := client.WalletNew(ctx, types.KTBLS)
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
// Create that address.
|
||||||
|
msg := &types.Message{
|
||||||
|
From: client.DefaultKey.Address,
|
||||||
|
To: addr,
|
||||||
|
Value: big.Zero(),
|
||||||
|
}
|
||||||
|
|
||||||
|
sm, err := client.MpoolPushMessage(ctx, msg, nil)
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
_, err = client.StateWaitMsg(ctx, sm.Cid(), 3, api.LookbackNoLimit, true)
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
// Make sure we can estimate gas even if we have no funds.
|
||||||
|
msg2 := &types.Message{
|
||||||
|
From: addr,
|
||||||
|
To: client.DefaultKey.Address,
|
||||||
|
Method: account.Methods.PubkeyAddress,
|
||||||
|
Value: big.Zero(),
|
||||||
|
}
|
||||||
|
|
||||||
|
limit, err := client.GasEstimateGasLimit(ctx, msg2, types.EmptyTSK)
|
||||||
|
require.NoError(t, err)
|
||||||
|
require.NotZero(t, limit)
|
||||||
|
}
|
@ -258,8 +258,8 @@ func gasEstimateGasLimit(
|
|||||||
) (int64, error) {
|
) (int64, error) {
|
||||||
msg := *msgIn
|
msg := *msgIn
|
||||||
msg.GasLimit = build.BlockGasLimit
|
msg.GasLimit = build.BlockGasLimit
|
||||||
msg.GasFeeCap = types.NewInt(uint64(build.MinimumBaseFee) + 1)
|
msg.GasFeeCap = big.Zero()
|
||||||
msg.GasPremium = types.NewInt(1)
|
msg.GasPremium = big.Zero()
|
||||||
|
|
||||||
fromA, err := smgr.ResolveToKeyAddress(ctx, msgIn.From, currTs)
|
fromA, err := smgr.ResolveToKeyAddress(ctx, msgIn.From, currTs)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -9,6 +9,7 @@ import (
|
|||||||
"golang.org/x/xerrors"
|
"golang.org/x/xerrors"
|
||||||
|
|
||||||
"github.com/filecoin-project/go-address"
|
"github.com/filecoin-project/go-address"
|
||||||
|
"github.com/filecoin-project/go-state-types/big"
|
||||||
|
|
||||||
"github.com/filecoin-project/lotus/api"
|
"github.com/filecoin-project/lotus/api"
|
||||||
"github.com/filecoin-project/lotus/chain/messagepool"
|
"github.com/filecoin-project/lotus/chain/messagepool"
|
||||||
@ -178,8 +179,9 @@ func (a *MpoolAPI) MpoolPushMessage(ctx context.Context, msg *types.Message, spe
|
|||||||
return nil, xerrors.Errorf("mpool push: getting origin balance: %w", err)
|
return nil, xerrors.Errorf("mpool push: getting origin balance: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
if b.LessThan(msg.Value) {
|
requiredFunds := big.Add(msg.Value, msg.RequiredFunds())
|
||||||
return nil, xerrors.Errorf("mpool push: not enough funds: %s < %s", b, msg.Value)
|
if b.LessThan(requiredFunds) {
|
||||||
|
return nil, xerrors.Errorf("mpool push: not enough funds: %s < %s", b, requiredFunds)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Sign and push the message
|
// Sign and push the message
|
||||||
|
Loading…
Reference in New Issue
Block a user