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
3 changes: 2 additions & 1 deletion Directory.Packages.props
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,7 @@
<PackageVersion Include="Open.NAT.Core" Version="2.1.0.5" />
<PackageVersion Include="PierTwo.Lantern.Discv5.WireProtocol" Version="1.0.0-preview.6" />
<PackageVersion Include="Polly" Version="8.6.4" />
<PackageVersion Include="prometheus-net" Version="8.2.1" />
<PackageVersion Include="prometheus-net.AspNetCore" Version="8.2.1" />
<PackageVersion Include="Prometheus.Client.MetricPusher" Version="3.3.0" />
<PackageVersion Include="Pyroscope" Version="0.13.0" />
Expand All @@ -89,4 +90,4 @@
<PackageVersion Include="Websocket.Client" Version="5.3.0" />
<PackageVersion Include="ZstdSharp.Port" Version="0.8.6" />
</ItemGroup>
</Project>
</Project>
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
// SPDX-FileCopyrightText: 2025 Demerzel Solutions Limited
// SPDX-License-Identifier: LGPL-3.0-only

using Nethermind.Core;
using Nethermind.Core.Crypto;
using Nethermind.State.Flat;

namespace Nethermind.Blockchain;

public class CanonicalStateRootFinder(IBlockTree blockTree): ICanonicalStateRootFinder
{
public Hash256? GetCanonicalStateRootAtBlock(long blockNumber)
{
BlockHeader? header = blockTree.FindHeader(blockNumber, BlockTreeLookupOptions.RequireCanonical);
return header?.StateRoot;
}
}
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;
using Autofac;
using Nethermind.Blockchain;
using Nethermind.Core;
Expand Down
7 changes: 7 additions & 0 deletions src/Nethermind/Nethermind.Core.Test/TestMemColumnDb.cs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
// SPDX-FileCopyrightText: 2023 Demerzel Solutions Limited
// SPDX-License-Identifier: LGPL-3.0-only

using System;
using System.Collections.Generic;
using Nethermind.Db;

Expand Down Expand Up @@ -30,6 +31,12 @@ public IColumnsWriteBatch<TKey> StartWriteBatch()
{
return new InMemoryColumnWriteBatch<TKey>(this);
}

public IColumnDbSnapshot<TKey> CreateSnapshot()
{
throw new Exception("Snapshot not implemented");
}

public void Dispose() { }
public void Flush(bool onlyWal = false) { }
}
5 changes: 5 additions & 0 deletions src/Nethermind/Nethermind.Core/Account.cs
Original file line number Diff line number Diff line change
Expand Up @@ -127,6 +127,11 @@ public Account WithChangedCodeHash(Hash256 newCodeHash)
}

public AccountStruct ToStruct() => new(Nonce, Balance, StorageRoot, CodeHash);

public override string ToString()
{
return $"N:{Nonce},B:{Balance},S{StorageRoot},C:{CodeHash}";
}
}

public readonly struct AccountStruct : IEquatable<AccountStruct>
Expand Down
1 change: 1 addition & 0 deletions src/Nethermind/Nethermind.Core/Address.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
// SPDX-License-Identifier: LGPL-3.0-only

using System;
using System.Buffers.Binary;
using System.ComponentModel;
using System.Diagnostics;
using System.Globalization;
Expand Down
8 changes: 7 additions & 1 deletion src/Nethermind/Nethermind.Core/Crypto/Hash256.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
// SPDX-License-Identifier: LGPL-3.0-only

using System;
using System.Buffers.Binary;
using System.Diagnostics;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
Expand Down Expand Up @@ -113,7 +114,12 @@ public readonly struct Hash256AsKey(Hash256 key) : IEquatable<Hash256AsKey>, ICo
public bool Equals(Hash256AsKey other) => Equals(_key, other._key);
public override int GetHashCode() => _key?.GetHashCode() ?? 0;

public int CompareTo(Hash256AsKey other) => _key.CompareTo(other._key);
public int CompareTo(Hash256AsKey other)
{
if (_key is null && other._key is not null) return -1;
if (_key is null && other._key is null) return 0;
return _key!.CompareTo(other._key);
}
}

[DebuggerStepThrough]
Expand Down
2 changes: 1 addition & 1 deletion src/Nethermind/Nethermind.Core/IKeyValueStore.cs
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,7 @@ public interface IMergeableKeyValueStore : IWriteOnlyKeyValueStore
void Merge(ReadOnlySpan<byte> key, ReadOnlySpan<byte> value, WriteFlags flags = WriteFlags.None);
}

