Skip to content
Merged
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
7 changes: 5 additions & 2 deletions src/Nethermind/Nethermind.Api/IInitConfig.cs
Original file line number Diff line number Diff line change
Expand Up @@ -39,10 +39,10 @@ public interface IInitConfig : IConfig
[ConfigItem(Description = "The hash of the genesis block. If not specified, the genesis block validity is not checked which is useful in the case of ad hoc test/private networks.", DefaultValue = "null")]
string? GenesisHash { get; set; }

[ConfigItem(Description = "The path to the static nodes file.", DefaultValue = "Data/static-nodes.json")]
[ConfigItem(Description = "The path to the static nodes file.", DefaultValue = "static-nodes.json")]
string StaticNodesPath { get; set; }

[ConfigItem(Description = "The path to the trusted nodes file.", DefaultValue = "Data/trusted-nodes.json")]
[ConfigItem(Description = "The path to the trusted nodes file.", DefaultValue = "trusted-nodes.json")]
string TrustedNodesPath { get; set; }

[ConfigItem(Description = "The name of the log file.", DefaultValue = "log.txt")]
Expand All @@ -69,6 +69,9 @@ public interface IInitConfig : IConfig
[ConfigItem(Description = "The maximum number of bad blocks observed on the network that will be stored on disk.", DefaultValue = "100")]
long? BadBlocksStored { get; set; }

[ConfigItem(Description = "The path to the Nethermind data directory. Defaults to Nethermind's current directory.", DefaultValue = "null", HiddenFromDocs = true)]
string? DataDir { get; set; }

[ConfigItem(Description = "[TECHNICAL] Disable garbage collector on newPayload", DefaultValue = "true", HiddenFromDocs = true)]
bool DisableGcOnNewPayload { get; set; }

Expand Down
7 changes: 4 additions & 3 deletions src/Nethermind/Nethermind.Api/InitConfig.cs
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,8 @@ public class InitConfig : IInitConfig
public string BaseDbPath { get; set; } = "db";
public string LogFileName { get; set; } = "log.txt";
public string? GenesisHash { get; set; }
public string StaticNodesPath { get; set; } = "Data/static-nodes.json";
public string TrustedNodesPath { get; set; } = "Data/trusted-nodes.json";
public string StaticNodesPath { get; set; } = "static-nodes.json";
public string TrustedNodesPath { get; set; } = "trusted-nodes.json";
public string? KzgSetupPath { get; set; } = null;
public string LogDirectory { get; set; } = "logs";
public string? LogRules { get; set; } = null;
Expand All @@ -28,7 +28,7 @@ public class InitConfig : IInitConfig
public DiagnosticMode DiagnosticMode { get; set; } = DiagnosticMode.None;
public DumpOptions AutoDump { get; set; } = DumpOptions.Default;

public string RpcDbUrl { get; set; } = String.Empty;
public string RpcDbUrl { get; set; } = string.Empty;
public long? MemoryHint { get; set; }
public long? BadBlocksStored { get; set; } = 100;
public bool DisableGcOnNewPayload { get; set; } = true;
Expand All @@ -39,6 +39,7 @@ public class InitConfig : IInitConfig
public int BackgroundTaskConcurrency { get; set; } = 2;
public int BackgroundTaskMaxNumber { get; set; } = 1024;
public bool InRunnerTest { get; set; } = false;
public string? DataDir { get; set; }

[Obsolete("Use DiagnosticMode with MemDb instead")]
public bool UseMemDb
Expand Down
7 changes: 4 additions & 3 deletions src/Nethermind/Nethermind.Init/Modules/DiscoveryModule.cs
Original file line number Diff line number Diff line change
Expand Up @@ -43,12 +43,13 @@ protected override void Load(ContainerBuilder builder)
.AddKeyedSingleton<INodeSource>(NodeSourceToDiscV4Feeder.SourceKey, ctx => ctx.Resolve<EnrDiscovery>())

