Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
214 commits
Select commit Hold shift + click to select a range
954f8f5
Kademlia codes
asdacap Apr 15, 2025
ebbae61
Commit before I do something bad
asdacap Apr 16, 2025
0fbaa51
Better default
asdacap Apr 16, 2025
c6fcc4f
It does work, just really slow
asdacap Apr 16, 2025
d865921
It does work. Just need some metric.
asdacap Apr 17, 2025
b0aac86
More discovery message
asdacap Apr 17, 2025
74c25cd
Allow disabling static labels
asdacap Apr 17, 2025
853f1a7
Allow disabling static labels
asdacap Apr 17, 2025
e1163c5
Merge branch 'feature/better-discv4-metrics' into feature/kademlia-di…
asdacap Apr 17, 2025
3440fbb
Address comment
asdacap Apr 18, 2025
170cf29
Merge remote-tracking branch 'origin/feature/better-discv4-metrics' i…
asdacap Apr 18, 2025
a6cd971
This is confusing AF
asdacap Apr 22, 2025
10295f6
Merge remote-tracking branch 'origin/master' into feature/kademlia-di…
asdacap Apr 27, 2025
18dcfd5
Ok, I see where the problem is
asdacap Apr 28, 2025
56cbe78
Fix the neighbour issue
asdacap Apr 28, 2025
b37793e
Cleaner
asdacap Apr 30, 2025
3b1919e
Slight cleanup
asdacap Apr 30, 2025
5cb8568
Poor simplification attempt
asdacap Apr 30, 2025
90b50c6
Remove bucket list
asdacap Apr 30, 2025
c824035
Reducing change
asdacap Apr 30, 2025
8440f68
Fix tests
asdacap Apr 30, 2025
4dfdcd2
Fix tests
asdacap Apr 30, 2025
7929753
Slight cleanup
asdacap Apr 30, 2025
26e48ef
Simplification
asdacap Apr 30, 2025
37a3502
Exit logic
asdacap Apr 30, 2025
744d792
Configurable limit
asdacap Apr 30, 2025
dc23995
Merge remote-tracking branch 'origin/master' into feature/kademlia-di…
asdacap May 7, 2025
d040d5d
Some cleanup
asdacap May 7, 2025
90b7934
Refinement
asdacap May 7, 2025
51524bc
Refinement
asdacap May 8, 2025
894a9ef
Respond with two nodes message.
asdacap May 12, 2025
169bcca
Fix build
asdacap May 12, 2025
dee4927
Fix some test
asdacap May 12, 2025
497c1c8
Fix unit tests
asdacap May 12, 2025
d1bba3a
Fix E2E
asdacap May 12, 2025
ce1541f
Slight cleanup
asdacap May 12, 2025
5d77123
Hide some error
asdacap May 12, 2025
c510776
Improved candidate count metric
asdacap May 12, 2025
9b81905
Experiment
asdacap May 12, 2025
e9a90ec
Remove unnecessary code
asdacap May 12, 2025
f2325e2
Send optional enr
asdacap May 12, 2025
b3be4c6
Merge remote-tracking branch 'origin/master' into feature/kademlia-di…
asdacap May 12, 2025
1a73860
Fix test build
asdacap May 12, 2025
2302278
Additional todo
asdacap May 12, 2025
18ac3f2
Remove nodes locator
asdacap May 12, 2025
b85ce7e
Nodestats
asdacap May 12, 2025
4f2d413
Remove discovery manager
asdacap May 12, 2025
917c9d4
Remove content extension
asdacap May 12, 2025
ee8fe72
Reducing change
asdacap May 12, 2025
e623c44
Lets just save for now
asdacap May 13, 2025
2279c7f
Remove routing table
asdacap May 13, 2025
cea08d8
Move session into one class
asdacap May 13, 2025
90a5fe1
Remove NodeFilter
asdacap May 13, 2025
291d6dd
Pass cancellation token
asdacap May 13, 2025
033c7f7
Fix
asdacap May 13, 2025
121d9b0
Fix throttle logic
asdacap May 13, 2025
7aa73f1
ISolating
asdacap May 13, 2025
a7e8f03
Cleanup attempt
asdacap May 13, 2025
da1312c
Some refinement
asdacap May 14, 2025
aa133ab
Change the unit test
asdacap May 14, 2025
f42a7b2
Reduce timeout
asdacap May 14, 2025
319e6ad
Unit tests
asdacap May 14, 2025
97c4211
NSubstitute
asdacap May 14, 2025
d7e1a7a
Whitespace
asdacap May 14, 2025
9f47dea
Merge remote-tracking branch 'origin/master' into feature/kademlia-di…
asdacap May 14, 2025
4ed05f4
Remove some code
asdacap May 14, 2025
aef2d12
Remove more metric
asdacap May 14, 2025
e2eb741
Gonna commit this first
asdacap May 14, 2025
b50807a
Extract node record provider
asdacap May 14, 2025
31ab6f7
DiscV5 to DI
asdacap May 14, 2025
adde8e0
DiscV4 to DI
asdacap May 14, 2025
5253f1c
Consolidate the network storage initialization
asdacap May 14, 2025
1adb534
Allow more margin
asdacap May 15, 2025
f0e1b36
Override discovery db in test also
asdacap May 15, 2025
0ecd9f5
Merge branch 'master' into refactor/move-discovery-initialization
asdacap May 15, 2025
ec29d12
Whitespace
asdacap May 15, 2025
0925a19
Merge branch 'refactor/move-discovery-initialization' into feature/ka…
asdacap May 15, 2025
6a2022f
Fix build
asdacap May 15, 2025
64893ae
Merge remote-tracking branch 'origin/master' into feature/kademlia-di…
asdacap May 16, 2025
2e76e44
Tests
asdacap May 16, 2025
b0e8660
Merge remote-tracking branch 'origin/master' into feature/kademlia-di…
asdacap May 20, 2025
9c3ae6b
Slight code reduction
asdacap May 20, 2025
30c22be
Reducing change
asdacap May 21, 2025
14a1ada
Reducing change
asdacap May 21, 2025
45962ba
Reducing change
asdacap May 21, 2025
fa41f0c
Reducing change
asdacap May 21, 2025
3d93ace
Nodes to array segment
asdacap May 21, 2025
f1eeeef
Extract some logic out to DiscoveryPersistenceManager.cs
asdacap May 21, 2025
1d25869
Merge branch 'feature/reduce-change-to-discv4' into feature/kademlia-…
asdacap May 21, 2025
e0431a8
Remove unnecessary comment
asdacap May 21, 2025
77540b6
Remove unnecessary class
asdacap May 21, 2025
d5ba1ff
Fix simulation
asdacap May 21, 2025
0fc5e2e
Merge remote-tracking branch 'origin/master' into feature/kademlia-di…
asdacap May 21, 2025
e7a54c3
Fix build
asdacap May 21, 2025
9cd429e
More attempted lookup
asdacap May 21, 2025
594a157
Trying to simplify
asdacap May 21, 2025
2d7c42c
KBucket does not need
asdacap May 21, 2025
0c49205
Slight cleanup
asdacap May 22, 2025
9806c30
Fix build
asdacap May 22, 2025
fc91f9d
Rename and comment
asdacap May 22, 2025
a709097
Remove original lookup code
asdacap May 22, 2025
58313f7
Fix test
asdacap May 22, 2025
9ffdeba
Reduce code
asdacap May 22, 2025
d0e910e
More xor test
asdacap May 22, 2025
6d1c6d8
Whitespace
asdacap May 22, 2025
67f0193
Merge remote-tracking branch 'origin/master' into feature/kademlia-di…
asdacap Jul 4, 2025
0d9509c
Make the node lookup generic
asdacap Jul 4, 2025
32922dd
Address comment
asdacap Jul 4, 2025
f013df6
Remove strange
asdacap Jul 4, 2025
0335ea5
Fix build
asdacap Jul 4, 2025
e1e617f
Merge origin/master into feature/kademlia-discv4
flcl42 May 18, 2026
35fdd3a
Some fixes (#11654)
flcl42 May 19, 2026
6c4f8aa
Merge branch 'master' into feature/kademlia-discv4
flcl42 May 19, 2026
221c120
Review
flcl42 May 21, 2026
3291f46
Simplify
flcl42 May 21, 2026
375a88c
Fix spelling
flcl42 May 21, 2026
bf8866e
test(discovery): dedupe discv4/kademlia tests
LukaszRozmej May 22, 2026
9a2c6b9
refactor(discovery): address review comments
LukaszRozmej May 22, 2026
e8e11e9
fix(discovery): address review findings + fill test gaps
LukaszRozmej May 22, 2026
d9544a1
Merge remote-tracking branch 'origin/master' into pr-8616
LukaszRozmej May 22, 2026
d745ab5
test(discovery): dedupe new Kademlia and persistence tests
LukaszRozmej May 22, 2026
2b78b36
Merge origin/master into feature/kademlia-discv4
flcl42 May 22, 2026
91a8860
Merge remote-tracking branch 'origin/feature/kademlia-discv4' into fe…
flcl42 May 22, 2026
c6f7aab
Extract generic Kademlia and harden native discv5
flcl42 May 22, 2026
043f4e9
Align discv5 discovery lifecycle
flcl42 May 23, 2026
50e86f9
Set Ethereum discovery versions
flcl42 May 25, 2026
febda46
Merge master into generic Kademlia discovery
flcl42 May 27, 2026
0e1ba97
Harden discv5 ENR handling
flcl42 May 27, 2026
cd48718
Drain Kademlia background operations
flcl42 May 27, 2026
6b37cdf
Avoid peer penalties on lookup cancellation
flcl42 May 27, 2026
6c48383
Validate ENR key ordering and size
flcl42 May 27, 2026
dd1c35c
Require ENR v4 identity
flcl42 May 27, 2026
6ec92a5
Validate discv5 relayed ENR addresses
flcl42 May 27, 2026
d510357
Harden discv5 node ingestion
flcl42 May 27, 2026
b3c20ac
Harden discv5 ENR relay validation
flcl42 May 27, 2026
1abb491
Recover stale discv5 sessions
flcl42 May 27, 2026
c105bd0
Gate discv5 shared node ingestion
flcl42 May 27, 2026
7540b95
Merge remote-tracking branch 'origin/master' into generic-kad-2
flcl42 May 27, 2026
8bf6a82
Bound discv4 discovery node dedupe
flcl42 May 27, 2026
5b7cef2
Require discv4 bond before node health updates
flcl42 May 27, 2026
5a0761f
Harden discovery receive paths
flcl42 May 27, 2026
ec864a4
Reduce discv5 allocation pressure
flcl42 May 28, 2026
d0ada32
Add distance service
flcl42 May 28, 2026
a60aac2
Reduce discv5 message allocations
flcl42 May 28, 2026
4abfa13
Merge remote-tracking branch 'origin/master' into generic-kad-2
flcl42 May 28, 2026
5fde794
Fix PR validation failures
flcl42 May 29, 2026
cbd1fab
Merge origin/master into generic-kad-2
flcl42 May 31, 2026
8ad3ff7
Refactor more
flcl42 Jun 1, 2026
c644dd4
Rename
flcl42 Jun 1, 2026
20c6b26
Merge remote-tracking branch 'origin/master' into generic-kad-2
flcl42 Jun 1, 2026
148c82a
Refactor more
flcl42 Jun 1, 2026
c257aed
More moves and cleanup
flcl42 Jun 2, 2026
7a4cb6c
Add discv5 trace logging
flcl42 Jun 2, 2026
d3252bd
Fix PR CI failures
flcl42 Jun 2, 2026
51374a1
Fix and cut
flcl42 Jun 2, 2026
73ce7f0
Merge branch 'master' into generic-kad-2
flcl42 Jun 2, 2026
7c37920
Use native compressed ECDH
flcl42 Jun 2, 2026
6781fe9
Stabilize discovery E2E test
flcl42 Jun 2, 2026
88096d4
Fix review
flcl42 Jun 2, 2026
7b23431
Harden discv5 packet dispatch
flcl42 Jun 3, 2026
25a00d6
Restore Kademlia distance SIMD
flcl42 Jun 3, 2026
8bfcf7f
Remove unused Kademlia factory
flcl42 Jun 3, 2026
4826b76
Reduce discovery duplication
flcl42 Jun 3, 2026
464af4b
Harden Kademlia cleanup
flcl42 Jun 3, 2026
274df2d
Tidy Kademlia tests
flcl42 Jun 3, 2026
ecac6ad
Add async node health disposal
flcl42 Jun 3, 2026
6283f39
More unification
flcl42 Jun 3, 2026
55f9aba
Tidy discovery follow-ups
flcl42 Jun 4, 2026
22dc769
Harden discovery lookup nodes
flcl42 Jun 4, 2026
34a5c46
Review
flcl42 Jun 4, 2026
fb775f4
More fixes
flcl42 Jun 4, 2026
15cc266
Clean NodeTests imports
flcl42 Jun 4, 2026
d00b47f
Refactor discovery types
flcl42 Jun 5, 2026
8d91fb8
Better naming for double lru
flcl42 Jun 8, 2026
bab7ede
Merge branch 'master' into generic-kad-2
flcl42 Jun 8, 2026
84a7bee
Review
flcl42 Jun 9, 2026
d71022e
Merge branch 'generic-kad-2' of github.com:NethermindEth/nethermind i…
flcl42 Jun 9, 2026
815862f
Fix enodes in discv5 and build
flcl42 Jun 9, 2026
caab1ae
Use pooled set in Kademlia
flcl42 Jun 9, 2026
1a8e526
Consolidate ENR builders in discovery tests
LukaszRozmej Jun 9, 2026
7813457
Remove duplicate ToHash test helpers
LukaszRozmej Jun 9, 2026
1abe8a9
More pooled
flcl42 Jun 9, 2026
a3f87c3
Merge branch 'generic-kad-2' of github.com:NethermindEth/nethermind i…
flcl42 Jun 9, 2026
7aeafbd
More locals init skipped
flcl42 Jun 9, 2026
43cc5d2
Remove unused discovery usings
flcl42 Jun 10, 2026
9af85fc
More fixes
flcl42 Jun 10, 2026
98b9fdd
Merge remote-tracking branch 'origin/master' into generic-kad-2
flcl42 Jun 10, 2026
a49775a
Null not expected
flcl42 Jun 11, 2026
34a6cf6
Fix tests
flcl42 Jun 11, 2026
5a3c9b4
Fix dos vector
flcl42 Jun 11, 2026
0ea629e
Fix discovery serialization review
flcl42 Jun 12, 2026
7a93ef6
Reduce discovery token allocations
flcl42 Jun 12, 2026
cfdf4f2
Prevent a malformed discv5 packet from killing a worker loop
flcl42 Jun 13, 2026
b3f5e09
Test cases
flcl42 Jun 15, 2026
dc9dedb
Better rlp encoder init
flcl42 Jun 15, 2026
f1aa511
Reduce discovery retention
flcl42 Jun 16, 2026
7f8adc4
Merge remote-tracking branch 'origin/master' into generic-kad-2
flcl42 Jun 16, 2026
da8eb5f
feat: host-side prerequisites for the embedded beacon chain plugin (S…
asdacap Jun 18, 2026
0640843
Harden discv4 unsolicited responses
flcl42 Jun 18, 2026
150e959
Merge master into generic-kad-2
flcl42 Jun 18, 2026
c7cbf75
More magic words
flcl42 Jun 18, 2026
f4b4eba
Some fixes
flcl42 Jun 18, 2026
b6a1c6c
Simplify Kademlia test keys
flcl42 Jun 19, 2026
ca09665
Refine discovery review fixes
flcl42 Jun 19, 2026
dc72968
Refine LRU eviction
flcl42 Jun 19, 2026
44d7ff6
Deduplicate ENR signer tests
flcl42 Jun 19, 2026
cd50eaf
Move more discovery into kad
flcl42 Jun 22, 2026
dddbe6b
Fix stab config
flcl42 Jun 22, 2026
1927bc1
Merge remote-tracking branch 'origin/master' into generic-kad-2
flcl42 Jun 22, 2026
eddc286
Fix discv4 node source self emission
flcl42 Jun 22, 2026
6eb3c62
Remove unused merge usings
flcl42 Jun 22, 2026
2db358b
Address discv5 review feedback
flcl42 Jun 22, 2026
ae1fb22
Refine discovery review fixes
flcl42 Jun 23, 2026
6dcc35b
Merge remote-tracking branch 'origin/master' into generic-kad-2
flcl42 Jun 23, 2026
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
2 changes: 1 addition & 1 deletion .github/workflows/rpc-comparison.yml
Original file line number Diff line number Diff line change
Expand Up @@ -142,7 +142,7 @@ jobs:
network: ${{ inputs.network }}
convert_to_paprika: "${{ inputs.convert_to_paprika }}"

# Spawn a pruned Geth node via the smoke-tests framework
# Spawn a pruned Geth node via the smoke-tests framework
create_geth_node:
name: Spawn pruned Geth node
uses: ./.github/workflows/run-a-geth-node.yml
Expand Down
1 change: 0 additions & 1 deletion Directory.Packages.props
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,6 @@
<PackageVersion Include="NUnit.Analyzers" Version="4.14.0" />
<PackageVersion Include="NUnit3TestAdapter" Version="6.2.0" />
<PackageVersion Include="Open.NAT.Core" Version="2.1.0.5" />
<PackageVersion Include="PierTwo.Lantern.Discv5.WireProtocol" Version="1.0.0-preview.8" />
<PackageVersion Include="Polly" Version="8.6.6" />
<PackageVersion Include="prometheus-net.AspNetCore" Version="8.2.1" />
<PackageVersion Include="Prometheus.Client.MetricPusher" Version="3.3.0" />
Expand Down
2 changes: 1 addition & 1 deletion src/Nethermind/Nethermind.Config/Nethermind.Config.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,11 @@
<ItemGroup>
<PackageReference Include="Microsoft.Extensions.Caching.Memory" />
<PackageReference Include="NonBlocking" />
<PackageReference Include="PierTwo.Lantern.Discv5.WireProtocol" PrivateAssets="all" />
<PackageReference Include="System.Configuration.ConfigurationManager" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\Nethermind.Core\Nethermind.Core.csproj" />
<ProjectReference Include="..\Nethermind.Network.Enr\Nethermind.Network.Enr.csproj" />
</ItemGroup>
<ItemGroup>
<EmbeddedResource Include="..\Chains\**\*.*">
Expand Down
33 changes: 18 additions & 15 deletions src/Nethermind/Nethermind.Config/NetworkNode.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,9 @@
// SPDX-License-Identifier: LGPL-3.0-only

#nullable enable
using Lantern.Discv5.Enr;
using Lantern.Discv5.Enr.Entries;
using Lantern.Discv5.Enr.Identity;
using Lantern.Discv5.Enr.Identity.V4;
using Nethermind.Core.Crypto;
using Nethermind.Logging;
using Nethermind.Network.Enr;
using System;
using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis;
Expand All @@ -20,11 +17,8 @@ namespace Nethermind.Config;
/// </summary>
public class NetworkNode
{
private static readonly EnrFactory _enrFactory = new(new EnrEntryRegistry());
private static readonly IIdentityVerifier identityVerifier = new IdentityVerifierV4();

private readonly Enode? _enode;
private readonly Enr? _enr;
private readonly NodeRecord? _enr;

Comment thread
flcl42 marked this conversation as resolved.
[MemberNotNullWhen(true, nameof(Enode))]
[MemberNotNullWhen(false, nameof(Enr))]
Expand All @@ -42,7 +36,7 @@ public NetworkNode(string nodeString)
}
else
{
_enr = _enrFactory.CreateFromString(nodeString, identityVerifier);
_enr = NodeRecord.FromEnrString(nodeString);
}
}

Expand Down Expand Up @@ -82,7 +76,7 @@ public static NetworkNode[] ParseNodes(string[]? nodeRecords, ILogger logger)
return [.. nodes];
}

