From eb460e410416a7a66910f4cc271569710b979dc2 Mon Sep 17 00:00:00 2001 From: piersy Date: Fri, 21 Jun 2024 17:10:32 +0100 Subject: [PATCH] Handle migrated celo transactions (#150) Introduces support for encoding/decoding legacy celo transaction types. That covers: Type 0 - The legacy transaction has been updated and now has the celo specific fields added Type 124 - The v1 of the dynamic fee tx. Additionally the transaction code has been updated to be less invasive to the op-geth repo by moving celo code into celo specific files and by removing celo specific methods added to the TxData interface. Additionally I reversed the EthCompatible boolean field since it's used to determine how to encode a legacy tx, and if unset (I.E. EthCompatible == false) then the legacy tx would be encoded as a celo legacy tx, which of course broke a lot of tests. So now the field is called CeloLegacy and if unset the tx will be encoded as an eth compatible transaction. --- accounts/external/backend.go | 2 +- core/blockchain_celo_test.go | 2 +- core/state_processor.go | 2 +- core/state_transition.go | 2 +- core/txpool/legacypool/celo_list_test.go | 2 +- core/txpool/legacypool/legacypool.go | 4 +- core/types/celo_denominated_tx.go | 6 +- core/types/celo_dynamic_fee_tx.go | 60 +++++--- core/types/celo_dynamic_fee_tx_v2.go | 131 +++++++++++++++++ core/types/celo_transaction.go | 49 ++++++- core/types/celo_transaction_marshalling.go | 133 +++++++++++++++++ core/types/celo_transaction_signing.go | 16 +- core/types/celo_tx_legacy.go | 162 +++++++++++++++++++++ core/types/deposit_tx.go | 3 - core/types/receipt.go | 12 +- core/types/receipt_test.go | 4 +- core/types/transaction.go | 31 +--- core/types/transaction_marshalling.go | 81 ++--------- core/types/tx_access_list.go | 3 - core/types/tx_blob.go | 3 - core/types/tx_dynamic_fee.go | 3 - core/types/tx_legacy.go | 29 ++-- internal/ethapi/api.go | 2 +- internal/ethapi/api_test.go | 4 +- internal/ethapi/transaction_args.go | 2 +- 25 files changed, 571 insertions(+), 177 deletions(-) create mode 100644 core/types/celo_dynamic_fee_tx_v2.go create mode 100644 core/types/celo_transaction_marshalling.go create mode 100644 core/types/celo_tx_legacy.go diff --git a/accounts/external/backend.go b/accounts/external/backend.go index 49b5f2e934..28c6dccabb 100644 --- a/accounts/external/backend.go +++ b/accounts/external/backend.go @@ -215,7 +215,7 @@ func (api *ExternalSigner) SignTx(account accounts.Account, tx *types.Transactio switch tx.Type() { case types.LegacyTxType, types.AccessListTxType: args.GasPrice = (*hexutil.Big)(tx.GasPrice()) - case types.DynamicFeeTxType, types.CeloDynamicFeeTxType, types.CeloDenominatedTxType: + case types.DynamicFeeTxType, types.CeloDynamicFeeTxV2Type, types.CeloDenominatedTxType: args.MaxFeePerGas = (*hexutil.Big)(tx.GasFeeCap()) args.MaxPriorityFeePerGas = (*hexutil.Big)(tx.GasTipCap()) default: diff --git a/core/blockchain_celo_test.go b/core/blockchain_celo_test.go index 7775b88188..f2185b7111 100644 --- a/core/blockchain_celo_test.go +++ b/core/blockchain_celo_test.go @@ -77,7 +77,7 @@ func testNativeTransferWithFeeCurrency(t *testing.T, scheme string, feeCurrencyA _, blocks, _ := GenerateChainWithGenesis(gspec, engine, 1, func(i int, b *BlockGen) { b.SetCoinbase(common.Address{1}) - txdata := &types.CeloDynamicFeeTx{ + txdata := &types.CeloDynamicFeeTxV2{ ChainID: gspec.Config.ChainID, Nonce: 0, To: &aa, diff --git a/core/state_processor.go b/core/state_processor.go index bc50b2f294..e34dbbd556 100644 --- a/core/state_processor.go +++ b/core/state_processor.go @@ -153,7 +153,7 @@ func applyTransaction(msg *Message, config *params.ChainConfig, gp *GasPool, sta *receipt.DepositReceiptVersion = types.CanyonDepositReceiptVersion } } - if tx.Type() == types.CeloDynamicFeeTxType { + if tx.Type() == types.CeloDynamicFeeTxV2Type { alternativeBaseFee := evm.Context.BaseFee if msg.FeeCurrency != nil { alternativeBaseFee, err = exchange.ConvertGoldToCurrency(evm.Context.ExchangeRates, msg.FeeCurrency, evm.Context.BaseFee) diff --git a/core/state_transition.go b/core/state_transition.go index bf6aa00591..8b3ad766a9 100644 --- a/core/state_transition.go +++ b/core/state_transition.go @@ -212,7 +212,7 @@ func TransactionToMessage(tx *types.Transaction, s types.Signer, baseFee *big.In } // If baseFee provided, set gasPrice to effectiveGasPrice. if baseFee != nil { - if tx.Type() == types.CeloDynamicFeeTxType { + if tx.Type() == types.CeloDynamicFeeTxV2Type { var err error baseFee, err = exchange.ConvertGoldToCurrency(exchangeRates, msg.FeeCurrency, baseFee) if err != nil { diff --git a/core/txpool/legacypool/celo_list_test.go b/core/txpool/legacypool/celo_list_test.go index 5cba5966b0..31b6741c34 100644 --- a/core/txpool/legacypool/celo_list_test.go +++ b/core/txpool/legacypool/celo_list_test.go @@ -11,7 +11,7 @@ import ( ) func txC(nonce int, feeCap int, tipCap int, gas int, currency *common.Address) *types.Transaction { - return types.NewTx(&types.CeloDynamicFeeTx{ + return types.NewTx(&types.CeloDynamicFeeTxV2{ GasFeeCap: big.NewInt(int64(feeCap)), GasTipCap: big.NewInt(int64(tipCap)), FeeCurrency: currency, diff --git a/core/txpool/legacypool/legacypool.go b/core/txpool/legacypool/legacypool.go index 7abd75203a..0facd29673 100644 --- a/core/txpool/legacypool/legacypool.go +++ b/core/txpool/legacypool/legacypool.go @@ -290,7 +290,7 @@ func New(config Config, chain BlockChain) *LegacyPool { // pool, specifically, whether it is a Legacy, AccessList or Dynamic transaction. func (pool *LegacyPool) Filter(tx *types.Transaction) bool { switch tx.Type() { - case types.LegacyTxType, types.AccessListTxType, types.DynamicFeeTxType, types.CeloDynamicFeeTxType: + case types.LegacyTxType, types.AccessListTxType, types.DynamicFeeTxType, types.CeloDynamicFeeTxV2Type: return true default: return false @@ -642,7 +642,7 @@ func (pool *LegacyPool) validateTxBasics(tx *types.Transaction, local bool) erro types.LegacyTxType, types.AccessListTxType, types.DynamicFeeTxType, - types.CeloDynamicFeeTxType), + types.CeloDynamicFeeTxV2Type), MaxSize: txMaxSize, MinTip: pool.gasTip.Load().ToBig(), EffectiveGasCeil: pool.config.EffectiveGasCeil, diff --git a/core/types/celo_denominated_tx.go b/core/types/celo_denominated_tx.go index 977397d650..21ed9da556 100644 --- a/core/types/celo_denominated_tx.go +++ b/core/types/celo_denominated_tx.go @@ -8,6 +8,8 @@ import ( "github.com/ethereum/go-ethereum/rlp" ) +const CeloDenominatedTxType = 0x7a + type CeloDenominatedTx struct { ChainID *big.Int Nonce uint64 @@ -115,7 +117,3 @@ func (tx *CeloDenominatedTx) encode(b *bytes.Buffer) error { func (tx *CeloDenominatedTx) decode(input []byte) error { return rlp.DecodeBytes(input, tx) } - -func (tx *CeloDenominatedTx) feeCurrency() *common.Address { return tx.FeeCurrency } - -func (tx *CeloDenominatedTx) maxFeeInFeeCurrency() *big.Int { return tx.MaxFeeInFeeCurrency } diff --git a/core/types/celo_dynamic_fee_tx.go b/core/types/celo_dynamic_fee_tx.go index 800addd11e..f1fab1f4d8 100644 --- a/core/types/celo_dynamic_fee_tx.go +++ b/core/types/celo_dynamic_fee_tx.go @@ -1,4 +1,18 @@ -// TODO: needs copyright header? +// Copyright 2024 The Celo Authors +// This file is part of the celo library. +// +// The celo library is free software: you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// The celo library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public License +// along with the celo library. If not, see . package types @@ -10,19 +24,21 @@ import ( "github.com/ethereum/go-ethereum/rlp" ) -// CeloDynamicFeeTx represents a CIP-64 transaction. -type CeloDynamicFeeTx struct { - ChainID *big.Int - Nonce uint64 - GasTipCap *big.Int - GasFeeCap *big.Int - Gas uint64 - To *common.Address `rlp:"nil"` // nil means contract creation - Value *big.Int - Data []byte - AccessList AccessList +const CeloDynamicFeeTxType = 0x7c - FeeCurrency *common.Address `rlp:"nil"` // nil means native currency +type CeloDynamicFeeTx struct { + ChainID *big.Int + Nonce uint64 + GasTipCap *big.Int + GasFeeCap *big.Int + Gas uint64 + FeeCurrency *common.Address `rlp:"nil"` // nil means native currency + GatewayFeeRecipient *common.Address `rlp:"nil"` // nil means no gateway fee is paid + GatewayFee *big.Int `rlp:"nil"` + To *common.Address `rlp:"nil"` // nil means contract creation + Value *big.Int + Data []byte + AccessList AccessList // Signature values V *big.Int `json:"v" gencodec:"required"` @@ -33,13 +49,15 @@ type CeloDynamicFeeTx struct { // copy creates a deep copy of the transaction data and initializes all fields. func (tx *CeloDynamicFeeTx) copy() TxData { cpy := &CeloDynamicFeeTx{ - Nonce: tx.Nonce, - To: copyAddressPtr(tx.To), - Data: common.CopyBytes(tx.Data), - Gas: tx.Gas, - FeeCurrency: copyAddressPtr(tx.FeeCurrency), + Nonce: tx.Nonce, + To: copyAddressPtr(tx.To), + Data: common.CopyBytes(tx.Data), + Gas: tx.Gas, + FeeCurrency: copyAddressPtr(tx.FeeCurrency), + GatewayFeeRecipient: copyAddressPtr(tx.GatewayFeeRecipient), // These are copied below. AccessList: make(AccessList, len(tx.AccessList)), + GatewayFee: new(big.Int), Value: new(big.Int), ChainID: new(big.Int), GasTipCap: new(big.Int), @@ -61,6 +79,9 @@ func (tx *CeloDynamicFeeTx) copy() TxData { if tx.GasFeeCap != nil { cpy.GasFeeCap.Set(tx.GasFeeCap) } + if tx.GatewayFee != nil { + cpy.GatewayFee.Set(tx.GatewayFee) + } if tx.V != nil { cpy.V.Set(tx.V) } @@ -113,6 +134,3 @@ func (tx *CeloDynamicFeeTx) encode(b *bytes.Buffer) error { func (tx *CeloDynamicFeeTx) decode(input []byte) error { return rlp.DecodeBytes(input, tx) } - -func (tx *CeloDynamicFeeTx) feeCurrency() *common.Address { return tx.FeeCurrency } -func (tx *CeloDynamicFeeTx) maxFeeInFeeCurrency() *big.Int { return nil } diff --git a/core/types/celo_dynamic_fee_tx_v2.go b/core/types/celo_dynamic_fee_tx_v2.go new file mode 100644 index 0000000000..45f83a5b70 --- /dev/null +++ b/core/types/celo_dynamic_fee_tx_v2.go @@ -0,0 +1,131 @@ +// Copyright 2024 The Celo Authors +// This file is part of the celo library. +// +// The celo library is free software: you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// The celo library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public License +// along with the celo library. If not, see . + +package types + +import ( + "bytes" + "math/big" + + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/rlp" +) + +const CeloDynamicFeeTxV2Type = 0x7b + +// CeloDynamicFeeTxV2 represents a CIP-64 transaction. +type CeloDynamicFeeTxV2 struct { + ChainID *big.Int + Nonce uint64 + GasTipCap *big.Int + GasFeeCap *big.Int + Gas uint64 + To *common.Address `rlp:"nil"` // nil means contract creation + Value *big.Int + Data []byte + AccessList AccessList + + FeeCurrency *common.Address `rlp:"nil"` // nil means native currency + + // Signature values + V *big.Int `json:"v" gencodec:"required"` + R *big.Int `json:"r" gencodec:"required"` + S *big.Int `json:"s" gencodec:"required"` +} + +// copy creates a deep copy of the transaction data and initializes all fields. +func (tx *CeloDynamicFeeTxV2) copy() TxData { + cpy := &CeloDynamicFeeTxV2{ + Nonce: tx.Nonce, + To: copyAddressPtr(tx.To), + Data: common.CopyBytes(tx.Data), + Gas: tx.Gas, + FeeCurrency: copyAddressPtr(tx.FeeCurrency), + // These are copied below. + AccessList: make(AccessList, len(tx.AccessList)), + Value: new(big.Int), + ChainID: new(big.Int), + GasTipCap: new(big.Int), + GasFeeCap: new(big.Int), + V: new(big.Int), + R: new(big.Int), + S: new(big.Int), + } + copy(cpy.AccessList, tx.AccessList) + if tx.Value != nil { + cpy.Value.Set(tx.Value) + } + if tx.ChainID != nil { + cpy.ChainID.Set(tx.ChainID) + } + if tx.GasTipCap != nil { + cpy.GasTipCap.Set(tx.GasTipCap) + } + if tx.GasFeeCap != nil { + cpy.GasFeeCap.Set(tx.GasFeeCap) + } + if tx.V != nil { + cpy.V.Set(tx.V) + } + if tx.R != nil { + cpy.R.Set(tx.R) + } + if tx.S != nil { + cpy.S.Set(tx.S) + } + return cpy +} + +// accessors for innerTx. +func (tx *CeloDynamicFeeTxV2) txType() byte { return CeloDynamicFeeTxV2Type } +func (tx *CeloDynamicFeeTxV2) chainID() *big.Int { return tx.ChainID } +func (tx *CeloDynamicFeeTxV2) accessList() AccessList { return tx.AccessList } +func (tx *CeloDynamicFeeTxV2) data() []byte { return tx.Data } +func (tx *CeloDynamicFeeTxV2) gas() uint64 { return tx.Gas } +func (tx *CeloDynamicFeeTxV2) gasFeeCap() *big.Int { return tx.GasFeeCap } +func (tx *CeloDynamicFeeTxV2) gasTipCap() *big.Int { return tx.GasTipCap } +func (tx *CeloDynamicFeeTxV2) gasPrice() *big.Int { return tx.GasFeeCap } +func (tx *CeloDynamicFeeTxV2) value() *big.Int { return tx.Value } +func (tx *CeloDynamicFeeTxV2) nonce() uint64 { return tx.Nonce } +func (tx *CeloDynamicFeeTxV2) to() *common.Address { return tx.To } +func (tx *CeloDynamicFeeTxV2) isSystemTx() bool { return false } + +func (tx *CeloDynamicFeeTxV2) effectiveGasPrice(dst *big.Int, baseFee *big.Int) *big.Int { + if baseFee == nil { + return dst.Set(tx.GasFeeCap) + } + tip := dst.Sub(tx.GasFeeCap, baseFee) + if tip.Cmp(tx.GasTipCap) > 0 { + tip.Set(tx.GasTipCap) + } + return tip.Add(tip, baseFee) +} + +func (tx *CeloDynamicFeeTxV2) rawSignatureValues() (v, r, s *big.Int) { + return tx.V, tx.R, tx.S +} + +func (tx *CeloDynamicFeeTxV2) setSignatureValues(chainID, v, r, s *big.Int) { + tx.ChainID, tx.V, tx.R, tx.S = chainID, v, r, s +} + +func (tx *CeloDynamicFeeTxV2) encode(b *bytes.Buffer) error { + return rlp.Encode(b, tx) +} + +func (tx *CeloDynamicFeeTxV2) decode(input []byte) error { + return rlp.DecodeBytes(input, tx) +} diff --git a/core/types/celo_transaction.go b/core/types/celo_transaction.go index 9cc79a7c0e..06dbd52ed4 100644 --- a/core/types/celo_transaction.go +++ b/core/types/celo_transaction.go @@ -1,9 +1,48 @@ +// Copyright 2024 The Celo Authors +// This file is part of the celo library. +// +// The celo library is free software: you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// The celo library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public License +// along with the celo library. If not, see . + package types import ( + "math/big" + + "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common/exchange" ) +// FeeCurrency returns the fee currency of the transaction if there is one. +func (tx *Transaction) FeeCurrency() *common.Address { + var feeCurrency *common.Address + switch t := tx.inner.(type) { + case *CeloDynamicFeeTxV2: + feeCurrency = t.FeeCurrency + } + return feeCurrency +} + +// MaxFeeInFeeCurrency returns the maximum fee in the fee currency of the transaction if there is one. +func (tx *Transaction) MaxFeeInFeeCurrency() *big.Int { + var maxFeeInFeeCurrency *big.Int + switch t := tx.inner.(type) { + case *CeloDenominatedTx: + maxFeeInFeeCurrency = t.MaxFeeInFeeCurrency + } + return maxFeeInFeeCurrency +} + // CompareWithRates compares the effective gas price of two transactions according to the exchange rates and // the base fees in the transactions currencies. func CompareWithRates(a, b *Transaction, ratesAndFees *exchange.RatesAndFees) int { @@ -17,16 +56,16 @@ func CompareWithRates(a, b *Transaction, ratesAndFees *exchange.RatesAndFees) in } rates := ratesAndFees.Rates if ratesAndFees.HasBaseFee() { - tipA := a.EffectiveGasTipValue(ratesAndFees.GetBaseFeeIn(a.inner.feeCurrency())) - tipB := b.EffectiveGasTipValue(ratesAndFees.GetBaseFeeIn(b.inner.feeCurrency())) - c, _ := exchange.CompareValue(rates, tipA, a.inner.feeCurrency(), tipB, b.inner.feeCurrency()) + tipA := a.EffectiveGasTipValue(ratesAndFees.GetBaseFeeIn(a.FeeCurrency())) + tipB := b.EffectiveGasTipValue(ratesAndFees.GetBaseFeeIn(b.FeeCurrency())) + c, _ := exchange.CompareValue(rates, tipA, a.FeeCurrency(), tipB, b.FeeCurrency()) return c } // Compare fee caps if baseFee is not specified or effective tips are equal feeA := a.inner.gasFeeCap() feeB := b.inner.gasFeeCap() - c, _ := exchange.CompareValue(rates, feeA, a.inner.feeCurrency(), feeB, b.inner.feeCurrency()) + c, _ := exchange.CompareValue(rates, feeA, a.FeeCurrency(), feeB, b.FeeCurrency()) if c != 0 { return c } @@ -34,6 +73,6 @@ func CompareWithRates(a, b *Transaction, ratesAndFees *exchange.RatesAndFees) in // Compare tips if effective tips and fee caps are equal tipCapA := a.inner.gasTipCap() tipCapB := b.inner.gasTipCap() - c, _ = exchange.CompareValue(rates, tipCapA, a.inner.feeCurrency(), tipCapB, b.inner.feeCurrency()) + c, _ = exchange.CompareValue(rates, tipCapA, a.FeeCurrency(), tipCapB, b.FeeCurrency()) return c } diff --git a/core/types/celo_transaction_marshalling.go b/core/types/celo_transaction_marshalling.go new file mode 100644 index 0000000000..109342a366 --- /dev/null +++ b/core/types/celo_transaction_marshalling.go @@ -0,0 +1,133 @@ +// Copyright 2024 The Celo Authors +// This file is part of the celo library. +// +// The celo library is free software: you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// The celo library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public License +// along with the celo library. If not, see . + +package types + +import ( + "encoding/json" + "errors" + "math/big" + + "github.com/ethereum/go-ethereum/common/hexutil" +) + +func celoTransactionMarshal(tx *Transaction) ([]byte, bool, error) { + var enc txJSON + // These are set for all tx types. + enc.Hash = tx.Hash() + enc.Type = hexutil.Uint64(tx.Type()) + switch itx := tx.inner.(type) { + case *CeloDynamicFeeTxV2: + enc.ChainID = (*hexutil.Big)(itx.ChainID) + enc.Nonce = (*hexutil.Uint64)(&itx.Nonce) + enc.To = tx.To() + enc.Gas = (*hexutil.Uint64)(&itx.Gas) + enc.MaxFeePerGas = (*hexutil.Big)(itx.GasFeeCap) + enc.MaxPriorityFeePerGas = (*hexutil.Big)(itx.GasTipCap) + enc.FeeCurrency = itx.FeeCurrency + enc.Value = (*hexutil.Big)(itx.Value) + enc.Input = (*hexutil.Bytes)(&itx.Data) + enc.AccessList = &itx.AccessList + enc.V = (*hexutil.Big)(itx.V) + enc.R = (*hexutil.Big)(itx.R) + enc.S = (*hexutil.Big)(itx.S) + default: + return nil, false, nil + } + bytes, err := json.Marshal(&enc) + return bytes, true, err +} + +func celoTransactionUnmarshal(dec txJSON, inner *TxData) (bool, error) { + switch dec.Type { + case CeloDynamicFeeTxV2Type: + var itx CeloDynamicFeeTxV2 + *inner = &itx + if dec.ChainID == nil { + return true, errors.New("missing required field 'chainId' in transaction") + } + itx.ChainID = (*big.Int)(dec.ChainID) + if dec.Nonce == nil { + return true, errors.New("missing required field 'nonce' in transaction") + } + itx.Nonce = uint64(*dec.Nonce) + if dec.To != nil { + itx.To = dec.To + } + if dec.Gas == nil { + return true, errors.New("missing required field 'gas' for txdata") + } + itx.Gas = uint64(*dec.Gas) + if dec.MaxPriorityFeePerGas == nil { + return true, errors.New("missing required field 'maxPriorityFeePerGas' for txdata") + } + itx.GasTipCap = (*big.Int)(dec.MaxPriorityFeePerGas) + if dec.MaxFeePerGas == nil { + return true, errors.New("missing required field 'maxFeePerGas' for txdata") + } + itx.GasFeeCap = (*big.Int)(dec.MaxFeePerGas) + if dec.Value == nil { + return true, errors.New("missing required field 'value' in transaction") + } + itx.FeeCurrency = dec.FeeCurrency + itx.Value = (*big.Int)(dec.Value) + if dec.Input == nil { + return true, errors.New("missing required field 'input' in transaction") + } + itx.Data = *dec.Input + if dec.V == nil { + return true, errors.New("missing required field 'v' in transaction") + } + if dec.AccessList != nil { + itx.AccessList = *dec.AccessList + } + itx.V = (*big.Int)(dec.V) + if dec.R == nil { + return true, errors.New("missing required field 'r' in transaction") + } + itx.R = (*big.Int)(dec.R) + if dec.S == nil { + return true, errors.New("missing required field 's' in transaction") + } + itx.S = (*big.Int)(dec.S) + withSignature := itx.V.Sign() != 0 || itx.R.Sign() != 0 || itx.S.Sign() != 0 + if withSignature { + if err := sanityCheckSignature(itx.V, itx.R, itx.S, false); err != nil { + return true, err + } + } + default: + return false, nil + } + + return true, nil +} + +func celoDecodeTyped(b []byte) (TxData, bool, error) { + var inner TxData + switch b[0] { + case CeloDenominatedTxType: + inner = new(CeloDenominatedTx) + case CeloDynamicFeeTxV2Type: + inner = new(CeloDynamicFeeTxV2) + case CeloDynamicFeeTxType: + inner = new(CeloDynamicFeeTx) + default: + return nil, false, nil + } + err := inner.decode(b[1:]) + return inner, true, err +} diff --git a/core/types/celo_transaction_signing.go b/core/types/celo_transaction_signing.go index 1dffdbe408..0fe6ed3eb4 100644 --- a/core/types/celo_transaction_signing.go +++ b/core/types/celo_transaction_signing.go @@ -1,18 +1,18 @@ -// Copyright 2016 The go-ethereum Authors -// This file is part of the go-ethereum library. +// Copyright 2024 The Celo Authors +// This file is part of the celo library. // -// The go-ethereum library is free software: you can redistribute it and/or modify +// The celo library is free software: you can redistribute it and/or modify // it under the terms of the GNU Lesser General Public License as published by // the Free Software Foundation, either version 3 of the License, or // (at your option) any later version. // -// The go-ethereum library is distributed in the hope that it will be useful, +// The celo library is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU Lesser General Public License for more details. // // You should have received a copy of the GNU Lesser General Public License -// along with the go-ethereum library. If not, see . +// along with the celo library. If not, see . package types @@ -36,7 +36,7 @@ func NewCel2Signer(chainId *big.Int) Signer { } func (s cel2Signer) Sender(tx *Transaction) (common.Address, error) { - if tx.Type() != CeloDynamicFeeTxType && tx.Type() != CeloDenominatedTxType { + if tx.Type() != CeloDynamicFeeTxV2Type && tx.Type() != CeloDenominatedTxType { return s.londonSigner.Sender(tx) } V, R, S := tx.RawSignatureValues() @@ -55,7 +55,7 @@ func (s cel2Signer) Equal(s2 Signer) bool { } func (s cel2Signer) SignatureValues(tx *Transaction, sig []byte) (R, S, V *big.Int, err error) { - if tx.Type() != CeloDynamicFeeTxType && tx.Type() != CeloDenominatedTxType { + if tx.Type() != CeloDynamicFeeTxV2Type && tx.Type() != CeloDenominatedTxType { return s.londonSigner.SignatureValues(tx, sig) } @@ -73,7 +73,7 @@ func (s cel2Signer) SignatureValues(tx *Transaction, sig []byte) (R, S, V *big.I // Hash returns the hash to be signed by the sender. // It does not uniquely identify the transaction. func (s cel2Signer) Hash(tx *Transaction) common.Hash { - if tx.Type() == CeloDynamicFeeTxType { + if tx.Type() == CeloDynamicFeeTxV2Type { return prefixedRlpHash( tx.Type(), []interface{}{ diff --git a/core/types/celo_tx_legacy.go b/core/types/celo_tx_legacy.go new file mode 100644 index 0000000000..b1ea042095 --- /dev/null +++ b/core/types/celo_tx_legacy.go @@ -0,0 +1,162 @@ +// Copyright 2024 The Celo Authors +// This file is part of the celo library. +// +// The celo library is free software: you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// The celo library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public License +// along with the celo library. If not, see . + +package types + +import ( + "io" + "math/big" + + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/rlp" +) + +var ethCompatibleTxNumFields = 9 + +// ethCompatibleTxRlpList is used for RLP encoding/decoding of eth-compatible transactions. +// As such, it: +// (a) excludes the Celo-only fields, +// (b) doesn't need the Hash or EthCompatible fields, and +// (c) doesn't need the `json` or `gencodec` tags +type ethCompatibleTxRlpList struct { + Nonce uint64 // nonce of sender account + GasPrice *big.Int // wei per gas + Gas uint64 // gas limit + To *common.Address `rlp:"nil"` // nil means contract creation + Value *big.Int // wei amount + Data []byte // contract invocation input data + V, R, S *big.Int // signature values +} + +// celoTxRlpList is used for RLP encoding/decoding of celo transactions. +type celoTxRlpList struct { + Nonce uint64 // nonce of sender account + GasPrice *big.Int // wei per gas + Gas uint64 // gas limit + FeeCurrency *common.Address `rlp:"nil"` // nil means native currency + GatewayFeeRecipient *common.Address `rlp:"nil"` // nil means no gateway fee is paid + GatewayFee *big.Int `rlp:"nil"` + To *common.Address `rlp:"nil"` // nil means contract creation + Value *big.Int // wei amount + Data []byte // contract invocation input data + V, R, S *big.Int // signature values +} + +func toEthCompatibleRlpList(tx LegacyTx) ethCompatibleTxRlpList { + return ethCompatibleTxRlpList{ + Nonce: tx.Nonce, + GasPrice: tx.GasPrice, + Gas: tx.Gas, + To: tx.To, + Value: tx.Value, + Data: tx.Data, + V: tx.V, + R: tx.R, + S: tx.S, + } +} + +func toCeloRlpList(tx LegacyTx) celoTxRlpList { + return celoTxRlpList{ + Nonce: tx.Nonce, + GasPrice: tx.GasPrice, + Gas: tx.Gas, + To: tx.To, + Value: tx.Value, + Data: tx.Data, + V: tx.V, + R: tx.R, + S: tx.S, + + // Celo specific fields + FeeCurrency: tx.FeeCurrency, + GatewayFeeRecipient: tx.GatewayFeeRecipient, + GatewayFee: tx.GatewayFee, + } +} + +func setTxFromEthCompatibleRlpList(tx *LegacyTx, rlplist ethCompatibleTxRlpList) { + tx.Nonce = rlplist.Nonce + tx.GasPrice = rlplist.GasPrice + tx.Gas = rlplist.Gas + tx.To = rlplist.To + tx.Value = rlplist.Value + tx.Data = rlplist.Data + tx.V = rlplist.V + tx.R = rlplist.R + tx.S = rlplist.S + tx.Hash = nil // txdata.Hash is calculated and saved inside tx.Hash() + + // Celo specific fields + tx.FeeCurrency = nil + tx.GatewayFeeRecipient = nil + tx.GatewayFee = big.NewInt(0) + tx.CeloLegacy = false +} + +func setTxFromCeloRlpList(tx *LegacyTx, rlplist celoTxRlpList) { + tx.Nonce = rlplist.Nonce + tx.GasPrice = rlplist.GasPrice + tx.Gas = rlplist.Gas + tx.To = rlplist.To + tx.Value = rlplist.Value + tx.Data = rlplist.Data + tx.V = rlplist.V + tx.R = rlplist.R + tx.S = rlplist.S + tx.Hash = nil // txdata.Hash is calculated and saved inside tx.Hash() + + // Celo specific fields + tx.FeeCurrency = rlplist.FeeCurrency + tx.GatewayFeeRecipient = rlplist.GatewayFeeRecipient + tx.GatewayFee = rlplist.GatewayFee + tx.CeloLegacy = true +} + +// EncodeRLP implements rlp.Encoder +func (tx *LegacyTx) EncodeRLP(w io.Writer) error { + if tx.CeloLegacy { + return rlp.Encode(w, toCeloRlpList(*tx)) + } else { + return rlp.Encode(w, toEthCompatibleRlpList(*tx)) + } +} + +// DecodeRLP implements rlp.Decoder +func (tx *LegacyTx) DecodeRLP(s *rlp.Stream) (err error) { + _, size, _ := s.Kind() + var raw rlp.RawValue + err = s.Decode(&raw) + if err != nil { + return err + } + headerSize := len(raw) - int(size) + numElems, err := rlp.CountValues(raw[headerSize:]) + if err != nil { + return err + } + if numElems == ethCompatibleTxNumFields { + rlpList := ethCompatibleTxRlpList{} + err = rlp.DecodeBytes(raw, &rlpList) + setTxFromEthCompatibleRlpList(tx, rlpList) + } else { + var rlpList celoTxRlpList + err = rlp.DecodeBytes(raw, &rlpList) + setTxFromCeloRlpList(tx, rlpList) + } + + return err +} diff --git a/core/types/deposit_tx.go b/core/types/deposit_tx.go index bbfec79323..4131ee7af0 100644 --- a/core/types/deposit_tx.go +++ b/core/types/deposit_tx.go @@ -101,6 +101,3 @@ func (tx *DepositTx) encode(b *bytes.Buffer) error { func (tx *DepositTx) decode(input []byte) error { return rlp.DecodeBytes(input, tx) } - -func (tx *DepositTx) feeCurrency() *common.Address { return nil } -func (tx *DepositTx) maxFeeInFeeCurrency() *big.Int { return nil } diff --git a/core/types/receipt.go b/core/types/receipt.go index 69e143ff8b..5ce8302dd3 100644 --- a/core/types/receipt.go +++ b/core/types/receipt.go @@ -278,7 +278,7 @@ func (r *Receipt) EncodeRLP(w io.Writer) error { func (r *Receipt) encodeTyped(data *receiptRLP, w *bytes.Buffer) error { w.WriteByte(r.Type) switch r.Type { - case CeloDynamicFeeTxType: + case CeloDynamicFeeTxV2Type: withBaseFee := &celoDynamicReceiptRLP{data.PostStateOrStatus, data.CumulativeGasUsed, data.Bloom, data.Logs, r.BaseFee} return rlp.Encode(w, withBaseFee) case DepositTxType: @@ -362,7 +362,7 @@ func (r *Receipt) decodeTyped(b []byte) error { } r.Type = b[0] return r.setFromRLP(data) - case CeloDynamicFeeTxType: + case CeloDynamicFeeTxV2Type: var data celoDynamicReceiptRLP err := rlp.DecodeBytes(b[1:], &data) if err != nil { @@ -435,7 +435,7 @@ type ReceiptForStorage Receipt func (r *ReceiptForStorage) EncodeRLP(_w io.Writer) error { w := rlp.NewEncoderBuffer(_w) outerList := w.List() - if r.Type == CeloDynamicFeeTxType { + if r.Type == CeloDynamicFeeTxV2Type { // Mark receipt as CeloDynamicFee receipt by starting with an empty list listIndex := w.List() w.ListEnd(listIndex) @@ -455,7 +455,7 @@ func (r *ReceiptForStorage) EncodeRLP(_w io.Writer) error { w.WriteUint64(*r.DepositReceiptVersion) } } - if r.Type == CeloDynamicFeeTxType { + if r.Type == CeloDynamicFeeTxV2Type { w.WriteBigInt(r.BaseFee) } w.ListEnd(outerList) @@ -576,7 +576,7 @@ func (rs Receipts) EncodeIndex(i int, w *bytes.Buffer) { switch r.Type { case AccessListTxType, DynamicFeeTxType, BlobTxType: rlp.Encode(w, data) - case CeloDynamicFeeTxType: + case CeloDynamicFeeTxV2Type: celoDynamicData := &celoDynamicReceiptRLP{data.PostStateOrStatus, data.CumulativeGasUsed, data.Bloom, data.Logs, r.BaseFee} rlp.Encode(w, celoDynamicData) case DepositTxType: @@ -608,7 +608,7 @@ func (rs Receipts) DeriveFields(config *params.ChainConfig, hash common.Hash, nu rs[i].Type = txs[i].Type() rs[i].TxHash = txs[i].Hash() // The CeloDynamicFeeTxs set the baseFee in the receipt - if txs[i].Type() != CeloDynamicFeeTxType { + if txs[i].Type() != CeloDynamicFeeTxV2Type { rs[i].EffectiveGasPrice = txs[i].inner.effectiveGasPrice(new(big.Int), baseFee) } else { rs[i].EffectiveGasPrice = txs[i].inner.effectiveGasPrice(new(big.Int), rs[i].BaseFee) diff --git a/core/types/receipt_test.go b/core/types/receipt_test.go index 25e468ec86..58c67f3790 100644 --- a/core/types/receipt_test.go +++ b/core/types/receipt_test.go @@ -115,7 +115,7 @@ var ( }, }, BaseFee: new(big.Int).SetUint64(1), - Type: CeloDynamicFeeTxType, + Type: CeloDynamicFeeTxV2Type, } depositReceiptNoNonce = &Receipt{ Status: ReceiptStatusFailed, @@ -1094,7 +1094,7 @@ func TestRoundTripReceiptForStorage(t *testing.T) { require.Equal(t, test.rcpt.Logs, d.Logs) require.Equal(t, test.rcpt.DepositNonce, d.DepositNonce) require.Equal(t, test.rcpt.DepositReceiptVersion, d.DepositReceiptVersion) - if test.rcpt.Type == CeloDynamicFeeTxType { + if test.rcpt.Type == CeloDynamicFeeTxV2Type { require.Equal(t, test.rcpt.EffectiveGasPrice, d.EffectiveGasPrice) } }) diff --git a/core/types/transaction.go b/core/types/transaction.go index 6db82c6430..63f313734f 100644 --- a/core/types/transaction.go +++ b/core/types/transaction.go @@ -50,9 +50,6 @@ const ( AccessListTxType = 0x01 DynamicFeeTxType = 0x02 BlobTxType = 0x03 - // CeloDynamicFeeTxType = 0x7c old Celo tx type with gateway fee - CeloDynamicFeeTxType = 0x7b - CeloDenominatedTxType = 0x7a ) // Transaction is an Ethereum transaction. @@ -108,10 +105,6 @@ type TxData interface { encode(*bytes.Buffer) error decode([]byte) error - - // Celo specific fields - feeCurrency() *common.Address - maxFeeInFeeCurrency() *big.Int } // EncodeRLP implements rlp.Encoder @@ -210,16 +203,17 @@ func (tx *Transaction) decodeTyped(b []byte) (TxData, error) { if len(b) <= 1 { return nil, errShortTypedTx } + + if inner, isCelo, err := celoDecodeTyped(b); isCelo { + return inner, err + } + var inner TxData switch b[0] { case AccessListTxType: inner = new(AccessListTx) case DynamicFeeTxType: inner = new(DynamicFeeTx) - case CeloDynamicFeeTxType: - inner = new(CeloDynamicFeeTx) - case CeloDenominatedTxType: - inner = new(CeloDenominatedTx) case BlobTxType: inner = new(BlobTx) case DepositTxType: @@ -627,21 +621,6 @@ func (tx *Transaction) WithSignature(signer Signer, sig []byte) (*Transaction, e return &Transaction{inner: cpy, time: tx.time}, nil } -// FeeCurrency returns the fee currency of the transaction. Nil implies paying in CELO. -func (tx *Transaction) FeeCurrency() *common.Address { - return copyAddressPtr(tx.inner.feeCurrency()) -} - -// MaxFeeInFeeCurrency is only used to guard against very quickly changing exchange rates. -// Txs must be discarded if MaxFeeInFeeCurrency is exceeded. -func (tx *Transaction) MaxFeeInFeeCurrency() *big.Int { - mfifc := tx.inner.maxFeeInFeeCurrency() - if mfifc == nil { - return nil - } - return new(big.Int).Set(mfifc) -} - // Transactions implements DerivableList for transactions. type Transactions []*Transaction diff --git a/core/types/transaction_marshalling.go b/core/types/transaction_marshalling.go index b800f524e9..3b68418d86 100644 --- a/core/types/transaction_marshalling.go +++ b/core/types/transaction_marshalling.go @@ -90,6 +90,9 @@ func (tx *txJSON) yParityValue() (*big.Int, error) { // MarshalJSON marshals as JSON with a hash. func (tx *Transaction) MarshalJSON() ([]byte, error) { + if marshalled, isCelo, err := celoTransactionMarshal(tx); isCelo { + return marshalled, err + } var enc txJSON // These are set for all tx types. enc.Hash = tx.Hash() @@ -142,21 +145,6 @@ func (tx *Transaction) MarshalJSON() ([]byte, error) { yparity := itx.V.Uint64() enc.YParity = (*hexutil.Uint64)(&yparity) - case *CeloDynamicFeeTx: - enc.ChainID = (*hexutil.Big)(itx.ChainID) - enc.Nonce = (*hexutil.Uint64)(&itx.Nonce) - enc.To = tx.To() - enc.Gas = (*hexutil.Uint64)(&itx.Gas) - enc.MaxFeePerGas = (*hexutil.Big)(itx.GasFeeCap) - enc.MaxPriorityFeePerGas = (*hexutil.Big)(itx.GasTipCap) - enc.FeeCurrency = tx.FeeCurrency() - enc.Value = (*hexutil.Big)(itx.Value) - enc.Input = (*hexutil.Bytes)(&itx.Data) - enc.AccessList = &itx.AccessList - enc.V = (*hexutil.Big)(itx.V) - enc.R = (*hexutil.Big)(itx.R) - enc.S = (*hexutil.Big)(itx.S) - case *BlobTx: enc.ChainID = (*hexutil.Big)(itx.ChainID.ToBig()) enc.Nonce = (*hexutil.Uint64)(&itx.Nonce) @@ -206,6 +194,12 @@ func (tx *Transaction) UnmarshalJSON(input []byte) error { // Decode / verify fields according to transaction type. var inner TxData + + if isCelo, err := celoTransactionUnmarshal(dec, &inner); isCelo { + tx.setDecoded(inner, 0) + return err + } + switch dec.Type { case LegacyTxType: var itx LegacyTx @@ -369,63 +363,6 @@ func (tx *Transaction) UnmarshalJSON(input []byte) error { } } - case CeloDynamicFeeTxType: - var itx CeloDynamicFeeTx - inner = &itx - if dec.ChainID == nil { - return errors.New("missing required field 'chainId' in transaction") - } - itx.ChainID = (*big.Int)(dec.ChainID) - if dec.Nonce == nil { - return errors.New("missing required field 'nonce' in transaction") - } - itx.Nonce = uint64(*dec.Nonce) - if dec.To != nil { - itx.To = dec.To - } - if dec.Gas == nil { - return errors.New("missing required field 'gas' for txdata") - } - itx.Gas = uint64(*dec.Gas) - if dec.MaxPriorityFeePerGas == nil { - return errors.New("missing required field 'maxPriorityFeePerGas' for txdata") - } - itx.GasTipCap = (*big.Int)(dec.MaxPriorityFeePerGas) - if dec.MaxFeePerGas == nil { - return errors.New("missing required field 'maxFeePerGas' for txdata") - } - itx.GasFeeCap = (*big.Int)(dec.MaxFeePerGas) - if dec.Value == nil { - return errors.New("missing required field 'value' in transaction") - } - itx.FeeCurrency = dec.FeeCurrency - itx.Value = (*big.Int)(dec.Value) - if dec.Input == nil { - return errors.New("missing required field 'input' in transaction") - } - itx.Data = *dec.Input - if dec.V == nil { - return errors.New("missing required field 'v' in transaction") - } - if dec.AccessList != nil { - itx.AccessList = *dec.AccessList - } - itx.V = (*big.Int)(dec.V) - if dec.R == nil { - return errors.New("missing required field 'r' in transaction") - } - itx.R = (*big.Int)(dec.R) - if dec.S == nil { - return errors.New("missing required field 's' in transaction") - } - itx.S = (*big.Int)(dec.S) - withSignature := itx.V.Sign() != 0 || itx.R.Sign() != 0 || itx.S.Sign() != 0 - if withSignature { - if err := sanityCheckSignature(itx.V, itx.R, itx.S, false); err != nil { - return err - } - } - case BlobTxType: var itx BlobTx inner = &itx diff --git a/core/types/tx_access_list.go b/core/types/tx_access_list.go index 618b3de863..59880b0eab 100644 --- a/core/types/tx_access_list.go +++ b/core/types/tx_access_list.go @@ -128,6 +128,3 @@ func (tx *AccessListTx) encode(b *bytes.Buffer) error { func (tx *AccessListTx) decode(input []byte) error { return rlp.DecodeBytes(input, tx) } - -func (tx *AccessListTx) feeCurrency() *common.Address { return nil } -func (tx *AccessListTx) maxFeeInFeeCurrency() *big.Int { return nil } diff --git a/core/types/tx_blob.go b/core/types/tx_blob.go index 728cb2b952..ceaeedb20d 100644 --- a/core/types/tx_blob.go +++ b/core/types/tx_blob.go @@ -237,6 +237,3 @@ func (tx *BlobTx) decode(input []byte) error { } return nil } - -func (tx *BlobTx) feeCurrency() *common.Address { return nil } -func (tx *BlobTx) maxFeeInFeeCurrency() *big.Int { return nil } diff --git a/core/types/tx_dynamic_fee.go b/core/types/tx_dynamic_fee.go index e23accb299..9c52cde577 100644 --- a/core/types/tx_dynamic_fee.go +++ b/core/types/tx_dynamic_fee.go @@ -124,6 +124,3 @@ func (tx *DynamicFeeTx) encode(b *bytes.Buffer) error { func (tx *DynamicFeeTx) decode(input []byte) error { return rlp.DecodeBytes(input, tx) } - -func (tx *DynamicFeeTx) feeCurrency() *common.Address { return nil } -func (tx *DynamicFeeTx) maxFeeInFeeCurrency() *big.Int { return nil } diff --git a/core/types/tx_legacy.go b/core/types/tx_legacy.go index d1489d5292..a5e30522b8 100644 --- a/core/types/tx_legacy.go +++ b/core/types/tx_legacy.go @@ -25,13 +25,25 @@ import ( // LegacyTx is the transaction data of the original Ethereum transactions. type LegacyTx struct { - Nonce uint64 // nonce of sender account - GasPrice *big.Int // wei per gas - Gas uint64 // gas limit - To *common.Address `rlp:"nil"` // nil means contract creation - Value *big.Int // wei amount - Data []byte // contract invocation input data - V, R, S *big.Int // signature values + Nonce uint64 // nonce of sender account + GasPrice *big.Int // wei per gas + Gas uint64 // gas limit + + // Celo-specific fields + FeeCurrency *common.Address // nil means native currency + GatewayFeeRecipient *common.Address // nil means no gateway fee is paid + GatewayFee *big.Int + + To *common.Address `rlp:"nil"` // nil means contract creation + Value *big.Int // wei amount + Data []byte // contract invocation input data + V, R, S *big.Int // signature values + + // This is only used when marshaling to JSON. + Hash *common.Hash `rlp:"-"` + + // Whether this is a celo legacy transaction (i.e. with FeeCurrency, GatewayFeeRecipient and GatewayFee) + CeloLegacy bool `rlp:"-"` } // NewTransaction creates an unsigned legacy transaction. @@ -124,6 +136,3 @@ func (tx *LegacyTx) encode(*bytes.Buffer) error { func (tx *LegacyTx) decode([]byte) error { panic("decode called on LegacyTx)") } - -func (tx *LegacyTx) feeCurrency() *common.Address { return nil } -func (tx *LegacyTx) maxFeeInFeeCurrency() *big.Int { return nil } diff --git a/internal/ethapi/api.go b/internal/ethapi/api.go index e67fee25f3..3594bccc10 100644 --- a/internal/ethapi/api.go +++ b/internal/ethapi/api.go @@ -1544,7 +1544,7 @@ func newRPCTransaction(tx *types.Transaction, blockHash common.Hash, blockNumber result.ChainID = (*hexutil.Big)(tx.ChainId()) result.YParity = &yparity - case types.DynamicFeeTxType, types.CeloDynamicFeeTxType, types.CeloDenominatedTxType: + case types.DynamicFeeTxType, types.CeloDynamicFeeTxV2Type, types.CeloDenominatedTxType: al := tx.AccessList() yparity := hexutil.Uint64(v.Sign()) result.Accesses = &al diff --git a/internal/ethapi/api_test.go b/internal/ethapi/api_test.go index e8a6449e91..3801d7ac45 100644 --- a/internal/ethapi/api_test.go +++ b/internal/ethapi/api_test.go @@ -2314,7 +2314,7 @@ func TestCeloTransaction_RoundTripRpcJSON(t *testing.T) { } func celoTransactionTypes(addr common.Address, config *params.ChainConfig) []types.TxData { return []types.TxData{ - &types.CeloDynamicFeeTx{ + &types.CeloDynamicFeeTxV2{ ChainID: config.ChainID, Nonce: 5, GasTipCap: big.NewInt(6), @@ -2334,7 +2334,7 @@ func celoTransactionTypes(addr common.Address, config *params.ChainConfig) []typ R: big.NewInt(10), S: big.NewInt(11), }, - &types.CeloDynamicFeeTx{ + &types.CeloDynamicFeeTxV2{ ChainID: config.ChainID, Nonce: 5, GasTipCap: big.NewInt(6), diff --git a/internal/ethapi/transaction_args.go b/internal/ethapi/transaction_args.go index 34148b6959..7758c966bf 100644 --- a/internal/ethapi/transaction_args.go +++ b/internal/ethapi/transaction_args.go @@ -556,7 +556,7 @@ func (args *TransactionArgs) toTransaction() *types.Transaction { } if args.FeeCurrency != nil { if args.IsFeeCurrencyDenominated() { - data = &types.CeloDynamicFeeTx{ + data = &types.CeloDynamicFeeTxV2{ To: args.To, ChainID: (*big.Int)(args.ChainID), Nonce: uint64(*args.Nonce),