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

Use Nethermind as Optimism Sequencer #7287

Merged
merged 12 commits into from
Jul 31, 2024
42 changes: 25 additions & 17 deletions src/Nethermind/Nethermind.JsonRpc.Test/Modules/TestRpcBlockchain.cs
Original file line number Diff line number Diff line change
Expand Up @@ -105,12 +105,36 @@ public Builder<T> WithConfig(IJsonRpcConfig config)
return this;
}

public Builder<T> WithEthRpcModule(Func<TestRpcBlockchain, IEthRpcModule> builder)
{
_blockchain._ethRpcModuleBuilder = builder;
return this;
}

public async Task<T> Build(
ISpecProvider? specProvider = null,
UInt256? initialValues = null) =>
(T)(await _blockchain.Build(specProvider, initialValues, true));
}

private Func<TestRpcBlockchain, IEthRpcModule> _ethRpcModuleBuilder = @this => new EthRpcModule(
@this.RpcConfig,
@this.Bridge,
@this.BlockFinder,
@this.ReceiptFinder,
@this.StateReader,
@this.TxPool,
@this.TxSender,
@this.TestWallet,
LimboLogs.Instance,
@this.SpecProvider,
@this.GasPriceOracle,
new EthSyncingInfo(@this.BlockTree, @this.ReceiptStorage, new SyncConfig(),
new StaticSelector(SyncMode.All), Substitute.For<ISyncProgressResolver>(), @this.LogManager),
@this.FeeHistoryOracle ??
new FeeHistoryOracle(@this.BlockTree, @this.ReceiptStorage, @this.SpecProvider),
new BlocksConfig().SecondsPerSlot);