public override string ToString() => IsEnode ? Enode.ToString() : Enr.ToString();
public override string ToString() => IsEnode ? Enode.ToString() : Enr.EnrString;

public NetworkNode(PublicKey publicKey, string ip, int port, long reputation = 0)
: this(new Enode(publicKey, IPAddress.Parse(ip), port)) => Reputation = reputation;
Expand All @@ -91,11 +85,20 @@ public NetworkNode(PublicKey publicKey, string ip, int port, long reputation = 0

public Enode? Enode => _enode;

public Enr? Enr => _enr;
public NodeRecord? Enr => _enr;

public PublicKey NodeId => IsEnode ? Enode.PublicKey : new PublicKey(Enr.GetEntry<EntrySecp256K1>(EnrEntryKey.Secp256K1).Value);
public string Host => IsEnode ? Enode.HostIp.ToString() : Enr.GetEntry<EntryIp>(EnrEntryKey.Ip).Value.ToString();
public IPAddress HostIp => IsEnode ? Enode.HostIp : Enr.GetEntry<EntryIp>(EnrEntryKey.Ip).Value;
public int Port => IsEnode ? Enode.Port : Enr.GetEntry<EntryTcp>(EnrEntryKey.Tcp).Value;
public PublicKey NodeId => IsEnode ? Enode.PublicKey : GetEnrPublicKey();
public string Host => IsEnode ? Enode.HostIp.ToString() : HostIp.ToString();
public IPAddress HostIp => IsEnode ? Enode.HostIp : Enr!.DiscoveryIp ?? IPAddress.None;
public int Port => IsEnode ? Enode.Port : Enr!.DiscoveryPort ?? 0;
public int DiscoveryPort => IsEnode ? Enode.DiscoveryPort : Enr!.DiscoveryPort ?? 0;
public long Reputation { get; set; }

private PublicKey GetEnrPublicKey()
{
CompressedPublicKey publicKey = Enr!.GetObj<CompressedPublicKey>(EnrContentKey.SecP256k1)
?? throw new InvalidOperationException("ENR is missing secp256k1 public key.");

return publicKey.Decompress();
}
}
144 changes: 144 additions & 0 deletions src/Nethermind/Nethermind.Core.Test/Caching/LruCacheTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -235,6 +235,82 @@ public void Can_delete()
Assert.That(cache.Delete(_addresses[0]), Is.False);
}

