Skip to content
Merged
Show file tree
Hide file tree
Changes from 27 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion scripts/known-failing-hive-tests.txt
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,12 @@

eth_getStorageAt/get-storage-invalid-key (nethermind)
eth_getStorageAt/get-storage-invalid-key-too-large (nethermind)
eth_createAccessList/create-al-abi-revert (nethermind)
eth_estimateGas/estimate-with-eip4844 (nethermind)
eth_sendRawTransaction/send-blob-tx (nethermind)
eth_simulateV1/ethSimulate-instrict-gas-38013 (nethermind)
eth_simulateV1/ethSimulate-run-gas-spending (nethermind)
eth_simulateV1/ethSimulate-run-out-of-gas-in-block-38015 (nethermind)
eth_simulateV1/ethSimulate-simple-more-params-validate (nethermind)
eth_simulateV1/ethSimulate-two-blocks-with-complete-eth-sends (nethermind)
eth_simulateV1/ethSimulate-use-as-many-features-as-possible (nethermind)

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,6 @@ public class BlobTransactionForRpc : EIP1559TransactionForRpc, IFromTransaction<
public override TxType? Type => TxType;

[JsonIgnore(Condition = JsonIgnoreCondition.Never)]
[JsonDiscriminator]
Comment thread
LukaszRozmej marked this conversation as resolved.
public UInt256? MaxFeePerBlobGas { get; set; }

// TODO: Each item should be a 32 byte array
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -123,27 +123,29 @@ internal static void RegisterTransactionType<T>() where T : TransactionForRpc, I

public override TransactionForRpc? Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
{
const string TypeFieldKey = nameof(TransactionForRpc.Type);
// Copy the reader so we can do a double parse:
// The first parse is used to check for fields, while the second parses the entire Transaction
Utf8JsonReader txTypeReader = reader;
JsonObject untyped = JsonSerializer.Deserialize<JsonObject>(ref txTypeReader, options);

TxType? txType = null;
if (untyped.TryGetPropertyValue(TypeFieldKey, out JsonNode? node))
Type concreteTxType = DeriveTxType(untyped, options);

return (TransactionForRpc?)JsonSerializer.Deserialize(ref reader, concreteTxType, options);
}

private Type DeriveTxType(JsonObject untyped, JsonSerializerOptions options)

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
private Type DeriveTxType(JsonObject untyped, JsonSerializerOptions options)
private Type DeriveTxType(JsonObject untyped)

{
const TxType defaultTxType = TxType.EIP1559;
const string gasPriceFieldKey = nameof(LegacyTransactionForRpc.GasPrice);

if (untyped.ContainsKey(gasPriceFieldKey))
{
txType = node.Deserialize<TxType?>(options);
return typeof(LegacyTransactionForRpc);
}
Comment on lines +152 to +155

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If Legacy is first item in _txTypes we can probably drop this if?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think it's last. So we should return Legacy if gasPrice is set. Even if we have blobHashes

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ok we have:

// Adding in reverse order so newer tx types are in priority

Interesting, maybe we should do that ignoring index?

So:

int indexOfPreviousTxType = _txTypes.FindIndex(t => t.TxType != TxType.Legacy && t.TxType < typeInfo.TxType); ?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't understand what's typeInfo.TxType. I think now it's very straight-forward


Type concreteTxType =
(
txType is not null
? _txTypes.FirstOrDefault(p => p.TxType == txType)
: _txTypes.FirstOrDefault(p => p.DiscriminatorProperties.Any(name => untyped.ContainsKey(name)), _txTypes[^1])
)?.Type
?? throw new JsonException("Unknown transaction type");

return (TransactionForRpc?)JsonSerializer.Deserialize(ref reader, concreteTxType, options);
return _txTypes
.FirstOrDefault(p => p.TxType == defaultTxType || p.DiscriminatorProperties.Any(untyped.ContainsKey),
_txTypes[^1]).Type;

@LukaszRozmej LukaszRozmej Oct 29, 2025

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't get it...

Won't this often default to defaultTxType and it is based on order?

I would expect something like below:

Suggested change
return _txTypes
.FirstOrDefault(p => p.TxType == defaultTxType || p.DiscriminatorProperties.Any(untyped.ContainsKey),
_txTypes[^1]).Type;
return _txTypes.FirstOrDefault(p => p.DiscriminatorProperties.Any(untyped.ContainsKey))?.Type ?? defaultTxType;

}

public override void Write(Utf8JsonWriter writer, TransactionForRpc value, JsonSerializerOptions options)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ public static IEnumerable TxJsonTestCases
yield return Make(TxType.Legacy, """{}""");
yield return Make(TxType.Legacy, """{"type":null}""");
yield return Make(TxType.Legacy, """{"additionalField":""}""");
yield return Make(TxType.Legacy, """{"MaxFeePerBlobGas":"0x0"}""");

