Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Refactor TransactionForRpc #7446

Closed
wants to merge 78 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
78 commits
Select commit Hold shift + click to select a range
84178b8
Initial `RpcLegacyTransaction`
emlautarom1 Sep 4, 2024
a2739f4
Change field order
emlautarom1 Sep 5, 2024
af3b042
Support null as `ChainId` through `TransactionBuilder`
emlautarom1 Sep 5, 2024
ec1a21e
Initial `RpcAccessListTransaction`
emlautarom1 Sep 5, 2024
88dd0e3
Add `RandomSignature`s
emlautarom1 Sep 5, 2024
e9994ea
Use `TestItem` random `Signature`s
emlautarom1 Sep 5, 2024
1839a0d
Initial `RpcEIP1559Transaction`
emlautarom1 Sep 5, 2024
2833a9e
Rename `TestCaseSource`
emlautarom1 Sep 5, 2024
3caed48
Fix `DefaultChainId`
emlautarom1 Sep 5, 2024
67ec222
Guarantee Blob transaction invariants
emlautarom1 Sep 5, 2024
0f997c9
Initial `RpcBlobTransaction`
emlautarom1 Sep 5, 2024
5ae394a
Initial `IRpcTransaction`
emlautarom1 Sep 10, 2024
14d3cae
Initial `IRpcTransactionConverter`
emlautarom1 Sep 10, 2024
11c237e
Move `RpcXTransaction` to class hierarchy
emlautarom1 Sep 10, 2024
7580bc4
Merge `RPCXTransactionTests` into a single test
emlautarom1 Sep 10, 2024
b073e50
Rename test class
emlautarom1 Sep 11, 2024
a13fcc0
Initial `RpcOptimismTransaction`
emlautarom1 Sep 11, 2024
48326d5
Add `WithSourceHash` to builder
emlautarom1 Sep 11, 2024
16765be
Initial `RpcAccessList`
emlautarom1 Sep 11, 2024
f673490
Annotate converter instead of registering
emlautarom1 Sep 11, 2024
cdd4f23
Use annotation for `IRpcTransaction`
emlautarom1 Sep 11, 2024
a9f6277
Initial `RpcGenericTransaction`
emlautarom1 Sep 12, 2024
7db803b
Initial JSON deserialization code
emlautarom1 Sep 13, 2024
0fee0cf
Remove `TxReceipt` for now
emlautarom1 Sep 13, 2024
19686a1
Test for member equality in JSON (de)serialization
emlautarom1 Sep 13, 2024
38f2a1f
Introduce `ITransactionConverter<T>`
emlautarom1 Sep 13, 2024
4e040bf
Add `TODO`
emlautarom1 Sep 13, 2024
07690be
Update inline docs
emlautarom1 Sep 13, 2024
92394c1
Whitespace
emlautarom1 Sep 13, 2024
b7c42cf
Delete unused classes
emlautarom1 Sep 13, 2024
fe8e7e7
Define `RpcNethermindTransaction` as base class
emlautarom1 Sep 13, 2024
c76f72f
Inherit from `RpcNethermindTransaction`
emlautarom1 Sep 13, 2024
629dda7
Add `TransactionConverterExtraData`
emlautarom1 Sep 13, 2024
e3c884a
Add `ToTransaction`
emlautarom1 Sep 13, 2024
33213e5
Implement `ToTransaction`
emlautarom1 Sep 13, 2024
115dbfc
Update inline docs
emlautarom1 Sep 13, 2024
fb91767
Remove deprecated fields in Blob transactions
emlautarom1 Sep 13, 2024
90fe6fa
Retrofit `Data ~ Input` fix
emlautarom1 Sep 13, 2024
121e057
Move docs
emlautarom1 Sep 13, 2024
cbc3b7f
Initial `ToTransactionWithDefaults`
emlautarom1 Sep 16, 2024
3660df5
Change `ChainId` from UInt256 to ulong in JSON DTO
emlautarom1 Sep 16, 2024
5311804
Update inline TODOs
emlautarom1 Sep 16, 2024
f8c0495
Implement remaining `ToTransactionWithDefaults`
emlautarom1 Sep 16, 2024
dd43cf9
Add `From` field
emlautarom1 Sep 16, 2024
34de464
Add defaults test
emlautarom1 Sep 16, 2024
f8283e4
Add `EnsureDefaults`
emlautarom1 Sep 16, 2024
0b63ce6
Add test ignore
emlautarom1 Sep 16, 2024
eb98675
Forward `baseFee`
emlautarom1 Sep 16, 2024
11b1522
Use `RpcGenericTransaction` approach
emlautarom1 Sep 16, 2024
f4dd96b
Update flow docs
emlautarom1 Sep 16, 2024
8ee417e
Remove JSON constructor
emlautarom1 Sep 16, 2024
422460b
Add `IToTransaction<T>`
emlautarom1 Sep 16, 2024
416a21e
Add `RpcGenericTransaction`
emlautarom1 Sep 16, 2024
e2683f9
Implement `IToTransaction, IFromTransaction`
emlautarom1 Sep 16, 2024
1bb457d
Implement `ToTransactionWithDefaults`
emlautarom1 Sep 16, 2024
aaf6d53
Remove deleted files
emlautarom1 Sep 16, 2024
443115c
Implement `IToTransaction, IFromTransaction` for OP
emlautarom1 Sep 16, 2024
c431ad9
Add `EnsureDefaults`
emlautarom1 Sep 16, 2024
6cda988
Remove roundtrip tests
emlautarom1 Sep 16, 2024
e2e7691
Test for Nethermind fields
emlautarom1 Sep 16, 2024
5ad5049
Move files
emlautarom1 Sep 16, 2024
825d455
Proper inline docs
emlautarom1 Sep 16, 2024
5f3e553
Rename class
emlautarom1 Sep 16, 2024
79761d0
Fix import
emlautarom1 Sep 16, 2024
1ff3356
Simplify XML reference
emlautarom1 Sep 16, 2024
80264f4
Fix imports
emlautarom1 Sep 16, 2024
e07620d
Make fields `init` only
emlautarom1 Sep 16, 2024
70abd1b
Add transition `RpcGenericTransactionExtensions`
emlautarom1 Sep 16, 2024
aba2970
Preserve nullability
emlautarom1 Sep 16, 2024
70b175c
Simplify accessor
emlautarom1 Sep 16, 2024
93f94a9
Remove `chainId` from `ToTransactionWithDefaults`
emlautarom1 Sep 16, 2024
a9a06f4
Add more fallback methods durin dev
emlautarom1 Sep 16, 2024
4d88ba9
Remove `IRpcTransaction`
emlautarom1 Sep 16, 2024
e5d576d
Mimic `RpcNethermindTransaction.TransactionConverter`
emlautarom1 Sep 16, 2024
1d13861
Remove duplicated comment
emlautarom1 Sep 16, 2024
8a70ee5
Merge branch 'master' into refactor/individual-transaction-for-rpc
emlautarom1 Sep 16, 2024
04133ef
Fix whitespace
emlautarom1 Sep 16, 2024
4a07b2e
Merge branch 'master' into refactor/individual-transaction-for-rpc
emlautarom1 Sep 18, 2024
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
10 changes: 10 additions & 0 deletions src/Nethermind/Nethermind.Core.Test/Builders/TestItem.cs
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,13 @@ static TestItem()
Keccaks[i - 1] = Keccak.Compute(PublicKeys[i - 1].Bytes);
ValueKeccaks[i - 1] = Keccaks[i - 1];
}