[Test]
public void Can_remove_and_return_value()
{
LruCache<Address, Account> cache = new(Capacity, "test");
cache.Set(_addresses[0], _accounts[0]);

Assert.That(cache.TryRemove(_addresses[0], out Account? removed), Is.True);
Assert.That(removed, Is.EqualTo(_accounts[0]));
Assert.That(cache.TryRemove(_addresses[0], out removed), Is.False);
Assert.That(removed, Is.Null);
}

[Test]
public void Evict_is_called_when_capacity_replaces_oldest()
{
int evicted = 0;
LruCache<int, int> cache = new TestEvictingLruCache<int, int>(2, "test", value => evicted = value);

cache.Set(1, 10);
cache.Set(2, 20);
cache.Set(3, 30);

Assert.That(evicted, Is.EqualTo(10));
}

[Test]
public void Evict_is_called_when_existing_value_is_replaced()
{
int evicted = 0;
LruCache<int, int> cache = new TestEvictingLruCache<int, int>(2, "test", value => evicted = value);

cache.Set(1, 10);
cache.Set(1, 11);

Assert.That(evicted, Is.EqualTo(10));
Assert.That(cache.Get(1), Is.EqualTo(11));
}

[Test]
public void TryRemove_returns_value_without_calling_evict()
{
int evicted = 0;
LruCache<int, int> cache = new TestEvictingLruCache<int, int>(2, "test", value => evicted = value);
cache.Set(1, 10);

Assert.That(cache.TryRemove(1, out int removed), Is.True);

Assert.That(removed, Is.EqualTo(10));
Assert.That(evicted, Is.Zero);
}