// Uses by RPC also.
.AddSingleton<IStaticNodesManager, ILogManager>((logManager) => new StaticNodesManager(initConfig.StaticNodesPath, logManager))
.AddSingleton<IStaticNodesManager, ILogManager>(logManager =>
new StaticNodesManager(initConfig.StaticNodesPath.GetApplicationResourcePath(initConfig.DataDir), logManager))
// This load from file.
.AddSingleton<NodesLoader>()

.AddSingleton<ITrustedNodesManager, ILogManager>((logManager) =>
new TrustedNodesManager(initConfig.TrustedNodesPath, logManager))
.AddSingleton<ITrustedNodesManager, ILogManager>(logManager =>
new TrustedNodesManager(initConfig.TrustedNodesPath.GetApplicationResourcePath(initConfig.DataDir), logManager))

.Bind<INodeSource, IStaticNodesManager>()

Expand Down
3 changes: 2 additions & 1 deletion src/Nethermind/Nethermind.Network/INodeSource.cs
Original file line number Diff line number Diff line change
@@ -1,15 +1,16 @@
// SPDX-FileCopyrightText: 2022 Demerzel Solutions Limited
// SPDX-License-Identifier: LGPL-3.0-only

using Nethermind.Stats.Model;
using System;
using System.Collections.Generic;
using System.Threading;
using Nethermind.Stats.Model;

namespace Nethermind.Network;

public interface INodeSource
{
IAsyncEnumerable<Node> DiscoverNodes(CancellationToken cancellationToken);

event EventHandler<NodeEventArgs> NodeRemoved;
}
17 changes: 8 additions & 9 deletions src/Nethermind/Nethermind.Network/IStaticNodesManager.cs
Original file line number Diff line number Diff line change
Expand Up @@ -5,14 +5,13 @@
using System.Threading.Tasks;
using Nethermind.Config;

namespace Nethermind.Network
namespace Nethermind.Network;

public interface IStaticNodesManager : INodeSource
{
public interface IStaticNodesManager : INodeSource
{
IEnumerable<NetworkNode> Nodes { get; }
Task InitAsync();
Task<bool> AddAsync(string enode, bool updateFile = true);
Task<bool> RemoveAsync(string enode, bool updateFile = true);
bool IsStatic(string enode);
}
IEnumerable<NetworkNode> Nodes { get; }
Task InitAsync();
Task<bool> AddAsync(string enode, bool updateFile = true);
Task<bool> RemoveAsync(string enode, bool updateFile = true);
bool IsStatic(string enode);
}
19 changes: 9 additions & 10 deletions src/Nethermind/Nethermind.Network/ITrustedNodesManager.cs
Original file line number Diff line number Diff line change
@@ -1,18 +1,17 @@
// SPDX-FileCopyrightText: 2024 Demerzel Solutions Limited
// SPDX-FileCopyrightText: 2025 Demerzel Solutions Limited
// SPDX-License-Identifier: LGPL-3.0-only

using System.Collections.Generic;
using System.Threading.Tasks;
using Nethermind.Config;

namespace Nethermind.Network
namespace Nethermind.Network;

