diff --git a/scripts/known-failing-hive-tests.txt b/scripts/known-failing-hive-tests.txt index 8b1b62be06b0..9a04671e37bb 100644 --- a/scripts/known-failing-hive-tests.txt +++ b/scripts/known-failing-hive-tests.txt @@ -10,6 +10,7 @@ eth_simulateV1/ethSimulate-check-invalid-nonce (nethermind) eth_simulateV1/ethSimulate-gas-fees-and-value-error-38014-with-validation (nethermind) eth_simulateV1/ethSimulate-simple-no-funds-with-validation (nethermind) eth_simulateV1/ethSimulate-simple-no-funds-with-validation-without-nonces (nethermind) +eth_simulateV1/ethSimulate-simple-send-from-contract-with-validation (nethermind) # graphql diff --git a/src/Nethermind/Nethermind.JsonRpc.Test/Modules/Eth/Simulate/EthSimulateTestsBlocksAndTransactions.cs b/src/Nethermind/Nethermind.JsonRpc.Test/Modules/Eth/Simulate/EthSimulateTestsBlocksAndTransactions.cs index 2ee6e297c9fc..f8fc9ed74a16 100644 --- a/src/Nethermind/Nethermind.JsonRpc.Test/Modules/Eth/Simulate/EthSimulateTestsBlocksAndTransactions.cs +++ b/src/Nethermind/Nethermind.JsonRpc.Test/Modules/Eth/Simulate/EthSimulateTestsBlocksAndTransactions.cs @@ -702,4 +702,141 @@ public async Task eth_simulateV1_intrinsic_gas_returns_spec_error_code_and_messa Assert.That(result.Result!.Error, Is.EqualTo(SimulateErrorMessages.IntrinsicGas)); } + /// + /// Regression test: eth_simulateV1 with validation:true and a nonce below the account's current + /// nonce must return -38010 (NonceTooLow). + /// + [Test] + public async Task eth_simulateV1_nonce_too_low_returns_spec_error_code() + { + TestRpcBlockchain chain = await EthRpcSimulateTestsBase.CreateChain(); + + // Set the account's nonce to 10, then send a tx with nonce 0 (below current). + SimulatePayload payload = new() + { + BlockStateCalls = + [ + new() + { + StateOverrides = new Dictionary + { + { TestItem.AddressA, new AccountOverride { Balance = 1.Ether, Nonce = 10 } } + }, + Calls = + [ + new LegacyTransactionForRpc + { + From = TestItem.AddressA, + To = TestItem.AddressB, + Value = UInt256.Zero, + Nonce = 0, + GasPrice = UInt256.Zero, + Gas = 21_000 + } + ] + } + ], + Validation = true + }; + + ResultWrapper>> result = + chain.EthRpcModule.eth_simulateV1(payload, BlockParameter.Latest); + + Assert.That(result.ErrorCode, Is.EqualTo(ErrorCodes.NonceTooLow)); + } + + /// + /// Regression test: eth_simulateV1 with validation:true and a nonce above the account's current + /// nonce must return -38011 (NonceTooHigh). + /// + [Test] + public async Task eth_simulateV1_nonce_too_high_returns_spec_error_code() + { + TestRpcBlockchain chain = await EthRpcSimulateTestsBase.CreateChain(); + + // Account nonce is 0; send a tx with nonce 100 (way above current). + SimulatePayload payload = new() + { + BlockStateCalls = + [ + new() + { + StateOverrides = new Dictionary + { + { TestItem.AddressA, new AccountOverride { Balance = 1.Ether } } + }, + Calls = + [ + new LegacyTransactionForRpc + { + From = TestItem.AddressA, + To = TestItem.AddressB, + Value = UInt256.Zero, + Nonce = 100, + GasPrice = UInt256.Zero, + Gas = 21_000 + } + ] + } + ], + Validation = true + }; + + ResultWrapper>> result = + chain.EthRpcModule.eth_simulateV1(payload, BlockParameter.Latest); + + Assert.That(result.ErrorCode, Is.EqualTo(ErrorCodes.NonceTooHigh)); + } + + /// + /// Regression test: eth_simulateV1 with validation:true and a sender address that has deployed + /// code (EIP-3607) must return -38024 (SenderIsNotEoa). + /// + [Test] + public async Task eth_simulateV1_sender_is_not_eoa_returns_spec_error_code() + { + OverridableReleaseSpec spec = new(London.Instance) { IsEip3607Enabled = true }; + TestSpecProvider specProvider = new(spec) { AllowTestChainOverride = false }; + TestRpcBlockchain chain = await TestRpcBlockchain.ForTest(new TestRpcBlockchain()).Build(specProvider); + + // Override TestItem.AddressC with contract code — makes it a non-EOA sender. + SimulatePayload payload = new() + { + BlockStateCalls = + [ + new() + { + StateOverrides = new Dictionary + { + { + TestItem.AddressC, + new AccountOverride + { + Balance = 1.Ether, + Code = Bytes.FromHexString("0x60006000") + } + } + }, + Calls = + [ + new LegacyTransactionForRpc + { + From = TestItem.AddressC, + To = TestItem.AddressB, + Value = UInt256.Zero, + GasPrice = UInt256.Zero, + Gas = 21_000 + } + ] + } + ], + Validation = true + }; + + ResultWrapper>> result = + chain.EthRpcModule.eth_simulateV1(payload, BlockParameter.Latest); + + Assert.That(result.ErrorCode, Is.EqualTo(ErrorCodes.SenderIsNotEoa)); + } + } diff --git a/src/Nethermind/Nethermind.JsonRpc/ErrorCodes.cs b/src/Nethermind/Nethermind.JsonRpc/ErrorCodes.cs index d981d9169868..bdc798a89f80 100644 --- a/src/Nethermind/Nethermind.JsonRpc/ErrorCodes.cs +++ b/src/Nethermind/Nethermind.JsonRpc/ErrorCodes.cs @@ -122,28 +122,43 @@ public static class ErrorCodes /// public const int Default = -32000; + /// + /// Transaction nonce is lower than the account's current nonce — eth_simulateV1 spec error + /// + public const int NonceTooLow = -38010; + + /// + /// Transaction nonce is higher than the account's current nonce — eth_simulateV1 spec error + /// + public const int NonceTooHigh = -38011; + /// /// Transaction maxFeePerGas is below the block base fee — eth_simulateV1 spec error /// public const int FeeCapBelowBaseFee = -38012; /// - /// Transaction gas limit is below the intrinsic gas cost + /// Transaction gas limit is below the intrinsic gas cost — eth_simulateV1 spec error /// public const int IntrinsicGas = -38013; /// - /// Not enough value to cover transaction costs + /// Not enough value to cover transaction costs — eth_simulateV1 spec error /// public const int InsufficientFunds = -38014; /// - /// Gas limit reached + /// Gas limit reached — eth_simulateV1 spec error /// public const int BlockGasLimitReached = -38015; /// - /// EIP-3860. Code size is to big + /// Sender account has deployed code (is not an EOA) — eth_simulateV1 spec error + /// + public const int SenderIsNotEoa = -38024; + + /// + /// EIP-3860. Code size is too big — eth_simulateV1 spec error /// public const int MaxInitCodeSizeExceeded = -38025; diff --git a/src/Nethermind/Nethermind.JsonRpc/Modules/Eth/SimulateTxExecutor.cs b/src/Nethermind/Nethermind.JsonRpc/Modules/Eth/SimulateTxExecutor.cs index eec1f4ba985e..66cc6205cc22 100644 --- a/src/Nethermind/Nethermind.JsonRpc/Modules/Eth/SimulateTxExecutor.cs +++ b/src/Nethermind/Nethermind.JsonRpc/Modules/Eth/SimulateTxExecutor.cs @@ -255,11 +255,11 @@ private static int MapSimulateErrorCode(TransactionResult txResult) TransactionResult.ErrorType.MaxFeePerGasBelowBaseFee or TransactionResult.ErrorType.MinerPremiumNegative => ErrorCodes.FeeCapBelowBaseFee, TransactionResult.ErrorType.NonceOverflow => ErrorCodes.InternalError, - TransactionResult.ErrorType.SenderHasDeployedCode => ErrorCodes.InvalidParams, + TransactionResult.ErrorType.SenderHasDeployedCode => ErrorCodes.SenderIsNotEoa, TransactionResult.ErrorType.SenderNotSpecified => ErrorCodes.InternalError, TransactionResult.ErrorType.TransactionSizeOverMaxInitCodeSize => ErrorCodes.MaxInitCodeSizeExceeded, - TransactionResult.ErrorType.TransactionNonceTooHigh => ErrorCodes.InternalError, - TransactionResult.ErrorType.TransactionNonceTooLow => ErrorCodes.InternalError, + TransactionResult.ErrorType.TransactionNonceTooHigh => ErrorCodes.NonceTooHigh, + TransactionResult.ErrorType.TransactionNonceTooLow => ErrorCodes.NonceTooLow, _ => ErrorCodes.InternalError }; }