Skip to content
Merged
Show file tree
Hide file tree
Changes from 8 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 @@ -25,7 +25,7 @@ public ReceiptCanonicalityMonitor(IReceiptStorage? receiptStorage, ILogManager?
{
_receiptStorage = receiptStorage ?? throw new ArgumentNullException(nameof(receiptStorage));
_logger = logManager?.GetClassLogger() ?? throw new ArgumentNullException(nameof(logManager));
_receiptStorage.ReceiptsInserted += OnBlockAddedToMain;
_receiptStorage.NewCanonicalReceipts += OnBlockAddedToMain;
}

private void OnBlockAddedToMain(object sender, BlockReplacementEventArgs e)
Expand Down Expand Up @@ -55,7 +55,7 @@ private void TriggerReceiptInsertedEvent(Block newBlock, Block? previousBlock)

public void Dispose()
{
_receiptStorage.ReceiptsInserted -= OnBlockAddedToMain;
_receiptStorage.NewCanonicalReceipts -= OnBlockAddedToMain;
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,13 @@ public interface IReceiptStorage : IReceiptFinder
void RemoveReceipts(Block block);

/// <summary>
/// Receipts for a block are inserted
/// Receipts for a new main block are inserted
Comment thread
alexb5dh marked this conversation as resolved.
Outdated
/// </summary>
event EventHandler<BlockReplacementEventArgs> ReceiptsInserted;
event EventHandler<BlockReplacementEventArgs> NewCanonicalReceipts;
Comment thread
alexb5dh marked this conversation as resolved.
Outdated

/// <summary>
/// Any receipts are inserted
/// </summary>
Comment thread
alexb5dh marked this conversation as resolved.
event EventHandler<ReceiptsEventArgs> ReceiptsInserted;
Comment thread
alexb5dh marked this conversation as resolved.
Outdated
Comment thread
benaadams marked this conversation as resolved.
Outdated
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,8 @@ public class InMemoryReceiptStorage : IReceiptStorage
private readonly ConcurrentDictionary<Hash256AsKey, TxReceipt> _transactions = new();

#pragma warning disable CS0067
public event EventHandler<BlockReplacementEventArgs> ReceiptsInserted;
public event EventHandler<BlockReplacementEventArgs> NewCanonicalReceipts;
public event EventHandler<ReceiptsEventArgs>? ReceiptsInserted;
#pragma warning restore CS0067

public InMemoryReceiptStorage(bool allowReceiptIterator = true, IBlockTree? blockTree = null)
Expand All @@ -32,7 +33,7 @@ public InMemoryReceiptStorage(bool allowReceiptIterator = true, IBlockTree? bloc
private void BlockTree_BlockAddedToMain(object? sender, BlockReplacementEventArgs e)
{
EnsureCanonical(e.Block);
ReceiptsInserted?.Invoke(this, e);
NewCanonicalReceipts?.Invoke(this, e);
}

public Hash256 FindBlockHash(Hash256 txHash)
Expand Down Expand Up @@ -73,6 +74,8 @@ public void Insert(Block block, TxReceipt[] txReceipts, IReleaseSpec spec, bool
{
EnsureCanonical(block);
}

ReceiptsInserted?.Invoke(this, new(block.Header, txReceipts));
}

public bool HasBlock(long blockNumber, Hash256 hash)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,8 @@ public class NullReceiptStorage : IReceiptStorage
public static NullReceiptStorage Instance { get; } = new();

#pragma warning disable CS0067
public event EventHandler<BlockReplacementEventArgs> ReceiptsInserted;
public event EventHandler<BlockReplacementEventArgs> NewCanonicalReceipts;
Comment thread
alexb5dh marked this conversation as resolved.
Outdated
public event EventHandler<ReceiptsEventArgs>? ReceiptsInserted;
#pragma warning restore CS0067

public Hash256? FindBlockHash(Hash256 hash) => null;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,8 @@ public class PersistentReceiptStorage : IReceiptStorage
private const int CacheSize = 64;
private readonly LruCache<ValueHash256, TxReceipt[]> _receiptsCache = new(CacheSize, CacheSize, "receipts");

public event EventHandler<BlockReplacementEventArgs> ReceiptsInserted;
public event EventHandler<BlockReplacementEventArgs> NewCanonicalReceipts;
Comment thread
alexb5dh marked this conversation as resolved.
Outdated
public event EventHandler<ReceiptsEventArgs>? ReceiptsInserted;

public PersistentReceiptStorage(
IColumnsDb<ReceiptsColumns> receiptsDb,
Expand Down Expand Up @@ -73,7 +74,7 @@ public PersistentReceiptStorage(
private void BlockTreeOnBlockAddedToMain(object? sender, BlockReplacementEventArgs e)
{
EnsureCanonical(e.Block);
ReceiptsInserted?.Invoke(this, e);
NewCanonicalReceipts?.Invoke(this, e);

// Dont block main loop
Task.Run(() =>
Expand Down Expand Up @@ -288,6 +289,8 @@ public void Insert(Block block, TxReceipt[]? txReceipts, IReleaseSpec spec, bool
{
EnsureCanonical(block, lastBlockNumber);
}

ReceiptsInserted?.Invoke(this, new(block.Header, txReceipts));
}

public long MigratedBlockNumber
Expand Down
15 changes: 15 additions & 0 deletions src/Nethermind/Nethermind.Core.Test/Builders/RandomExtensions.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
// SPDX-FileCopyrightText: 2025 Demerzel Solutions Limited
// SPDX-License-Identifier: LGPL-3.0-only

using System;
using System.Collections.Generic;
using Nethermind.Crypto;

Comment thread
benaadams marked this conversation as resolved.
namespace Nethermind.Core.Test.Builders;

public static class RandomExtensions
{
public static T NextFrom<T>(this Random random, IReadOnlyList<T> values) => values[random.Next(values.Count)];

public static T NextFrom<T>(this ICryptoRandom random, IReadOnlyList<T> values) => values[random.NextInt(values.Count)];
}
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@
using System.Text.Json;
using FluentAssertions;
using Nethermind.Core.Extensions;
using Nethermind.Core.Test.Builders;
using Nethermind.Crypto;
using Nethermind.Serialization.Json;
using NUnit.Framework;

Expand Down Expand Up @@ -294,6 +296,22 @@ public void Fuzz_RandomHex_SegmentationInvariant()
}
}

[Test]
public void Test_DictionaryKey()
{
var random = new CryptoRandom();
var dictionary = new Dictionary<byte[], int?>
{
{ Bytes.FromHexString("0x0"), null },
{ Bytes.FromHexString("0x1"), random.NextInt(int.MaxValue) },
{ Build.An.Address.TestObject.Bytes, random.NextInt(int.MaxValue) },
{ random.GenerateRandomBytes(10), random.NextInt(int.MaxValue) },
{ random.GenerateRandomBytes(32), random.NextInt(int.MaxValue) },
};

TestConverter(dictionary, new ByteArrayConverter());
}

private static ReadOnlySequence<byte> JsonForLiteral(string literal) =>
MakeSequence(Encoding.UTF8.GetBytes(literal));

Expand Down
15 changes: 12 additions & 3 deletions src/Nethermind/Nethermind.Core.Test/Json/ConverterTestBase.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.Collections;
using System.Text.Json;
using System.Text.Json.Serialization;
using NUnit.Framework;
Expand All @@ -10,7 +11,10 @@ namespace Nethermind.Core.Test.Json;

public class ConverterTestBase<T>
{
protected void TestConverter(T? item, Func<T, T, bool> equalityComparer, JsonConverter<T> converter)
protected void TestConverter(T? item, Func<T, T, bool> equalityComparer, JsonConverter<T> converter) =>
TestConverter(item, converter, equalityComparer);

protected void TestConverter<TItem>(TItem? item, JsonConverter<T> converter, Func<TItem, TItem, bool>? equalityComparer = null)
{
var options = new JsonSerializerOptions
{
Expand All @@ -22,10 +26,15 @@ protected void TestConverter(T? item, Func<T, T, bool> equalityComparer, JsonCon

string result = JsonSerializer.Serialize(item, options);

T? deserialized = JsonSerializer.Deserialize<T>(result, options);
TItem? deserialized = JsonSerializer.Deserialize<TItem>(result, options);

#pragma warning disable CS8604
Assert.That(equalityComparer(item, deserialized), Is.True);
if (equalityComparer is not null)
Assert.That(equalityComparer(item, deserialized), Is.True);
else if (item is IEnumerable itemE && deserialized is IEnumerable deserializedE)
Assert.That(deserializedE, Is.EquivalentTo(itemE));
else
Assert.That(deserialized, Is.EqualTo(item));
#pragma warning restore CS8604
}
}
12 changes: 12 additions & 0 deletions src/Nethermind/Nethermind.Core/Collections/DictionaryExtensions.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;
using System.Collections.Generic;
using System.Runtime.InteropServices;

Expand All @@ -13,4 +14,15 @@ public static void Increment<TKey>(this Dictionary<TKey, int> dictionary, TKey k
ref int res = ref CollectionsMarshal.GetValueRefOrAddDefault(dictionary, key, out bool _);
res++;
}

public static TValue GetOrAdd<TKey, TValue>(this Dictionary<TKey, TValue> dictionary, TKey key, Func<TKey, TValue> factory)
Comment thread
alexb5dh marked this conversation as resolved.
Outdated
where TKey : notnull
{
ref TValue? existing = ref CollectionsMarshal.GetValueRefOrAddDefault(dictionary, key, out bool exists);

if (!exists)
existing = factory(key);

return existing!;
}
}
8 changes: 7 additions & 1 deletion src/Nethermind/Nethermind.Core/Extensions/Bytes.cs
Original file line number Diff line number Diff line change
Expand Up @@ -262,7 +262,7 @@ public static byte[] PadLeft(this ReadOnlySpan<byte> bytes, int length, byte pad
return result;
}

public static byte[] PadRight(this byte[] bytes, int length)
public static byte[] PadRight(this byte[] bytes, int length, byte padding = 0)
{
if (bytes.Length == length)
{
Expand All @@ -276,6 +276,12 @@ public static byte[] PadRight(this byte[] bytes, int length)

byte[] result = new byte[length];
Buffer.BlockCopy(bytes, 0, result, 0, bytes.Length);

if (padding != 0)
{
result.AsSpan(bytes.Length, length - bytes.Length).Fill(padding);
}

return result;
}

Expand Down
4 changes: 2 additions & 2 deletions src/Nethermind/Nethermind.Core/Extensions/SizeExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,7 @@ public static long KiB(this int @this)
return ((long)@this).KiB();
}

public static string SizeToString(this long @this, bool useSi = false, int precision = 1)
public static string SizeToString(this long @this, bool useSi = false, bool addSpace = false, int precision = 1)
{
string[] suf = useSi ? ["B", "KB", "MB", "GB", "TB"] : ["B", "KiB", "MiB", "GiB", "TiB"];
if (@this == 0)
Expand All @@ -77,7 +77,7 @@ public static string SizeToString(this long @this, bool useSi = false, int preci
long bytes = Math.Abs(@this);
int place = Math.Min(suf.Length - 1, Convert.ToInt32(Math.Floor(Math.Log(bytes, useSi ? 1000 : 1024))));
double num = Math.Round(bytes / Math.Pow(useSi ? 1000 : 1024, place), precision);
return (Math.Sign(@this) * num).ToString() + suf[place];
return string.Concat(Math.Sign(@this) * num, addSpace ? " " : "", suf[place]);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -23,8 +23,12 @@ public static async Task<bool> WaitOneAsync(this WaitHandle handle, int millisec
millisecondsTimeout,
true);
tokenRegistration = cancellationToken.Register(
static state => ((TaskCompletionSource<bool>)state!).TrySetCanceled(),
tcs);
static state =>
{
var (tcs, ct) = ((TaskCompletionSource<bool> tcs, CancellationToken ct))state!;
tcs.TrySetCanceled(ct);
},
(tcs, cancellationToken));

return await tcs.Task;
}
Expand Down
7 changes: 7 additions & 0 deletions src/Nethermind/Nethermind.Core/FakeWriteBatch.cs
Original file line number Diff line number Diff line change
Expand Up @@ -31,5 +31,12 @@ public void Set(ReadOnlySpan<byte> key, byte[]? value, WriteFlags flags = WriteF
{
_storePretendingToSupportBatches.Set(key, value, flags);
}

public void Merge(ReadOnlySpan<byte> key, ReadOnlySpan<byte> value, WriteFlags flags = WriteFlags.None)
Comment thread
alexb5dh marked this conversation as resolved.
{
throw new NotSupportedException("Merging is not supported by this implementation.");
}

public void Clear() { }
}
}
5 changes: 5 additions & 0 deletions src/Nethermind/Nethermind.Core/IKeyValueStore.cs
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,11 @@ public interface IWriteOnlyKeyValueStore
void Remove(ReadOnlySpan<byte> key) => Set(key, null);
}

public interface IMergeableKeyValueStore
Comment thread
alexb5dh marked this conversation as resolved.
Outdated
{
void Merge(ReadOnlySpan<byte> key, ReadOnlySpan<byte> value, WriteFlags flags = WriteFlags.None);
}

public interface ISortedKeyValueStore : IKeyValueStore
{
byte[]? FirstKey { get; }
Expand Down
5 changes: 4 additions & 1 deletion src/Nethermind/Nethermind.Core/IWriteBatch.cs
Original file line number Diff line number Diff line change
Expand Up @@ -5,5 +5,8 @@

namespace Nethermind.Core
{
public interface IWriteBatch : IDisposable, IWriteOnlyKeyValueStore;
public interface IWriteBatch : IDisposable, IWriteOnlyKeyValueStore, IMergeableKeyValueStore
{
void Clear();
Comment thread
alexb5dh marked this conversation as resolved.
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -173,7 +173,7 @@ public static void Convert(ref Utf8JsonReader reader, scoped Span<byte> span)
private static void ThrowFormatException() => throw new FormatException();

[DoesNotReturn, StackTraceHidden]
private static void ThrowInvalidOperationException() => throw new InvalidOperationException();
private static Exception ThrowInvalidOperationException() => throw new InvalidOperationException();
Comment thread
asdacap marked this conversation as resolved.
Outdated
Comment thread
alexb5dh marked this conversation as resolved.
Outdated

public override void Write(
Utf8JsonWriter writer,
Expand Down Expand Up @@ -246,4 +246,14 @@ public static void Convert(
if (array is not null)
ArrayPool<byte>.Shared.Return(array);
}

public override byte[] ReadAsPropertyName(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
{
return Convert(ref reader) ?? throw ThrowInvalidOperationException();
Comment thread
alexb5dh marked this conversation as resolved.
Outdated
}

public override void WriteAsPropertyName(Utf8JsonWriter writer, byte[] value, JsonSerializerOptions options)
{
Convert(writer, value, static (w, h) => w.WritePropertyName(h), skipLeadingZeros: false, addQuotations: false, addHexPrefix: true);
}
}
6 changes: 3 additions & 3 deletions src/Nethermind/Nethermind.Core/ProgressLogger.cs
Original file line number Diff line number Diff line change
Expand Up @@ -47,9 +47,9 @@ public void IncrementSkipped(int skipped = 1)
Interlocked.Add(ref _skipped, skipped);
}

public void SetMeasuringPoint()
public void SetMeasuringPoint(bool resetCompletion = true)
{
UtcEndTime = null;
if (resetCompletion) UtcEndTime = null;

if (UtcStartTime is not null)
{
Expand Down Expand Up @@ -169,7 +169,7 @@ public void LogProgress()
_lastReportState = reportState;
_logger.Info(reportString);
}
SetMeasuringPoint();
SetMeasuringPoint(resetCompletion: false);
}

private string DefaultFormatter()
Expand Down
19 changes: 19 additions & 0 deletions src/Nethermind/Nethermind.Core/Utils/ConcurrentWriteBatcher.cs
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,23 @@ public void PutSpan(ReadOnlySpan<byte> key, ReadOnlySpan<byte> value, WriteFlags
ReturnWriteBatch(currentBatch);
}

public void Merge(ReadOnlySpan<byte> key, ReadOnlySpan<byte> value, WriteFlags flags = WriteFlags.None)
{
IWriteBatch currentBatch = RentWriteBatch();
currentBatch.Merge(key, value, flags);
ReturnWriteBatch(currentBatch);
}

public void Clear()
{
ThrowIfDisposed();
Comment thread
alexb5dh marked this conversation as resolved.
Outdated

foreach (IWriteBatch batch in _batches)
{
batch.Clear();
}
}

public void Set(ReadOnlySpan<byte> key, byte[]? value, WriteFlags flags = WriteFlags.None)
{
IWriteBatch currentBatch = RentWriteBatch();
Expand Down Expand Up @@ -70,4 +87,6 @@ private IWriteBatch RentWriteBatch()

return currentBatch;
}

private void ThrowIfDisposed() => ObjectDisposedException.ThrowIf(_disposing, this);
}
Loading