Send dynamic fee tx parameters
This commit is contained in:
parent
81b58b39ec
commit
03700c934c
|
@ -8,6 +8,7 @@ import (
|
|||
"github.com/ethereum/go-ethereum/common"
|
||||
"github.com/ethereum/go-ethereum/common/hexutil"
|
||||
gethtypes "github.com/ethereum/go-ethereum/core/types"
|
||||
"github.com/ethereum/go-ethereum/log"
|
||||
"github.com/ethereum/go-ethereum/rlp"
|
||||
|
||||
"github.com/status-im/status-go/eth-node/types"
|
||||
|
@ -60,10 +61,13 @@ func (w *rpcWrapper) EstimateGas(ctx context.Context, msg ethereum.CallMsg) (uin
|
|||
// If the transaction was a contract creation use the TransactionReceipt method to get the
|
||||
// contract address after the transaction has been mined.
|
||||
func (w *rpcWrapper) SendTransaction(ctx context.Context, tx *gethtypes.Transaction) error {
|
||||
log.Info("encoding transaction to bytes", "tx", tx)
|
||||
data, err := rlp.EncodeToBytes(tx)
|
||||
if err != nil {
|
||||
log.Error("failed to encode transaction to bytes", "tx", tx, "err", err)
|
||||
return err
|
||||
}
|
||||
log.Info("encoded transaction to bytes", "tx", tx)
|
||||
return w.rpcClient.CallContext(ctx, nil, "eth_sendRawTransaction", types.EncodeHex(data))
|
||||
}
|
||||
|
||||
|
|
|
@ -264,7 +264,7 @@ func (t *Transactor) validateAndPropagate(selectedAccount *account.SelectedExtKe
|
|||
nonce = uint64(*args.Nonce)
|
||||
}
|
||||
gasPrice := (*big.Int)(args.GasPrice)
|
||||
if args.GasPrice == nil {
|
||||
if !args.IsDynamicFeeTx() && args.GasPrice == nil {
|
||||
ctx, cancel = context.WithTimeout(context.Background(), t.rpcCallTimeout)
|
||||
defer cancel()
|
||||
gasPrice, err = t.gasCalculator.SuggestGasPrice(ctx)
|
||||
|
@ -277,7 +277,9 @@ func (t *Transactor) validateAndPropagate(selectedAccount *account.SelectedExtKe
|
|||
value := (*big.Int)(args.Value)
|
||||
|
||||
var gas uint64
|
||||
if args.Gas == nil {
|
||||
if args.Gas != nil {
|
||||
gas = uint64(*args.Gas)
|
||||
} else if args.Gas == nil && !args.IsDynamicFeeTx() {
|
||||
ctx, cancel = context.WithTimeout(context.Background(), t.rpcCallTimeout)
|
||||
defer cancel()
|
||||
|
||||
|
@ -303,20 +305,20 @@ func (t *Transactor) validateAndPropagate(selectedAccount *account.SelectedExtKe
|
|||
t.log.Info("default gas will be used because estimated is lower", "estimated", gas, "default", defaultGas)
|
||||
gas = defaultGas
|
||||
}
|
||||
} else {
|
||||
gas = uint64(*args.Gas)
|
||||
}
|
||||
|
||||
tx := t.buildTransactionWithOverrides(nonce, value, gas, gasPrice, args)
|
||||
|
||||
signedTx, err := gethtypes.SignTx(tx, gethtypes.NewLondonSigner(chainID), selectedAccount.AccountKey.PrivateKey)
|
||||
if err != nil {
|
||||
t.log.Info("ERROR SIGNIN TRANSACTION", "hash", hash)
|
||||
return hash, err
|
||||
}
|
||||
ctx, cancel = context.WithTimeout(context.Background(), t.rpcCallTimeout)
|
||||
defer cancel()
|
||||
|
||||
if err := t.sender.SendTransaction(ctx, signedTx); err != nil {
|
||||
t.log.Info("ERROR SENDING TRANSACTION", "hash", hash)
|
||||
return hash, err
|
||||
}
|
||||
return types.Hash(signedTx.Hash()), nil
|
||||
|
@ -335,7 +337,37 @@ func (t *Transactor) buildTransactionWithOverrides(nonce uint64, value *big.Int,
|
|||
var tx *gethtypes.Transaction
|
||||
|
||||
if args.To != nil {
|
||||
tx = gethtypes.NewTransaction(nonce, common.Address(*args.To), value, gas, gasPrice, args.GetInput())
|
||||
to := common.Address(*args.To)
|
||||
var txData gethtypes.TxData
|
||||
|
||||
t.log.Info("checking fee for dynamic", "args", args)
|
||||
|
||||
if args.IsDynamicFeeTx() {
|
||||
gasTipCap := (*big.Int)(args.MaxPriorityFeePerGas)
|
||||
gasFeeCap := (*big.Int)(args.MaxFeePerGas)
|
||||
|
||||
txData = &gethtypes.DynamicFeeTx{
|
||||
Nonce: nonce,
|
||||
Gas: gas,
|
||||
GasTipCap: gasTipCap,
|
||||
GasFeeCap: gasFeeCap,
|
||||
To: &to,
|
||||
Value: value,
|
||||
Data: args.GetInput(),
|
||||
}
|
||||
t.log.Info("is dynamic", "txdata", txData)
|
||||
} else {
|
||||
txData = &gethtypes.LegacyTx{
|
||||
Nonce: nonce,
|
||||
GasPrice: gasPrice,
|
||||
Gas: gas,
|
||||
To: &to,
|
||||
Value: value,
|
||||
Data: args.GetInput(),
|
||||
}
|
||||
t.log.Info("is not dynamic", "txdata", txData)
|
||||
}
|
||||
tx = gethtypes.NewTx(txData)
|
||||
t.logNewTx(args, gas, gasPrice, value)
|
||||
} else {
|
||||
tx = gethtypes.NewContractCreation(nonce, value, gas, gasPrice, args.GetInput())
|
||||
|
|
|
@ -80,17 +80,19 @@ func (s *TransactorSuite) setupTransactionPoolAPI(args SendTxArgs, returnNonce,
|
|||
var usedGas hexutil.Uint64
|
||||
var usedGasPrice *big.Int
|
||||
s.txServiceMock.EXPECT().GetTransactionCount(gomock.Any(), gomock.Eq(common.Address(account.Address)), gethrpc.PendingBlockNumber).Return(&returnNonce, nil)
|
||||
if args.GasPrice == nil {
|
||||
usedGasPrice = (*big.Int)(testGasPrice)
|
||||
s.txServiceMock.EXPECT().GasPrice(gomock.Any()).Return(testGasPrice, nil)
|
||||
} 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
|
||||
if !args.IsDynamicFeeTx() {
|
||||
if args.GasPrice == nil {
|
||||
usedGasPrice = (*big.Int)(testGasPrice)
|
||||
s.txServiceMock.EXPECT().GasPrice(gomock.Any()).Return(testGasPrice, nil)
|
||||
} 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)
|
||||
|
@ -99,16 +101,35 @@ func (s *TransactorSuite) setupTransactionPoolAPI(args SendTxArgs, returnNonce,
|
|||
}
|
||||
|
||||
func (s *TransactorSuite) rlpEncodeTx(args SendTxArgs, config *params.NodeConfig, account *account.SelectedExtKey, nonce *hexutil.Uint64, gas hexutil.Uint64, gasPrice *big.Int) hexutil.Bytes {
|
||||
newTx := gethtypes.NewTransaction(
|
||||
uint64(*nonce),
|
||||
common.Address(*args.To),
|
||||
args.Value.ToInt(),
|
||||
uint64(gas),
|
||||
gasPrice,
|
||||
[]byte(args.Input),
|
||||
)
|
||||
var txData gethtypes.TxData
|
||||
to := common.Address(*args.To)
|
||||
if args.IsDynamicFeeTx() {
|
||||
gasTipCap := (*big.Int)(args.MaxPriorityFeePerGas)
|
||||
gasFeeCap := (*big.Int)(args.MaxFeePerGas)
|
||||
|
||||
txData = &gethtypes.DynamicFeeTx{
|
||||
Nonce: uint64(*nonce),
|
||||
Gas: uint64(gas),
|
||||
GasTipCap: gasTipCap,
|
||||
GasFeeCap: gasFeeCap,
|
||||
To: &to,
|
||||
Value: args.Value.ToInt(),
|
||||
Data: args.GetInput(),
|
||||
}
|
||||
} else {
|
||||
txData = &gethtypes.LegacyTx{
|
||||
Nonce: uint64(*nonce),
|
||||
GasPrice: gasPrice,
|
||||
Gas: uint64(gas),
|
||||
To: &to,
|
||||
Value: args.Value.ToInt(),
|
||||
Data: args.GetInput(),
|
||||
}
|
||||
}
|
||||
|
||||
newTx := gethtypes.NewTx(txData)
|
||||
chainID := big.NewInt(int64(config.NetworkID))
|
||||
signedTx, err := gethtypes.SignTx(newTx, gethtypes.NewEIP155Signer(chainID), account.AccountKey.PrivateKey)
|
||||
signedTx, err := gethtypes.SignTx(newTx, gethtypes.NewLondonSigner(chainID), account.AccountKey.PrivateKey)
|
||||
s.NoError(err)
|
||||
data, err := rlp.EncodeToBytes(signedTx)
|
||||
s.NoError(err)
|
||||
|
@ -122,29 +143,47 @@ func (s *TransactorSuite) TestGasValues() {
|
|||
AccountKey: &types.Key{PrivateKey: key},
|
||||
}
|
||||
testCases := []struct {
|
||||
name string
|
||||
gas *hexutil.Uint64
|
||||
gasPrice *hexutil.Big
|
||||
name string
|
||||
gas *hexutil.Uint64
|
||||
gasPrice *hexutil.Big
|
||||
maxFeePerGas *hexutil.Big
|
||||
maxPriorityFeePerGas *hexutil.Big
|
||||
}{
|
||||
{
|
||||
"noGasDef",
|
||||
nil,
|
||||
nil,
|
||||
nil,
|
||||
nil,
|
||||
},
|
||||
{
|
||||
"gasDefined",
|
||||
&testGas,
|
||||
nil,
|
||||
nil,
|
||||
nil,
|
||||
},
|
||||
{
|
||||
"gasPriceDefined",
|
||||
nil,
|
||||
testGasPrice,
|
||||
nil,
|
||||
nil,
|
||||
},
|
||||
{
|
||||
"nilSignTransactionSpecificArgs",
|
||||
nil,
|
||||
nil,
|
||||
nil,
|
||||
nil,
|
||||
},
|
||||
|
||||
{
|
||||
"maxFeeAndPriorityset",
|
||||
nil,
|
||||
nil,
|
||||
testGasPrice,
|
||||
testGasPrice,
|
||||
},
|
||||
}
|
||||
|
||||
|
@ -152,10 +191,12 @@ func (s *TransactorSuite) TestGasValues() {
|
|||
s.T().Run(testCase.name, func(t *testing.T) {
|
||||
s.SetupTest()
|
||||
args := SendTxArgs{
|
||||
From: account.FromAddress(utils.TestConfig.Account1.WalletAddress),
|
||||
To: account.ToAddress(utils.TestConfig.Account2.WalletAddress),
|
||||
Gas: testCase.gas,
|
||||
GasPrice: testCase.gasPrice,
|
||||
From: account.FromAddress(utils.TestConfig.Account1.WalletAddress),
|
||||
To: account.ToAddress(utils.TestConfig.Account2.WalletAddress),
|
||||
Gas: testCase.gas,
|
||||
GasPrice: testCase.gasPrice,
|
||||
MaxFeePerGas: testCase.maxFeePerGas,
|
||||
MaxPriorityFeePerGas: testCase.maxPriorityFeePerGas,
|
||||
}
|
||||
s.setupTransactionPoolAPI(args, testNonce, testNonce, selectedAccount, nil)
|
||||
|
||||
|
@ -309,7 +350,7 @@ func (s *TransactorSuite) TestSendTransactionWithSignature() {
|
|||
}
|
||||
|
||||
// simulate transaction signed externally
|
||||
signer := gethtypes.NewEIP155Signer(chainID)
|
||||
signer := gethtypes.NewLondonSigner(chainID)
|
||||
tx := gethtypes.NewTransaction(uint64(nonce), common.Address(to), (*big.Int)(value), uint64(gas), (*big.Int)(gasPrice), data)
|
||||
hash := signer.Hash(tx)
|
||||
sig, err := gethcrypto.Sign(hash[:], privKey)
|
||||
|
|
|
@ -38,12 +38,14 @@ type GasCalculator interface {
|
|||
// This struct is based on go-ethereum's type in internal/ethapi/api.go, but we have freedom
|
||||
// over the exact layout of this struct.
|
||||
type SendTxArgs struct {
|
||||
From types.Address `json:"from"`
|
||||
To *types.Address `json:"to"`
|
||||
Gas *hexutil.Uint64 `json:"gas"`
|
||||
GasPrice *hexutil.Big `json:"gasPrice"`
|
||||
Value *hexutil.Big `json:"value"`
|
||||
Nonce *hexutil.Uint64 `json:"nonce"`
|
||||
From types.Address `json:"from"`
|
||||
To *types.Address `json:"to"`
|
||||
Gas *hexutil.Uint64 `json:"gas"`
|
||||
GasPrice *hexutil.Big `json:"gasPrice"`
|
||||
Value *hexutil.Big `json:"value"`
|
||||
Nonce *hexutil.Uint64 `json:"nonce"`
|
||||
MaxFeePerGas *hexutil.Big `json:"maxFeePerGas"`
|
||||
MaxPriorityFeePerGas *hexutil.Big `json:"maxPriorityFeePerGas"`
|
||||
// We keep both "input" and "data" for backward compatibility.
|
||||
// "input" is a preferred field.
|
||||
// see `vendor/github.com/ethereum/go-ethereum/internal/ethapi/api.go:1107`
|
||||
|
@ -62,6 +64,11 @@ func (args SendTxArgs) Valid() bool {
|
|||
return bytes.Equal(args.Input, args.Data)
|
||||
}
|
||||
|
||||
// IsDynamicFeeTx checks whether dynamic fee parameters are set for the tx
|
||||
func (args SendTxArgs) IsDynamicFeeTx() bool {
|
||||
return args.MaxFeePerGas != nil && args.MaxPriorityFeePerGas != nil
|
||||
}
|
||||
|
||||
// GetInput returns either Input or Data field's value dependent on what is filled.
|
||||
func (args SendTxArgs) GetInput() types.HexBytes {
|
||||
if !isNilOrEmpty(args.Input) {
|
||||
|
|
Loading…
Reference in New Issue