[Test]
public void Disposing_cache_disposes_evicted_values()
{
DisposingLruCache<int, DisposableValue> cache = new(1, "test");
DisposableValue evicted = new();

cache.Set(1, evicted);
cache.Set(2, new DisposableValue());

Assert.That(evicted.IsDisposed, Is.True);
}

[Test]
public void Disposing_cache_try_remove_transfers_ownership()
{
DisposingLruCache<int, DisposableValue> cache = new(1, "test");
DisposableValue removed = new();
cache.Set(1, removed);

Assert.That(cache.TryRemove(1, out DisposableValue? actual), Is.True);

Assert.That(actual, Is.SameAs(removed));
Assert.That(removed.IsDisposed, Is.False);
}

[Test]
public void Clear_should_free_all_capacity()
{
Expand All @@ -261,6 +337,29 @@ public void Clear_should_free_all_capacity()
}
}

[TestCase(EvictionOperation.Delete, false)]
[TestCase(EvictionOperation.ReplaceExisting, true)]
[TestCase(EvictionOperation.ReplaceOldest, false)]
[TestCase(EvictionOperation.Clear, false)]
public async Task Evict_is_invoked_outside_lock(EvictionOperation operation, bool expectedContainsResult)
{
LruCache<int, int> cache = null!;
TaskCompletionSource<bool> evictResult = new(TaskCreationOptions.RunContinuationsAsynchronously);
cache = new TestEvictingLruCache<int, int>(2, "test", _ => evictResult.SetResult(cache.Contains(1)));
cache.Set(1, 10);
if (operation == EvictionOperation.ReplaceOldest)
{
cache.Set(2, 20);
}

Task operationTask = Task.Run(() => RunEvictionOperation(cache, operation));
Task completedTask = await Task.WhenAny(operationTask, Task.Delay(TimeSpan.FromSeconds(5)));

Assert.That(completedTask, Is.SameAs(operationTask));
await operationTask;
Assert.That(await evictResult.Task.WaitAsync(TimeSpan.FromSeconds(5)), Is.EqualTo(expectedContainsResult));
}

