Skip to content
Open
Show file tree
Hide file tree
Changes from 1 commit
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 @@ -186,6 +186,27 @@ public async Task Eth_get_transaction_by_block_number_and_index_out_of_bounds()
Assert.That(serialized, Is.EqualTo("{\"jsonrpc\":\"2.0\",\"result\":null,\"id\":67}"));
}

[Test]
public async Task Eth_config_does_not_include_all_by_default()
{
using Context ctx = await Context.Create();
string serialized = await ctx.Test.TestEthRpc("eth_config");
JToken result = JToken.Parse(serialized)["result"]!;
result.Should().NotBeNull();
result["all"].Should().BeNull();
}

[Test]
public async Task Eth_config_returns_all_forks_when_requested()
{
using Context ctx = await Context.Create();
string serialized = await ctx.Test.TestEthRpc("eth_config", true);
JToken result = JToken.Parse(serialized)["result"]!;
result.Should().NotBeNull();
JArray allForks = (JArray)result["all"]!;
allForks.Count.Should().BeGreaterThan(0);
}

[TestCase(false, "{\"jsonrpc\":\"2.0\",\"result\":{\"difficulty\":\"0xf4240\",\"extraData\":\"0x010203\",\"gasLimit\":\"0x3d0900\",\"gasUsed\":\"0x0\",\"hash\":\"0xa2a9f03b9493046696099d27b2612b99497aa1f392ec966716ab393c715a5bb6\",\"logsBloom\":\"0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000\",\"miner\":\"0x0000000000000000000000000000000000000000\",\"mixHash\":\"0x2ba5557a4c62a513c7e56d1bf13373e0da6bec016755483e91589fe1c6d212e2\",\"nonce\":\"0x00000000000003e8\",\"number\":\"0x0\",\"parentHash\":\"0xff483e972a04a9a62bb4b7d04ae403c615604e4090521ecc5bb7af67f71be09c\",\"receiptsRoot\":\"0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421\",\"sha3Uncles\":\"0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347\",\"size\":\"0x201\",\"stateRoot\":\"0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421\",\"totalDifficulty\":\"0x0\",\"timestamp\":\"0xf4240\",\"transactions\":[],\"transactionsRoot\":\"0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421\",\"uncles\":[]},\"id\":67}")]
[TestCase(true, "{\"jsonrpc\":\"2.0\",\"result\":{\"difficulty\":\"0xf4240\",\"extraData\":\"0x010203\",\"gasLimit\":\"0x3d0900\",\"gasUsed\":\"0x0\",\"hash\":\"0xa2a9f03b9493046696099d27b2612b99497aa1f392ec966716ab393c715a5bb6\",\"logsBloom\":\"0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000\",\"miner\":\"0x0000000000000000000000000000000000000000\",\"mixHash\":\"0x2ba5557a4c62a513c7e56d1bf13373e0da6bec016755483e91589fe1c6d212e2\",\"nonce\":\"0x00000000000003e8\",\"number\":\"0x0\",\"parentHash\":\"0xff483e972a04a9a62bb4b7d04ae403c615604e4090521ecc5bb7af67f71be09c\",\"receiptsRoot\":\"0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421\",\"sha3Uncles\":\"0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347\",\"size\":\"0x201\",\"stateRoot\":\"0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421\",\"totalDifficulty\":\"0x0\",\"timestamp\":\"0xf4240\",\"baseFeePerGas\":\"0x0\",\"transactions\":[],\"transactionsRoot\":\"0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421\",\"uncles\":[]},\"id\":67}")]
public async Task Eth_get_uncle_by_block_number_and_index(bool eip1559, string expectedJson)
Expand Down
2 changes: 2 additions & 0 deletions src/Nethermind/Nethermind.JsonRpc/Data/ForkConfigSummary.cs
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,8 @@ public class ForkConfigSummary

[JsonIgnore(Condition = JsonIgnoreCondition.Never)]
public required ForkConfig? Last { get; init; }

public IReadOnlyList<ForkConfig>? All { get; init; }
}

public class ForkConfig
Expand Down
41 changes: 27 additions & 14 deletions src/Nethermind/Nethermind.JsonRpc/Modules/Eth/EthRpcModule.cs
Original file line number Diff line number Diff line change
Expand Up @@ -802,38 +802,51 @@ private ResultWrapper<TResult> GetStateFailureResult<TResult>(BlockHeader header
};
}