yield return Make(TxType.AccessList, """{"type":null,"accessList":[]}""");
yield return Make(TxType.AccessList, """{"nonce":"0x0","to":null,"value":"0x0","accessList":[]}""");
Expand All @@ -55,11 +56,10 @@ public static IEnumerable TxJsonTestCases
yield return Make(TxType.EIP1559, """{"maxFeePerGas":"0x0"}""");
yield return Make(TxType.EIP1559, """{"maxPriorityFeePerGas":"0x0"}""");
yield return Make(TxType.EIP1559, """{"MaxPriorityFeePerGas":"0x0"}""");
yield return Make(TxType.EIP1559, """{"nonce":"0x0","to":null,"value":"0x0","maxPriorityFeePerGas":"0x0", "maxFeePerGas":"0x0","maxFeePerBlobGas":"0x0"}""");

yield return Make(TxType.Blob, """{"nonce":"0x0","to":null,"value":"0x0","accessList":[],"maxFeePerBlobGas":"0x0"}""");
yield return Make(TxType.Blob, """{"nonce":"0x0","to":null,"value":"0x0","maxPriorityFeePerGas":"0x0", "maxFeePerGas":"0x0","maxFeePerBlobGas":"0x0"}""");
yield return Make(TxType.Blob, """{"nonce":"0x0","to":null,"value":"0x0","accessList":[],"blobVersionedHashes":[]}""");
yield return Make(TxType.Blob, """{"maxFeePerBlobGas":"0x0", "blobVersionedHashes":[]}""");
yield return Make(TxType.Blob, """{"MaxFeePerBlobGas":"0x0"}""");
yield return Make(TxType.Blob, """{"blobVersionedHashes":[]}""");
yield return Make(TxType.Blob, """{"BlobVersionedHashes":null}""");
yield return Make(TxType.Blob, """{"blobVersionedHashes":["0x01f1872d656b7a820d763e6001728b9b883f829b922089ec6ad7f5f1665470dc"]}""");
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ public async Task Test_debug_simulate_eth_moved()
TestRpcBlockchain chain = await EthRpcSimulateTestsBase.CreateChain();

UInt256 nonceA = chain.ReadOnlyState.GetNonce(TestItem.AddressA);
Transaction txMainnetAtoB = EthSimulateTestsBlocksAndTransactions.GetTransferTxData(nonceA, chain.EthereumEcdsa, TestItem.PrivateKeyA, TestItem.AddressB, 1);
Transaction txMainnetAtoB = EthSimulateTestsBlocksAndTransactions.GetTransferTxData(nonceA, chain.EthereumEcdsa, TestItem.PrivateKeyA, TestItem.AddressB, 1, type: TxType.Legacy);

SimulatePayload<TransactionForRpc> payload = EthSimulateTestsBlocksAndTransactions.CreateEthMovedPayload(chain, nonceA);

Expand Down Expand Up @@ -93,7 +93,7 @@ public async Task Test_debug_simulate_transactions_forced_fail()
UInt256 nonceA = chain.ReadOnlyState.GetNonce(TestItem.AddressA);

Transaction txMainnetAtoB =
EthSimulateTestsBlocksAndTransactions.GetTransferTxData(nonceA, chain.EthereumEcdsa, TestItem.PrivateKeyA, TestItem.AddressB, 1);
EthSimulateTestsBlocksAndTransactions.GetTransferTxData(nonceA, chain.EthereumEcdsa, TestItem.PrivateKeyA, TestItem.AddressB, 1, type: TxType.Legacy);

SimulatePayload<TransactionForRpc> payload = EthSimulateTestsBlocksAndTransactions.CreateTransactionsForcedFail(chain, nonceA);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -141,10 +141,11 @@ public static SimulatePayload<TransactionForRpc> CreateTransactionsForcedFail(Te
};
}