[Test]
public void Delete_keeps_internal_structure()
{
Expand Down Expand Up @@ -301,5 +400,50 @@ public void Wrong_capacity_number_at_constructor()
});

}

private static void RunEvictionOperation(LruCache<int, int> cache, EvictionOperation operation)
{
switch (operation)
{
case EvictionOperation.Delete:
cache.Delete(1);
return;
case EvictionOperation.ReplaceExisting:
cache.Set(1, 11);
return;
case EvictionOperation.ReplaceOldest:
cache.Set(3, 30);
return;
case EvictionOperation.Clear:
cache.Clear();
return;
default:
throw new ArgumentOutOfRangeException(nameof(operation), operation, null);
}
}

public enum EvictionOperation
{
Delete,
ReplaceExisting,
ReplaceOldest,
Clear
}

private sealed class TestEvictingLruCache<TKey, TValue>(
int maxCapacity,
string name,
Action<TValue> evict) : LruCache<TKey, TValue>(maxCapacity, name)
where TKey : notnull
{
protected override void Evict(TValue value) => evict(value);
}

private sealed class DisposableValue : IDisposable
{
public bool IsDisposed { get; private set; }

public void Dispose() => IsDisposed = true;
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -10,5 +10,5 @@ public class InsecureProtectedPrivateKey(PrivateKey privateKey) : IProtectedPriv
{
public PublicKey PublicKey => privateKey.PublicKey;
public CompressedPublicKey CompressedPublicKey => privateKey.CompressedPublicKey;
public PrivateKey Unprotect() => privateKey;
public PrivateKey Unprotect() => new(privateKey.KeyBytes);
}
Original file line number Diff line number Diff line change
Expand Up @@ -83,7 +83,7 @@ public async Task StartDiscovery(CancellationToken cancellationToken)
await ctx.Resolve<IStaticNodesManager>().InitAsync();

_discoveryApp = ctx.Resolve<IDiscoveryApp>();
_ = _discoveryApp.StartAsync(); // Bootstrap is not blocking by default
await _discoveryApp.StartAsync();

_peerPool = ctx.Resolve<IPeerPool>();
_peerPool.Start();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,6 @@ protected override void Load(ContainerBuilder builder)
// These two don't use the DB provider
.AddKeyedSingleton<IFullDb>(DbNames.PeersDb, (_) => new MemDb())
.AddKeyedSingleton<IFullDb>(DbNames.DiscoveryNodes, (_) => new MemDb())
.AddKeyedSingleton<IFullDb>(DbNames.DiscoveryV5Nodes, (_) => new MemDb())
.AddSingleton<IChannelFactory, INetworkConfig>(networkConfig => new LocalChannelFactory(networkGroup ?? nameof(TestEnvironmentModule), networkConfig))
.AddSingleton(NodeFilter.AcceptAll) // Disable inbound rate limiting for in-memory channels

Expand Down
23 changes: 23 additions & 0 deletions src/Nethermind/Nethermind.Core/Caching/DisposingLruCache.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
// SPDX-FileCopyrightText: 2026 Demerzel Solutions Limited
// SPDX-License-Identifier: LGPL-3.0-only

using System;

namespace Nethermind.Core.Caching;

public sealed class DisposingLruCache<TKey, TValue> : LruCache<TKey, TValue>
where TKey : notnull
where TValue : IDisposable
{
public DisposingLruCache(int maxCapacity, int startCapacity, string name)
: base(maxCapacity, startCapacity, name)
{
}

public DisposingLruCache(int maxCapacity, string name)
: base(maxCapacity, name)
{
}

protected override void Evict(TValue value) => value.Dispose();
}
Loading
Loading