public interface ITrustedNodesManager : INodeSource
{
public interface ITrustedNodesManager : INodeSource
{
IEnumerable<NetworkNode> Nodes { get; }
Task InitAsync();
Task<bool> AddAsync(Enode enode, bool updateFile = true);
Task<bool> RemoveAsync(Enode enode, bool updateFile = true);
bool IsTrusted(Enode enode);
}
IEnumerable<NetworkNode> Nodes { get; }
Task InitAsync();
Task<bool> AddAsync(Enode enode, bool updateFile = true);
Task<bool> RemoveAsync(Enode enode, bool updateFile = true);
bool IsTrusted(Enode enode);
}
18 changes: 7 additions & 11 deletions src/Nethermind/Nethermind.Network/Nethermind.Network.csproj
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
<Project Sdk="Microsoft.NET.Sdk">
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<Nullable>annotations</Nullable>
</PropertyGroup>
Expand All @@ -19,20 +19,16 @@
</ItemGroup>
<ItemGroup>
<Compile Remove="Swarm\**" />
</ItemGroup>
<ItemGroup>
<EmbeddedResource Remove="Swarm\**" />
</ItemGroup>
<ItemGroup>
<None Remove="Swarm\**" />
</ItemGroup>
<ItemGroup>
<Compile Remove="Whisper\**" />
</ItemGroup>
<ItemGroup>
<EmbeddedResource Remove="Whisper\**" />
</ItemGroup>
<ItemGroup>
<None Remove="Whisper\**" />
<EmbeddedResource Include="StaticNodes\static-nodes.json">
<LogicalName>static-nodes.json</LogicalName>
</EmbeddedResource>
<EmbeddedResource Include="TrustedNodes\trusted-nodes.json">
<LogicalName>trusted-nodes.json</LogicalName>
</EmbeddedResource>
</ItemGroup>
</Project>
114 changes: 114 additions & 0 deletions src/Nethermind/Nethermind.Network/NodesManager.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,114 @@
// SPDX-FileCopyrightText: 2025 Demerzel Solutions Limited
// SPDX-License-Identifier: LGPL-3.0-only

using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text.Json;
using System.Threading.Tasks;
using Nethermind.Config;
using Nethermind.Core.Crypto;
using Nethermind.Logging;
using Nethermind.Serialization.Json;

namespace Nethermind.Network;

public abstract class NodesManager(string path, ILogger logger)
{
private static readonly char[] _separator = ['\r', '\n'];

protected readonly ILogger _logger = logger;
protected ConcurrentDictionary<PublicKey, NetworkNode> _nodes = [];

private void EnsureFile(string resource)
{
if (File.Exists(path))
return;

// Create the directory if needed
Directory.CreateDirectory(Path.GetDirectoryName(path));

if (_logger.IsDebug) _logger.Debug($"Nodes file was not found, creating one at {Path.GetFullPath(path)}");

using Stream actualNodes = File.Create(path);
using Stream embeddedNodes = typeof(NodesManager).Assembly.GetManifestResourceStream(resource);

if (embeddedNodes is null)
{
if (_logger.IsDebug) _logger.Debug($"Embedded resource {resource} was not found");

File.WriteAllText(path, "[]\n");
}
else
{
embeddedNodes.CopyTo(actualNodes);
}
}

protected virtual void LogNodeList(string title, IDictionary<PublicKey, NetworkNode> nodes)
{
if (_logger.IsDebug && nodes.Count != 0)
{
var separator = $"{Environment.NewLine} ";

_logger.Debug($"{title}:{separator}{string.Join(separator, nodes.Values.Select(n => n.ToString()))}");
}
}

protected virtual async Task<ConcurrentDictionary<PublicKey, NetworkNode>> ParseNodes(string fallbackResource)
{
EnsureFile(fallbackResource);

string data = await File.ReadAllTextAsync(path);

IEnumerable<string>? rawNodes;

try
{
rawNodes = JsonSerializer.Deserialize<HashSet<string>>(data);
}
catch (JsonException)
{
rawNodes = data.Split(_separator, StringSplitOptions.RemoveEmptyEntries).ToHashSet();
}

ConcurrentDictionary<PublicKey, NetworkNode> nodes = [];

foreach (string? n in rawNodes ?? [])
{
NetworkNode node;

try
{
node = new(n);
}
catch (ArgumentException ex)
{
if (_logger.IsError) _logger.Error($"Failed to parse node: {n}", ex);

continue;
}

nodes.TryAdd(node.NodeId, node);
}

if (_logger.IsInfo)
_logger.Info($"Loaded {nodes.Count} nodes from {Path.GetFullPath(path)}");

return nodes;
}

protected virtual Task SaveFileAsync()
{
ArgumentException.ThrowIfNullOrWhiteSpace(path);

string contents = JsonSerializer.Serialize(
_nodes.Select(static n => n.Value.ToString()),
EthereumJsonSerializer.JsonOptionsIndented
);

return File.WriteAllTextAsync(path, contents);
}
}
Loading