public ResultWrapper<JsonNode> eth_config()
public ResultWrapper<JsonNode> eth_config(bool? showAllForks = null)
{
ForkActivationsSummary forks = forkInfo.GetForkActivationsSummary(_blockFinder.Head?.Header);
IReadOnlyList<ForkConfig>? allForkConfigs = null;

return ResultWrapper<JsonNode>.Success(JsonNode.Parse(JsonSerializer.Serialize((new ForkConfigSummary
if (showAllForks is true)
{
Current = GetForkConfig(forks.Current, _specProvider)!,
Next = GetForkConfig(forks.Next, _specProvider),
Last = GetForkConfig(forks.Last, _specProvider)
}), UnchangedDictionaryKeyOptions)));
IReadOnlyList<Fork> forkSchedule = forkInfo.GetAllForks();
List<ForkConfig> forkConfigs = new(forkSchedule.Count);

static ForkConfig? GetForkConfig(Fork? fork, ISpecProvider specProvider)
{
if (fork is null)
foreach (Fork scheduledFork in forkSchedule)
{
return null;
forkConfigs.Add(BuildForkConfig(scheduledFork, _specProvider));
}

IReleaseSpec? spec = specProvider.GetSpec(fork.Value.Activation.BlockNumber, fork.Value.Activation.Timestamp);
allForkConfigs = forkConfigs;
}

return ResultWrapper<JsonNode>.Success(JsonNode.Parse(JsonSerializer.Serialize(new ForkConfigSummary
{
Current = BuildForkConfig(forks.Current, _specProvider),
Next = GetForkConfigOrNull(forks.Next, _specProvider),
Last = GetForkConfigOrNull(forks.Last, _specProvider),
All = allForkConfigs
}, UnchangedDictionaryKeyOptions)));

static ForkConfig? GetForkConfigOrNull(Fork? fork, ISpecProvider specProvider) =>
fork is null ? null : BuildForkConfig(fork.Value, specProvider);

static ForkConfig BuildForkConfig(Fork fork, ISpecProvider specProvider)
{
IReleaseSpec spec = specProvider.GetSpec(fork.Activation.BlockNumber, fork.Activation.Timestamp);

return new ForkConfig
{
ActivationTime = fork.Value.Activation.Timestamp is not null ? (int)fork.Value.Activation.Timestamp : null,
ActivationBlock = fork.Value.Activation.Timestamp is null ? (int)fork.Value.Activation.BlockNumber : null,
ActivationTime = fork.Activation.Timestamp is not null ? (int)fork.Activation.Timestamp : null,
ActivationBlock = fork.Activation.Timestamp is null ? (int)fork.Activation.BlockNumber : null,
BlobSchedule = spec.IsEip4844Enabled ? new BlobScheduleSettingsForRpc
{
BaseFeeUpdateFraction = (int)spec.BlobBaseFeeUpdateFraction,
Max = (int)spec.MaxBlobCount,
Target = (int)spec.TargetBlobCount,
} : null,
ChainId = specProvider.ChainId,
ForkId = fork.Value.Id.HashBytes,
ForkId = fork.Id.HashBytes,
Precompiles = spec.ListPrecompiles(),
SystemContracts = spec.ListSystemContracts(),
};
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -289,7 +289,7 @@ ResultWrapper<TransactionForRpc> eth_getTransactionByBlockNumberAndIndex(
[JsonRpcMethod(IsImplemented = true, Description = "Retrieves Account with code and no storageRoot via Address and Blocknumber", IsSharable = true)]
ResultWrapper<AccountInfoForRpc?> eth_getAccountInfo([JsonRpcParameter(ExampleValue = "[\"0xaa00000000000000000000000000000000000000\", \"latest\"]")] Address accountAddress, BlockParameter? blockParameter = null);

[JsonRpcMethod(IsImplemented = true, Description = "Provides configuration data for the current and next fork", IsSharable = true)]
ResultWrapper<JsonNode> eth_config();
[JsonRpcMethod(IsImplemented = true, Description = "Provides configuration data for the current and next fork or the full fork schedule", IsSharable = true)]
ResultWrapper<JsonNode> eth_config([JsonRpcParameter(Description = "Returns every known fork when true", ExampleValue = "[true]")] bool? showAllForks = null);
}
}
6 changes: 6 additions & 0 deletions src/Nethermind/Nethermind.Network/ForkInfo.cs
Original file line number Diff line number Diff line change
Expand Up @@ -176,5 +176,11 @@ public ForkActivationsSummary GetForkActivationsSummary(BlockHeader? head)
Last = isNextPresent ? new Fork(Forks[^1].Activation, Forks[^1].Id) : null,
};
}

public IReadOnlyList<Fork> GetAllForks()
{
EnsureInitialized();
return Forks;
}
}
}
3 changes: 3 additions & 0 deletions src/Nethermind/Nethermind.Network/IForkInfo.cs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
// SPDX-FileCopyrightText: 2025 Demerzel Solutions Limited
// SPDX-License-Identifier: LGPL-3.0-only

using System.Collections.Generic;
using Nethermind.Core;
using Nethermind.Core.Specs;

Expand All @@ -19,6 +20,8 @@ public interface IForkInfo
ValidationResult ValidateForkId(ForkId peerId, BlockHeader? head);

ForkActivationsSummary GetForkActivationsSummary(BlockHeader? head);

IReadOnlyList<Fork> GetAllForks();
}

public readonly record struct Fork(ForkActivation Activation, ForkId Id);
Expand Down