byte[] r = new byte[32];
byte[] s = new byte[32];
r[1] = 1;
s[2] = 2;
RandomSignatureA = new Signature(r, s, 27);
RandomSignatureB = new Signature(r, s, 28);
}

public static Hash256 KeccakFromNumber(int i)
Expand Down Expand Up @@ -92,6 +99,9 @@ public static Hash256 KeccakFromNumber(int i)
public static Address AddressE = PublicKeyE.Address;
public static Address AddressF = PublicKeyF.Address;

public static readonly Signature RandomSignatureA;
public static readonly Signature RandomSignatureB;

public static Withdrawal WithdrawalA_1Eth = new() { Address = AddressA, Index = 1, ValidatorIndex = 2001, AmountInGwei = 1_000_000_000 };
public static Withdrawal WithdrawalB_2Eth = new() { Address = AddressB, Index = 2, ValidatorIndex = 2002, AmountInGwei = 2_000_000_000 };
public static Withdrawal WithdrawalC_3Eth = new() { Address = AddressC, Index = 3, ValidatorIndex = 2003, AmountInGwei = 3_000_000_000 };
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@ public TransactionBuilder<T> WithCode(byte[] data)
return this;
}

public TransactionBuilder<T> WithChainId(ulong chainId)
public TransactionBuilder<T> WithChainId(ulong? chainId)
{
TestObjectInternal.ChainId = chainId;
return this;
Expand Down Expand Up @@ -265,6 +265,16 @@ public TransactionBuilder<T> SignedAndResolved(PrivateKey? privateKey = null)
protected override void BeforeReturn()
{
base.BeforeReturn();

// Since hash calculation requires certail values to be present in Blob transactions
// we initalize them to sane defaults here.
// TODO: This should be removed when we have a proper Transaction type hierarchy
if (TestObjectInternal.Type == TxType.Blob)
{
TestObjectInternal.BlobVersionedHashes ??= [];
TestObjectInternal.MaxFeePerBlobGas ??= 0;
}

if (TestObjectInternal.IsSigned)
{
TestObjectInternal.Hash = TestObjectInternal.CalculateHash();
Expand All @@ -282,5 +292,11 @@ public TransactionBuilder<T> WithIsServiceTransaction(bool isServiceTransaction)
TestObjectInternal.IsServiceTransaction = isServiceTransaction;
return this;
}

public TransactionBuilder<T> WithSourceHash(Hash256? sourceHash)
{
TestObjectInternal.SourceHash = sourceHash;
return this;
}
}
}
23 changes: 23 additions & 0 deletions src/Nethermind/Nethermind.Facade/Eth/IFromTransaction.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
// SPDX-FileCopyrightText: 2022 Demerzel Solutions Limited
// SPDX-License-Identifier: LGPL-3.0-only

