Skip to content

Commit

Permalink
Fix TxDecoder registration (#7497)
Browse files Browse the repository at this point in the history
Co-authored-by: lukasz.rozmej <[email protected]>
Co-authored-by: Ben Adams <[email protected]>
  • Loading branch information
3 people authored Sep 27, 2024
1 parent 27c18db commit d9f88cd
Show file tree
Hide file tree
Showing 21 changed files with 108 additions and 57 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ public interface INethermindPlugin : IAsyncDisposable

string Author { get; }

void InitRlpDecoders(INethermindApi api) { }
void InitTxTypesAndRlpDecoders(INethermindApi api) { }

Task Init(INethermindApi nethermindApi) => Task.CompletedTask;

Expand Down
6 changes: 3 additions & 3 deletions src/Nethermind/Nethermind.Crypto/TransactionExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -4,17 +4,17 @@
using Nethermind.Core;
using Nethermind.Core.Crypto;
using Nethermind.Serialization.Rlp;
using System;

namespace Nethermind.Crypto
{
public static class TransactionExtensions
{
private static readonly Lazy<TxDecoder> _txDecoder = new(() => TxDecoder.Instance);
private static readonly TxDecoder _txDecoder = TxDecoder.Instance;

public static Hash256 CalculateHash(this Transaction transaction)
{
KeccakRlpStream stream = new();
_txDecoder.Value.Encode(stream, transaction, RlpBehaviors.SkipTypedWrapping);
_txDecoder.Encode(stream, transaction, RlpBehaviors.SkipTypedWrapping);
return stream.GetHash();
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ public void Setup()
public void Init_eth_stats_plugin_does_not_throw_exception(bool enabled)
{
StatsConfig = new EthStatsConfig() { Enabled = enabled };
Assert.DoesNotThrow(() => _plugin.InitRlpDecoders(_context));
Assert.DoesNotThrow(() => _plugin.InitTxTypesAndRlpDecoders(_context));
Assert.DoesNotThrowAsync(async () => await _plugin.Init(_context));
Assert.DoesNotThrowAsync(async () => await _plugin.InitNetworkProtocol());
Assert.DoesNotThrowAsync(async () => await _plugin.InitRpcModules());
Expand Down
2 changes: 1 addition & 1 deletion src/Nethermind/Nethermind.Init/Steps/DatabaseMigrations.cs
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@

namespace Nethermind.Init.Steps
{
[RunnerStepDependencies(typeof(InitRlp), typeof(InitDatabase), typeof(InitializeBlockchain), typeof(InitializeNetwork))]
[RunnerStepDependencies(typeof(InitTxTypesAndRlp), typeof(InitDatabase), typeof(InitializeBlockchain), typeof(InitializeNetwork))]
public sealed class DatabaseMigrations : IStep
{
private readonly IApiWithNetwork _api;
Expand Down
2 changes: 1 addition & 1 deletion src/Nethermind/Nethermind.Init/Steps/InitCrypto.cs
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@

namespace Nethermind.Init.Steps
{
[RunnerStepDependencies(typeof(InitRlp))]
[RunnerStepDependencies(typeof(InitTxTypesAndRlp))]
public class InitCrypto : IStep
{
private readonly IBasicApi _api;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,27 +7,26 @@
using System.Threading.Tasks;
using Nethermind.Api;
using Nethermind.Api.Extensions;
using Nethermind.Consensus.Validators;
using Nethermind.Core.Attributes;
using Nethermind.Network;
using Nethermind.Serialization.Rlp;

namespace Nethermind.Init.Steps
{
[RunnerStepDependencies(typeof(ApplyMemoryHint))]
public class InitRlp : IStep
public class InitTxTypesAndRlp(INethermindApi api) : IStep
{
private readonly INethermindApi _api;

public InitRlp(INethermindApi api)
{
_api = api ?? throw new ArgumentNullException(nameof(api));
}
private readonly INethermindApi _api = api ?? throw new ArgumentNullException(nameof(api));

[Todo(Improve.Refactor, "Automatically scan all the references solutions?")]
public virtual Task Execute(CancellationToken _)
{
if (_api.SpecProvider is null) throw new StepDependencyException(nameof(_api.SpecProvider));

// we need to initialize everything transaction related before block tree
_api.TxValidator = new TxValidator(_api.SpecProvider.ChainId);

Assembly? assembly = Assembly.GetAssembly(typeof(NetworkNodeDecoder));
if (assembly is not null)
{
Expand All @@ -36,7 +35,7 @@ public virtual Task Execute(CancellationToken _)

foreach (INethermindPlugin plugin in _api.Plugins)
{
plugin.InitRlpDecoders(_api);
plugin.InitTxTypesAndRlpDecoders(_api);
}

return Task.CompletedTask;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@

namespace Nethermind.Init.Steps
{
[RunnerStepDependencies(typeof(InitRlp), typeof(InitDatabase), typeof(MigrateConfigs), typeof(SetupKeyStore))]
[RunnerStepDependencies(typeof(InitTxTypesAndRlp), typeof(InitDatabase), typeof(MigrateConfigs), typeof(SetupKeyStore))]
public class InitializeBlockTree : IStep
{
private readonly IBasicApi _get;
Expand Down
3 changes: 1 addition & 2 deletions src/Nethermind/Nethermind.Init/Steps/InitializeBlockchain.cs
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,6 @@ protected virtual Task InitBlockchain()
{
(IApiWithStores getApi, IApiWithBlockchain setApi) = _api.ForBlockchain;
setApi.TransactionComparerProvider = new TransactionComparerProvider(getApi.SpecProvider!, getApi.BlockTree!.AsReadOnly());
setApi.TxValidator = new TxValidator(_api.SpecProvider!.ChainId);

IInitConfig initConfig = getApi.Config<IInitConfig>();
IBlocksConfig blocksConfig = getApi.Config<IBlocksConfig>();
Expand Down Expand Up @@ -93,7 +92,7 @@ protected virtual Task InitBlockchain()
setApi.TxPoolInfoProvider = new TxPoolInfoProvider(chainHeadInfoProvider.AccountStateProvider, txPool);
setApi.GasPriceOracle = new GasPriceOracle(getApi.BlockTree!, getApi.SpecProvider, _api.LogManager, blocksConfig.MinGasPrice);
BlockCachePreWarmer? preWarmer = blocksConfig.PreWarmStateOnBlockProcessing
? new(new(_api.WorldStateManager!, _api.BlockTree!, _api.SpecProvider, _api.LogManager, _api.WorldState), _api.SpecProvider, _api.LogManager, preBlockCaches)
? new(new(_api.WorldStateManager!, _api.BlockTree!, _api.SpecProvider, _api.LogManager, _api.WorldState), _api.SpecProvider!, _api.LogManager, preBlockCaches)
: null;
IBlockProcessor mainBlockProcessor = setApi.MainBlockProcessor = CreateBlockProcessor(preWarmer);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,6 @@
using Nethermind.JsonRpc.Data;
using Nethermind.Logging;
using Nethermind.Serialization.Rlp;
using Nethermind.Serialization.Rlp.TxDecoders;
using Nethermind.State;
using Nethermind.Trie;

Expand All @@ -39,7 +38,7 @@ public class TraceRpcModule : ITraceRpcModule
private readonly IReceiptFinder _receiptFinder;
private readonly ITracer _tracer;
private readonly IBlockFinder _blockFinder;
private readonly Lazy<TxDecoder> _txDecoder = new(() => TxDecoder.Instance);
private readonly TxDecoder _txDecoder = TxDecoder.Instance;
private readonly IJsonRpcConfig _jsonRpcConfig;
private readonly TimeSpan _cancellationTokenTimeout;
private readonly IStateReader _stateReader;
Expand Down Expand Up @@ -110,7 +109,7 @@ public ResultWrapper<IEnumerable<ParityTxTraceFromReplay>> trace_callMany(Transa
/// </summary>
public ResultWrapper<ParityTxTraceFromReplay> trace_rawTransaction(byte[] data, string[] traceTypes)
{
Transaction tx = _txDecoder.Value.Decode(new RlpStream(data), RlpBehaviors.SkipTypedWrapping);
Transaction tx = _txDecoder.Decode(new RlpStream(data), RlpBehaviors.SkipTypedWrapping);
return TraceTx(tx, traceTypes, BlockParameter.Latest);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ public abstract class SyncPeerProtocolHandlerBase : ZeroProtocolHandlerBase, ISy

protected Hash256 _remoteHeadBlockHash;
protected readonly ITimestamper _timestamper;
protected readonly Lazy<TxDecoder> _txDecoder = new(() => TxDecoder.Instance);
protected readonly TxDecoder _txDecoder;

protected readonly MessageQueue<GetBlockHeadersMessage, IOwnedReadOnlyList<BlockHeader?>> _headersRequests;
protected readonly MessageQueue<GetBlockBodiesMessage, (OwnedBlockBodies, long)> _bodiesRequests;
Expand Down Expand Up @@ -87,6 +87,7 @@ protected SyncPeerProtocolHandlerBase(ISession session,
SyncServer = syncServer ?? throw new ArgumentNullException(nameof(syncServer));
BackgroundTaskScheduler = new BackgroundTaskSchedulerWrapper(this, backgroundTaskScheduler ?? throw new ArgumentNullException(nameof(BackgroundTaskScheduler)));
_timestamper = Timestamper.Default;
_txDecoder = TxDecoder.Instance;
_headersRequests = new MessageQueue<GetBlockHeadersMessage, IOwnedReadOnlyList<BlockHeader>>(Send);
_bodiesRequests = new MessageQueue<GetBlockBodiesMessage, (OwnedBlockBodies, long)>(Send);

Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
// SPDX-FileCopyrightText: 2022 Demerzel Solutions Limited
// SPDX-License-Identifier: LGPL-3.0-only

using System;
using System.Linq;
using DotNetty.Buffers;
using Nethermind.Core;
Expand Down Expand Up @@ -57,7 +56,7 @@ public BlockBodiesMessage Deserialize(IByteBuffer byteBuffer)

private class BlockBodyDecoder : IRlpValueDecoder<BlockBody>
{
private readonly Lazy<TxDecoder> _txDecoder = new(() => TxDecoder.Instance);
private readonly TxDecoder _txDecoder = TxDecoder.Instance;
private readonly HeaderDecoder _headerDecoder = new();
private readonly WithdrawalDecoder _withdrawalDecoderDecoder = new();
private readonly ConsensusRequestDecoder _requestsDecoder = new();
Expand All @@ -73,7 +72,7 @@ public int GetBodyLength(BlockBody b) =>
+ (b.Withdrawals is not null ? Rlp.LengthOfSequence(GetWithdrawalsLength(b.Withdrawals)) : 0)
+ (b.Requests is not null ? Rlp.LengthOfSequence(GetRequestsLength(b.Requests)) : 0);

private int GetTxLength(Transaction[] transactions) => transactions.Sum(t => _txDecoder.Value.GetLength(t, RlpBehaviors.None));
private int GetTxLength(Transaction[] transactions) => transactions.Sum(t => _txDecoder.GetLength(t, RlpBehaviors.None));

private int GetUnclesLength(BlockHeader[] headers) => headers.Sum(t => _headerDecoder.GetLength(t, RlpBehaviors.None));

Expand All @@ -92,7 +91,7 @@ public int GetBodyLength(BlockBody b) =>

// quite significant allocations (>0.5%) here based on a sample 3M blocks sync
// (just on these delegates)
Transaction[] transactions = ctx.DecodeArray(_txDecoder.Value);
Transaction[] transactions = ctx.DecodeArray(_txDecoder);
BlockHeader[] uncles = ctx.DecodeArray(_headerDecoder);
Withdrawal[]? withdrawals = null;
ConsensusRequest[]? requests = null;
Expand All @@ -115,7 +114,7 @@ public void Serialize(RlpStream stream, BlockBody body)
stream.StartSequence(GetTxLength(body.Transactions));
foreach (Transaction? txn in body.Transactions)
{
_txDecoder.Value.Encode(stream, txn);
stream.Encode(txn);
}

stream.StartSequence(GetUnclesLength(body.Uncles));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,12 @@
using Nethermind.Core;
using Nethermind.Core.Collections;
using Nethermind.Serialization.Rlp;
using System;

namespace Nethermind.Network.P2P.Subprotocols.Eth.V62.Messages
{
public class TransactionsMessageSerializer : IZeroInnerMessageSerializer<TransactionsMessage>
{
private readonly Lazy<TxDecoder> _txDecoder = new(() => TxDecoder.Instance);
private readonly TxDecoder _decoder = TxDecoder.Instance;

public void Serialize(IByteBuffer byteBuffer, TransactionsMessage message)
{
Expand All @@ -22,7 +21,7 @@ public void Serialize(IByteBuffer byteBuffer, TransactionsMessage message)
nettyRlpStream.StartSequence(contentLength);
for (int i = 0; i < message.Transactions.Count; i++)
{
_txDecoder.Value.Encode(nettyRlpStream, message.Transactions[i], RlpBehaviors.InMempoolForm);
nettyRlpStream.Encode(message.Transactions[i], RlpBehaviors.InMempoolForm);
}
}

Expand All @@ -38,7 +37,7 @@ public int GetLength(TransactionsMessage message, out int contentLength)
contentLength = 0;
for (int i = 0; i < message.Transactions.Count; i++)
{
contentLength += _txDecoder.Value.GetLength(message.Transactions[i], RlpBehaviors.InMempoolForm);
contentLength += _decoder.GetLength(message.Transactions[i], RlpBehaviors.InMempoolForm);
}

return Rlp.LengthOfSequence(contentLength);
Expand Down
47 changes: 47 additions & 0 deletions src/Nethermind/Nethermind.Optimism.Test/RlpDecoderTests.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
// SPDX-FileCopyrightText: 2024 Demerzel Solutions Limited
// SPDX-License-Identifier: LGPL-3.0-only

using FluentAssertions;
using Nethermind.Core;
using Nethermind.Core.Test.Builders;
using Nethermind.Serialization.Rlp;
using NUnit.Framework;

namespace Nethermind.Optimism.Test;

public class RlpDecoderTests
{
[Test]
public void Can_decode_non_null_Transaction()
{
TxDecoder decoder = TxDecoder.Instance;
decoder.RegisterDecoder(new OptimismTxDecoder<Transaction>());

Transaction tx = Build.A.Transaction.WithType(TxType.DepositTx).TestObject;

RlpStream rlpStream = new(decoder.GetLength(tx, RlpBehaviors.None));
decoder.Encode(rlpStream, tx);
rlpStream.Reset();

Transaction? decodedTx = decoder.Decode(rlpStream);

decodedTx.Should().NotBeNull();
}

[Test]
public void Can_decode_non_null_Transaction_through_Rlp()
{
TxDecoder decoder = TxDecoder.Instance;
decoder.RegisterDecoder(new OptimismTxDecoder<Transaction>());

Transaction tx = Build.A.Transaction.WithType(TxType.DepositTx).TestObject;

RlpStream rlpStream = new(decoder.GetLength(tx, RlpBehaviors.None));
decoder.Encode(rlpStream, tx);
rlpStream.Reset();

Transaction? decodedTx = Rlp.Decode<Transaction?>(rlpStream);

decodedTx.Should().NotBeNull();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,6 @@
using Nethermind.Consensus.Producers;
using Nethermind.Consensus.Validators;
using Nethermind.Consensus.Withdrawals;
using Nethermind.Core;
using Nethermind.Evm;
using Nethermind.Evm.TransactionProcessing;
using Nethermind.Init.Steps;
Expand All @@ -29,8 +28,6 @@ protected override async Task InitBlockchain()
api.L1CostHelper = new(api.SpecHelper, api.ChainSpec.Optimism.L1BlockAddress);

await base.InitBlockchain();

api.RegisterTxType(TxType.DepositTx, new OptimismTxDecoder<Transaction>(), Always.Valid);
}

protected override ITransactionProcessor CreateTransactionProcessor(CodeInfoRepository codeInfoRepository, VirtualMachine virtualMachine)
Expand Down
5 changes: 4 additions & 1 deletion src/Nethermind/Nethermind.Optimism/OptimismPlugin.cs
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,8 @@
using Nethermind.Blockchain;
using Nethermind.Blockchain.Receipts;
using Nethermind.Consensus.Rewards;
using Nethermind.Consensus.Validators;
using Nethermind.Core;
using Nethermind.Merge.Plugin.Synchronization;
using Nethermind.Synchronization.ParallelSync;
using Nethermind.HealthChecks;
Expand Down Expand Up @@ -74,10 +76,11 @@ public INethermindApi CreateApi(IConfigProvider configProvider, IJsonSerializer
ILogManager logManager, ChainSpec chainSpec) =>
new OptimismNethermindApi(configProvider, jsonSerializer, logManager, chainSpec);

public void InitRlpDecoders(INethermindApi api)
public void InitTxTypesAndRlpDecoders(INethermindApi api)
{
if (ShouldRunSteps(api))
{
api.RegisterTxType(TxType.DepositTx, new OptimismTxDecoder<Transaction>(), Always.Valid);
Rlp.RegisterDecoders(typeof(OptimismReceiptMessageDecoder).Assembly, true);
}
}
Expand Down
6 changes: 3 additions & 3 deletions src/Nethermind/Nethermind.Serialization.Rlp/BlockDecoder.cs
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ namespace Nethermind.Serialization.Rlp
public class BlockDecoder : IRlpValueDecoder<Block>, IRlpStreamDecoder<Block>
{
private readonly HeaderDecoder _headerDecoder = new();
private readonly Lazy<TxDecoder> _txDecoder = new(() => TxDecoder.Instance);
private readonly TxDecoder _txDecoder = TxDecoder.Instance;
private readonly WithdrawalDecoder _withdrawalDecoder = new();
private readonly ConsensusRequestDecoder _consensusRequestsDecoder = new();

Expand Down Expand Up @@ -180,7 +180,7 @@ private int GetTxLength(Block item, RlpBehaviors rlpBehaviors)
int txLength = 0;
for (int i = 0; i < item.Transactions.Length; i++)
{
txLength += _txDecoder.Value.GetLength(item.Transactions[i], rlpBehaviors);
txLength += _txDecoder.GetLength(item.Transactions[i], rlpBehaviors);
}

return txLength;
Expand Down Expand Up @@ -338,7 +338,7 @@ public void Encode(RlpStream stream, Block? item, RlpBehaviors rlpBehaviors = Rl
stream.StartSequence(txsLength);
for (int i = 0; i < item.Transactions.Length; i++)
{
_txDecoder.Value.Encode(stream, item.Transactions[i]);
stream.Encode(item.Transactions[i]);
}

stream.StartSequence(unclesLength);
Expand Down
6 changes: 6 additions & 0 deletions src/Nethermind/Nethermind.Serialization.Rlp/RlpStream.cs
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ public class RlpStream
private static readonly HeaderDecoder _headerDecoder = new();
private static readonly BlockDecoder _blockDecoder = new();
private static readonly BlockInfoDecoder _blockInfoDecoder = new();
private static readonly TxDecoder _txDecoder = TxDecoder.Instance;
private static readonly WithdrawalDecoder _withdrawalDecoder = new();
private static readonly ConsensusRequestDecoder _requestsDecoder = new();
private static readonly LogEntryDecoder _logEntryDecoder = LogEntryDecoder.Instance;
Expand Down Expand Up @@ -65,6 +66,11 @@ public void Encode(BlockHeader value)
_headerDecoder.Encode(this, value);
}

public void Encode(Transaction value, RlpBehaviors rlpBehaviors = RlpBehaviors.None)
{
_txDecoder.Encode(this, value, rlpBehaviors);
}

public void Encode(Withdrawal value) => _withdrawalDecoder.Encode(this, value);
public void Encode(ConsensusRequest value) => _requestsDecoder.Encode(this, value);

Expand Down
Loading

0 comments on commit d9f88cd

Please sign in to comment.