protected override async Task<TestBlockchain> Build(
ISpecProvider? specProvider = null,
UInt256? initialValues = null,
Expand Down Expand Up @@ -145,23 +169,7 @@ protected override async Task<TestBlockchain> Build(
TxSender ??= new TxPoolSender(TxPool, TxSealer, NonceManager, EthereumEcdsa ?? new EthereumEcdsa(specProvider.ChainId, LogManager));
GasPriceOracle ??= new GasPriceOracle(BlockFinder, SpecProvider, LogManager);
FeeHistoryOracle ??= new FeeHistoryOracle(BlockTree, ReceiptStorage, SpecProvider);
ISyncConfig syncConfig = new SyncConfig();
EthRpcModule = new EthRpcModule(
RpcConfig,
Bridge,
BlockFinder,
ReceiptFinder,
StateReader,
TxPool,
TxSender,
TestWallet,
LimboLogs.Instance,
SpecProvider,
GasPriceOracle,
new EthSyncingInfo(BlockTree, ReceiptStorage, syncConfig,
new StaticSelector(SyncMode.All), Substitute.For<ISyncProgressResolver>(), LogManager),
FeeHistoryOracle,
blocksConfig.SecondsPerSlot);
EthRpcModule = _ethRpcModuleBuilder(this);

return this;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
<PackageReference Include="RichardSzalay.MockHttp" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\Nethermind.JsonRpc.Test\Nethermind.JsonRpc.Test.csproj" />
<ProjectReference Include="..\Nethermind.Optimism\Nethermind.Optimism.csproj" />
</ItemGroup>

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

using System.Threading.Tasks;
using Nethermind.Blockchain.Synchronization;
using Nethermind.Config;
using Nethermind.Core;
using Nethermind.Core.Extensions;
using Nethermind.Core.Test.Builders;
using Nethermind.Crypto;
using Nethermind.Facade;
using Nethermind.Facade.Eth;
using Nethermind.JsonRpc.Client;
using Nethermind.JsonRpc.Modules.Eth.FeeHistory;
using Nethermind.JsonRpc.Test.Modules;
using Nethermind.Logging;
using Nethermind.Optimism.Rpc;
using Nethermind.Serialization.Rlp;
using Nethermind.Synchronization.ParallelSync;
using Nethermind.TxPool;
using NSubstitute;
using NUnit.Framework;

namespace Nethermind.Optimism.Test.Rpc;

public class OptimismEthRpcModuleTest
{
[Test]
public async Task Sequencer_send_transaction_with_signature_will_not_try_to_sign()
Copy link
Contributor Author

Choose a reason for hiding this comment

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

This test is pretty much a copy/paste of:

public async Task Send_transaction_with_signature_will_not_try_to_sign()

{
IBlockchainBridge bridge = Substitute.For<IBlockchainBridge>();
ITxSender txSender = Substitute.For<ITxSender>();
txSender.SendTransaction(tx: Arg.Any<Transaction>(), txHandlingOptions: TxHandlingOptions.PersistentBroadcast)
.Returns(returnThis: (TestItem.KeccakA, AcceptTxResult.Accepted));

EthereumEcdsa ethereumEcdsa = new EthereumEcdsa(chainId: TestBlockchainIds.ChainId, logManager: LimboLogs.Instance);
TestRpcBlockchain rpcBlockchain = await TestRpcBlockchain
.ForTest(sealEngineType: SealEngineType.Optimism)
.WithBlockchainBridge(bridge)
.WithTxSender(txSender)
.WithOptimismEthRpcModule(
sequencerRpcClient: null /* explicitly using null to behave as Sequencer */,
accountStateProvider: Substitute.For<IAccountStateProvider>(),
ecdsa: new OptimismEthereumEcdsa(ethereumEcdsa),
sealer: Substitute.For<ITxSealer>(),
opSpecHelper: Substitute.For<IOptimismSpecHelper>())
.Build();

Transaction tx = Build.A.Transaction
.Signed(ecdsa: ethereumEcdsa, privateKey: TestItem.PrivateKeyA)
.TestObject;
string serialized = await rpcBlockchain.TestEthRpc("eth_sendRawTransaction", Rlp.Encode(item: tx, behaviors: RlpBehaviors.None).Bytes.ToHexString());

await txSender.Received().SendTransaction(tx: Arg.Any<Transaction>(), txHandlingOptions: TxHandlingOptions.PersistentBroadcast);
Assert.That(actual: serialized, expression: Is.EqualTo(expected: $$"""{"jsonrpc":"2.0","result":"{{TestItem.KeccakA.Bytes.ToHexString(withZeroX: true)}}","id":67}"""));
}
}

internal static class TestRpcBlockchainExt
{
public static TestRpcBlockchain.Builder<TestRpcBlockchain> WithOptimismEthRpcModule(
this TestRpcBlockchain.Builder<TestRpcBlockchain> @this,
IJsonRpcClient? sequencerRpcClient,
IAccountStateProvider accountStateProvider,
IEthereumEcdsa ecdsa,
ITxSealer sealer,
IOptimismSpecHelper opSpecHelper)
{
return @this.WithEthRpcModule(blockchain => new OptimismEthRpcModule(
blockchain.RpcConfig,
blockchain.Bridge,
blockchain.BlockFinder,
blockchain.ReceiptFinder,
blockchain.StateReader,
blockchain.TxPool,
blockchain.TxSender,
blockchain.TestWallet,
LimboLogs.Instance,
blockchain.SpecProvider,
blockchain.GasPriceOracle,
new EthSyncingInfo(blockchain.BlockTree, blockchain.ReceiptStorage, new SyncConfig(),
new StaticSelector(SyncMode.All), Substitute.For<ISyncProgressResolver>(), blockchain.LogManager),
blockchain.FeeHistoryOracle ??
new FeeHistoryOracle(blockchain.BlockTree, blockchain.ReceiptStorage, blockchain.SpecProvider),
new BlocksConfig().SecondsPerSlot,

sequencerRpcClient, accountStateProvider, ecdsa, sealer, opSpecHelper
));
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,6 @@ IOptimismSpecHelper opSpecHelper
private readonly IGasPriceOracle _gasPriceOracle = gasPriceOracle ?? throw new ArgumentNullException(nameof(gasPriceOracle));
private readonly IEthSyncingInfo _ethSyncingInfo = ethSyncingInfo ?? throw new ArgumentNullException(nameof(ethSyncingInfo));
private readonly IFeeHistoryOracle _feeHistoryOracle = feeHistoryOracle ?? throw new ArgumentNullException(nameof(feeHistoryOracle));
private readonly IJsonRpcClient? _sequencerRpcClient = sequencerRpcClient ?? throw new ArgumentNullException(nameof(sequencerRpcClient));
private readonly IAccountStateProvider _accountStateProvider = accountStateProvider ?? throw new ArgumentNullException(nameof(accountStateProvider));
private readonly IEthereumEcdsa _ecdsa = ecdsa ?? throw new ArgumentNullException(nameof(ecdsa));
private readonly ITxSealer _sealer = sealer ?? throw new ArgumentNullException(nameof(sealer));
Expand All @@ -82,7 +81,7 @@ public override IOptimismEthRpcModule Create()
_feeHistoryOracle,
secondsPerSlot,

_sequencerRpcClient,
sequencerRpcClient,
_accountStateProvider,
_ecdsa,
_sealer,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -130,13 +130,15 @@ public override async Task<ResultWrapper<Hash256>> eth_sendRawTransaction(byte[]
{
if (_sequencerRpcClient is null)
{
return ResultWrapper<Hash256>.Fail("No sequencer url in the config");
return await base.eth_sendRawTransaction(transaction);
}

Hash256? result = await _sequencerRpcClient.Post<Hash256>(nameof(eth_sendRawTransaction), transaction);
if (result is null)
{
return ResultWrapper<Hash256>.Fail("Failed to forward transaction");
}

return ResultWrapper<Hash256>.Success(result);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ protected override void RegisterEthRpcModule(IRpcModuleProvider rpcModuleProvide

if (_config.SequencerUrl is null && _logger.IsWarn)
{
_logger.Warn($"SequencerUrl is not set.");
_logger.Warn($"SequencerUrl is not set. Nethermind will behave as a Sequencer");
}

BasicJsonRpcClient? sequencerJsonRpcClient = _config.SequencerUrl is null
Expand Down