diff --git a/core/types/receipt.go b/core/types/receipt.go index 5344814249..6c46d55265 100644 --- a/core/types/receipt.go +++ b/core/types/receipt.go @@ -610,11 +610,17 @@ func (rs Receipts) DeriveFields(config *params.ChainConfig, hash common.Hash, nu rs[i].Type = txs[i].Type() rs[i].TxHash = txs[i].Hash() - // The post transition CeloDynamicFeeV2Txs set the baseFee in the receipt - if rs[i].BaseFee == nil { - 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) + // Pre-gingerbred the base fee was stored in state, but we don't try to recover it here, since A) we don't have + // access to the objects required to get the state and B) retrieving the base fee is quite code heavy and we + // don't want to bring that code across from the celo L1 to op-geth. In the celo L1 we would return a nil base + // fee if the state was not available, so that is what we do here. + if config.IsGingerbread(new(big.Int).SetUint64(number)) { + // The post transition CeloDynamicFeeV2Txs set the baseFee in the receipt + if rs[i].BaseFee == nil { + 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) + } } // EIP-4844 blob transaction fields diff --git a/internal/ethapi/api.go b/internal/ethapi/api.go index b297f2d6d9..d37bc5d3fa 100644 --- a/internal/ethapi/api.go +++ b/internal/ethapi/api.go @@ -1589,7 +1589,7 @@ func newRPCTransaction(tx *types.Transaction, blockHash common.Hash, blockNumber result.ChainID = (*hexutil.Big)(tx.ChainId()) result.YParity = &yparity - case types.DynamicFeeTxType, types.CeloDynamicFeeTxV2Type, types.CeloDenominatedTxType: + case types.DynamicFeeTxType, types.CeloDynamicFeeTxType, types.CeloDynamicFeeTxV2Type, types.CeloDenominatedTxType: al := tx.AccessList() yparity := hexutil.Uint64(v.Sign()) result.Accesses = &al @@ -1597,13 +1597,34 @@ func newRPCTransaction(tx *types.Transaction, blockHash common.Hash, blockNumber result.YParity = &yparity result.GasFeeCap = (*hexutil.Big)(tx.GasFeeCap()) result.GasTipCap = (*hexutil.Big)(tx.GasTipCap()) - // if the transaction has been mined, compute the effective gas price - if receipt != nil { + + // Note that celo denominated txs always have the gas price denominated in celo (the native currency) + isNativeFeeCurrency := tx.FeeCurrency() == nil || tx.Type() == types.CeloDenominatedTxType + isGingerbread := config.IsGingerbread(new(big.Int).SetUint64(blockNumber)) + isCel2 := config.IsCel2(blockTime) + + if blockHash == (common.Hash{}) { + // This is a pending transaction, for pending transactions we set the gas price to gas fee cap. + result.GasPrice = (*hexutil.Big)(tx.GasFeeCap()) + } else if isGingerbread && isNativeFeeCurrency { + // Post gingerbread mined transaction with a native fee currency, we can compute the effective gas price. + result.GasPrice = (*hexutil.Big)(effectiveGasPrice(tx, baseFee)) + } else if isCel2 && tx.Type() == types.CeloDynamicFeeTxV2Type { + // Mined post Cel2 celoDynamicFeeTxV2 transaction, we can get the gas price from the receipt + // Assert that we should have a receipt + if receipt == nil { + panic(fmt.Sprintf("no corresponding receipt provided for celoDynamicFeeTxV2 transaction %s", tx.Hash().Hex())) + } result.GasPrice = (*hexutil.Big)(receipt.EffectiveGasPrice) } else { - result.GasPrice = (*hexutil.Big)(tx.GasFeeCap()) + // Otherwise this is either a: + // - pre-gingerbread transaction + // - post-gingerbread native fee currency transaction but no base fee was provided + // - post-gingerbread pre-cel2 transaction with a non-native fee currency + // + // In these cases we can't calculate the gas price. + result.GasPrice = nil } - case types.BlobTxType: al := tx.AccessList() yparity := hexutil.Uint64(v.Sign()) @@ -1658,12 +1679,12 @@ func newRPCTransactionFromBlockIndex(ctx context.Context, b *types.Block, index return nil } tx := txs[index] - rcpt := depositTxReceipt(ctx, b.Hash(), index, backend, tx) + rcpt := txReceipt(ctx, b.Hash(), index, backend, tx) return newRPCTransaction(tx, b.Hash(), b.NumberU64(), b.Time(), index, b.BaseFee(), config, rcpt) } -func depositTxReceipt(ctx context.Context, blockHash common.Hash, index uint64, backend Backend, tx *types.Transaction) *types.Receipt { - if tx.Type() != types.DepositTxType { +func txReceipt(ctx context.Context, blockHash common.Hash, index uint64, backend Backend, tx *types.Transaction) *types.Receipt { + if tx.Type() != types.DepositTxType && tx.Type() != types.CeloDynamicFeeTxV2Type { return nil } receipts, err := backend.GetReceipts(ctx, blockHash) @@ -1917,7 +1938,7 @@ func (api *TransactionAPI) GetTransactionByHash(ctx context.Context, hash common if err != nil { return nil, err } - rcpt := depositTxReceipt(ctx, blockHash, index, api.b, tx) + rcpt := txReceipt(ctx, blockHash, index, api.b, tx) return newRPCTransaction(tx, blockHash, blockNumber, header.Time, index, header.BaseFee, api.b.ChainConfig(), rcpt), nil } diff --git a/internal/ethapi/celo_api_test.go b/internal/ethapi/celo_api_test.go index 92e14f3687..7cf030547e 100644 --- a/internal/ethapi/celo_api_test.go +++ b/internal/ethapi/celo_api_test.go @@ -28,29 +28,14 @@ var ( transactionIndex uint64 = 15 blockhash = common.HexToHash("0x6ba4a8c1bfe2619eb498e5296e81b1c393b13cba0198ed63dea0ee3aa619b073") blockNumber uint64 = 100 + blockTime uint64 = 100 ) func TestNewRPCTransactionLegacy(t *testing.T) { - // Enable all block based forks so we get the most recent upstream signer. + config := allEnabledChainConfig() + // Set cel2 time to 2000 so that we don't activate the cel2 fork. var cel2Time uint64 = 2000 - config := ¶ms.ChainConfig{ - ChainID: big.NewInt(44787), - EIP150Block: big.NewInt(0), - EIP155Block: big.NewInt(0), - EIP158Block: big.NewInt(0), - ByzantiumBlock: big.NewInt(0), - ConstantinopleBlock: big.NewInt(0), - PetersburgBlock: big.NewInt(0), - IstanbulBlock: big.NewInt(0), - MuirGlacierBlock: big.NewInt(0), - BerlinBlock: big.NewInt(0), - LondonBlock: big.NewInt(0), - Cel2Time: &cel2Time, - } - // Block time is set to before Cel2Time so we don't activate the cel2 fork. - // This gives us the celo legacy signer (legacy transactions are deprecated - // after cel2). - blockTime := uint64(1000) + config.Cel2Time = &cel2Time s := types.MakeSigner(config, new(big.Int).SetUint64(blockNumber), blockTime) key, err := crypto.GenerateKey() @@ -75,31 +60,8 @@ func TestNewRPCTransactionLegacy(t *testing.T) { signed, err := types.SignTx(tx, s, key) require.NoError(t, err) - rpcTx := newRPCTransaction(signed, blockhash, blockNumber, blockTime, transactionIndex, baseFee, config, nil) - - // check newRPCTransaction has the expected fields - // Ethereum fields - checkRPCTransactionFields( - t, - rpcTx, - to, - value, - gasLimit, - gasPrice, - nonce, - config.ChainID, - signed.Hash(), - blockhash, - blockNumber, - transactionIndex, - ) - // Celo fields - assert.Equal(t, feeCurrency, *rpcTx.FeeCurrency) - assert.Equal(t, (*hexutil.Big)(gatewayFee), rpcTx.GatewayFee) - assert.Equal(t, gatewayFeeRecipient, *rpcTx.GatewayFeeRecipient) - assert.Equal(t, false, *rpcTx.EthCompatible) - assert.Nil(t, rpcTx.MaxFeeInFeeCurrency) + checkTxFields(t, signed, rpcTx, s, blockhash, blockNumber, transactionIndex, nil) }) t.Run("WithoutCeloFields", func(t *testing.T) { @@ -115,63 +77,457 @@ func TestNewRPCTransactionLegacy(t *testing.T) { signed, err := types.SignTx(tx, s, key) require.NoError(t, err) rpcTx := newRPCTransaction(signed, blockhash, blockNumber, blockTime, transactionIndex, baseFee, config, nil) + checkTxFields(t, signed, rpcTx, s, blockhash, blockNumber, transactionIndex, nil) + }) +} - // check newRPCTransaction has the expected fields - // Ethereum fields - checkRPCTransactionFields( - t, - rpcTx, - to, - value, - gasLimit, - gasPrice, - nonce, - config.ChainID, - signed.Hash(), - blockhash, - blockNumber, - transactionIndex, - ) - // Celo fields - assert.Nil(t, rpcTx.FeeCurrency) - assert.Nil(t, rpcTx.GatewayFee) - assert.Nil(t, rpcTx.GatewayFeeRecipient) - assert.Nil(t, rpcTx.EthCompatible) - assert.Nil(t, rpcTx.MaxFeeInFeeCurrency) +func TestNewRPCTransactionDynamicFee(t *testing.T) { + key, err := crypto.GenerateKey() + require.NoError(t, err) + feeCap := big.NewInt(1000) + tipCap := big.NewInt(100) + + t.Run("PendingTransactions", func(t *testing.T) { + // For pending transactions we expect the gas price to be the gas fee cap. + gasFeeCap := func(t *testing.T, tx *types.Transaction, rpcTx *RPCTransaction) { + assert.Equal(t, (*hexutil.Big)(feeCap), rpcTx.GasPrice) + } + overrides := map[string]func(*testing.T, *types.Transaction, *RPCTransaction){"gasPrice": gasFeeCap} + config := allEnabledChainConfig() + s := types.MakeSigner(config, new(big.Int).SetUint64(blockNumber), blockTime) + + // An empty bockhash signals pending transactions (I.E no mined block) + blockhash := common.Hash{} + t.Run("DynamicFeeTx", func(t *testing.T) { + tx := types.NewTx(&types.DynamicFeeTx{ + ChainID: config.ChainID, + Nonce: nonce, + Gas: gasLimit, + GasFeeCap: feeCap, + GasTipCap: tipCap, + + To: &to, + Value: value, + Data: []byte{}, + }) + + signed, err := types.SignTx(tx, s, key) + require.NoError(t, err) + + rpcTx := newRPCTransaction(signed, blockhash, blockNumber, blockTime, transactionIndex, baseFee, config, nil) + checkTxFields(t, signed, rpcTx, s, blockhash, blockNumber, transactionIndex, overrides) + }) + + t.Run("CeloDynamicFeeTxV2", func(t *testing.T) { + tx := types.NewTx(&types.CeloDynamicFeeTxV2{ + ChainID: config.ChainID, + Nonce: nonce, + Gas: gasLimit, + GasFeeCap: feeCap, + GasTipCap: tipCap, + FeeCurrency: &feeCurrency, + + To: &to, + Value: value, + Data: []byte{}, + }) + + signed, err := types.SignTx(tx, s, key) + require.NoError(t, err) + + rpcTx := newRPCTransaction(signed, blockhash, blockNumber, blockTime, transactionIndex, baseFee, config, nil) + checkTxFields(t, signed, rpcTx, s, blockhash, blockNumber, transactionIndex, overrides) + }) + }) + + t.Run("PreGingerbreadMinedDynamicTxs", func(t *testing.T) { + nilGasPrice := func(t *testing.T, tx *types.Transaction, rpcTx *RPCTransaction) { + assert.Nil(t, rpcTx.GasPrice) + } + overrides := map[string]func(*testing.T, *types.Transaction, *RPCTransaction){"gasPrice": nilGasPrice} + // For a pre gingerbread mined dynamic txs we expect the gas price to be unset, because without the state we + // cannot retrieve the base fee, and we currently have no implementation in op-geth to handle retrieving the + // base fee from state. + config := allEnabledChainConfig() + config.GingerbreadBlock = big.NewInt(200) // Setup config so that gingerbread is not active. + cel2Time := uint64(1000) + config.Cel2Time = &cel2Time // also deactivate cel2 + s := types.MakeSigner(config, new(big.Int).SetUint64(blockNumber), blockTime) + + t.Run("DynamicFeeTx", func(t *testing.T) { + tx := types.NewTx(&types.DynamicFeeTx{ + ChainID: config.ChainID, + Nonce: nonce, + Gas: gasLimit, + GasFeeCap: feeCap, + GasTipCap: tipCap, + + To: &to, + Value: value, + Data: []byte{}, + }) + + signed, err := types.SignTx(tx, s, key) + require.NoError(t, err) + + rpcTx := newRPCTransaction(signed, blockhash, blockNumber, blockTime, transactionIndex, baseFee, config, nil) + checkTxFields(t, signed, rpcTx, s, blockhash, blockNumber, transactionIndex, overrides) + }) + + t.Run("CeloDynamicFeeTx", func(t *testing.T) { + tx := types.NewTx(&types.CeloDynamicFeeTx{ + ChainID: config.ChainID, + Nonce: nonce, + Gas: gasLimit, + GasFeeCap: feeCap, + GasTipCap: tipCap, + GatewayFee: gatewayFee, + GatewayFeeRecipient: &gatewayFeeRecipient, + + To: &to, + Value: value, + Data: []byte{}, + }) + + signed, err := types.SignTx(tx, s, key) + require.NoError(t, err) + + rpcTx := newRPCTransaction(signed, blockhash, blockNumber, blockTime, transactionIndex, baseFee, config, nil) + checkTxFields(t, signed, rpcTx, s, blockhash, blockNumber, transactionIndex, overrides) + }) + }) + + t.Run("PostGingerbreadMinedDynamicTxsWithNativeFeeCurrency", func(t *testing.T) { + // For a post gingerbread mined dynamic tx with a native fee currency we expect the gas price to be the + // effective gas price calculated with the base fee available on the block. + effectiveGasPrice := func(t *testing.T, tx *types.Transaction, rpcTx *RPCTransaction) { + assert.Equal(t, (*hexutil.Big)(effectiveGasPrice(tx, baseFee)), rpcTx.GasPrice) + } + overrides := map[string]func(*testing.T, *types.Transaction, *RPCTransaction){"gasPrice": effectiveGasPrice} + + config := allEnabledChainConfig() + s := types.MakeSigner(config, new(big.Int).SetUint64(blockNumber), blockTime) + + t.Run("DynamicFeeTx", func(t *testing.T) { + tx := types.NewTx(&types.DynamicFeeTx{ + ChainID: config.ChainID, + Nonce: nonce, + Gas: gasLimit, + GasFeeCap: feeCap, + GasTipCap: tipCap, + + To: &to, + Value: value, + Data: []byte{}, + }) + + signed, err := types.SignTx(tx, s, key) + require.NoError(t, err) + + rpcTx := newRPCTransaction(signed, blockhash, blockNumber, blockTime, transactionIndex, baseFee, config, nil) + checkTxFields(t, signed, rpcTx, s, blockhash, blockNumber, transactionIndex, overrides) + }) + + t.Run("CeloDynamicFeeTx", func(t *testing.T) { + // CeloDynamicFeeTxs are deprecated after cel2 so we need to ensure cel2time is not activated + config := allEnabledChainConfig() + cel2Time := uint64(1000) + config.Cel2Time = &cel2Time + s := types.MakeSigner(config, new(big.Int).SetUint64(blockNumber), blockTime) + + tx := types.NewTx(&types.CeloDynamicFeeTx{ + ChainID: config.ChainID, + Nonce: nonce, + Gas: gasLimit, + GasFeeCap: feeCap, + GasTipCap: tipCap, + GatewayFee: gatewayFee, + GatewayFeeRecipient: &gatewayFeeRecipient, + + To: &to, + Value: value, + Data: []byte{}, + }) + + signed, err := types.SignTx(tx, s, key) + require.NoError(t, err) + + rpcTx := newRPCTransaction(signed, blockhash, blockNumber, blockTime, transactionIndex, baseFee, config, nil) + checkTxFields(t, signed, rpcTx, s, blockhash, blockNumber, transactionIndex, overrides) + }) + + t.Run("CeloDynamicFeeTxV2", func(t *testing.T) { + tx := types.NewTx(&types.CeloDynamicFeeTxV2{ + ChainID: config.ChainID, + Nonce: nonce, + Gas: gasLimit, + GasFeeCap: feeCap, + GasTipCap: tipCap, + + To: &to, + Value: value, + Data: []byte{}, + }) + + signed, err := types.SignTx(tx, s, key) + require.NoError(t, err) + + rpcTx := newRPCTransaction(signed, blockhash, blockNumber, blockTime, transactionIndex, baseFee, config, nil) + checkTxFields(t, signed, rpcTx, s, blockhash, blockNumber, transactionIndex, overrides) + }) + + // TODO unskip this when cip 66 txs are enabled currently they are not supporeted in the celo signer. + t.Run("CeloDenominatedTx", func(t *testing.T) { + t.Skip("CeloDenominatedTx is currently not supported in the celo signer") + tx := types.NewTx(&types.CeloDenominatedTx{ + ChainID: config.ChainID, + Nonce: nonce, + Gas: gasLimit, + GasFeeCap: feeCap, + GasTipCap: tipCap, + FeeCurrency: &feeCurrency, + MaxFeeInFeeCurrency: big.NewInt(100000), + + To: &to, + Value: value, + Data: []byte{}, + }) + + signed, err := types.SignTx(tx, s, key) + require.NoError(t, err) + + rpcTx := newRPCTransaction(signed, blockhash, blockNumber, blockTime, transactionIndex, baseFee, config, nil) + checkTxFields(t, signed, rpcTx, s, blockhash, blockNumber, transactionIndex, overrides) + }) + }) + + t.Run("PostGingerbreadPreCel2MinedDynamicTxsWithNonNativeFeeCurrency", func(t *testing.T) { + // For a post gingerbread mined dynamic txs with a non native fee currency we expect the gas price to be unset, + // because without the state we cannot retrieve the base fee, and we currently have no implementation in op-geth + // to handle retrieving the base fee from state. + + nilGasPrice := func(t *testing.T, tx *types.Transaction, rpcTx *RPCTransaction) { + assert.Nil(t, rpcTx.GasPrice) + } + overrides := map[string]func(*testing.T, *types.Transaction, *RPCTransaction){"gasPrice": nilGasPrice} + + config := allEnabledChainConfig() + cel2Time := uint64(1000) + config.Cel2Time = &cel2Time // Deactivate cel2 + s := types.MakeSigner(config, new(big.Int).SetUint64(blockNumber), blockTime) + + t.Run("CeloDynamicFeeTx", func(t *testing.T) { + // CeloDynamicFeeTxs are deprecated after cel2 so we need to ensure cel2time is not activated + config := allEnabledChainConfig() + cel2Time := uint64(1000) + config.Cel2Time = &cel2Time + s := types.MakeSigner(config, new(big.Int).SetUint64(blockNumber), blockTime) + + tx := types.NewTx(&types.CeloDynamicFeeTx{ + ChainID: config.ChainID, + Nonce: nonce, + Gas: gasLimit, + GasFeeCap: feeCap, + GasTipCap: tipCap, + FeeCurrency: &feeCurrency, + GatewayFee: gatewayFee, + GatewayFeeRecipient: &gatewayFeeRecipient, + + To: &to, + Value: value, + Data: []byte{}, + }) + + signed, err := types.SignTx(tx, s, key) + require.NoError(t, err) + + rpcTx := newRPCTransaction(signed, blockhash, blockNumber, blockTime, transactionIndex, baseFee, config, nil) + checkTxFields(t, signed, rpcTx, s, blockhash, blockNumber, transactionIndex, overrides) + }) + + t.Run("CeloDynamicFeeTxV2", func(t *testing.T) { + tx := types.NewTx(&types.CeloDynamicFeeTxV2{ + ChainID: config.ChainID, + Nonce: nonce, + Gas: gasLimit, + GasFeeCap: feeCap, + GasTipCap: tipCap, + FeeCurrency: &feeCurrency, + + To: &to, + Value: value, + Data: []byte{}, + }) + + signed, err := types.SignTx(tx, s, key) + require.NoError(t, err) + + rpcTx := newRPCTransaction(signed, blockhash, blockNumber, blockTime, transactionIndex, baseFee, config, nil) + checkTxFields(t, signed, rpcTx, s, blockhash, blockNumber, transactionIndex, overrides) + }) + }) + + t.Run("PostCel2MinedDynamicTxs", func(t *testing.T) { + receipt := &types.Receipt{} + receipt.EffectiveGasPrice = big.NewInt(1234) + effectiveGasPrice := func(t *testing.T, tx *types.Transaction, rpcTx *RPCTransaction) { + assert.Equal(t, (*hexutil.Big)(receipt.EffectiveGasPrice), rpcTx.GasPrice) + } + overrides := map[string]func(*testing.T, *types.Transaction, *RPCTransaction){"gasPrice": effectiveGasPrice} + + config := allEnabledChainConfig() + s := types.MakeSigner(config, new(big.Int).SetUint64(blockNumber), blockTime) + + t.Run("CeloDynamicFeeTxV2", func(t *testing.T) { + // For a pre gingerbread mined dynamic fee tx we expect the gas price to be unset. + tx := types.NewTx(&types.CeloDynamicFeeTxV2{ + ChainID: config.ChainID, + Nonce: nonce, + Gas: gasLimit, + GasFeeCap: feeCap, + GasTipCap: tipCap, + FeeCurrency: &feeCurrency, + + To: &to, + Value: value, + Data: []byte{}, + }) + + signed, err := types.SignTx(tx, s, key) + require.NoError(t, err) + + rpcTx := newRPCTransaction(signed, blockhash, blockNumber, blockTime, transactionIndex, baseFee, config, receipt) + checkTxFields(t, signed, rpcTx, s, blockhash, blockNumber, transactionIndex, overrides) + }) }) } -func checkRPCTransactionFields( +func allEnabledChainConfig() *params.ChainConfig { + zeroTime := uint64(0) + return ¶ms.ChainConfig{ + ChainID: big.NewInt(44787), + HomesteadBlock: big.NewInt(0), + EIP150Block: big.NewInt(0), + EIP155Block: big.NewInt(0), + EIP158Block: big.NewInt(0), + ByzantiumBlock: big.NewInt(0), + ConstantinopleBlock: big.NewInt(0), + PetersburgBlock: big.NewInt(0), + IstanbulBlock: big.NewInt(0), + MuirGlacierBlock: big.NewInt(0), + BerlinBlock: big.NewInt(0), + LondonBlock: big.NewInt(0), + ArrowGlacierBlock: big.NewInt(0), + GrayGlacierBlock: big.NewInt(0), + ShanghaiTime: &zeroTime, + CancunTime: &zeroTime, + RegolithTime: &zeroTime, + CanyonTime: &zeroTime, + EcotoneTime: &zeroTime, + FjordTime: &zeroTime, + Cel2Time: &zeroTime, + GingerbreadBlock: big.NewInt(0), + } +} + +// checkTxFields for the most part checks that the fields of the rpcTx match those of the provided tx, it allows for +// overriding some checks by providing a map of fieldName -> overrideFunc. +func checkTxFields( t *testing.T, + tx *types.Transaction, rpcTx *RPCTransaction, - to common.Address, - value *big.Int, - gasLimit uint64, - gasPrice *big.Int, - nonce uint64, - chainID *big.Int, - hash common.Hash, + signer types.Signer, blockhash common.Hash, blockNumber uint64, transactionIndex uint64, + overrides map[string]func(*testing.T, *types.Transaction, *RPCTransaction), ) { - assert.Equal(t, to, *rpcTx.To) - assert.Equal(t, (*hexutil.Big)(value), rpcTx.Value) - assert.Equal(t, hexutil.Bytes{}, rpcTx.Input) - assert.Equal(t, hexutil.Uint64(gasLimit), rpcTx.Gas) - assert.Equal(t, (*hexutil.Big)(gasPrice), rpcTx.GasPrice) - assert.Equal(t, hash, rpcTx.Hash) - assert.Equal(t, hexutil.Uint64(nonce), rpcTx.Nonce) - assert.Equal(t, (*hexutil.Big)(chainID), rpcTx.ChainID) - assert.Equal(t, hexutil.Uint64(types.LegacyTxType), rpcTx.Type) - assert.Nil(t, rpcTx.Accesses) - assert.Nil(t, rpcTx.GasFeeCap) - assert.Nil(t, rpcTx.GasTipCap) - assert.Nil(t, rpcTx.MaxFeePerBlobGas) - assert.Equal(t, []common.Hash(nil), rpcTx.BlobVersionedHashes) - // Added fields (not part of the transaction type) - assert.Equal(t, &blockhash, rpcTx.BlockHash) - assert.Equal(t, (*hexutil.Big)(big.NewInt(int64(blockNumber))), rpcTx.BlockNumber) - assert.Equal(t, hexutil.Uint64(transactionIndex), *rpcTx.TransactionIndex) + // + // If blockhash is empty it signifies a pending tx and for pending txs the block hash, block number and tx index are + // not set on the rpcTx. on the result. + if blockhash == (common.Hash{}) { + assert.Nil(t, rpcTx.BlockHash) + assert.Nil(t, rpcTx.BlockNumber) + assert.Nil(t, rpcTx.TransactionIndex) + } else { + assert.Equal(t, &blockhash, rpcTx.BlockHash) + assert.Equal(t, (*hexutil.Big)(big.NewInt(int64(blockNumber))), rpcTx.BlockNumber) + assert.Equal(t, hexutil.Uint64(transactionIndex), *rpcTx.TransactionIndex) + } + + from, err := types.Sender(signer, tx) + require.NoError(t, err) + + assert.Equal(t, from, rpcTx.From) + assert.Equal(t, hexutil.Uint64(tx.Gas()), rpcTx.Gas) + assert.Equal(t, tx.To(), rpcTx.To) + override, ok := overrides["gasPrice"] + if ok { + override(t, tx, rpcTx) + } else { + assert.Equal(t, (*hexutil.Big)(tx.GasPrice()), rpcTx.GasPrice) + } + switch tx.Type() { + case types.DynamicFeeTxType, types.CeloDynamicFeeTxType, types.CeloDynamicFeeTxV2Type, types.CeloDenominatedTxType: + assert.Equal(t, (*hexutil.Big)(tx.GasFeeCap()), rpcTx.GasFeeCap) + assert.Equal(t, (*hexutil.Big)(tx.GasTipCap()), rpcTx.GasTipCap) + default: + assert.Nil(t, rpcTx.GasFeeCap) + assert.Nil(t, rpcTx.GasTipCap) + } + assert.Equal(t, (*hexutil.Big)(tx.BlobGasFeeCap()), rpcTx.MaxFeePerBlobGas) + assert.Equal(t, tx.Hash(), rpcTx.Hash) + assert.Equal(t, (hexutil.Bytes)(tx.Data()), rpcTx.Input) + assert.Equal(t, hexutil.Uint64(tx.Nonce()), rpcTx.Nonce) + assert.Equal(t, tx.To(), rpcTx.To) + assert.Equal(t, (*hexutil.Big)(tx.Value()), rpcTx.Value) + assert.Equal(t, hexutil.Uint64(tx.Type()), rpcTx.Type) + switch tx.Type() { + case types.AccessListTxType, types.DynamicFeeTxType, types.CeloDynamicFeeTxType, types.CeloDynamicFeeTxV2Type, types.CeloDenominatedTxType, types.BlobTxType: + assert.Equal(t, tx.AccessList(), *rpcTx.Accesses) + default: + assert.Nil(t, rpcTx.Accesses) + } + + assert.Equal(t, (*hexutil.Big)(tx.ChainId()), rpcTx.ChainID) + assert.Equal(t, tx.BlobHashes(), rpcTx.BlobVersionedHashes) + + v, r, s := tx.RawSignatureValues() + assert.Equal(t, (*hexutil.Big)(v), rpcTx.V) + assert.Equal(t, (*hexutil.Big)(r), rpcTx.R) + assert.Equal(t, (*hexutil.Big)(s), rpcTx.S) + + switch tx.Type() { + case types.AccessListTxType, types.DynamicFeeTxType, types.CeloDynamicFeeTxType, types.CeloDynamicFeeTxV2Type, types.CeloDenominatedTxType, types.BlobTxType: + yparity := (hexutil.Uint64)(v.Sign()) + assert.Equal(t, &yparity, rpcTx.YParity) + default: + assert.Nil(t, rpcTx.YParity) + } + + // optimism fields + switch tx.Type() { + case types.DepositTxType: + assert.Equal(t, tx.SourceHash(), rpcTx.SourceHash) + assert.Equal(t, tx.Mint(), rpcTx.Mint) + assert.Equal(t, tx.IsSystemTx(), rpcTx.IsSystemTx) + default: + assert.Nil(t, rpcTx.SourceHash) + assert.Nil(t, rpcTx.Mint) + assert.Nil(t, rpcTx.IsSystemTx) + } + + assert.Nil(t, rpcTx.DepositReceiptVersion) + + // celo fields + assert.Equal(t, tx.FeeCurrency(), rpcTx.FeeCurrency) + assert.Equal(t, (*hexutil.Big)(tx.MaxFeeInFeeCurrency()), rpcTx.MaxFeeInFeeCurrency) + if tx.Type() == types.LegacyTxType && tx.IsCeloLegacy() { + assert.Equal(t, false, *rpcTx.EthCompatible) + } else { + assert.Nil(t, rpcTx.EthCompatible) + } + assert.Equal(t, (*hexutil.Big)(tx.GatewayFee()), rpcTx.GatewayFee) + assert.Equal(t, tx.GatewayFeeRecipient(), rpcTx.GatewayFeeRecipient) } diff --git a/params/config.go b/params/config.go index bef0b6b0f3..094147eb7b 100644 --- a/params/config.go +++ b/params/config.go @@ -270,6 +270,7 @@ var ( CancunTime: nil, PragueTime: nil, VerkleTime: nil, + GingerbreadBlock: big.NewInt(0), Cel2Time: newUint64(0), TerminalTotalDifficulty: nil, TerminalTotalDifficultyPassed: false, @@ -328,6 +329,7 @@ var ( ArrowGlacierBlock: big.NewInt(0), GrayGlacierBlock: big.NewInt(0), MergeNetsplitBlock: big.NewInt(0), + GingerbreadBlock: big.NewInt(0), ShanghaiTime: newUint64(0), CancunTime: newUint64(0), PragueTime: nil,