public static Transaction GetTransferTxData(UInt256 nonce, IEthereumEcdsa ethereumEcdsa, PrivateKey from, Address to, UInt256 amount)
public static Transaction GetTransferTxData(UInt256 nonce, IEthereumEcdsa ethereumEcdsa, PrivateKey from, Address to, UInt256 amount, TxType type = TxType.EIP1559)
{
Transaction tx = new()
{
Type = type,
Value = amount,
Nonce = nonce,
GasLimit = 50_000,
Expand Down Expand Up @@ -192,7 +193,7 @@ public async Task Test_eth_simulate_eth_moved()
TestRpcBlockchain chain = await EthRpcSimulateTestsBase.CreateChain();

UInt256 nonceA = chain.ReadOnlyState.GetNonce(TestItem.AddressA);
Transaction txMainnetAtoB = GetTransferTxData(nonceA, chain.EthereumEcdsa, TestItem.PrivateKeyA, TestItem.AddressB, 1);
Transaction txMainnetAtoB = GetTransferTxData(nonceA, chain.EthereumEcdsa, TestItem.PrivateKeyA, TestItem.AddressB, 1, type: TxType.Legacy);

SimulatePayload<TransactionForRpc> payload = CreateEthMovedPayload(chain, nonceA);

Expand Down Expand Up @@ -233,7 +234,7 @@ public async Task Test_eth_simulate_transactions_forced_fail()
UInt256 nonceA = chain.ReadOnlyState.GetNonce(TestItem.AddressA);

Transaction txMainnetAtoB =
GetTransferTxData(nonceA, chain.EthereumEcdsa, TestItem.PrivateKeyA, TestItem.AddressB, 1);
GetTransferTxData(nonceA, chain.EthereumEcdsa, TestItem.PrivateKeyA, TestItem.AddressB, 1, type: TxType.Legacy);

SimulatePayload<TransactionForRpc> payload = CreateTransactionsForcedFail(chain, nonceA);

Expand Down Expand Up @@ -276,6 +277,7 @@ public static SimulatePayload<TransactionForRpc> CreateTransferLogsAddressPayloa
},
"calls": [
{
"type": "0x3",
"from": "0xc000000000000000000000000000000000000000",
"to": "0xc100000000000000000000000000000000000000",
"gas": "0x5208",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ public async Task Test_trace_simulate_eth_moved()
TestRpcBlockchain chain = await EthRpcSimulateTestsBase.CreateChain();

UInt256 nonceA = chain.ReadOnlyState.GetNonce(TestItem.AddressA);
Transaction txMainnetAtoB = EthSimulateTestsBlocksAndTransactions.GetTransferTxData(nonceA, chain.EthereumEcdsa, TestItem.PrivateKeyA, TestItem.AddressB, 1);
Transaction txMainnetAtoB = EthSimulateTestsBlocksAndTransactions.GetTransferTxData(nonceA, chain.EthereumEcdsa, TestItem.PrivateKeyA, TestItem.AddressB, 1, type: TxType.Legacy);

SimulatePayload<TransactionForRpc> payload = EthSimulateTestsBlocksAndTransactions.CreateEthMovedPayload(chain, nonceA);

Expand Down Expand Up @@ -89,7 +89,7 @@ public async Task Test_trace_simulate_transactions_forced_fail()
UInt256 nonceA = chain.ReadOnlyState.GetNonce(TestItem.AddressA);

Transaction txMainnetAtoB =
EthSimulateTestsBlocksAndTransactions.GetTransferTxData(nonceA, chain.EthereumEcdsa, TestItem.PrivateKeyA, TestItem.AddressB, 1);
EthSimulateTestsBlocksAndTransactions.GetTransferTxData(nonceA, chain.EthereumEcdsa, TestItem.PrivateKeyA, TestItem.AddressB, 1, type: TxType.Legacy);

SimulatePayload<TransactionForRpc> payload = EthSimulateTestsBlocksAndTransactions.CreateTransactionsForcedFail(chain, nonceA);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,6 @@ protected override SimulatePayload<TransactionWithSourceDetails> Prepare(Simulat
StateOverrides = blockStateCall.StateOverrides,
Calls = blockStateCall.Calls?.Select(callTransactionModel =>
{
callTransactionModel = UpdateTxType(callTransactionModel);
LegacyTransactionForRpc asLegacy = callTransactionModel as LegacyTransactionForRpc;
bool hadGasLimitInRequest = asLegacy?.Gas is not null;
bool hadNonceInRequest = asLegacy?.Nonce is not null;
Expand Down Expand Up @@ -76,30 +75,6 @@ protected override SimulatePayload<TransactionWithSourceDetails> Prepare(Simulat
return result;
}

private static TransactionForRpc UpdateTxType(TransactionForRpc rpcTransaction)
{
// TODO: This is a bit messy since we're changing the transaction type
if (rpcTransaction is LegacyTransactionForRpc legacy && rpcTransaction is not EIP1559TransactionForRpc)
{
rpcTransaction = new EIP1559TransactionForRpc
{
Nonce = legacy.Nonce,
To = legacy.To,
From = legacy.From,
Gas = legacy.Gas,
Value = legacy.Value,
Input = legacy.Input,
GasPrice = legacy.GasPrice,
ChainId = legacy.ChainId,
V = legacy.V,
R = legacy.R,
S = legacy.S,
};
}

return rpcTransaction;
}

public override ResultWrapper<IReadOnlyList<SimulateBlockResult<TTrace>>> Execute(
SimulatePayload<TransactionForRpc> call,
BlockParameter? blockParameter,
Expand Down
Loading