public interface ISortedKeyValueStore : IKeyValueStore
public interface ISortedKeyValueStore : IReadOnlyKeyValueStore
{
byte[]? FirstKey { get; }
byte[]? LastKey { get; }
Expand Down
139 changes: 139 additions & 0 deletions src/Nethermind/Nethermind.Core/Utils/RefCountingDisposable.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,139 @@
using System;
using System.Diagnostics;
using System.Diagnostics.CodeAnalysis;
using System.Runtime.InteropServices;
using System.Threading;

namespace Nethermind.Core.Utils;

/// <summary>
/// Provides a component that can be disposed multiple times and runs <see cref="CleanUp"/> only on the last dispose.
/// </summary>
public abstract class RefCountingDisposable : IDisposable
{
private const int Single = 1;
private const int NoAccessors = 0;
private const int Disposing = -1;

protected PaddedValue _leases;

protected RefCountingDisposable(int initialCount = Single)
{
_leases.Value = initialCount;
}

public void AcquireLease()
{
if (TryAcquireLease() == false)
{
ThrowCouldNotAcquire();
}

[DoesNotReturn]
[StackTraceHidden]
static void ThrowCouldNotAcquire()
{
throw new Exception("The lease cannot be acquired");
}
}

protected bool TryAcquireLease()
{
// Volatile read for starting value
var current = Volatile.Read(ref _leases.Value);
if (current == Disposing)
{
// Already disposed
return false;
}

while (true)
{
var prev = Interlocked.CompareExchange(ref _leases.Value, current + Single, current);
if (prev == current)
{
// Successfully acquired
return true;
}
if (prev == Disposing)
{
// Already disposed
return false;
}

// Try again with new starting value
current = prev;
// Add PAUSE instruction to reduce shared core contention
Thread.SpinWait(1);
}
}

/// <summary>
/// Disposes it once, decreasing the lease count by 1.
/// </summary>
public void Dispose() => ReleaseLeaseOnce();

private void ReleaseLeaseOnce()
{
// Volatile read for starting value
var current = Volatile.Read(ref _leases.Value);
if (current <= NoAccessors)
{
// Mismatched Acquire/Release
ThrowOverDisposed();
}

while (true)
{
var prev = Interlocked.CompareExchange(ref _leases.Value, current - Single, current);
if (prev != current)
{
current = prev;
// Add PAUSE instruction to reduce shared core contention
Thread.SpinWait(1);
continue;
}
if (prev == Single)
{
// Last use, try to dispose underlying
break;
}
if (prev <= NoAccessors)
{
// Mismatched Acquire/Release
ThrowOverDisposed();
}

// Successfully released
return;
}

if (Interlocked.CompareExchange(ref _leases.Value, Disposing, NoAccessors) == NoAccessors)
{
// set to disposed by this Release
CleanUp();
}

[DoesNotReturn]
[StackTraceHidden]
static void ThrowOverDisposed()
{
throw new Exception("The lease has already been disposed");
}
}

protected abstract void CleanUp();

public override string ToString()
{
var leases = Volatile.Read(ref _leases.Value);
return leases == Disposing ? "Disposed" : $"Leases: {leases}";
}

[StructLayout(LayoutKind.Explicit, Size = 128)]
protected struct PaddedValue
{
[FieldOffset(64)]
public long Value;
}
}
23 changes: 23 additions & 0 deletions src/Nethermind/Nethermind.Core/Utils/RefCountingDisposableBox.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
// SPDX-FileCopyrightText: 2025 Demerzel Solutions Limited
// SPDX-License-Identifier: LGPL-3.0-only

using System;

namespace Nethermind.Core.Utils;

public class RefCountingDisposableBox<T>(T item): RefCountingDisposable
where T : IDisposable
{

public T Item => item;

public bool TryAcquire()
{
return TryAcquireLease();
}

protected override void CleanUp()
{
Item.Dispose();
}
}
13 changes: 13 additions & 0 deletions src/Nethermind/Nethermind.Db.Rocks/ColumnDb.cs
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,19 @@ public IEnumerable<byte[]> GetAllValues(bool ordered = false)
return _mainDb.GetAllValuesCore(iterator);
}

public IDbSnapshot CreateSnapshot()
{
ReadOptions readOptions = new();
Snapshot snapshot = _mainDb._db.CreateSnapshot();
readOptions.SetSnapshot(snapshot);

return new DbOnTheRocks.DbSnapshot(
_mainDb,
readOptions,
_columnFamily,
snapshot);
}

public IWriteBatch StartWriteBatch()
{
return new ColumnsDbWriteBatch(this, (DbOnTheRocks.RocksDbWriteBatch)_mainDb.StartWriteBatch());
Expand Down
30 changes: 30 additions & 0 deletions src/Nethermind/Nethermind.Db.Rocks/ColumnsDb.cs
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,10 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.InteropServices;
using FastEnumUtility;
using Nethermind.Core;
using Nethermind.Core.Extensions;
using Nethermind.Db.Rocks.Config;
using Nethermind.Logging;
using RocksDbSharp;
Expand Down Expand Up @@ -156,4 +158,32 @@ public void Merge(ReadOnlySpan<byte> key, ReadOnlySpan<byte> value, WriteFlags f
_writeBatch._writeBatch.Merge(key, value, _column._columnFamily, flags);
}
}

IColumnDbSnapshot<T> IColumnsDb<T>.CreateSnapshot()
{
Snapshot snapshot = _db.CreateSnapshot();
return new ColumnDbSnapshot(this, snapshot);
}

private class ColumnDbSnapshot(
ColumnsDb<T> columnsDb,
Snapshot snapshot
) : IColumnDbSnapshot<T>
{
public IReadOnlyKeyValueStore GetColumn(T key)
{
ReadOptions options = new ReadOptions();
options.SetSnapshot(snapshot);
return new DbOnTheRocks.DbSnapshot(
columnsDb,
options,
columnsDb._columnDbs[key]._columnFamily,
snapshot);
}

public void Dispose()
{
snapshot.Dispose();
}
}
}
Loading
Loading