Allow gas estimation for DynamicFeeTx in transactor (#5521)
* fix_: allow gas estimation for DynamicFeeTx * test_: added tests for BuildAndValidateTransaction * fix_: using IsDynamicTx for gasPrice suggestion * fix_: hash transaction check Co-authored-by: Stefan Dunca <47554641+stefandunca@users.noreply.github.com> --------- Co-authored-by: Stefan Dunca <47554641+stefandunca@users.noreply.github.com>
This commit is contained in:
parent
9403475572
commit
7e4322b45a
|
@ -281,7 +281,7 @@ func (t *Transactor) HashTransaction(args SendTxArgs) (validatedArgs SendTxArgs,
|
|||
gasPrice := (*big.Int)(args.GasPrice)
|
||||
gasFeeCap := (*big.Int)(args.MaxFeePerGas)
|
||||
gasTipCap := (*big.Int)(args.MaxPriorityFeePerGas)
|
||||
if args.GasPrice == nil && args.MaxFeePerGas == nil {
|
||||
if args.GasPrice == nil && !args.IsDynamicFeeTx() {
|
||||
ctx, cancel := context.WithTimeout(context.Background(), t.rpcCallTimeout)
|
||||
defer cancel()
|
||||
gasPrice, err = t.rpcWrapper.SuggestGasPrice(ctx)
|
||||
|
@ -306,7 +306,7 @@ func (t *Transactor) HashTransaction(args SendTxArgs) (validatedArgs SendTxArgs,
|
|||
gethTo = common.Address(*args.To)
|
||||
gethToPtr = &gethTo
|
||||
}
|
||||
if args.GasPrice == nil {
|
||||
if args.IsDynamicFeeTx() {
|
||||
gas, err = t.rpcWrapper.EstimateGas(ctx, ethereum.CallMsg{
|
||||
From: common.Address(args.From),
|
||||
To: gethToPtr,
|
||||
|
@ -334,7 +334,7 @@ func (t *Transactor) HashTransaction(args SendTxArgs) (validatedArgs SendTxArgs,
|
|||
newNonce := hexutil.Uint64(nonce)
|
||||
newGas := hexutil.Uint64(gas)
|
||||
validatedArgs.Nonce = &newNonce
|
||||
if args.GasPrice != nil {
|
||||
if !args.IsDynamicFeeTx() {
|
||||
validatedArgs.GasPrice = (*hexutil.Big)(gasPrice)
|
||||
} else {
|
||||
validatedArgs.MaxPriorityFeePerGas = (*hexutil.Big)(gasTipCap)
|
||||
|
@ -380,6 +380,7 @@ func (t *Transactor) validateAndBuildTransaction(rpcWrapper *rpcWrapper, args Se
|
|||
defer cancel()
|
||||
|
||||
gasPrice := (*big.Int)(args.GasPrice)
|
||||
// GasPrice should be estimated only for LegacyTx
|
||||
if !args.IsDynamicFeeTx() && args.GasPrice == nil {
|
||||
gasPrice, err = rpcWrapper.SuggestGasPrice(ctx)
|
||||
if err != nil {
|
||||
|
@ -391,7 +392,7 @@ func (t *Transactor) validateAndBuildTransaction(rpcWrapper *rpcWrapper, args Se
|
|||
var gas uint64
|
||||
if args.Gas != nil {
|
||||
gas = uint64(*args.Gas)
|
||||
} else if args.Gas == nil && !args.IsDynamicFeeTx() {
|
||||
} else {
|
||||
ctx, cancel = context.WithTimeout(context.Background(), t.rpcCallTimeout)
|
||||
defer cancel()
|
||||
|
||||
|
@ -403,13 +404,26 @@ func (t *Transactor) validateAndBuildTransaction(rpcWrapper *rpcWrapper, args Se
|
|||
gethTo = common.Address(*args.To)
|
||||
gethToPtr = &gethTo
|
||||
}
|
||||
gas, err = rpcWrapper.EstimateGas(ctx, ethereum.CallMsg{
|
||||
if args.IsDynamicFeeTx() {
|
||||
gasFeeCap := (*big.Int)(args.MaxFeePerGas)
|
||||
gasTipCap := (*big.Int)(args.MaxPriorityFeePerGas)
|
||||
gas, err = t.rpcWrapper.EstimateGas(ctx, ethereum.CallMsg{
|
||||
From: common.Address(args.From),
|
||||
To: gethToPtr,
|
||||
GasFeeCap: gasFeeCap,
|
||||
GasTipCap: gasTipCap,
|
||||
Value: value,
|
||||
Data: args.GetInput(),
|
||||
})
|
||||
} else {
|
||||
gas, err = t.rpcWrapper.EstimateGas(ctx, ethereum.CallMsg{
|
||||
From: common.Address(args.From),
|
||||
To: gethToPtr,
|
||||
GasPrice: gasPrice,
|
||||
Value: value,
|
||||
Data: args.GetInput(),
|
||||
})
|
||||
}
|
||||
if err != nil {
|
||||
return tx, err
|
||||
}
|
||||
|
|
|
@ -92,13 +92,14 @@ func (s *TransactorSuite) setupTransactionPoolAPI(args SendTxArgs, returnNonce,
|
|||
} else {
|
||||
usedGasPrice = (*big.Int)(args.GasPrice)
|
||||
}
|
||||
}
|
||||
|
||||
if args.Gas == nil {
|
||||
s.txServiceMock.EXPECT().EstimateGas(gomock.Any(), gomock.Any()).Return(testGas, nil)
|
||||
usedGas = testGas
|
||||
} else {
|
||||
usedGas = *args.Gas
|
||||
}
|
||||
}
|
||||
// Prepare the transaction and RLP encode it.
|
||||
data := s.rlpEncodeTx(args, s.nodeConfig, account, &resultNonce, usedGas, usedGasPrice)
|
||||
// Expect the RLP encoded transaction.
|
||||
|
@ -213,6 +214,114 @@ func (s *TransactorSuite) TestGasValues() {
|
|||
}
|
||||
}
|
||||
|
||||
func (s *TransactorSuite) setupBuildTransactionMocks(args SendTxArgs, account *account.SelectedExtKey) {
|
||||
s.txServiceMock.EXPECT().GetTransactionCount(gomock.Any(), gomock.Eq(common.Address(account.Address)), gethrpc.PendingBlockNumber).Return(&testNonce, nil)
|
||||
|
||||
if !args.IsDynamicFeeTx() && args.GasPrice == nil {
|
||||
s.txServiceMock.EXPECT().GasPrice(gomock.Any()).Return(testGasPrice, nil)
|
||||
}
|
||||
|
||||
if args.Gas == nil {
|
||||
s.txServiceMock.EXPECT().EstimateGas(gomock.Any(), gomock.Any()).Return(testGas, nil)
|
||||
}
|
||||
}
|
||||
|
||||
func (s *TransactorSuite) TestBuildAndValidateTransaction() {
|
||||
key, _ := gethcrypto.GenerateKey()
|
||||
selectedAccount := &account.SelectedExtKey{
|
||||
Address: account.FromAddress(utils.TestConfig.Account1.WalletAddress),
|
||||
AccountKey: &types.Key{PrivateKey: key},
|
||||
}
|
||||
|
||||
chainID := s.nodeConfig.NetworkID
|
||||
fromAddress := account.FromAddress(utils.TestConfig.Account1.WalletAddress)
|
||||
toAddress := account.ToAddress(utils.TestConfig.Account2.WalletAddress)
|
||||
value := (*hexutil.Big)(big.NewInt(10))
|
||||
|
||||
expectedGasPrice := (*big.Int)(testGasPrice)
|
||||
expectedGas := uint64(testGas)
|
||||
expectedNonce := uint64(testNonce)
|
||||
|
||||
s.T().Run("DynamicFeeTransaction", func(t *testing.T) {
|
||||
s.SetupTest()
|
||||
|
||||
gas := hexutil.Uint64(21000)
|
||||
args := SendTxArgs{
|
||||
From: fromAddress,
|
||||
To: toAddress,
|
||||
Gas: &gas,
|
||||
Value: value,
|
||||
MaxFeePerGas: testGasPrice,
|
||||
MaxPriorityFeePerGas: testGasPrice,
|
||||
}
|
||||
s.setupBuildTransactionMocks(args, selectedAccount)
|
||||
|
||||
tx, err := s.manager.ValidateAndBuildTransaction(chainID, args)
|
||||
s.NoError(err)
|
||||
s.Equal(tx.Gas(), uint64(gas), "The gas shouldn't be estimated, but should use the gas from the Tx")
|
||||
s.Equal(tx.GasFeeCap(), expectedGasPrice, "The maxFeePerGas should be the same as in the original Tx")
|
||||
s.Equal(tx.GasTipCap(), expectedGasPrice, "The maxPriorityFeePerGas should be the same as in the original Tx")
|
||||
s.Equal(tx.Type(), uint8(gethtypes.DynamicFeeTxType), "The transaction type should be DynamicFeeTxType")
|
||||
})
|
||||
|
||||
s.T().Run("DynamicFeeTransaction with gas estimation", func(t *testing.T) {
|
||||
s.SetupTest()
|
||||
args := SendTxArgs{
|
||||
From: fromAddress,
|
||||
To: toAddress,
|
||||
Value: value,
|
||||
MaxFeePerGas: testGasPrice,
|
||||
MaxPriorityFeePerGas: testGasPrice,
|
||||
}
|
||||
s.setupBuildTransactionMocks(args, selectedAccount)
|
||||
|
||||
tx, err := s.manager.ValidateAndBuildTransaction(chainID, args)
|
||||
s.NoError(err)
|
||||
s.Equal(tx.Gas(), expectedGas, "The gas should be estimated if not present in the original Tx")
|
||||
s.Equal(tx.Nonce(), expectedNonce, "The nonce should be added if not present in the original Tx")
|
||||
s.Equal(tx.GasFeeCap(), expectedGasPrice, "The maxFeePerGas should be the same as in the original Tx")
|
||||
s.Equal(tx.GasTipCap(), expectedGasPrice, "The maxPriorityFeePerGas should be the same as in the original Tx")
|
||||
s.Equal(tx.Type(), uint8(gethtypes.DynamicFeeTxType), "The transaction type should be DynamicFeeTxType")
|
||||
})
|
||||
|
||||
s.T().Run("LegacyTransaction", func(t *testing.T) {
|
||||
s.SetupTest()
|
||||
|
||||
gas := hexutil.Uint64(21000)
|
||||
gasPrice := (*hexutil.Big)(big.NewInt(10))
|
||||
args := SendTxArgs{
|
||||
From: fromAddress,
|
||||
To: toAddress,
|
||||
Value: value,
|
||||
Gas: &gas,
|
||||
GasPrice: gasPrice,
|
||||
}
|
||||
s.setupBuildTransactionMocks(args, selectedAccount)
|
||||
|
||||
tx, err := s.manager.ValidateAndBuildTransaction(chainID, args)
|
||||
s.NoError(err)
|
||||
s.Equal(tx.Gas(), uint64(gas), "The gas shouldn't be estimated, but should use the gas from the Tx")
|
||||
s.Equal(tx.GasPrice(), expectedGasPrice, "The gasPrice should be the same as in the original Tx")
|
||||
s.Equal(tx.Type(), uint8(gethtypes.LegacyTxType), "The transaction type should be LegacyTxType")
|
||||
})
|
||||
s.T().Run("LegacyTransaction without gas estimation", func(t *testing.T) {
|
||||
s.SetupTest()
|
||||
|
||||
args := SendTxArgs{
|
||||
From: fromAddress,
|
||||
To: toAddress,
|
||||
Value: value,
|
||||
}
|
||||
s.setupBuildTransactionMocks(args, selectedAccount)
|
||||
|
||||
tx, err := s.manager.ValidateAndBuildTransaction(chainID, args)
|
||||
s.NoError(err)
|
||||
s.Equal(tx.Gas(), expectedGas, "The gas should be estimated if not present in the original Tx")
|
||||
s.Equal(tx.GasPrice(), expectedGasPrice, "The gasPrice should be estimated if not present in the original Tx")
|
||||
s.Equal(tx.Type(), uint8(gethtypes.LegacyTxType), "The transaction type should be LegacyTxType")
|
||||
})
|
||||
}
|
||||
|
||||
func (s *TransactorSuite) TestArgsValidation() {
|
||||
args := SendTxArgs{
|
||||
From: account.FromAddress(utils.TestConfig.Account1.WalletAddress),
|
||||
|
|
Loading…
Reference in New Issue