using Nethermind.Core;
using Nethermind.Core.Crypto;
using Nethermind.Int256;

namespace Nethermind.Facade.Eth;

public interface IFromTransaction<out T>
{
T FromTransaction(Transaction tx, TransactionConverterExtraData extraData);
T FromTransaction(Transaction tx) => FromTransaction(tx, new TransactionConverterExtraData());
}

public readonly struct TransactionConverterExtraData
{
public Hash256? BlockHash { get; init; }
public long? BlockNumber { get; init; }
public int? TxIndex { get; init; }
public UInt256? BaseFee { get; init; }
public TxReceipt Receipt { get; init; }
}
13 changes: 13 additions & 0 deletions src/Nethermind/Nethermind.Facade/Eth/IToTransaction.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
// SPDX-FileCopyrightText: 2022 Demerzel Solutions Limited
// SPDX-License-Identifier: LGPL-3.0-only

using Nethermind.Core;

namespace Nethermind.Facade.Eth;

// TODO: We might want to lift this to `Core`
public interface IToTransaction<in T>
{
Transaction ToTransaction(T t);
Transaction ToTransactionWithDefaults(T t);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
// SPDX-FileCopyrightText: 2022 Demerzel Solutions Limited
// SPDX-License-Identifier: LGPL-3.0-only

using System.Collections.Generic;
using System.Linq;
using Nethermind.Core;
using Nethermind.Core.Eip2930;
using Nethermind.Int256;
using Nethermind.Serialization.Json;
using System.Text.Json.Serialization;
using System.Text.Json;
using System;

namespace Nethermind.Facade.Eth.RpcTransaction;

[JsonConverter(typeof(JsonConverterImpl))]
public record RpcAccessList
{
private readonly List<Item> _items;

[JsonConstructor]
public RpcAccessList() { }

private RpcAccessList(List<Item> items)
{
_items = items;
}

private class Item
{
public Address Address { get; set; }

[JsonConverter(typeof(StorageCellIndexConverter))]
public IEnumerable<UInt256> StorageKeys { get; set; }

[JsonConstructor]
public Item() { }

public Item(Address address, List<UInt256> storageKeys)
{
Address = address;
StorageKeys = storageKeys;
}
}

public static RpcAccessList FromAccessList(AccessList? accessList) =>
accessList is null
? new RpcAccessList([])
: new RpcAccessList(accessList.Select(item => new Item(item.Address, [.. item.StorageKeys])).ToList());

public AccessList ToAccessList()
{
AccessList.Builder builder = new();
foreach (Item item in _items)
{
builder.AddAddress(item.Address);
foreach (UInt256 index in item.StorageKeys)
{
builder.AddStorage(index);
}
}

return builder.Build();
}

public static readonly JsonConverter<RpcAccessList> JsonConverter = new JsonConverterImpl();

public class JsonConverterImpl : JsonConverter<RpcAccessList>
{
public override RpcAccessList? Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
{
List<Item> list = JsonSerializer.Deserialize<List<Item>>(ref reader, options);
return list is null ? null : new RpcAccessList(list);
}

public override void Write(Utf8JsonWriter writer, RpcAccessList value, JsonSerializerOptions options)
{
JsonSerializer.Serialize(writer, value._items, options);
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
// SPDX-FileCopyrightText: 2022 Demerzel Solutions Limited
// SPDX-License-Identifier: LGPL-3.0-only

using Nethermind.Core;
using Nethermind.Core.Crypto;
using Nethermind.Int256;

namespace Nethermind.Facade.Eth.RpcTransaction;

public class RpcAccessListTransaction : RpcLegacyTransaction
{
// HACK: To ensure that serialized Txs always have a `ChainId` we keep the last loaded `ChainSpec`.
// See: https://github.com/NethermindEth/nethermind/pull/6061#discussion_r1321634914
public static UInt256? DefaultChainId { get; set; }

public RpcAccessList AccessList { get; set; }

public new UInt256 ChainId { get; set; }

public UInt256 YParity { get; set; }

/// <summary>
/// For backwards compatibility, <c>v</c> is optionally provided as an alternative to <c>yParity</c>.
/// This field is <b>DEPRECATED</b> and all use of it should migrate to <c>yParity</c>.
/// </summary>
public override UInt256 V { get; set; }

public RpcAccessListTransaction(Transaction transaction, int? txIndex = null, Hash256? blockHash = null, long? blockNumber = null)
: base(transaction, txIndex, blockHash, blockNumber)
{
AccessList = RpcAccessList.FromAccessList(transaction.AccessList);
ChainId = transaction.ChainId
?? DefaultChainId
?? BlockchainIds.Mainnet;
YParity = transaction.Signature?.RecoveryId ?? 0;
V = YParity;
}

public new class Converter : IToTransaction<RpcGenericTransaction>, IFromTransaction<RpcAccessListTransaction>
{
private readonly RpcLegacyTransaction.Converter _baseConverter = new();

public RpcAccessListTransaction FromTransaction(Transaction tx, TransactionConverterExtraData extraData)
=> new(tx, txIndex: extraData.TxIndex, blockHash: extraData.BlockHash, blockNumber: extraData.BlockNumber);

public Transaction ToTransaction(RpcGenericTransaction rpcTx)
{
var tx = _baseConverter.ToTransaction(rpcTx);
tx.AccessList = rpcTx.AccessList?.ToAccessList() ?? Core.Eip2930.AccessList.Empty;
return tx;
}

public Transaction ToTransactionWithDefaults(RpcGenericTransaction rpcTx)
{
var tx = _baseConverter.ToTransactionWithDefaults(rpcTx);
tx.AccessList = rpcTx.AccessList?.ToAccessList() ?? Core.Eip2930.AccessList.Empty;
return tx;
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
// SPDX-FileCopyrightText: 2022 Demerzel Solutions Limited
// SPDX-License-Identifier: LGPL-3.0-only

using System.Text.Json.Serialization;
using Nethermind.Core;
using Nethermind.Core.Crypto;
using Nethermind.Int256;

namespace Nethermind.Facade.Eth.RpcTransaction;

public class RpcBlobTransaction : RpcEIP1559Transaction
{
public UInt256 MaxFeePerBlobGas { get; set; }

// TODO: Each item should be a 32 byte array
// Currently we don't enforce this (hashes can have any length)
public byte[][] BlobVersionedHashes { get; set; }

[JsonIgnore(Condition = JsonIgnoreCondition.Always)]
public override UInt256 GasPrice { get; set; }

[JsonIgnore(Condition = JsonIgnoreCondition.Always)]
public override UInt256 V { get; set; }

public RpcBlobTransaction(Transaction transaction, int? txIndex = null, Hash256? blockHash = null, long? blockNumber = null, UInt256? baseFee = null)
: base(transaction, txIndex, blockHash, blockNumber, baseFee)
{
MaxFeePerBlobGas = transaction.MaxFeePerBlobGas ?? 0;
BlobVersionedHashes = transaction.BlobVersionedHashes ?? [];
}

public new class Converter : IToTransaction<RpcGenericTransaction>, IFromTransaction<RpcBlobTransaction>
{
private readonly RpcEIP1559Transaction.Converter _baseConverter = new();

public RpcBlobTransaction FromTransaction(Transaction tx, TransactionConverterExtraData extraData)
=> new(tx, txIndex: extraData.TxIndex, blockHash: extraData.BlockHash, blockNumber: extraData.BlockNumber, baseFee: extraData.BaseFee);

public Transaction ToTransaction(RpcGenericTransaction rpcTx)
{
var tx = _baseConverter.ToTransaction(rpcTx);
tx.MaxFeePerBlobGas = rpcTx.MaxFeePerBlobGas;
tx.BlobVersionedHashes = rpcTx.BlobVersionedHashes;
return tx;
}

public Transaction ToTransactionWithDefaults(RpcGenericTransaction rpcTx)
{
var tx = _baseConverter.ToTransaction(rpcTx);
tx.MaxFeePerBlobGas = rpcTx.MaxFeePerBlobGas;
tx.BlobVersionedHashes = rpcTx.BlobVersionedHashes;
return tx;
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
// SPDX-FileCopyrightText: 2022 Demerzel Solutions Limited
// SPDX-License-Identifier: LGPL-3.0-only

using Nethermind.Core;
using Nethermind.Core.Crypto;
using Nethermind.Int256;

namespace Nethermind.Facade.Eth.RpcTransaction;

public class RpcEIP1559Transaction : RpcAccessListTransaction
{
public UInt256 MaxPriorityFeePerGas { get; set; }

public UInt256 MaxFeePerGas { get; set; }

/// <summary>
/// The effective gas price paid by the sender in wei. For transactions not yet included in a block, this value should be set equal to the max fee per gas.
/// This field is <b>DEPRECATED</b>, please transition to using <c>effectiveGasPrice</c> in the receipt object going forward.
/// </summary>
public override UInt256 GasPrice { get; set; }

public RpcEIP1559Transaction(Transaction transaction, int? txIndex = null, Hash256? blockHash = null, long? blockNumber = null, UInt256? baseFee = null)
: base(transaction, txIndex, blockHash, blockNumber)
{
MaxFeePerGas = transaction.MaxFeePerGas;
MaxPriorityFeePerGas = transaction.MaxPriorityFeePerGas;
GasPrice = baseFee is not null
? transaction.CalculateEffectiveGasPrice(eip1559Enabled: true, baseFee.Value)
: transaction.MaxFeePerGas;
}

public new class Converter : IToTransaction<RpcGenericTransaction>, IFromTransaction<RpcEIP1559Transaction>
{
private readonly RpcAccessListTransaction.Converter _baseConverter = new();

public RpcEIP1559Transaction FromTransaction(Transaction tx, TransactionConverterExtraData extraData)
=> new(tx, txIndex: extraData.TxIndex, blockHash: extraData.BlockHash, blockNumber: extraData.BlockNumber, baseFee: extraData.BaseFee);

public Transaction ToTransaction(RpcGenericTransaction rpcTx)
{
var tx = _baseConverter.ToTransaction(rpcTx);
tx.GasPrice = rpcTx.MaxPriorityFeePerGas ?? 0;
tx.DecodedMaxFeePerGas = rpcTx.MaxFeePerGas ?? 0;
return tx;
}

public Transaction ToTransactionWithDefaults(RpcGenericTransaction rpcTx)
{
var tx = _baseConverter.ToTransaction(rpcTx);
tx.GasPrice = rpcTx.MaxPriorityFeePerGas ?? 0;
tx.DecodedMaxFeePerGas = rpcTx.MaxFeePerGas ?? 0;
return tx;
}
}
}
Loading
Loading