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:
Aayush Rajasekaran 2022-07-13 11:57:22 -04:00 committed by GitHub
commit 57e5aa667f
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 92 additions and 72 deletions

View File

@ -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

View File

@ -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

View File

@ -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)
}
}

View 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)
}

View File

@ -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 {

View File

@ -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