diff --git a/src/Nethermind/Nethermind.Core.Test/Json/NullableTxTypeConverterTests.cs b/src/Nethermind/Nethermind.Core.Test/Json/NullableTxTypeConverterTests.cs
new file mode 100644
index 00000000000..fb1ebab3ce9
--- /dev/null
+++ b/src/Nethermind/Nethermind.Core.Test/Json/NullableTxTypeConverterTests.cs
@@ -0,0 +1,39 @@
+// Copyright (c) 2021 Demerzel Solutions Limited
+// This file is part of the Nethermind library.
+//
+// The Nethermind 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 Nethermind 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 Nethermind. If not, see .
+//
+
+using Nethermind.Serialization.Json;
+using NUnit.Framework;
+
+namespace Nethermind.Core.Test.Json
+{
+ [TestFixture]
+ public class NullableTxTypeConverterTests : ConverterTestBase
+ {
+ [TestCase(null)]
+ [TestCase((TxType)0)]
+ [TestCase((TxType)15)]
+ [TestCase((TxType)16)]
+ [TestCase((TxType)255)]
+ [TestCase(TxType.Legacy)]
+ [TestCase(TxType.AccessList)]
+ [TestCase(TxType.EIP1559)]
+ public void Test_roundtrip(TxType? arg)
+ {
+ TestConverter(arg, (before, after) => before.Equals(after), new NullableTxTypeConverter());
+ }
+ }
+}
diff --git a/src/Nethermind/Nethermind.Core.Test/Json/TxTypeConverterTests.cs b/src/Nethermind/Nethermind.Core.Test/Json/TxTypeConverterTests.cs
index e8591b04d4b..5472fd95e7d 100644
--- a/src/Nethermind/Nethermind.Core.Test/Json/TxTypeConverterTests.cs
+++ b/src/Nethermind/Nethermind.Core.Test/Json/TxTypeConverterTests.cs
@@ -30,6 +30,7 @@ public class TxTypeConverterTests : ConverterTestBase
[TestCase((TxType)255)]
[TestCase(TxType.Legacy)]
[TestCase(TxType.AccessList)]
+ [TestCase(TxType.EIP1559)]
public void Test_roundtrip(TxType arg)
{
TestConverter(arg, (before, after) => before.Equals(after), new TxTypeConverter());
diff --git a/src/Nethermind/Nethermind.Evm/TransactionProcessing/TransactionProcessor.cs b/src/Nethermind/Nethermind.Evm/TransactionProcessing/TransactionProcessor.cs
index a4ee12a276f..ef0aed1016f 100644
--- a/src/Nethermind/Nethermind.Evm/TransactionProcessing/TransactionProcessor.cs
+++ b/src/Nethermind/Nethermind.Evm/TransactionProcessing/TransactionProcessor.cs
@@ -67,7 +67,17 @@ private enum ExecutionOptions
///
/// Commit and later restore state also skip validation, use for CallAndRestore
///
- CommitAndRestore = Commit | Restore | NoValidation
+ CommitAndRestore = Commit | Restore | NoValidation,
+
+ ///
+ /// Zero Gas price
+ ///
+ SkipGasPricingValidation = 8,
+
+ ///
+ /// Commit and restore with zero gas price
+ ///
+ CommitAndRestoreWithSkippingGasPricingValidation = CommitAndRestore | SkipGasPricingValidation
}
public TransactionProcessor(
@@ -95,7 +105,14 @@ public TransactionProcessor(
public void CallAndRestore(Transaction transaction, BlockHeader block, ITxTracer txTracer)
{
- Execute(transaction, block, txTracer, ExecutionOptions.CommitAndRestore);
+ bool skipGasPricing = _specProvider.GetSpec(block.Number).IsEip1559Enabled
+ ? (transaction.IsEip1559
+ ? (transaction.MaxFeePerGas.IsZero && transaction.MaxPriorityFeePerGas.IsZero)
+ : transaction.GasPrice.IsZero)
+ : transaction.GasPrice.IsZero;
+
+ Execute(transaction, block, txTracer,
+ skipGasPricing ? ExecutionOptions.CommitAndRestoreWithSkippingGasPricingValidation : ExecutionOptions.CommitAndRestore);
}
public void BuildUp(Transaction transaction, BlockHeader block, ITxTracer txTracer)
@@ -116,25 +133,51 @@ public void Trace(Transaction transaction, BlockHeader block, ITxTracer txTracer
Execute(transaction, block, txTracer, ExecutionOptions.NoValidation);
}
- private void QuickFail(Transaction tx, BlockHeader block, ITxTracer txTracer, bool eip658NotEnabled,
- string? reason)
+ private void QuickFail(Transaction tx, BlockHeader block, ITxTracer txTracer, bool eip658NotEnabled, string? reason, bool deleteCallerAccount = false)
{
- block.GasUsed += tx.GasLimit;
-
- Address recipient = tx.To ?? ContractAddress.From(
- tx.SenderAddress ?? Address.Zero,
- _stateProvider.GetNonce(tx.SenderAddress ?? Address.Zero));
+ try
+ {
+ // block.GasUsed += tx.GasLimit;
+ //
+ // Address recipient = tx.To ?? ContractAddress.From(
+ // tx.SenderAddress ?? Address.Zero,
+ // _stateProvider.GetNonce(tx.SenderAddress ?? Address.Zero));
+ //
+ // if (txTracer.IsTracingReceipt)
+ // {
+ // Keccak? stateRoot = null;
+ // if (eip658NotEnabled)
+ // {
+ // _stateProvider.RecalculateStateRoot();
+ // stateRoot = _stateProvider.StateRoot;
+ // }
+ //
+ // txTracer.MarkAsFailed(recipient, tx.GasLimit, Array.Empty(), reason ?? "invalid", stateRoot);
+
+ block.GasUsed += tx.GasLimit;
+
+ Address recipient = tx.To ?? ContractAddress.From(
+ tx.SenderAddress ?? Address.Zero,
+ _stateProvider.GetNonce(tx.SenderAddress ?? Address.Zero));
+
+ if (txTracer.IsTracingReceipt)
+ {
+ Keccak? stateRoot = null;
+ if (eip658NotEnabled)
+ {
+ _stateProvider.RecalculateStateRoot();
+ stateRoot = _stateProvider.StateRoot;
+ }
- if (txTracer.IsTracingReceipt)
+ txTracer.MarkAsFailed(recipient, tx.GasLimit, Array.Empty(), reason ?? "invalid", stateRoot);
+ }
+ }
+ finally
{
- Keccak? stateRoot = null;
- if (eip658NotEnabled)
+ if (deleteCallerAccount)
{
- _stateProvider.RecalculateStateRoot();
- stateRoot = _stateProvider.StateRoot;
+ _stateProvider.DeleteAccount(tx.SenderAddress ?? throw new InvalidOperationException());
}
-
- txTracer.MarkAsFailed(recipient, tx.GasLimit, Array.Empty(), reason ?? "invalid", stateRoot);
}
}
@@ -144,12 +187,16 @@ private void Execute(Transaction transaction, BlockHeader block, ITxTracer txTra
bool eip658NotEnabled = !_specProvider.GetSpec(block.Number).IsEip658Enabled;
// restore is CallAndRestore - previous call, we will restore state after the execution
+ //bool restore = (executionOptions & ExecutionOptions.Restore) != ExecutionOptions.None;
bool restore = (executionOptions & ExecutionOptions.Restore) == ExecutionOptions.Restore;
bool noValidation = (executionOptions & ExecutionOptions.NoValidation) == ExecutionOptions.NoValidation;
// commit - is for standard execute, we will commit thee state after execution
bool commit = (executionOptions & ExecutionOptions.Commit) == ExecutionOptions.Commit || eip658NotEnabled;
//!commit - is for build up during block production, we won't commit state after each transaction to support rollbacks
- //we commit only after all block is constructed
+ //we commit only after all block is constructed
+
+ bool skipGasPricing = (executionOptions & ExecutionOptions.SkipGasPricingValidation) == ExecutionOptions.SkipGasPricingValidation;
+
bool notSystemTransaction = !transaction.IsSystem();
bool deleteCallerAccount = false;
@@ -161,10 +208,26 @@ private void Execute(Transaction transaction, BlockHeader block, ITxTracer txTra
UInt256 value = transaction.Value;
- if (!transaction.TryCalculatePremiumPerGas(block.BaseFeePerGas, out UInt256 premiumPerGas) && !noValidation)
+ // if (!transaction.TryCalculatePremiumPerGas(block.BaseFeePerGas, out UInt256 premiumPerGas) && !noValidation)
+ // {
+ // TraceLogInvalidTx(transaction, "MINER_PREMIUM_IS_NEGATIVE");
+ // QuickFail(transaction, block, txTracer, eip658NotEnabled, "miner premium is negative");
+ // return;
+ // }
+ if (!skipGasPricing && restore && transaction.MaxPriorityFeePerGas > transaction.MaxFeePerGas)
+ {
+ TraceLogInvalidTx(transaction, "MAX PRIORITY FEE PER GAS HIGHER THAN MAX FEE PER GAS");
+ QuickFail(transaction, block, txTracer, eip658NotEnabled,
+ $"max priority fee per gas higher than max fee per gas: address {transaction.SenderAddress}, maxPriorityFeePerGas: {transaction.MaxPriorityFeePerGas}, maxFeePerGas: {transaction.MaxFeePerGas}");
+ return;
+ }
+
+ if (!transaction.TryCalculatePremiumPerGas(block.BaseFeePerGas, out UInt256 premiumPerGas) && !skipGasPricing && !restore)
{
- TraceLogInvalidTx(transaction, "MINER_PREMIUM_IS_NEGATIVE");
- QuickFail(transaction, block, txTracer, eip658NotEnabled, "miner premium is negative");
+ // max fee per gas (feeCap) less than block base fee
+ TraceLogInvalidTx(transaction, "MAX FEE PER GAS LESS THAN BLOCK BASE FEE");
+ QuickFail(transaction, block, txTracer, eip658NotEnabled,
+ $"max fee per gas less than block base fee: address {transaction.SenderAddress}, maxFeePerGas: {transaction.MaxFeePerGas}, baseFee {block.BaseFeePerGas}");
return;
}
@@ -200,15 +263,16 @@ private void Execute(Transaction transaction, BlockHeader block, ITxTracer txTra
if (gasLimit < intrinsicGas)
{
TraceLogInvalidTx(transaction, $"GAS_LIMIT_BELOW_INTRINSIC_GAS {gasLimit} < {intrinsicGas}");
- QuickFail(transaction, block, txTracer, eip658NotEnabled, "gas limit below intrinsic gas");
+ QuickFail(transaction, block, txTracer, eip658NotEnabled, $"gas limit below intrinsic gas: have {gasLimit}, want {intrinsicGas}");
return;
}
+ // if (!restore && gasLimit > block.GasLimit - block.GasUsed)
if (!noValidation && gasLimit > block.GasLimit - block.GasUsed)
{
TraceLogInvalidTx(transaction,
$"BLOCK_GAS_LIMIT_EXCEEDED {gasLimit} > {block.GasLimit} - {block.GasUsed}");
- QuickFail(transaction, block, txTracer, eip658NotEnabled, "block gas limit exceeded");
+ QuickFail(transaction, block, txTracer, eip658NotEnabled, $"block gas limit exceeded: gasLimit {gasLimit} > block gasLimit {block.GasLimit} - block gasUsed {block.GasUsed}");
return;
}
}
@@ -231,6 +295,7 @@ private void Execute(Transaction transaction, BlockHeader block, ITxTracer txTra
else
{
TraceLogInvalidTx(transaction, $"SENDER_ACCOUNT_DOES_NOT_EXIST {caller}");
+ // if (!commit || restore || effectiveGasPrice == UInt256.Zero)
if (!commit || noValidation || effectiveGasPrice == UInt256.Zero)
{
deleteCallerAccount = !commit || restore;
@@ -244,36 +309,45 @@ private void Execute(Transaction transaction, BlockHeader block, ITxTracer txTra
$"Failed to recover sender address on tx {transaction.Hash} when previously recovered sender account did not exist.");
}
}
+ UInt256 senderReservedGasPayment = skipGasPricing ? UInt256.Zero : (ulong) gasLimit * effectiveGasPrice;
- UInt256 senderReservedGasPayment = noValidation ? UInt256.Zero : (ulong)gasLimit * effectiveGasPrice;
+ // UInt256 senderReservedGasPayment = noValidation ? UInt256.Zero : (ulong)gasLimit * effectiveGasPrice;
if (notSystemTransaction)
{
UInt256 senderBalance = _stateProvider.GetBalance(caller);
- if (!noValidation && ((ulong)intrinsicGas * effectiveGasPrice + value > senderBalance ||
- senderReservedGasPayment + value > senderBalance))
+ // if (!noValidation && ((ulong)intrinsicGas * effectiveGasPrice + value > senderBalance ||
+ // senderReservedGasPayment + value > senderBalance))
+ if (!skipGasPricing && ((ulong) intrinsicGas * effectiveGasPrice + value > senderBalance || senderReservedGasPayment + value > senderBalance))
{
- TraceLogInvalidTx(transaction,
- $"INSUFFICIENT_SENDER_BALANCE: ({caller})_BALANCE = {senderBalance}");
- QuickFail(transaction, block, txTracer, eip658NotEnabled, "insufficient sender balance");
+ // TraceLogInvalidTx(transaction,
+ // $"INSUFFICIENT_SENDER_BALANCE: ({caller})_BALANCE = {senderBalance}");
+ // QuickFail(transaction, block, txTracer, eip658NotEnabled, "insufficient sender balance");
+ TraceLogInvalidTx(transaction, $"INSUFFICIENT_SENDER_BALANCE: ({caller})_BALANCE = {senderBalance}");
+ QuickFail(transaction, block, txTracer, eip658NotEnabled, $"insufficient funds for gas * price + value: address {caller}, have {senderBalance}, want {senderReservedGasPayment + value}", deleteCallerAccount && restore);
return;
}
- if (!noValidation && spec.IsEip1559Enabled && !transaction.IsFree() &&
- senderBalance < (UInt256)transaction.GasLimit * transaction.MaxFeePerGas + value)
+ // if (!noValidation && spec.IsEip1559Enabled && !transaction.IsFree() &&
+ // senderBalance < (UInt256)transaction.GasLimit * transaction.MaxFeePerGas + value)
+ if (!skipGasPricing && spec.IsEip1559Enabled && !transaction.IsServiceTransaction && senderBalance < (UInt256)transaction.GasLimit * transaction.MaxFeePerGas + value)
{
- TraceLogInvalidTx(transaction,
- $"INSUFFICIENT_MAX_FEE_PER_GAS_FOR_SENDER_BALANCE: ({caller})_BALANCE = {senderBalance}, MAX_FEE_PER_GAS: {transaction.MaxFeePerGas}");
- QuickFail(transaction, block, txTracer, eip658NotEnabled,
- "insufficient MaxFeePerGas for sender balance");
+ // TraceLogInvalidTx(transaction,
+ // $"INSUFFICIENT_MAX_FEE_PER_GAS_FOR_SENDER_BALANCE: ({caller})_BALANCE = {senderBalance}, MAX_FEE_PER_GAS: {transaction.MaxFeePerGas}");
+ // QuickFail(transaction, block, txTracer, eip658NotEnabled,
+ // "insufficient MaxFeePerGas for sender balance");
+ TraceLogInvalidTx(transaction, $"INSUFFICIENT_MAX_FEE_PER_GAS_FOR_SENDER_BALANCE: ({caller})_BALANCE = {senderBalance}, MAX_FEE_PER_GAS: {transaction.MaxFeePerGas}");
+ QuickFail(transaction, block, txTracer, eip658NotEnabled, $"insufficient MaxFeePerGas for sender balance: address {{caller}}, sender_balance = {senderBalance}, maxFeePerGas: {transaction.MaxFeePerGas}", deleteCallerAccount && restore);
return;
}
if (transaction.Nonce != _stateProvider.GetNonce(caller))
{
- TraceLogInvalidTx(transaction,
- $"WRONG_TRANSACTION_NONCE: {transaction.Nonce} (expected {_stateProvider.GetNonce(caller)})");
- QuickFail(transaction, block, txTracer, eip658NotEnabled, "wrong transaction nonce");
+ // TraceLogInvalidTx(transaction,
+ // $"WRONG_TRANSACTION_NONCE: {transaction.Nonce} (expected {_stateProvider.GetNonce(caller)})");
+ // QuickFail(transaction, block, txTracer, eip658NotEnabled, "wrong transaction nonce");
+ TraceLogInvalidTx(transaction, $"WRONG_TRANSACTION_NONCE: {transaction.Nonce} (expected {_stateProvider.GetNonce(caller)})");
+ QuickFail(transaction, block, txTracer, eip658NotEnabled, "wrong transaction nonce", deleteCallerAccount && restore);
return;
}
@@ -358,7 +432,7 @@ private void Execute(Transaction transaction, BlockHeader block, ITxTracer txTra
}
else
{
- // tks: there is similar code fo contract creation from init and from CREATE
+ // tks: there is similar code for contract creation from init and from CREATE
// this may lead to inconsistencies (however it is tested extensively in blockchain tests)
if (transaction.IsContractCreation)
{
diff --git a/src/Nethermind/Nethermind.JsonRpc.Test/Data/Eip2930Tests.cs b/src/Nethermind/Nethermind.JsonRpc.Test/Data/Eip2930Tests.cs
index 45d3ff80df7..0fa47781946 100644
--- a/src/Nethermind/Nethermind.JsonRpc.Test/Data/Eip2930Tests.cs
+++ b/src/Nethermind/Nethermind.JsonRpc.Test/Data/Eip2930Tests.cs
@@ -180,8 +180,8 @@ public void can_deserialize_not_provided_txType()
{
_transactionForRpc = _serializer.Deserialize("{\"nonce\":\"0x0\",\"blockHash\":null,\"blockNumber\":null,\"transactionIndex\":null,\"to\":null,\"value\":\"0x0\",\"gasPrice\":\"0x0\",\"gas\":\"0x0\",\"input\":null}");
- // if there is not TxType provided, default value should be TxType.Legacy equal 0
- _transactionForRpc.Type.Should().Be(0);
+ // if there is not TxType provided, default value should be null
+ _transactionForRpc.Type.Should().Be(null);
}
[Test]
@@ -189,8 +189,8 @@ public void can_deserialize_direct_null_txType()
{
_transactionForRpc = _serializer.Deserialize("{\"nonce\":\"0x0\",\"blockHash\":null,\"blockNumber\":null,\"transactionIndex\":null,\"to\":null,\"value\":\"0x0\",\"gasPrice\":\"0x0\",\"gas\":\"0x0\",\"input\":null,\"type\":null}");
- // if there is null TxType provided, still default value should be TxType.Legacy equal 0
- _transactionForRpc.Type.Should().Be(0);
+ // if there is null TxType provided, still default value should be null
+ _transactionForRpc.Type.Should().Be(null);
}
[Test]
diff --git a/src/Nethermind/Nethermind.JsonRpc.Test/Modules/Eth/EthRpcModuleTests.EstimateGas.cs b/src/Nethermind/Nethermind.JsonRpc.Test/Modules/Eth/EthRpcModuleTests.EstimateGas.cs
index 382553fc325..8c4b4bb9247 100644
--- a/src/Nethermind/Nethermind.JsonRpc.Test/Modules/Eth/EthRpcModuleTests.EstimateGas.cs
+++ b/src/Nethermind/Nethermind.JsonRpc.Test/Modules/Eth/EthRpcModuleTests.EstimateGas.cs
@@ -36,13 +36,35 @@ namespace Nethermind.JsonRpc.Test.Modules.Eth
public partial class EthRpcModuleTests
{
[Test]
- public async Task Eth_estimateGas_web3_should_return_insufficient_balance_error()
+ [TestCase("")]
+ [TestCase("\"type\":null, ")]
+ [TestCase("\"type\":\"0x0\", ")]
+ public async Task Eth_estimateGas_web3_should_return_insufficient_balance_error(string type)
{
using Context ctx = await Context.Create();
Address someAccount = new("0x0001020304050607080910111213141516171819");
ctx._test.ReadOnlyState.AccountExists(someAccount).Should().BeFalse();
TransactionForRpc transaction = ctx._test.JsonSerializer.Deserialize(
- "{\"from\":\"0x0001020304050607080910111213141516171819\",\"gasPrice\":\"0x100000\", \"data\": \"0x70a082310000000000000000000000006c1f09f6271fbe133db38db9c9280307f5d22160\", \"to\": \"0x0d8775f648430679a709e98d2b0cb6250d2887ef\", \"value\": 500}");
+ "{" + type + "\"from\":\"0x0001020304050607080910111213141516171819\",\"gasPrice\":\"0x100000\", \"data\": \"0x70a082310000000000000000000000006c1f09f6271fbe133db38db9c9280307f5d22160\", \"to\": \"0x0d8775f648430679a709e98d2b0cb6250d2887ef\", \"value\": 500}");
+ string serialized =
+ ctx._test.TestEthRpc("eth_estimateGas", ctx._test.JsonSerializer.Serialize(transaction));
+ Assert.AreEqual(
+ "{\"jsonrpc\":\"2.0\",\"error\":{\"code\":-32015,\"message\":\"insufficient funds for gas * price + value: address 0x0001020304050607080910111213141516171819, have 0, want 26214400000500\"},\"id\":67}",
+ serialized);
+ ctx._test.ReadOnlyState.AccountExists(someAccount).Should().BeFalse();
+ }
+
+ [Test]
+ [TestCase("")]
+ [TestCase("\"type\":null, ")]
+ [TestCase("\"type\":\"0x0\", ")]
+ public async Task Eth_estimateGas_web3_without_gas_pricing(string type)
+ {
+ using Context ctx = await Context.Create();
+ Address someAccount = new("0x0001020304050607080910111213141516171819");
+ ctx._test.ReadOnlyState.AccountExists(someAccount).Should().BeFalse();
+ TransactionForRpc transaction = ctx._test.JsonSerializer.Deserialize(
+ "{" + type + "\"from\":\"0x0001020304050607080910111213141516171819\", \"data\": \"0x70a082310000000000000000000000006c1f09f6271fbe133db38db9c9280307f5d22160\", \"to\": \"0x0d8775f648430679a709e98d2b0cb6250d2887ef\", \"value\": 500}");
string serialized =
ctx._test.TestEthRpc("eth_estimateGas", ctx._test.JsonSerializer.Serialize(transaction));
Assert.AreEqual(
@@ -50,46 +72,83 @@ public async Task Eth_estimateGas_web3_should_return_insufficient_balance_error(
serialized);
ctx._test.ReadOnlyState.AccountExists(someAccount).Should().BeFalse();
}
+
+ [Test]
+ [TestCase("")]
+ [TestCase("\"type\":null, ")]
+ [TestCase("\"type\":\"0x0\", ")]
+ public async Task Eth_estimateGas_web3_without_gas_pricing_and_value(string type)
+ {
+ using Context ctx = await Context.Create();
+ Address someAccount = new("0x0001020304050607080910111213141516171819");
+ ctx._test.ReadOnlyState.AccountExists(someAccount).Should().BeFalse();
+ TransactionForRpc transaction = ctx._test.JsonSerializer.Deserialize(
+ "{" + type + "\"from\":\"0x0001020304050607080910111213141516171819\", \"data\": \"0x70a082310000000000000000000000006c1f09f6271fbe133db38db9c9280307f5d22160\", \"to\": \"0x0d8775f648430679a709e98d2b0cb6250d2887ef\"}");
+ string serialized =
+ ctx._test.TestEthRpc("eth_estimateGas", ctx._test.JsonSerializer.Serialize(transaction));
+ Assert.AreEqual(
+ "{\"jsonrpc\":\"2.0\",\"result\":\"0x53b8\",\"id\":67}",
+ serialized);
+ ctx._test.ReadOnlyState.AccountExists(someAccount).Should().BeFalse();
+ }
[Test]
- public async Task Eth_estimateGas_web3_sample_not_enough_gas_system_account()
+ [TestCase("")]
+ [TestCase("\"type\":null, ")]
+ [TestCase("\"type\":\"0x0\", ")]
+ public async Task Eth_estimateGas_web3_sample_not_enough_gas_system_account(string type)
{
using Context ctx = await Context.Create();
ctx._test.ReadOnlyState.AccountExists(Address.SystemUser).Should().BeFalse();
TransactionForRpc transaction = ctx._test.JsonSerializer.Deserialize(
- "{\"gasPrice\":\"0x100000\", \"data\": \"0x70a082310000000000000000000000006c1f09f6271fbe133db38db9c9280307f5d22160\", \"to\": \"0x0d8775f648430679a709e98d2b0cb6250d2887ef\"}");
+ "{" + type + "\"gasPrice\":\"0x100000\", \"data\": \"0x70a082310000000000000000000000006c1f09f6271fbe133db38db9c9280307f5d22160\", \"to\": \"0x0d8775f648430679a709e98d2b0cb6250d2887ef\"}");
string serialized =
ctx._test.TestEthRpc("eth_estimateGas", ctx._test.JsonSerializer.Serialize(transaction));
- Assert.AreEqual("{\"jsonrpc\":\"2.0\",\"result\":\"0x53b8\",\"id\":67}", serialized);
+ Assert.AreEqual(
+ "{\"jsonrpc\":\"2.0\",\"error\":{\"code\":-32000,\"message\":\"insufficient funds for transfer: address 0xfffffffffffffffffffffffffffffffffffffffe\"},\"id\":67}",
+ serialized);
+
ctx._test.ReadOnlyState.AccountExists(Address.SystemUser).Should().BeFalse();
}
[Test]
- public async Task Eth_estimateGas_web3_sample_not_enough_gas_other_account()
+ [TestCase("")]
+ [TestCase("\"type\":null, ")]
+ [TestCase("\"type\":\"0x0\", ")]
+ public async Task Eth_estimateGas_web3_sample_not_enough_gas_other_account(string type)
{
using Context ctx = await Context.Create();
Address someAccount = new("0x0001020304050607080910111213141516171819");
ctx._test.ReadOnlyState.AccountExists(someAccount).Should().BeFalse();
TransactionForRpc transaction = ctx._test.JsonSerializer.Deserialize(
- "{\"from\":\"0x0001020304050607080910111213141516171819\",\"gasPrice\":\"0x100000\", \"data\": \"0x70a082310000000000000000000000006c1f09f6271fbe133db38db9c9280307f5d22160\", \"to\": \"0x0d8775f648430679a709e98d2b0cb6250d2887ef\"}");
+ "{" + type + "\"from\":\"0x0001020304050607080910111213141516171819\",\"gasPrice\":\"0x100000\", \"data\": \"0x70a082310000000000000000000000006c1f09f6271fbe133db38db9c9280307f5d22160\", \"to\": \"0x0d8775f648430679a709e98d2b0cb6250d2887ef\"}");
string serialized =
ctx._test.TestEthRpc("eth_estimateGas", ctx._test.JsonSerializer.Serialize(transaction));
- Assert.AreEqual("{\"jsonrpc\":\"2.0\",\"result\":\"0x53b8\",\"id\":67}", serialized);
+ Assert.AreEqual(
+ "{\"jsonrpc\":\"2.0\",\"error\":{\"code\":-32015,\"message\":\"insufficient funds for gas * price + value: address 0x0001020304050607080910111213141516171819, have 0, want 26214400000000\"},\"id\":67}",
+ serialized);
+
ctx._test.ReadOnlyState.AccountExists(someAccount).Should().BeFalse();
}
[Test]
- public async Task Eth_estimateGas_web3_above_block_gas_limit()
+ [TestCase("")]
+ [TestCase("\"type\":null, ")]
+ [TestCase("\"type\":\"0x0\", ")]
+ public async Task Eth_estimateGas_web3_below_intrinsic_gas_limit(string type)
{
using Context ctx = await Context.Create();
Address someAccount = new("0x0001020304050607080910111213141516171819");
ctx._test.ReadOnlyState.AccountExists(someAccount).Should().BeFalse();
TransactionForRpc transaction = ctx._test.JsonSerializer.Deserialize(
- "{\"from\":\"0x0001020304050607080910111213141516171819\",\"gas\":\"0x100000000\",\"gasPrice\":\"0x100000\", \"data\": \"0x70a082310000000000000000000000006c1f09f6271fbe133db38db9c9280307f5d22160\", \"to\": \"0x0d8775f648430679a709e98d2b0cb6250d2887ef\"}");
+ "{" + type + "\"from\":\"0x0001020304050607080910111213141516171819\",\"gas\":\"0x100\",\"gasPrice\":\"0x100000\", \"data\": \"0x70a082310000000000000000000000006c1f09f6271fbe133db38db9c9280307f5d22160\", \"to\": \"0x0d8775f648430679a709e98d2b0cb6250d2887ef\"}");
string serialized =
ctx._test.TestEthRpc("eth_estimateGas", ctx._test.JsonSerializer.Serialize(transaction));
- Assert.AreEqual("{\"jsonrpc\":\"2.0\",\"result\":\"0x53b8\",\"id\":67}", serialized);
+ Assert.AreEqual(
+ "{\"jsonrpc\":\"2.0\",\"error\":{\"code\":-32015,\"message\":\"gas limit below intrinsic gas: have 256, want 21432\"},\"id\":67}",
+ serialized);
+
ctx._test.ReadOnlyState.AccountExists(someAccount).Should().BeFalse();
}
@@ -173,52 +232,66 @@ public async Task Eth_estimate_gas_is_lower_with_optimized_access_list()
}
[Test]
- public async Task Estimate_gas_without_gas_pricing()
+ [TestCase("")]
+ [TestCase("\"type\":null, ")]
+ [TestCase("\"type\":\"0x0\", ")]
+ public async Task Estimate_gas_without_gas_pricing(string type)
{
using Context ctx = await Context.Create();
TransactionForRpc transaction = ctx._test.JsonSerializer.Deserialize(
- "{\"from\": \"0x0d8775f648430679a709e98d2b0cb6250d2887ef\", \"to\": \"0x0d8775f648430679a709e98d2b0cb6250d2887ef\"}");
+ "{" + type + "\"from\": \"0x0d8775f648430679a709e98d2b0cb6250d2887ef\", \"to\": \"0x0d8775f648430679a709e98d2b0cb6250d2887ef\"}");
string serialized = ctx._test.TestEthRpc("eth_estimateGas", ctx._test.JsonSerializer.Serialize(transaction));
Assert.AreEqual("{\"jsonrpc\":\"2.0\",\"result\":\"0x5208\",\"id\":67}", serialized);
}
[Test]
- public async Task Estimate_gas_with_gas_pricing()
+ [TestCase("")]
+ [TestCase("\"type\":null, ")]
+ [TestCase("\"type\":\"0x0\", ")]
+ public async Task Estimate_gas_with_gas_pricing(string type)
{
using Context ctx = await Context.Create();
TransactionForRpc transaction = ctx._test.JsonSerializer.Deserialize(
- "{\"from\": \"0x32e4e4c7c5d1cea5db5f9202a9e4d99e56c91a24\", \"to\": \"0x32e4e4c7c5d1cea5db5f9202a9e4d99e56c91a24\", \"gasPrice\": \"0x10\"}");
- string serialized = ctx._test.TestEthRpc("eth_estimateGas", ctx._test.JsonSerializer.Serialize(transaction));
- Assert.AreEqual("{\"jsonrpc\":\"2.0\",\"result\":\"0x5208\",\"id\":67}", serialized);
+ "{" + type + "\"from\": \"0x32e4e4c7c5d1cea5db5f9202a9e4d99e56c91a24\", \"to\": \"0x32e4e4c7c5d1cea5db5f9202a9e4d99e56c91a24\", \"gasPrice\": \"0x10\"}");
+ string serialized =
+ ctx._test.TestEthRpc("eth_estimateGas", ctx._test.JsonSerializer.Serialize(transaction));
+
+ Assert.AreEqual("{\"jsonrpc\":\"2.0\",\"error\":{\"code\":-32015,\"message\":\"insufficient funds for gas * price + value: address 0x32e4e4c7c5d1cea5db5f9202a9e4d99e56c91a24, have 0, want 400000000\"},\"id\":67}", serialized);
}
[Test]
- public async Task Estimate_gas_without_gas_pricing_after_1559_legacy()
+ [TestCase("")]
+ [TestCase("\"type\":null, ")]
+ [TestCase("\"type\":\"0x2\", ")]
+ public async Task Estimate_gas_without_gas_pricing_after_1559_legacy(string type)
{
using Context ctx = await Context.CreateWithLondonEnabled();
TransactionForRpc transaction = ctx._test.JsonSerializer.Deserialize(
- "{\"from\": \"0x32e4e4c7c5d1cea5db5f9202a9e4d99e56c91a24\", \"to\": \"0x32e4e4c7c5d1cea5db5f9202a9e4d99e56c91a24\", \"gasPrice\": \"0x10\"}");
+ "{" + type + "\"from\": \"0x32e4e4c7c5d1cea5db5f9202a9e4d99e56c91a24\", \"to\": \"0x32e4e4c7c5d1cea5db5f9202a9e4d99e56c91a24\"}");
string serialized = ctx._test.TestEthRpc("eth_estimateGas", ctx._test.JsonSerializer.Serialize(transaction));
Assert.AreEqual("{\"jsonrpc\":\"2.0\",\"result\":\"0x5208\",\"id\":67}", serialized);
+
}
[Test]
- public async Task Estimate_gas_without_gas_pricing_after_1559_new_type_of_transaction()
+ [TestCase("")]
+ [TestCase("\"type\":null, ")]
+ [TestCase("\"type\":\"0x2\", ")]
+ public async Task Estimate_gas_without_gas_pricing_after_1559_new_type_of_transaction(string type)
{
using Context ctx = await Context.CreateWithLondonEnabled();
TransactionForRpc transaction = ctx._test.JsonSerializer.Deserialize(
- "{\"from\": \"0x32e4e4c7c5d1cea5db5f9202a9e4d99e56c91a24\", \"to\": \"0x32e4e4c7c5d1cea5db5f9202a9e4d99e56c91a24\", \"type\": \"0x2\"}");
+ "{" + type + "\"from\": \"0x32e4e4c7c5d1cea5db5f9202a9e4d99e56c91a24\", \"to\": \"0x32e4e4c7c5d1cea5db5f9202a9e4d99e56c91a24\"}");
string serialized = ctx._test.TestEthRpc("eth_estimateGas", ctx._test.JsonSerializer.Serialize(transaction));
Assert.AreEqual("{\"jsonrpc\":\"2.0\",\"result\":\"0x5208\",\"id\":67}", serialized);
- byte[] code = Prepare.EvmCode
- .Op(Instruction.BASEFEE)
- .PushData(0)
- .Op(Instruction.SSTORE)
- .Done;
}
[Test]
- public async Task Estimate_gas_with_base_fee_opcode()
+ [TestCase("")]
+ [TestCase("\"type\":null, ")]
+ [TestCase("\"type\":\"0x0\", ")]
+ [TestCase("\"type\":\"0x2\", ")]
+ public async Task Estimate_gas_with_base_fee_opcode(string type)
{
using Context ctx = await Context.CreateWithLondonEnabled();
@@ -233,8 +306,10 @@ public async Task Estimate_gas_with_base_fee_opcode()
string dataStr = code.ToHexString();
TransactionForRpc transaction = ctx._test.JsonSerializer.Deserialize(
- $"{{\"from\": \"0x32e4e4c7c5d1cea5db5f9202a9e4d99e56c91a24\", \"type\": \"0x2\", \"data\": \"{dataStr}\"}}");
- string serialized = ctx._test.TestEthRpc("eth_estimateGas", ctx._test.JsonSerializer.Serialize(transaction));
+ $"{{{type}\"from\": \"0x32e4e4c7c5d1cea5db5f9202a9e4d99e56c91a24\", \"data\": \"{dataStr}\"}}");
+ string serialized =
+ ctx._test.TestEthRpc("eth_estimateGas", ctx._test.JsonSerializer.Serialize(transaction));
+
Assert.AreEqual(
"{\"jsonrpc\":\"2.0\",\"result\":\"0xe891\",\"id\":67}",
serialized);
@@ -260,6 +335,7 @@ public async Task Estimate_gas_with_revert()
serialized);
}
+
[Test]
public async Task should_estimate_transaction_with_deployed_code_when_eip3607_enabled()
{
@@ -276,5 +352,6 @@ public async Task should_estimate_transaction_with_deployed_code_when_eip3607_en
ctx._test.TestEthRpc("eth_estimateGas", ctx._test.JsonSerializer.Serialize(transaction), "latest");
Assert.AreEqual("{\"jsonrpc\":\"2.0\",\"result\":\"0x5208\",\"id\":67}", serialized);
}
+
}
}
diff --git a/src/Nethermind/Nethermind.JsonRpc.Test/Modules/Eth/EthRpcModuleTests.EthCall.cs b/src/Nethermind/Nethermind.JsonRpc.Test/Modules/Eth/EthRpcModuleTests.EthCall.cs
index 6cb72dfb156..893438612ba 100644
--- a/src/Nethermind/Nethermind.JsonRpc.Test/Modules/Eth/EthRpcModuleTests.EthCall.cs
+++ b/src/Nethermind/Nethermind.JsonRpc.Test/Modules/Eth/EthRpcModuleTests.EthCall.cs
@@ -33,55 +33,72 @@ namespace Nethermind.JsonRpc.Test.Modules.Eth
public partial class EthRpcModuleTests
{
[Test]
- public async Task Eth_call_web3_sample()
+ [TestCase("")]
+ [TestCase("\"type\":null, ")]
+ [TestCase("\"type\":\"0x0\", ")]
+ public async Task Eth_call_web3_sample(string type)
{
using Context ctx = await Context.Create();
TransactionForRpc transaction = ctx._test.JsonSerializer.Deserialize(
- "{\"data\": \"0x70a082310000000000000000000000006c1f09f6271fbe133db38db9c9280307f5d22160\", \"to\": \"0x0d8775f648430679a709e98d2b0cb6250d2887ef\"}");
+ "{" + type + "\"data\": \"0x70a082310000000000000000000000006c1f09f6271fbe133db38db9c9280307f5d22160\", \"to\": \"0x0d8775f648430679a709e98d2b0cb6250d2887ef\"}");
string serialized =
ctx._test.TestEthRpc("eth_call", ctx._test.JsonSerializer.Serialize(transaction), "0x0");
Assert.AreEqual("{\"jsonrpc\":\"2.0\",\"result\":\"0x\",\"id\":67}", serialized);
}
[Test]
- public async Task Eth_call_web3_sample_not_enough_gas_system_account()
+ [TestCase("")]
+ [TestCase("\"type\":null, ")]
+ [TestCase("\"type\":\"0x0\", ")]
+ public async Task Eth_call_web3_sample_not_enough_gas_system_account(string type)
{
using Context ctx = await Context.Create();
ctx._test.ReadOnlyState.AccountExists(Address.SystemUser).Should().BeFalse();
TransactionForRpc transaction = ctx._test.JsonSerializer.Deserialize(
- "{\"gasPrice\":\"0x100000\", \"data\": \"0x70a082310000000000000000000000006c1f09f6271fbe133db38db9c9280307f5d22160\", \"to\": \"0x0d8775f648430679a709e98d2b0cb6250d2887ef\"}");
+ "{" + type + "\"gasPrice\":\"0x100000\", \"data\": \"0x70a082310000000000000000000000006c1f09f6271fbe133db38db9c9280307f5d22160\", \"to\": \"0x0d8775f648430679a709e98d2b0cb6250d2887ef\"}");
string serialized =
ctx._test.TestEthRpc("eth_call", ctx._test.JsonSerializer.Serialize(transaction), "0x0");
- Assert.AreEqual("{\"jsonrpc\":\"2.0\",\"result\":\"0x\",\"id\":67}", serialized);
+ Assert.AreEqual(
+ "{\"jsonrpc\":\"2.0\",\"error\":{\"code\":-32000,\"message\":\"insufficient funds for transfer: address 0xfffffffffffffffffffffffffffffffffffffffe\"},\"id\":67}",
+ serialized);
ctx._test.ReadOnlyState.AccountExists(Address.SystemUser).Should().BeFalse();
+
}
[Test]
- public async Task Eth_call_web3_should_return_insufficient_balance_error()
+ [TestCase("")]
+ [TestCase("\"type\":null, ")]
+ [TestCase("\"type\":\"0x0\", ")]
+ public async Task Eth_call_web3_should_return_insufficient_balance_error(string type)
{
using Context ctx = await Context.Create();
Address someAccount = new("0x0001020304050607080910111213141516171819");
ctx._test.ReadOnlyState.AccountExists(someAccount).Should().BeFalse();
TransactionForRpc transaction = ctx._test.JsonSerializer.Deserialize(
- "{\"from\":\"0x0001020304050607080910111213141516171819\",\"gasPrice\":\"0x100000\", \"data\": \"0x70a082310000000000000000000000006c1f09f6271fbe133db38db9c9280307f5d22160\", \"to\": \"0x0d8775f648430679a709e98d2b0cb6250d2887ef\", \"value\": 500}");
+ "{" + type + "\"from\":\"0x0001020304050607080910111213141516171819\",\"gasPrice\":\"0x100000\", \"data\": \"0x70a082310000000000000000000000006c1f09f6271fbe133db38db9c9280307f5d22160\", \"to\": \"0x0d8775f648430679a709e98d2b0cb6250d2887ef\", \"value\": 500}");
string serialized = ctx._test.TestEthRpc("eth_call", ctx._test.JsonSerializer.Serialize(transaction));
Assert.AreEqual(
- "{\"jsonrpc\":\"2.0\",\"error\":{\"code\":-32000,\"message\":\"insufficient funds for transfer: address 0x0001020304050607080910111213141516171819\"},\"id\":67}",
+ "{\"jsonrpc\":\"2.0\",\"error\":{\"code\":-32015,\"message\":\"VM execution error.\",\"data\":\"insufficient funds for gas * price + value: address 0x0001020304050607080910111213141516171819, have 0, want 26214400000500\"},\"id\":67}",
serialized);
ctx._test.ReadOnlyState.AccountExists(someAccount).Should().BeFalse();
}
[Test]
- public async Task Eth_call_web3_sample_not_enough_gas_other_account()
+ [TestCase("")]
+ [TestCase("\"type\":null, ")]
+ [TestCase("\"type\":\"0x0\", ")]
+ public async Task Eth_call_web3_sample_not_enough_gas_other_account(string type)
{
using Context ctx = await Context.Create();
Address someAccount = new("0x0001020304050607080910111213141516171819");
ctx._test.ReadOnlyState.AccountExists(someAccount).Should().BeFalse();
TransactionForRpc transaction = ctx._test.JsonSerializer.Deserialize(
- "{\"from\":\"0x0001020304050607080910111213141516171819\",\"gasPrice\":\"0x100000\", \"data\": \"0x70a082310000000000000000000000006c1f09f6271fbe133db38db9c9280307f5d22160\", \"to\": \"0x0d8775f648430679a709e98d2b0cb6250d2887ef\"}");
+ "{" + type + "\"from\":\"0x0001020304050607080910111213141516171819\",\"gasPrice\":\"0x100000\", \"data\": \"0x70a082310000000000000000000000006c1f09f6271fbe133db38db9c9280307f5d22160\", \"to\": \"0x0d8775f648430679a709e98d2b0cb6250d2887ef\"}");
string serialized =
ctx._test.TestEthRpc("eth_call", ctx._test.JsonSerializer.Serialize(transaction), "0x0");
- Assert.AreEqual("{\"jsonrpc\":\"2.0\",\"result\":\"0x\",\"id\":67}", serialized);
+ Assert.AreEqual(
+ "{\"jsonrpc\":\"2.0\",\"error\":{\"code\":-32015,\"message\":\"VM execution error.\",\"data\":\"insufficient funds for gas * price + value: address 0x0001020304050607080910111213141516171819, have 0, want 26214400000000\"},\"id\":67}",
+ serialized);
ctx._test.ReadOnlyState.AccountExists(someAccount).Should().BeFalse();
}
@@ -103,7 +120,7 @@ public async Task Eth_call_no_recipient_should_work_as_init()
using Context ctx = await Context.Create();
TransactionForRpc transaction = new(Keccak.Zero, 1L, 1, new Transaction());
transaction.From = TestItem.AddressA;
- transaction.Data = new byte[] {1, 2, 3};
+ transaction.Data = new byte[] { 1, 2, 3 };
string serialized =
ctx._test.TestEthRpc("eth_call", ctx._test.JsonSerializer.Serialize(transaction), "latest");
@@ -112,7 +129,6 @@ public async Task Eth_call_no_recipient_should_work_as_init()
serialized);
}
-
[Test]
public async Task should_not_reject_transactions_with_deployed_code_when_eip3607_enabled()
{
@@ -186,53 +202,199 @@ public async Task Eth_call_with_accessList()
Assert.AreEqual("{\"jsonrpc\":\"2.0\",\"result\":\"0x010203\",\"id\":67}", serialized);
}
+ ///
+ /// 1. Before 1559: If you do not specify the gas price, 0 is used and you can call with accounts with 0 balance.
+ ///
[Test]
- public async Task Eth_call_without_gas_pricing()
+ [TestCase("")]
+ [TestCase("\"type\":null, ")]
+ [TestCase("\"type\":\"0x0\", ")]
+ public async Task Eth_call_without_gas_pricing(string type)
{
using Context ctx = await Context.Create();
TransactionForRpc transaction = ctx._test.JsonSerializer.Deserialize(
- "{\"from\": \"0x0d8775f648430679a709e98d2b0cb6250d2887ef\", \"to\": \"0x0d8775f648430679a709e98d2b0cb6250d2887ef\"}");
+ "{" + type + "\"from\": \"0x0d8775f648430679a709e98d2b0cb6250d2887ef\", \"to\": \"0x0d8775f648430679a709e98d2b0cb6250d2887ef\"}");
string serialized = ctx._test.TestEthRpc("eth_call", ctx._test.JsonSerializer.Serialize(transaction));
Assert.AreEqual("{\"jsonrpc\":\"2.0\",\"result\":\"0x\",\"id\":67}", serialized);
}
+ ///
+ /// 2. Before 1559: If you specify the gas price, it is used and checked with the account balance.
+ ///
+ [Test]
+ [TestCase("")]
+ [TestCase("\"type\":null, ")]
+ [TestCase("\"type\":\"0x0\", ")]
+ public async Task Eth_call_with_gas_pricing(string type)
+ {
+ using Context ctx = await Context.Create();
+ TransactionForRpc transaction = ctx._test.JsonSerializer.Deserialize(
+ "{" + type + "\"from\": \"0x32e4e4c7c5d1cea5db5f9202a9e4d99e56c91a24\", \"to\": \"0x32e4e4c7c5d1cea5db5f9202a9e4d99e56c91a24\", \"gasPrice\": \"0x10\"}");
+ string serialized = ctx._test.TestEthRpc("eth_call", ctx._test.JsonSerializer.Serialize(transaction));
+ Assert.AreEqual(
+ "{\"jsonrpc\":\"2.0\",\"error\":{\"code\":-32015,\"message\":\"VM execution error.\",\"data\":\"insufficient funds for gas * price + value: address 0x32e4e4c7c5d1cea5db5f9202a9e4d99e56c91a24, have 0, want 400000000\"},\"id\":67}",
+ serialized);
+ }
+
+ ///
+ /// 3. Before 1559: If you specify a gas price of type 1559, it will be ignored and the gas price will be 0.
+ ///
[Test]
- public async Task Eth_call_with_gas_pricing()
+ [TestCase("")]
+ [TestCase("\"type\":null, ")]
+ [TestCase("\"type\":\"0x0\", ")]
+ public async Task Eth_call_with_1559_gas_pricing(string type)
{
using Context ctx = await Context.Create();
TransactionForRpc transaction = ctx._test.JsonSerializer.Deserialize(
- "{\"from\": \"0x32e4e4c7c5d1cea5db5f9202a9e4d99e56c91a24\", \"to\": \"0x32e4e4c7c5d1cea5db5f9202a9e4d99e56c91a24\", \"gasPrice\": \"0x10\"}");
+ "{" + type + "\"from\": \"0x32e4e4c7c5d1cea5db5f9202a9e4d99e56c91a24\", \"to\": \"0x32e4e4c7c5d1cea5db5f9202a9e4d99e56c91a24\", \"maxFeePerGas\": \"0x100\"}");
string serialized = ctx._test.TestEthRpc("eth_call", ctx._test.JsonSerializer.Serialize(transaction));
Assert.AreEqual("{\"jsonrpc\":\"2.0\",\"result\":\"0x\",\"id\":67}", serialized);
}
[Test]
- public async Task Eth_call_without_gas_pricing_after_1559_legacy()
+ [TestCase("")]
+ [TestCase("\"type\":null, ")]
+ [TestCase("\"type\":\"0x2\", ")]
+ public async Task Eth_call_without_gas_pricing_after_1559_legacy(string type)
{
using Context ctx = await Context.CreateWithLondonEnabled();
TransactionForRpc transaction = ctx._test.JsonSerializer.Deserialize(
- "{\"from\": \"0x32e4e4c7c5d1cea5db5f9202a9e4d99e56c91a24\", \"to\": \"0x32e4e4c7c5d1cea5db5f9202a9e4d99e56c91a24\", \"gasPrice\": \"0x10\"}");
+ "{" + type + "\"from\": \"0x32e4e4c7c5d1cea5db5f9202a9e4d99e56c91a24\", \"to\": \"0x32e4e4c7c5d1cea5db5f9202a9e4d99e56c91a24\"}");
string serialized = ctx._test.TestEthRpc("eth_call", ctx._test.JsonSerializer.Serialize(transaction));
Assert.AreEqual("{\"jsonrpc\":\"2.0\",\"result\":\"0x\",\"id\":67}", serialized);
}
+ ///
+ /// 4. After 1559: If you do not specify the gas price, 0 is used and you can call with accounts with 0 balance. The basefee will be 0.
+ ///
[Test]
- public async Task Eth_call_without_gas_pricing_after_1559_new_type_of_transaction()
+ [TestCase("")]
+ [TestCase("\"type\":null, ")]
+ [TestCase("\"type\":\"0x2\", ")]
+ public async Task Eth_call_without_gas_pricing_after_1559_new_type_of_transaction(string type)
{
using Context ctx = await Context.CreateWithLondonEnabled();
TransactionForRpc transaction = ctx._test.JsonSerializer.Deserialize(
- "{\"from\": \"0x32e4e4c7c5d1cea5db5f9202a9e4d99e56c91a24\", \"to\": \"0x32e4e4c7c5d1cea5db5f9202a9e4d99e56c91a24\", \"type\": \"0x2\"}");
+ "{" + type + "\"from\": \"0x32e4e4c7c5d1cea5db5f9202a9e4d99e56c91a24\", \"to\": \"0x32e4e4c7c5d1cea5db5f9202a9e4d99e56c91a24\"}");
string serialized = ctx._test.TestEthRpc("eth_call", ctx._test.JsonSerializer.Serialize(transaction));
Assert.AreEqual("{\"jsonrpc\":\"2.0\",\"result\":\"0x\",\"id\":67}", serialized);
- byte[] code = Prepare.EvmCode
- .Op(Instruction.BASEFEE)
- .PushData(0)
- .Op(Instruction.SSTORE)
- .Done;
+ }
+
+ ///
+ /// 5. After 1559: In geth if you do specify a gas price, that is interpreted as both the max and priority fee
+ /// and your account balance is checked against them + the current base fee.
+ ///
+ [Test]
+ [TestCase("")]
+ [TestCase("\"type\":null, ")]
+ public async Task Eth_call_with_gas_pricing_after_1559_new_type_of_transaction(string type)
+ {
+ using Context ctx = await Context.CreateWithLondonEnabled();
+ TransactionForRpc transaction = ctx._test.JsonSerializer.Deserialize(
+ "{" + type + "\"gasPrice\": \"0x100000000\", \"from\": \"0x32e4e4c7c5d1cea5db5f9202a9e4d99e56c91a24\", \"to\": \"0x32e4e4c7c5d1cea5db5f9202a9e4d99e56c91a24\"}");
+ string serialized = ctx._test.TestEthRpc("eth_call", ctx._test.JsonSerializer.Serialize(transaction));
+ Assert.AreEqual(
+ "{\"jsonrpc\":\"2.0\",\"error\":{\"code\":-32015,\"message\":\"VM execution error.\",\"data\":\"insufficient funds for gas * price + value: address 0x32e4e4c7c5d1cea5db5f9202a9e4d99e56c91a24, have 0, want 107374182400000000\"},\"id\":67}",
+ serialized);
+ }
+
+ [Test]
+ [TestCase("")]
+ [TestCase("\"type\":null, ")]
+ [TestCase("\"type\":\"0x2\", ")]
+ public async Task Eth_call_with_gas_limit_after_1559_new_type_of_transaction(string type)
+ {
+ using Context ctx = await Context.CreateWithLondonEnabled();
+ TransactionForRpc transaction = ctx._test.JsonSerializer.Deserialize(
+ "{" + type + "\"from\": \"0x32e4e4c7c5d1cea5db5f9202a9e4d99e56c91a24\", \"to\": \"0x32e4e4c7c5d1cea5db5f9202a9e4d99e56c91a24\", \"gas\": \"0x1000\"}");
+ string serialized = ctx._test.TestEthRpc("eth_call", ctx._test.JsonSerializer.Serialize(transaction));
+ Assert.AreEqual(
+ "{\"jsonrpc\":\"2.0\",\"error\":{\"code\":-32015,\"message\":\"VM execution error.\",\"data\":\"gas limit below intrinsic gas: have 4096, want 21000\"},\"id\":67}",
+ serialized);
+ }
+
+ ///
+ /// 6. After 1559: If you specify a gas price of type 1559 and transaction type 0x2,
+ /// the transaction will be of type 1559 and your account balance is checked against them + the current basefee.
+ /// (maxFeePerGas)
+ ///
+ [Test]
+ [TestCase("")]
+ [TestCase("\"type\":null, ")]
+ [TestCase("\"type\":\"0x2\", ")]
+ public async Task Eth_call_with_max_fee_after_1559_new_type_of_transaction(string type)
+ {
+ using Context ctx = await Context.CreateWithLondonEnabled();
+ TransactionForRpc transaction = ctx._test.JsonSerializer.Deserialize(
+ "{" + type + "\"from\": \"0x32e4e4c7c5d1cea5db5f9202a9e4d99e56c91a24\", \"to\": \"0x32e4e4c7c5d1cea5db5f9202a9e4d99e56c91a24\", \"maxFeePerGas\": \"0x2DA2830C\", \"value\": \"0x2DA2830C\"}");
+ string serialized = ctx._test.TestEthRpc("eth_call", ctx._test.JsonSerializer.Serialize(transaction));
+ Assert.AreEqual(
+ "{\"jsonrpc\":\"2.0\",\"error\":{\"code\":-32015,\"message\":\"VM execution error.\",\"data\":\"insufficient funds for gas * price + value: address 0x32e4e4c7c5d1cea5db5f9202a9e4d99e56c91a24, have 0, want 19140625765625100\"},\"id\":67}",
+ serialized);
+ }
+
+ [Test]
+ [TestCase("")]
+ [TestCase("\"type\":null, ")]
+ [TestCase("\"type\":\"0x2\", ")]
+ public async Task Eth_call_with_max_fee_after_1559_new_type_of_transaction_success(string type)
+ {
+ using Context ctx = await Context.CreateWithLondonEnabled();
+ await ctx._test.AddFundsAfterLondon((new Address("0x32e4e4c7c5d1cea5db5f9202a9e4d99e56c91a24"), 2.Ether()));
+ TransactionForRpc transaction = ctx._test.JsonSerializer.Deserialize(
+ "{" + type + "\"from\": \"0x32e4e4c7c5d1cea5db5f9202a9e4d99e56c91a24\", \"to\": \"0x32e4e4c7c5d1cea5db5f9202a9e4d99e56c91a24\", \"maxPriorityFeePerGas\": \"0x2DA2830C\", \"maxFeePerGas\": \"0x2DA2830C\", \"value\": \"0x2DA2830C\"}");
+ string serialized = ctx._test.TestEthRpc("eth_call", ctx._test.JsonSerializer.Serialize(transaction));
+ Assert.AreEqual(2.Ether(),
+ ctx._test.ReadOnlyState.GetBalance(new Address("0x32e4e4c7c5d1cea5db5f9202a9e4d99e56c91a24")));
+ Assert.AreEqual("{\"jsonrpc\":\"2.0\",\"result\":\"0x\",\"id\":67}", serialized);
+ }
+
+ ///
+ /// 6. After 1559: If you specify a gas price of type 1559 and transaction type 0x2,
+ /// the transaction will be of type 1559 and your account balance is checked against them + the current basefee.
+ /// (maxFeePerGas)
+ ///
+ [Test]
+ [TestCase("")]
+ [TestCase("\"type\":null, ")]
+ [TestCase("\"type\":\"0x2\", ")]
+ public async Task Eth_call_with_max__priority_fee_after_1559_new_type_of_transaction(string type)
+ {
+ using Context ctx = await Context.CreateWithLondonEnabled();
+ TransactionForRpc transaction = ctx._test.JsonSerializer.Deserialize(
+ "{" + type + "\"from\": \"0x32e4e4c7c5d1cea5db5f9202a9e4d99e56c91a24\", \"to\": \"0x32e4e4c7c5d1cea5db5f9202a9e4d99e56c91a24\", \"maxFeePerGas\": \"0x2d5dd655ddD\"}");
+ string serialized = ctx._test.TestEthRpc("eth_call", ctx._test.JsonSerializer.Serialize(transaction));
+ Assert.AreEqual(
+ "{\"jsonrpc\":\"2.0\",\"error\":{\"code\":-32015,\"message\":\"VM execution error.\",\"data\":\"insufficient funds for gas * price + value: address 0x32e4e4c7c5d1cea5db5f9202a9e4d99e56c91a24, have 0, want 19140625000000000\"},\"id\":67}",
+ serialized);
}
[Test]
- public async Task Eth_call_with_base_fee_opcode()
+ [TestCase("")]
+ [TestCase("\"type\":null, ")]
+ [TestCase("\"type\":\"0x1\", ")]
+ [TestCase("\"type\":\"0x2\", ")]
+ public async Task Eth_call_with_dissimilar_account_nonce(string type)
+ {
+ using Context ctx = await Context.CreateWithLondonEnabled();
+ Address someAccount = new Address("0x0d8775f648430679a709e98d2b0cb6250d2887ef");
+ ctx._test.ReadOnlyState.AccountExists(someAccount).Should().BeFalse();
+ TransactionForRpc transaction = ctx._test.JsonSerializer.Deserialize(
+ "{" + type + "\"nonce\": \"105\", \"from\": \"0x0d8775f648430679a709e98d2b0cb6250d2887ef\", \"to\": \"0x0d8775f648430679a709e98d2b0cb6250d2887ef\"}");
+ string serialized = ctx._test.TestEthRpc("eth_call", ctx._test.JsonSerializer.Serialize(transaction));
+ Assert.AreEqual(
+ "{\"jsonrpc\":\"2.0\",\"error\":{\"code\":-32015,\"message\":\"VM execution error.\",\"data\":\"wrong transaction nonce\"},\"id\":67}",
+ serialized);
+ ctx._test.ReadOnlyState.AccountExists(someAccount).Should().BeFalse();
+ }
+
+ [Test]
+ [TestCase("")]
+ [TestCase("\"type\":null, ")]
+ [TestCase("\"type\":\"0x1\", ")]
+ [TestCase("\"type\":\"0x2\", ")]
+ public async Task Eth_call_with_base_fee_opcode(string type)
{
using Context ctx = await Context.CreateWithLondonEnabled();
@@ -247,12 +409,59 @@ public async Task Eth_call_with_base_fee_opcode()
string dataStr = code.ToHexString();
TransactionForRpc transaction = ctx._test.JsonSerializer.Deserialize(
- $"{{\"from\": \"0x32e4e4c7c5d1cea5db5f9202a9e4d99e56c91a24\", \"type\": \"0x2\", \"data\": \"{dataStr}\"}}");
+ $"{{{type}\"from\": \"0x32e4e4c7c5d1cea5db5f9202a9e4d99e56c91a24\", \"data\": \"{dataStr}\"}}");
string serialized = ctx._test.TestEthRpc("eth_call", ctx._test.JsonSerializer.Serialize(transaction));
Assert.AreEqual(
"{\"jsonrpc\":\"2.0\",\"result\":\"0x000000000000000000000000000000000000000000000000000000002da282a8\",\"id\":67}",
serialized);
}
+
+ [Test]
+ [TestCase("")]
+ [TestCase("\"type\":null, ")]
+ [TestCase("\"type\":\"0x1\", ")]
+ [TestCase("\"type\":\"0x2\", ")]
+ public async Task Eth_call_for_checking_invalid_input(string type)
+ {
+ using Context ctx = await Context.CreateWithLondonEnabled();
+ TransactionForRpc transaction = ctx._test.JsonSerializer.Deserialize(
+ "{" + type + "\"from\": \"0x32e4e4c7c5d1cea5db5f9202a9e4d99e56c91a24\", \"to\": \"0x32e4e4c7c5d1cea5db5f9202a9e4d99e56c91a24\", \"maxPriorityFeePerGas\": \"0x2DA2830C\", \"gasPrice\": \"0x2DA2830C\",}");
+ string serialized = ctx._test.TestEthRpc("eth_call", ctx._test.JsonSerializer.Serialize(transaction));
+ Assert.AreEqual(
+ "{\"jsonrpc\":\"2.0\",\"error\":{\"code\":-32000,\"message\":\"both gasPrice and (maxFeePerGas or maxPriorityFeePerGas) specified\"},\"id\":67}",
+ serialized);
+ }
+
+ [Test]
+ [TestCase("")]
+ [TestCase("\"type\":null, ")]
+ [TestCase("\"type\":\"0x1\", ")]
+ [TestCase("\"type\":\"0x2\", ")]
+ public async Task Eth_call_for_checking_invalid_input_2(string type)
+ {
+ using Context ctx = await Context.CreateWithLondonEnabled();
+ TransactionForRpc transaction = ctx._test.JsonSerializer.Deserialize(
+ "{" + type + "\"from\": \"0x32e4e4c7c5d1cea5db5f9202a9e4d99e56c91a24\", \"to\": \"0x32e4e4c7c5d1cea5db5f9202a9e4d99e56c91a24\", \"maxFeePerGas\": \"0x2DA2830C\", \"gasPrice\": \"0x2DA2830C\"}");
+ string serialized = ctx._test.TestEthRpc("eth_call", ctx._test.JsonSerializer.Serialize(transaction));
+ Assert.AreEqual(
+ "{\"jsonrpc\":\"2.0\",\"error\":{\"code\":-32000,\"message\":\"both gasPrice and (maxFeePerGas or maxPriorityFeePerGas) specified\"},\"id\":67}",
+ serialized);
+ }
+
+ [Test]
+ [TestCase("")]
+ [TestCase("\"type\":null, ")]
+ [TestCase("\"type\":\"0x2\", ")]
+ public async Task Eth_call_maxFeePerGas_less_than_block_baseFee(string type)
+ {
+ using Context ctx = await Context.CreateWithLondonEnabled();
+ TransactionForRpc transaction = ctx._test.JsonSerializer.Deserialize(
+ "{" + type + "\"from\": \"0x32e4e4c7c5d1cea5db5f9202a9e4d99e56c91a24\", \"to\": \"0x32e4e4c7c5d1cea5db5f9202a9e4d99e56c91a24\", \"maxFeePerGas\": \"0x2DA2830\"}");
+ string serialized = ctx._test.TestEthRpc("eth_call", ctx._test.JsonSerializer.Serialize(transaction));
+ Assert.AreEqual(
+ "{\"jsonrpc\":\"2.0\",\"error\":{\"code\":-32015,\"message\":\"VM execution error.\",\"data\":\"max fee per gas less than block base fee: address 0x32e4e4c7c5d1cea5db5f9202a9e4d99e56c91a24, maxFeePerGas: 47851568, baseFee 765625000\"},\"id\":67}",
+ serialized);
+ }
[Test]
public async Task Eth_call_with_revert()
diff --git a/src/Nethermind/Nethermind.JsonRpc.Test/Modules/TraceRpcModuleTests.cs b/src/Nethermind/Nethermind.JsonRpc.Test/Modules/TraceRpcModuleTests.cs
index d8dc5894a67..810880b3b71 100644
--- a/src/Nethermind/Nethermind.JsonRpc.Test/Modules/TraceRpcModuleTests.cs
+++ b/src/Nethermind/Nethermind.JsonRpc.Test/Modules/TraceRpcModuleTests.cs
@@ -619,7 +619,7 @@ public async Task Trace_call_simple_tx_test()
string transaction = "{\"from\":\"0xaaaaaaaa8583de65cc752fe3fad5098643244d22\",\"to\":\"0xd6a8d04cb9846759416457e2c593c99390092df6\"}";
string traceTypes = "[\"trace\"]";
string blockParameter = "latest";
- string expectedResult = "{\"jsonrpc\":\"2.0\",\"result\":{\"output\":\"0x\",\"stateDiff\":null,\"trace\":[{\"action\":{\"callType\":\"call\",\"from\":\"0xaaaaaaaa8583de65cc752fe3fad5098643244d22\",\"gas\":\"0x5f58ef8\",\"input\":\"0x\",\"to\":\"0xd6a8d04cb9846759416457e2c593c99390092df6\",\"value\":\"0x0\"},\"result\":{\"gasUsed\":\"0x0\",\"output\":\"0x\"},\"subtraces\":0,\"traceAddress\":[],\"type\":\"call\"}],\"vmTrace\":null},\"id\":67}";
+ string expectedResult = "{\"jsonrpc\":\"2.0\",\"result\":{\"output\":\"0x\",\"stateDiff\":null,\"trace\":[{\"action\":{\"callType\":\"call\",\"from\":\"0xaaaaaaaa8583de65cc752fe3fad5098643244d22\",\"gas\":\"0x17d2638\",\"input\":\"0x\",\"to\":\"0xd6a8d04cb9846759416457e2c593c99390092df6\",\"value\":\"0x0\"},\"result\":{\"gasUsed\":\"0x0\",\"output\":\"0x\"},\"subtraces\":0,\"traceAddress\":[],\"type\":\"call\"}],\"vmTrace\":null},\"id\":67}";
string serialized = RpcTest.TestSerializedRequest(
EthModuleFactory.Converters.Union(TraceModuleFactory.Converters).ToList(), context.TraceRpcModule,
@@ -628,8 +628,8 @@ public async Task Trace_call_simple_tx_test()
Assert.AreEqual(expectedResult, serialized, serialized.Replace("\"", "\\\""));
}
- [TestCase("{\"from\":\"0x7f554713be84160fdf0178cc8df86f5aabd33397\",\"to\":\"0xbe5c953dd0ddb0ce033a98f36c981f1b74d3b33f\",\"value\":\"0x0\",\"gasPrice\":\"0x119e04a40a\"}", "[\"trace\"]","{\"jsonrpc\":\"2.0\",\"result\":{\"output\":\"0x\",\"stateDiff\":null,\"trace\":[{\"action\":{\"callType\":\"call\",\"from\":\"0x7f554713be84160fdf0178cc8df86f5aabd33397\",\"gas\":\"0x5f58ef8\",\"input\":\"0x\",\"to\":\"0xbe5c953dd0ddb0ce033a98f36c981f1b74d3b33f\",\"value\":\"0x0\"},\"result\":{\"gasUsed\":\"0x0\",\"output\":\"0x\"},\"subtraces\":0,\"traceAddress\":[],\"type\":\"call\"}],\"vmTrace\":null},\"id\":67}")]
- [TestCase("{\"from\":\"0xc71acc7863f3bc7347b24c3b835643bd89d4d161\",\"to\":\"0xa760e26aa76747020171fcf8bda108dfde8eb930\",\"value\":\"0x0\",\"gasPrice\":\"0x2108eea5bc\"}", "[\"trace\"]", "{\"jsonrpc\":\"2.0\",\"result\":{\"output\":\"0x\",\"stateDiff\":null,\"trace\":[{\"action\":{\"callType\":\"call\",\"from\":\"0xc71acc7863f3bc7347b24c3b835643bd89d4d161\",\"gas\":\"0x5f58ef8\",\"input\":\"0x\",\"to\":\"0xa760e26aa76747020171fcf8bda108dfde8eb930\",\"value\":\"0x0\"},\"result\":{\"gasUsed\":\"0x0\",\"output\":\"0x\"},\"subtraces\":0,\"traceAddress\":[],\"type\":\"call\"}],\"vmTrace\":null},\"id\":67}")]
+ //[TestCase("{\"from\":\"0x7f554713be84160fdf0178cc8df86f5aabd33397\",\"to\":\"0xbe5c953dd0ddb0ce033a98f36c981f1b74d3b33f\",\"value\":\"0x0\",\"gasPrice\":\"0x482908C\",\"data\":\"0x\"}", "[\"trace\"]","{\"jsonrpc\":\"2.0\",\"result\":{\"output\":\"0x\",\"stateDiff\":null,\"trace\":[{\"action\":{\"callType\":\"call\",\"from\":\"0x7f554713be84160fdf0178cc8df86f5aabd33397\",\"gas\":\"0x17d7840\",\"input\":\"0x\",\"to\":\"0xbe5c953dd0ddb0ce033a98f36c981f1b74d3b33f\",\"value\":\"0x0\"},\"error\":\"insufficient funds for gas * price + value: address 0x7f554713be84160fdf0178cc8df86f5aabd33397, have 0, want 1891638707450000000\",\"subtraces\":0,\"traceAddress\":null,\"type\":null}],\"vmTrace\":null},\"id\":67}")]
+ [TestCase("{\"from\":\"0x38cd7db12edc7724a6a403c1a63d3c12682fd687\",\"to\":\"0xe4d75e9b493458d032a5c3cc1ee9b0712c1ece06\",\"gasPrice\":\"0x1512386900\",\"data\":\"0x\"}", "[\"trace\"]", "{\"jsonrpc\":\"2.0\",\"result\":{\"output\":\"0x\",\"stateDiff\":null,\"trace\":[{\"action\":{\"callType\":\"call\",\"from\":\"0xc71acc7863f3bc7347b24c3b835643bd89d4d161\",\"gas\":\"0x17d7840\",\"input\":\"0x\",\"to\":\"0xa760e26aa76747020171fcf8bda108dfde8eb930\",\"value\":\"0x0\"},\"result\":{\"gasUsed\":\"0x0\",\"output\":\"0x\"},\"subtraces\":0,\"traceAddress\":[],\"type\":\"call\"}],\"vmTrace\":null},\"id\":67}")]
public async Task Trace_call_without_blockParameter_test(string transaction, string traceTypes, string expectedResult)
{
Context context = new();
diff --git a/src/Nethermind/Nethermind.JsonRpc/Data/TransactionForRpc.cs b/src/Nethermind/Nethermind.JsonRpc/Data/TransactionForRpc.cs
index f430214fa35..558fe9f7081 100644
--- a/src/Nethermind/Nethermind.JsonRpc/Data/TransactionForRpc.cs
+++ b/src/Nethermind/Nethermind.JsonRpc/Data/TransactionForRpc.cs
@@ -16,6 +16,7 @@
using System;
using System.Collections.Generic;
+using System.ComponentModel;
using System.Linq;
using MathGmp.Native;
using Nethermind.Core;
@@ -103,7 +104,8 @@ public TransactionForRpc()
public UInt256? ChainId { get; set; }
- public TxType Type { get; set; }
+ [JsonProperty(NullValueHandling = NullValueHandling.Include)]
+ public TxType? Type { get; set; }
public AccessListItemForRpc[]? AccessList { get; set; }
@@ -129,7 +131,7 @@ public TransactionForRpc()
SenderAddress = From,
Value = Value ?? 0,
Data = Data ?? Input,
- Type = Type,
+ Type = Type ?? TxType.Legacy,
AccessList = TryGetAccessList(),
ChainId = chainId,
DecodedMaxFeePerGas = MaxFeePerGas ?? 0
@@ -156,7 +158,7 @@ public TransactionForRpc()
SenderAddress = From,
Value = Value ?? 0,
Data = Data ?? Input,
- Type = Type,
+ Type = Type ?? TxType.Legacy,
AccessList = TryGetAccessList(),
ChainId = chainId
};
diff --git a/src/Nethermind/Nethermind.JsonRpc/IJsonRpcConfig.cs b/src/Nethermind/Nethermind.JsonRpc/IJsonRpcConfig.cs
index f17df8e43d3..d6a895ca7a6 100644
--- a/src/Nethermind/Nethermind.JsonRpc/IJsonRpcConfig.cs
+++ b/src/Nethermind/Nethermind.JsonRpc/IJsonRpcConfig.cs
@@ -72,7 +72,7 @@ public interface IJsonRpcConfig : IConfig
[ConfigItem(
Description = "Gas limit for eth_call and eth_estimateGas",
- DefaultValue = "100000000")]
+ DefaultValue = "25000000")]
long? GasCap { get; set; }
[ConfigItem(
diff --git a/src/Nethermind/Nethermind.JsonRpc/JsonRpcConfig.cs b/src/Nethermind/Nethermind.JsonRpc/JsonRpcConfig.cs
index 603e4ffa6ed..e6361bd674b 100644
--- a/src/Nethermind/Nethermind.JsonRpc/JsonRpcConfig.cs
+++ b/src/Nethermind/Nethermind.JsonRpc/JsonRpcConfig.cs
@@ -42,8 +42,9 @@ public int WebSocketsPort
public string? IpcUnixDomainSocketPath { get; set; } = null;
public string[] EnabledModules { get; set; } = ModuleType.DefaultModules.ToArray();
+ public int FindLogBlockDepthLimit { get; set; } = 1000;
+ public long? GasCap { get; set; } = 25000000;
public string[] AdditionalRPCUrls { get; set; } = Array.Empty();
- public long? GasCap { get; set; } = 100000000;
public int ReportIntervalSeconds { get; set; } = 300;
public bool BufferResponses { get; set; }
public string CallsFilterFilePath { get; set; } = "Data/jsonrpc.filter";
diff --git a/src/Nethermind/Nethermind.JsonRpc/Modules/Eth/EthModule.TransactionExecutor.cs b/src/Nethermind/Nethermind.JsonRpc/Modules/Eth/EthModule.TransactionExecutor.cs
index 76351588368..1af736ca29a 100644
--- a/src/Nethermind/Nethermind.JsonRpc/Modules/Eth/EthModule.TransactionExecutor.cs
+++ b/src/Nethermind/Nethermind.JsonRpc/Modules/Eth/EthModule.TransactionExecutor.cs
@@ -21,10 +21,12 @@
using Nethermind.Core;
using Nethermind.Core.Eip2930;
using Nethermind.Core.Extensions;
+using Nethermind.Core.Specs;
using Nethermind.Evm;
using Nethermind.Facade;
using Nethermind.Int256;
using Nethermind.JsonRpc.Data;
+using Nethermind.Specs;
using Nethermind.Specs.Forks;
namespace Nethermind.JsonRpc.Modules.Eth
@@ -36,12 +38,14 @@ private abstract class TxExecutor
protected readonly IBlockchainBridge _blockchainBridge;
private readonly IBlockFinder _blockFinder;
private readonly IJsonRpcConfig _rpcConfig;
+ private readonly ISpecProvider _specProvider;
- protected TxExecutor(IBlockchainBridge blockchainBridge, IBlockFinder blockFinder, IJsonRpcConfig rpcConfig)
+ protected TxExecutor(IBlockchainBridge blockchainBridge, IBlockFinder blockFinder, IJsonRpcConfig rpcConfig, ISpecProvider specProvider)
{
_blockchainBridge = blockchainBridge;
_blockFinder = blockFinder;
_rpcConfig = rpcConfig;
+ _specProvider = specProvider;
}
public ResultWrapper ExecuteTx(
@@ -53,7 +57,6 @@ public ResultWrapper ExecuteTx(
{
return ResultWrapper.Fail(searchResult);
}
-
BlockHeader header = searchResult.Object;
if (!HasStateForBlock(_blockchainBridge, header))
{
@@ -63,6 +66,19 @@ public ResultWrapper ExecuteTx(
transactionCall.EnsureDefaults(_rpcConfig.GasCap);
+ if ((transactionCall.MaxFeePerGas != null || transactionCall.MaxPriorityFeePerGas != null) &&
+ transactionCall.GasPrice != null)
+ {
+ return ResultWrapper.Fail("both gasPrice and (maxFeePerGas or maxPriorityFeePerGas) specified", ErrorCodes.InvalidInput);
+ }
+
+ bool isEip1559Enabled = _specProvider.GetSpec(header.Number).IsEip1559Enabled;
+
+ transactionCall.Type ??= (isEip1559Enabled &&
+ (transactionCall.MaxFeePerGas != null || transactionCall.MaxPriorityFeePerGas != null))
+ ? TxType.EIP1559
+ : TxType.Legacy;
+
using CancellationTokenSource cancellationTokenSource = new(_rpcConfig.Timeout);
Transaction tx = transactionCall.ToTransaction(_blockchainBridge.GetChainId());
return ExecuteTx(header, tx, cancellationTokenSource.Token);
@@ -76,8 +92,8 @@ protected ResultWrapper GetInputError(BlockchainBridge.CallOutput resul
private class CallTxExecutor : TxExecutor
{
- public CallTxExecutor(IBlockchainBridge blockchainBridge, IBlockFinder blockFinder, IJsonRpcConfig rpcConfig)
- : base(blockchainBridge, blockFinder, rpcConfig)
+ public CallTxExecutor(IBlockchainBridge blockchainBridge, IBlockFinder blockFinder, IJsonRpcConfig rpcConfig, ISpecProvider specProvider)
+ : base(blockchainBridge, blockFinder, rpcConfig, specProvider)
{
}
@@ -98,8 +114,8 @@ protected override ResultWrapper ExecuteTx(BlockHeader header, Transacti
private class EstimateGasTxExecutor : TxExecutor
{
- public EstimateGasTxExecutor(IBlockchainBridge blockchainBridge, IBlockFinder blockFinder, IJsonRpcConfig rpcConfig)
- : base(blockchainBridge, blockFinder, rpcConfig)
+ public EstimateGasTxExecutor(IBlockchainBridge blockchainBridge, IBlockFinder blockFinder, IJsonRpcConfig rpcConfig, ISpecProvider specProvider)
+ : base(blockchainBridge, blockFinder, rpcConfig, specProvider)
{
}
@@ -122,8 +138,8 @@ private class CreateAccessListTxExecutor : TxExecutor
{
private readonly bool _optimize;
- public CreateAccessListTxExecutor(IBlockchainBridge blockchainBridge, IBlockFinder blockFinder, IJsonRpcConfig rpcConfig, bool optimize)
- : base(blockchainBridge, blockFinder, rpcConfig)
+ public CreateAccessListTxExecutor(IBlockchainBridge blockchainBridge, IBlockFinder blockFinder, IJsonRpcConfig rpcConfig, ISpecProvider specProvider, bool optimize)
+ : base(blockchainBridge, blockFinder, rpcConfig, specProvider)
{
_optimize = optimize;
}
diff --git a/src/Nethermind/Nethermind.JsonRpc/Modules/Eth/EthRpcModule.cs b/src/Nethermind/Nethermind.JsonRpc/Modules/Eth/EthRpcModule.cs
index 7f2fd49d1a3..cf7811071fb 100644
--- a/src/Nethermind/Nethermind.JsonRpc/Modules/Eth/EthRpcModule.cs
+++ b/src/Nethermind/Nethermind.JsonRpc/Modules/Eth/EthRpcModule.cs
@@ -362,15 +362,15 @@ private async Task> SendTx(Transaction tx,
}
public ResultWrapper eth_call(TransactionForRpc transactionCall, BlockParameter? blockParameter = null) =>
- new CallTxExecutor(_blockchainBridge, _blockFinder, _rpcConfig)
+ new CallTxExecutor(_blockchainBridge, _blockFinder, _rpcConfig, _specProvider)
.ExecuteTx(transactionCall, blockParameter);
public ResultWrapper eth_estimateGas(TransactionForRpc transactionCall, BlockParameter blockParameter) =>
- new EstimateGasTxExecutor(_blockchainBridge, _blockFinder, _rpcConfig)
+ new EstimateGasTxExecutor(_blockchainBridge, _blockFinder, _rpcConfig, _specProvider)
.ExecuteTx(transactionCall, blockParameter);
public ResultWrapper eth_createAccessList(TransactionForRpc transactionCall, BlockParameter? blockParameter = null, bool optimize = true) =>
- new CreateAccessListTxExecutor(_blockchainBridge, _blockFinder, _rpcConfig, optimize)
+ new CreateAccessListTxExecutor(_blockchainBridge, _blockFinder, _rpcConfig, _specProvider, optimize)
.ExecuteTx(transactionCall, blockParameter);
public ResultWrapper eth_getBlockByHash(Keccak blockHash, bool returnFullTransactionObjects)
diff --git a/src/Nethermind/Nethermind.Serialization.Json/EthereumJsonSerializer.cs b/src/Nethermind/Nethermind.Serialization.Json/EthereumJsonSerializer.cs
index b3678e262b2..47fbd95bc8a 100644
--- a/src/Nethermind/Nethermind.Serialization.Json/EthereumJsonSerializer.cs
+++ b/src/Nethermind/Nethermind.Serialization.Json/EthereumJsonSerializer.cs
@@ -54,7 +54,8 @@ public EthereumJsonSerializer()
new BigIntegerConverter(),
new NullableBigIntegerConverter(),
new PublicKeyConverter(),
- new TxTypeConverter()
+ new TxTypeConverter(),
+ new NullableTxTypeConverter()
});
public IList BasicConverters { get; } = CommonConverters.ToList();
@@ -74,7 +75,8 @@ public EthereumJsonSerializer()
new BigIntegerConverter(NumberConversion.Decimal),
new NullableBigIntegerConverter(NumberConversion.Decimal),
new PublicKeyConverter(),
- new TxTypeConverter()
+ new TxTypeConverter(),
+ new NullableTxTypeConverter()
};
public T Deserialize(Stream stream)
diff --git a/src/Nethermind/Nethermind.Serialization.Json/NullableTxTypeConverter.cs b/src/Nethermind/Nethermind.Serialization.Json/NullableTxTypeConverter.cs
new file mode 100644
index 00000000000..c2ed60c0e9c
--- /dev/null
+++ b/src/Nethermind/Nethermind.Serialization.Json/NullableTxTypeConverter.cs
@@ -0,0 +1,55 @@
+// Copyright (c) 2021 Demerzel Solutions Limited
+// This file is part of the Nethermind library.
+//
+// The Nethermind 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 Nethermind 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 Nethermind. If not, see .
+//
+
+using System;
+using Nethermind.Core;
+using Newtonsoft.Json;
+
+namespace Nethermind.Serialization.Json
+{
+ public class NullableTxTypeConverter : JsonConverter
+ {
+ private TxTypeConverter _txTypeConverter;
+
+ public NullableTxTypeConverter()
+ {
+ _txTypeConverter = new TxTypeConverter();
+ }
+
+ public override void WriteJson(JsonWriter writer, TxType? value, JsonSerializer serializer)
+ {
+ if (!value.HasValue)
+ {
+ writer.WriteNull();
+ return;
+ }
+
+ _txTypeConverter.WriteJson(writer, value.Value, serializer);
+ }
+
+ public override TxType? ReadJson(JsonReader reader, Type objectType, TxType? existingValue, bool hasExistingValue,
+ JsonSerializer serializer)
+ {
+ if (reader.TokenType == JsonToken.Null || reader.Value == null)
+ {
+ return null;
+ }
+
+ return _txTypeConverter.ReadJson(reader, objectType, existingValue ?? TxType.Legacy, hasExistingValue, serializer);
+ }
+ }
+}
diff --git a/src/int256 b/src/int256
index 548d4aee373..ab61bef664d 160000
--- a/src/int256
+++ b/src/int256
@@ -1 +1 @@
-Subproject commit 548d4aee373b48c68609ef1eb909673a76cde715
+Subproject commit ab61bef664d3238cdb6f3aa189501b2684350db2
diff --git a/src/rocksdb-sharp b/src/rocksdb-sharp
index 63cc551ecf8..0d6715ddaeb 160000
--- a/src/rocksdb-sharp
+++ b/src/rocksdb-sharp
@@ -1 +1 @@
-Subproject commit 63cc551ecf8bb1d37dbf9ce0c13ae9673073f235
+Subproject commit 0d6715ddaeb1adca540f31aee2e052957a1652e4