Skip to content
Draft
Show file tree
Hide file tree
Changes from all 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
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,24 @@ namespace Nethermind.Blockchain.Test;
[FixtureLifeCycle(LifeCycle.InstancePerTestCase)]
public class BlockchainProcessorTests
{
[Test]
public void LogDiagnosticTrace_does_not_throw_for_null_hash_variant()
{
ILogger logger = LimboLogs.Instance.GetClassLogger();

Assert.DoesNotThrow(() =>
BlockTraceDumper.LogDiagnosticTrace(NullBlockTracer.Instance, (Hash256)null!, logger));
}

[Test]
public void LogDiagnosticTrace_does_not_throw_for_default_either_variant()
{
ILogger logger = LimboLogs.Instance.GetClassLogger();

Assert.DoesNotThrow(() =>
BlockTraceDumper.LogDiagnosticTrace(NullBlockTracer.Instance, default(Either<Hash256, IList<Block>>), logger));
}

private class ProcessingTestContext
{
private readonly ILogManager _logManager = LimboLogs.Instance;
Expand Down
12 changes: 8 additions & 4 deletions src/Nethermind/Nethermind.Blockchain/LogTraceDumper.cs
Original file line number Diff line number Diff line change
Expand Up @@ -102,21 +102,25 @@ private static bool GetConditionAndHashString(Either<Hash256, IList<Block>> bloc
blockHash = failedBlockHash.ToString();
return false;
}
else

if (blocksOrHash.Is(out IList<Block> blocks))
{
blocksOrHash.To(out IList<Block> blocks);
condition = "valid on rerun";

if (blocks.Count == 1)
{
blockHash = blocks[0].Hash.ToString();
blockHash = blocks[0].Hash?.ToString() ?? "unknown";
}
else
{
blockHash = string.Join("|", blocks.Select(b => b.Hash.ToString()));
blockHash = string.Join("|", blocks.Select(static b => b.Hash?.ToString() ?? "unknown"));
}
return true;
}

condition = "unknown";
blockHash = "unknown";
return false;
}

private static FileStream GetFileStream(string name) =>
Expand Down
12 changes: 7 additions & 5 deletions src/Nethermind/Nethermind.JsonRpc/Modules/ModuleType.cs
Original file line number Diff line number Diff line change
Expand Up @@ -9,27 +9,29 @@ public static class ModuleType
{
public const string Admin = nameof(Admin);
public const string Clique = nameof(Clique);
public const string Engine = nameof(Engine);
public const string Db = nameof(Db);
public const string Debug = nameof(Debug);
public const string Deposit = nameof(Deposit);
public const string Engine = nameof(Engine);
public const string Erc20 = nameof(Erc20);
public const string Eth = nameof(Eth);
public const string LogIndex = nameof(LogIndex);
public const string Evm = nameof(Evm);
public const string Flashbots = nameof(Flashbots);
public const string Health = nameof(Health);
public const string Net = nameof(Net);
public const string Nft = nameof(Nft);
public const string Parity = nameof(Parity);
public const string Personal = nameof(Personal);
public const string Proof = nameof(Proof);
public const string Rbuilder = nameof(Rbuilder);
public const string Rpc = nameof(Rpc);
public const string Subscribe = nameof(Subscribe);
public const string Testing = nameof(Testing);
public const string Trace = nameof(Trace);
public const string TxPool = nameof(TxPool);
public const string Web3 = nameof(Web3);
public const string Deposit = nameof(Deposit);
public const string Health = nameof(Health);
public const string Rpc = nameof(Rpc);
public const string Rbuilder = nameof(Rbuilder);
public const string Vault = nameof(Vault);

public static IEnumerable<string> DefaultModules { get; } = new List<string>()
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,10 @@
using System.Text.Json;
using System.Threading;
using System.Threading.Tasks;
using Autofac;
using CkzgLib;
using FluentAssertions;
using Nethermind.Consensus.Producers;
using Nethermind.Core;
using Nethermind.Core.Extensions;
using Nethermind.Core.Test.Builders;
Expand Down Expand Up @@ -42,6 +44,45 @@ public async Task GetPayloadV5_should_return_all_the_blobs([Values(0, 1, 2, 3, 4
Assert.That(IBlobProofsManager.For(ProofVersion.V1).ValidateProofs(wrapper), Is.True);
}

[Test]
public async Task Testing_buildBlockV1_empty_block_with_empty_withdrawals_has_valid_hash()
{
MergeTestBlockchain chain = await CreateBlockchain(releaseSpec: Osaka.Instance);
ITestingRpcModule testingRpcModule = chain.Container.Resolve<ITestingRpcModule>();

Block head = chain.BlockTree.Head!;
PayloadAttributes payloadAttributes = new()
{
Timestamp = head.Timestamp + 12,
PrevRandao = TestItem.KeccakA,
SuggestedFeeRecipient = Address.Zero,
Withdrawals = [],
ParentBeaconBlockRoot = TestItem.KeccakB
};

ResultWrapper<GetPayloadV5Result?> buildResult = await testingRpcModule.testing_buildBlockV1(
head.Hash!,
payloadAttributes,
[],
[]);

buildResult.Result.Should().Be(Result.Success);
buildResult.Data.Should().NotBeNull();

ExecutionPayloadV3 executionPayload = buildResult.Data!.ExecutionPayload;
executionPayload.ExecutionRequests = buildResult.Data.ExecutionRequests;
executionPayload.TryGetBlock().Block!.CalculateHash().Should().Be(executionPayload.BlockHash);

ResultWrapper<PayloadStatusV1> newPayloadResult = await chain.EngineRpcModule.engine_newPayloadV4(
executionPayload,
[],
payloadAttributes.ParentBeaconBlockRoot,
buildResult.Data.ExecutionRequests);

newPayloadResult.Result.Should().Be(Result.Success);
newPayloadResult.Data.Status.Should().Be(PayloadStatus.Valid);
}

[Test]
public async Task GetBlobsV2_should_throw_if_more_than_128_requested_blobs([Values(128, 129)] int requestSize)
{
Expand Down
196 changes: 196 additions & 0 deletions src/Nethermind/Nethermind.Merge.Plugin.Test/MergePluginTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,28 +2,41 @@
// SPDX-License-Identifier: LGPL-3.0-only

using System;
using System.Threading;
using System.Text.Json;
using System.Text.Json.Serialization.Metadata;
using System.Threading.Tasks;
using Autofac;
using FluentAssertions;
using Nethermind.Api;
using Nethermind.Blockchain.Find;
using Nethermind.Blockchain.Synchronization;
using Nethermind.Config;
using Nethermind.Consensus;
using Nethermind.Consensus.Clique;
using Nethermind.Consensus.Processing;
using Nethermind.Consensus.Producers;
using Nethermind.Core;
using Nethermind.Core.Crypto;
using Nethermind.Core.Exceptions;
using Nethermind.Core.Specs;
using Nethermind.Evm;
using Nethermind.Evm.Tracing;
using Nethermind.HealthChecks;
using Nethermind.Int256;
using Nethermind.JsonRpc;
using Nethermind.JsonRpc.Modules;
using Nethermind.JsonRpc.Test;
using Nethermind.Logging;
using Nethermind.Merge.Plugin.BlockProduction;
using Nethermind.Merge.Plugin.Data;
using Nethermind.Runner.Ethereum.Modules;
using Nethermind.Runner.Test.Ethereum;
using Nethermind.Serialization.Json;
using Nethermind.Specs.Forks;
using Nethermind.Specs.ChainSpecStyle;
using Nethermind.Specs.Test.ChainSpecStyle;
using Nethermind.State.Proofs;
using NUnit.Framework;
using NSubstitute;

Expand Down Expand Up @@ -139,6 +152,189 @@ public async Task Initializes_correctly()
Assert.That(api.BlockProducer, Is.InstanceOf<MergeBlockProducer>());
}

[Test]
public async Task Init_registers_gas_limit_calculator_for_testing_rpc_module()
{
using IContainer container = BuildContainer();
INethermindApi api = container.Resolve<INethermindApi>();
await _consensusPlugin!.Init(api);
await _plugin.Init(api);

Assert.DoesNotThrow(() => container.Resolve<IGasLimitCalculator>());
}

[Test]
public async Task Testing_buildBlockV1_sets_excess_blob_gas_for_eip4844()
{
Hash256 parentHash = Keccak.Compute("parent");
BlockHeader parentHeader = new(
Keccak.Compute("grandparent"),
Keccak.OfAnEmptySequenceRlp,
Address.Zero,
UInt256.Zero,
1,
30_000_000,
1,
[])
{
Hash = parentHash,
TotalDifficulty = UInt256.Zero,
BaseFeePerGas = UInt256.One,
GasUsed = 0,
StateRoot = Keccak.EmptyTreeHash,
ReceiptsRoot = Keccak.EmptyTreeHash,
Bloom = Bloom.Empty,
BlobGasUsed = 0,
ExcessBlobGas = 0,
};

Block parentBlock = new(parentHeader, Array.Empty<Transaction>(), Array.Empty<BlockHeader>(), Array.Empty<Withdrawal>());
IBlockFinder blockFinder = Substitute.For<IBlockFinder>();
blockFinder.FindBlock(parentHash).Returns(parentBlock);

Hash256? suggestedWithdrawalsRoot = null;
IBlockchainProcessor blockchainProcessor = Substitute.For<IBlockchainProcessor>();
blockchainProcessor
.Process(Arg.Any<Block>(), Arg.Any<ProcessingOptions>(), Arg.Any<IBlockTracer>(), Arg.Any<CancellationToken>())
.Returns(static callInfo =>
{
Block block = callInfo.Arg<Block>();
block.Header.StateRoot ??= Keccak.EmptyTreeHash;
block.Header.ReceiptsRoot ??= Keccak.EmptyTreeHash;
block.Header.Bloom ??= Bloom.Empty;
block.Header.GasUsed = 0;
block.Header.Hash ??= Keccak.Compute("produced");
return block;
});
blockchainProcessor
.When(x => x.Process(Arg.Any<Block>(), Arg.Any<ProcessingOptions>(), Arg.Any<IBlockTracer>(), Arg.Any<CancellationToken>()))
.Do(callInfo =>
{
Block block = callInfo.Arg<Block>();
suggestedWithdrawalsRoot = block.Header.WithdrawalsRoot;
});

IMainProcessingContext mainProcessingContext = Substitute.For<IMainProcessingContext>();
mainProcessingContext.BlockchainProcessor.Returns(blockchainProcessor);

ISpecProvider specProvider = Substitute.For<ISpecProvider>();
specProvider.GetSpec(Arg.Any<ForkActivation>()).Returns(Osaka.Instance);

IGasLimitCalculator gasLimitCalculator = Substitute.For<IGasLimitCalculator>();
gasLimitCalculator.GetGasLimit(Arg.Any<BlockHeader>()).Returns(parentHeader.GasLimit);

TestingRpcModule module = new(
mainProcessingContext,
gasLimitCalculator,
specProvider,
blockFinder,
LimboLogs.Instance);

PayloadAttributes payloadAttributes = new()
{
Timestamp = parentHeader.Timestamp + 12,
PrevRandao = Keccak.Compute("randao"),
SuggestedFeeRecipient = Address.Zero,
Withdrawals =
[
new Withdrawal
{
Index = 0,
ValidatorIndex = 0,
Address = Address.Zero,
AmountInGwei = 1
}
],
ParentBeaconBlockRoot = Keccak.Compute("parentBeaconBlockRoot")
};

ResultWrapper<GetPayloadV5Result?> result = await module.testing_buildBlockV1(parentHash, payloadAttributes, Array.Empty<byte[]>(), Array.Empty<byte>());

result.Result.ResultType.Should().Be(ResultType.Success);
result.Data.Should().NotBeNull();
result.Data!.ExecutionPayload.BlobGasUsed.Should().Be(0);
result.Data!.ExecutionPayload.ExcessBlobGas.Should().Be(BlobGasCalculator.CalculateExcessBlobGas(parentHeader, Osaka.Instance));
suggestedWithdrawalsRoot.Should().Be(new WithdrawalTrie(payloadAttributes.Withdrawals!).RootHash);
}

[Test]
public async Task Testing_buildBlockV1_json_rpc_accepts_omitted_extraData()
{
Hash256 parentHash = Keccak.Compute("parent");
BlockHeader parentHeader = new(
Keccak.Compute("grandparent"),
Keccak.OfAnEmptySequenceRlp,
Address.Zero,
UInt256.Zero,
1,
30_000_000,
1,
[])
{
Hash = parentHash,
TotalDifficulty = UInt256.Zero,
BaseFeePerGas = UInt256.One,
GasUsed = 0,
StateRoot = Keccak.EmptyTreeHash,
ReceiptsRoot = Keccak.EmptyTreeHash,
Bloom = Bloom.Empty,
BlobGasUsed = 0,
ExcessBlobGas = 0,
};

Block parentBlock = new(parentHeader, Array.Empty<Transaction>(), Array.Empty<BlockHeader>(), Array.Empty<Withdrawal>());
IBlockFinder blockFinder = Substitute.For<IBlockFinder>();
blockFinder.FindBlock(parentHash).Returns(parentBlock);

IBlockchainProcessor blockchainProcessor = Substitute.For<IBlockchainProcessor>();
blockchainProcessor
.Process(Arg.Any<Block>(), Arg.Any<ProcessingOptions>(), Arg.Any<IBlockTracer>(), Arg.Any<CancellationToken>())
.Returns(static callInfo =>
{
Block block = callInfo.Arg<Block>();
block.Header.StateRoot ??= Keccak.EmptyTreeHash;
block.Header.ReceiptsRoot ??= Keccak.EmptyTreeHash;
block.Header.Bloom ??= Bloom.Empty;
block.Header.GasUsed = 0;
block.Header.Hash ??= Keccak.Compute("produced");
return block;
});

IMainProcessingContext mainProcessingContext = Substitute.For<IMainProcessingContext>();
mainProcessingContext.BlockchainProcessor.Returns(blockchainProcessor);

ISpecProvider specProvider = Substitute.For<ISpecProvider>();
specProvider.GetSpec(Arg.Any<ForkActivation>()).Returns(Osaka.Instance);

IGasLimitCalculator gasLimitCalculator = Substitute.For<IGasLimitCalculator>();
gasLimitCalculator.GetGasLimit(Arg.Any<BlockHeader>()).Returns(parentHeader.GasLimit);

TestingRpcModule module = new(
mainProcessingContext,
gasLimitCalculator,
specProvider,
blockFinder,
LimboLogs.Instance);

PayloadAttributes payloadAttributes = new()
{
Timestamp = parentHeader.Timestamp + 12,
PrevRandao = Keccak.Compute("randao"),
SuggestedFeeRecipient = Address.Zero,
Withdrawals = [],
ParentBeaconBlockRoot = Keccak.Compute("parentBeaconBlockRoot")
};

JsonRpcResponse response = await RpcTest.TestRequest<ITestingRpcModule>(
module,
nameof(ITestingRpcModule.testing_buildBlockV1),
parentHash,
payloadAttributes,
Array.Empty<byte[]>());

response.Should().BeOfType<JsonRpcSuccessResponse>();
}

[TestCase(true, true)]
[TestCase(false, true)]
[TestCase(true, false)]
Expand Down
Loading
Loading