From 7398e1f967940ff3343aede11c147dc3256c6097 Mon Sep 17 00:00:00 2001 From: "lukasz.rozmej" Date: Mon, 23 Sep 2024 11:05:55 +0200 Subject: [PATCH 1/3] Add clique_proposals --- .../CliqueBlockProducer.cs | 2 + .../CliqueRpcModule.cs | 74 +++++++------------ .../ICliqueBlockProducer.cs | 2 + .../ICliqueRpcModule.cs | 4 + 4 files changed, 33 insertions(+), 49 deletions(-) diff --git a/src/Nethermind/Nethermind.Consensus.Clique/CliqueBlockProducer.cs b/src/Nethermind/Nethermind.Consensus.Clique/CliqueBlockProducer.cs index caf677d9099..4f255ceca5e 100644 --- a/src/Nethermind/Nethermind.Consensus.Clique/CliqueBlockProducer.cs +++ b/src/Nethermind/Nethermind.Consensus.Clique/CliqueBlockProducer.cs @@ -99,6 +99,8 @@ public void ProduceOnTopOf(Hash256 hash) _signalsQueue.Add(_blockTree.FindBlock(hash, BlockTreeLookupOptions.None)); } + public IReadOnlyDictionary GetProposals() => _blockProducer.Proposals.ToDictionary(); + private void TimerOnElapsed(object sender, ElapsedEventArgs e) { try diff --git a/src/Nethermind/Nethermind.Consensus.Clique/CliqueRpcModule.cs b/src/Nethermind/Nethermind.Consensus.Clique/CliqueRpcModule.cs index 07142a25b7a..cc5ec1da3af 100644 --- a/src/Nethermind/Nethermind.Consensus.Clique/CliqueRpcModule.cs +++ b/src/Nethermind/Nethermind.Consensus.Clique/CliqueRpcModule.cs @@ -2,6 +2,7 @@ // SPDX-License-Identifier: LGPL-3.0-only using System; +using System.Collections.Generic; using System.Linq; using Nethermind.Blockchain; using Nethermind.Blockchain.Find; @@ -11,50 +12,46 @@ namespace Nethermind.Consensus.Clique { - public class CliqueRpcModule : ICliqueRpcModule + public class CliqueRpcModule( + ICliqueBlockProducerRunner? cliqueBlockProducer, + ISnapshotManager snapshotManager, + IBlockFinder blockTree) + : ICliqueRpcModule { private const string CannotVoteOnNonValidatorMessage = "Not a signer node - cannot vote"; - private readonly ICliqueBlockProducerRunner? _cliqueBlockProducer; - private readonly ISnapshotManager _snapshotManager; - private readonly IBlockFinder _blockTree; - - public CliqueRpcModule(ICliqueBlockProducerRunner? cliqueBlockProducer, ISnapshotManager snapshotManager, IBlockFinder blockTree) - { - _cliqueBlockProducer = cliqueBlockProducer; - _snapshotManager = snapshotManager ?? throw new ArgumentNullException(nameof(snapshotManager)); - _blockTree = blockTree ?? throw new ArgumentNullException(nameof(blockTree)); - } + private readonly ISnapshotManager _snapshotManager = snapshotManager ?? throw new ArgumentNullException(nameof(snapshotManager)); + private readonly IBlockFinder _blockTree = blockTree ?? throw new ArgumentNullException(nameof(blockTree)); public bool ProduceBlock(Hash256 parentHash) { - if (_cliqueBlockProducer is null) + if (cliqueBlockProducer is null) { return false; } - _cliqueBlockProducer?.ProduceOnTopOf(parentHash); + cliqueBlockProducer?.ProduceOnTopOf(parentHash); return true; } public void CastVote(Address signer, bool vote) { - if (_cliqueBlockProducer is null) + if (cliqueBlockProducer is null) { throw new InvalidOperationException(CannotVoteOnNonValidatorMessage); } - _cliqueBlockProducer.CastVote(signer, vote); + cliqueBlockProducer.CastVote(signer, vote); } public void UncastVote(Address signer) { - if (_cliqueBlockProducer is null) + if (cliqueBlockProducer is null) { throw new InvalidOperationException(CannotVoteOnNonValidatorMessage); } - _cliqueBlockProducer.UncastVote(signer); + cliqueBlockProducer.UncastVote(signer); } public Snapshot GetSnapshot() @@ -103,45 +100,24 @@ public string[] GetSignersAnnotated(Hash256 hash) .Select(s => string.Concat(s.Key, $" ({KnownAddresses.GetDescription(s.Key)})")).ToArray(); } - public ResultWrapper clique_produceBlock(Hash256 parentHash) - { - return ResultWrapper.Success(ProduceBlock(parentHash)); - } + public ResultWrapper clique_produceBlock(Hash256 parentHash) => ResultWrapper.Success(ProduceBlock(parentHash)); - public ResultWrapper clique_getSnapshot() - { - return ResultWrapper.Success(GetSnapshot()); - } + public ResultWrapper> clique_proposals() => + ResultWrapper>.Success(cliqueBlockProducer?.GetProposals() ?? new Dictionary()); - public ResultWrapper clique_getSnapshotAtHash(Hash256 hash) - { - return ResultWrapper.Success(GetSnapshot(hash)); - } + public ResultWrapper clique_getSnapshot() => ResultWrapper.Success(GetSnapshot()); - public ResultWrapper clique_getSigners() - { - return ResultWrapper.Success(GetSigners().ToArray()); - } + public ResultWrapper clique_getSnapshotAtHash(Hash256 hash) => ResultWrapper.Success(GetSnapshot(hash)); - public ResultWrapper clique_getSignersAtHash(Hash256 hash) - { - return ResultWrapper.Success(GetSigners(hash).ToArray()); - } + public ResultWrapper clique_getSigners() => ResultWrapper.Success(GetSigners().ToArray()); - public ResultWrapper clique_getSignersAtNumber(long number) - { - return ResultWrapper.Success(GetSigners(number).ToArray()); - } + public ResultWrapper clique_getSignersAtHash(Hash256 hash) => ResultWrapper.Success(GetSigners(hash).ToArray()); - public ResultWrapper clique_getSignersAnnotated() - { - return ResultWrapper.Success(GetSignersAnnotated().ToArray()); - } + public ResultWrapper clique_getSignersAtNumber(long number) => ResultWrapper.Success(GetSigners(number).ToArray()); - public ResultWrapper clique_getSignersAtHashAnnotated(Hash256 hash) - { - return ResultWrapper.Success(GetSignersAnnotated(hash).ToArray()); - } + public ResultWrapper clique_getSignersAnnotated() => ResultWrapper.Success(GetSignersAnnotated().ToArray()); + + public ResultWrapper clique_getSignersAtHashAnnotated(Hash256 hash) => ResultWrapper.Success(GetSignersAnnotated(hash).ToArray()); public ResultWrapper clique_getBlockSigner(Hash256? hash) { diff --git a/src/Nethermind/Nethermind.Consensus.Clique/ICliqueBlockProducer.cs b/src/Nethermind/Nethermind.Consensus.Clique/ICliqueBlockProducer.cs index e2fbc43492e..9604b49ce71 100644 --- a/src/Nethermind/Nethermind.Consensus.Clique/ICliqueBlockProducer.cs +++ b/src/Nethermind/Nethermind.Consensus.Clique/ICliqueBlockProducer.cs @@ -1,6 +1,7 @@ // SPDX-FileCopyrightText: 2022 Demerzel Solutions Limited // SPDX-License-Identifier: LGPL-3.0-only +using System.Collections.Generic; using Nethermind.Core; using Nethermind.Core.Crypto; @@ -11,5 +12,6 @@ public interface ICliqueBlockProducerRunner : IBlockProducerRunner void CastVote(Address signer, bool vote); void UncastVote(Address signer); void ProduceOnTopOf(Hash256 hash); + IReadOnlyDictionary GetProposals(); } } diff --git a/src/Nethermind/Nethermind.Consensus.Clique/ICliqueRpcModule.cs b/src/Nethermind/Nethermind.Consensus.Clique/ICliqueRpcModule.cs index dba1116bbb7..53440be3fd9 100644 --- a/src/Nethermind/Nethermind.Consensus.Clique/ICliqueRpcModule.cs +++ b/src/Nethermind/Nethermind.Consensus.Clique/ICliqueRpcModule.cs @@ -1,6 +1,7 @@ // SPDX-FileCopyrightText: 2022 Demerzel Solutions Limited // SPDX-License-Identifier: LGPL-3.0-only +using System.Collections.Generic; using Nethermind.Core; using Nethermind.Core.Crypto; using Nethermind.JsonRpc; @@ -43,5 +44,8 @@ public interface ICliqueRpcModule : IRpcModule [JsonRpcMethod(Description = "Forces Clique block producer to produce a new block", IsImplemented = true)] ResultWrapper clique_produceBlock(Hash256 parentHash); + + [JsonRpcMethod(Description = "Retrieves the current proposals the node is voting on.", IsImplemented = true)] + ResultWrapper> clique_proposals(); } } From 5a26cac475394c3e6a5677de786112f860aacc87 Mon Sep 17 00:00:00 2001 From: "lukasz.rozmej" Date: Mon, 23 Sep 2024 12:49:08 +0200 Subject: [PATCH 2/3] Fix JSON serialization of Snapshot --- .../SnapshotDecoderTests.cs | 3 +-- .../Nethermind.Consensus.Clique/Snapshot.cs | 17 +++++++++-------- .../SnapshotDecoder.cs | 3 +-- .../Nethermind.Core/AddressConverter.cs | 15 +++++++++++++++ .../Nethermind.Core/ByteArrayConverter.cs | 2 +- .../Extensions/SpanExtensions.cs | 4 ++-- 6 files changed, 29 insertions(+), 15 deletions(-) diff --git a/src/Nethermind/Nethermind.Clique.Test/SnapshotDecoderTests.cs b/src/Nethermind/Nethermind.Clique.Test/SnapshotDecoderTests.cs index 567fc487a96..8d9fc9cb4d7 100644 --- a/src/Nethermind/Nethermind.Clique.Test/SnapshotDecoderTests.cs +++ b/src/Nethermind/Nethermind.Clique.Test/SnapshotDecoderTests.cs @@ -67,8 +67,7 @@ private Snapshot GenerateSnapshot(Hash256 hash, long number, Address candidate) tally[candidate].Votes = 2; tally[_signer2] = new Tally(false); tally[_signer2].Votes = 1; - Snapshot snapshot = new(number, hash, signers, tally); - snapshot.Votes = votes; + Snapshot snapshot = new(number, hash, signers, tally) { Votes = votes }; return snapshot; } } diff --git a/src/Nethermind/Nethermind.Consensus.Clique/Snapshot.cs b/src/Nethermind/Nethermind.Consensus.Clique/Snapshot.cs index d98f6157ba8..3725511decd 100644 --- a/src/Nethermind/Nethermind.Consensus.Clique/Snapshot.cs +++ b/src/Nethermind/Nethermind.Consensus.Clique/Snapshot.cs @@ -13,8 +13,7 @@ public class Snapshot : ICloneable public long Number { get; set; } public Hash256 Hash { get; set; } public SortedList Signers { get; } - - public List Votes; + public List Votes { get; init; } internal Dictionary Tally { get; } internal Snapshot(long number, Hash256 hash, SortedList signers, Dictionary tally) @@ -31,12 +30,14 @@ internal Snapshot(long number, Hash256 hash, SortedList signers) { } - public object Clone() - { - Snapshot clone = new Snapshot(Number, Hash, new SortedList(Signers, AddressComparer.Instance), new Dictionary(Tally)); - clone.Votes = new List(Votes); - return clone; - } + public object Clone() => + new Snapshot(Number, + Hash, + new SortedList(Signers, AddressComparer.Instance), + new Dictionary(Tally)) + { + Votes = [..Votes] + }; public long SignerLimit => Signers.Count / 2 + 1; } diff --git a/src/Nethermind/Nethermind.Consensus.Clique/SnapshotDecoder.cs b/src/Nethermind/Nethermind.Consensus.Clique/SnapshotDecoder.cs index 87156c1e43b..eeb86589ee5 100644 --- a/src/Nethermind/Nethermind.Consensus.Clique/SnapshotDecoder.cs +++ b/src/Nethermind/Nethermind.Consensus.Clique/SnapshotDecoder.cs @@ -25,8 +25,7 @@ public Snapshot Decode(RlpStream rlpStream, RlpBehaviors rlpBehaviors = RlpBehav List votes = DecodeVotes(rlpStream); // Tally Dictionary tally = DecodeTally(rlpStream); - Snapshot snapshot = new Snapshot(number, hash, signers, tally); - snapshot.Votes = votes; + Snapshot snapshot = new(number, hash, signers, tally) { Votes = votes }; return snapshot; } diff --git a/src/Nethermind/Nethermind.Core/AddressConverter.cs b/src/Nethermind/Nethermind.Core/AddressConverter.cs index 808e383218f..9fcab4431b3 100644 --- a/src/Nethermind/Nethermind.Core/AddressConverter.cs +++ b/src/Nethermind/Nethermind.Core/AddressConverter.cs @@ -2,10 +2,12 @@ // SPDX-License-Identifier: LGPL-3.0-only using System; +using System.Runtime.CompilerServices; using System.Text.Json; using System.Text.Json.Serialization; using Nethermind.Core; +using Nethermind.Core.Extensions; namespace Nethermind.Serialization.Json; @@ -27,4 +29,17 @@ public override void Write( { ByteArrayConverter.Convert(writer, address.Bytes, skipLeadingZeros: false); } + + [SkipLocalsInit] + public override void WriteAsPropertyName(Utf8JsonWriter writer, + Address value, + JsonSerializerOptions options) + { + Span addressBytes = stackalloc byte[Address.Size * 2 + 2]; + addressBytes[0] = (byte)'0'; + addressBytes[1] = (byte)'x'; + Span hex = addressBytes.Slice(2); + value.Bytes.AsSpan().OutputBytesToByteHex(hex, false); + writer.WritePropertyName(addressBytes); + } } diff --git a/src/Nethermind/Nethermind.Core/ByteArrayConverter.cs b/src/Nethermind/Nethermind.Core/ByteArrayConverter.cs index 9e5c9b2cd3c..e02067a2cc7 100644 --- a/src/Nethermind/Nethermind.Core/ByteArrayConverter.cs +++ b/src/Nethermind/Nethermind.Core/ByteArrayConverter.cs @@ -15,7 +15,7 @@ namespace Nethermind.Serialization.Json; public class ByteArrayConverter : JsonConverter { - private readonly static ushort _hexPrefix = MemoryMarshal.Cast("0x"u8)[0]; + private static readonly ushort _hexPrefix = MemoryMarshal.Cast("0x"u8)[0]; public override byte[]? Read( ref Utf8JsonReader reader, diff --git a/src/Nethermind/Nethermind.Core/Extensions/SpanExtensions.cs b/src/Nethermind/Nethermind.Core/Extensions/SpanExtensions.cs index 1d6f49d57ee..bc45c174eb3 100644 --- a/src/Nethermind/Nethermind.Core/Extensions/SpanExtensions.cs +++ b/src/Nethermind/Nethermind.Core/Extensions/SpanExtensions.cs @@ -55,7 +55,7 @@ public static string ToHexString(this in Span span, bool withZeroX, bool n } [DebuggerStepThrough] - private unsafe static string ToHexViaLookup(ReadOnlySpan bytes, bool withZeroX, bool skipLeadingZeros, bool withEip55Checksum) + private static unsafe string ToHexViaLookup(ReadOnlySpan bytes, bool withZeroX, bool skipLeadingZeros, bool withEip55Checksum) { if (withEip55Checksum) { @@ -82,7 +82,7 @@ private unsafe static string ToHexViaLookup(ReadOnlySpan bytes, bool withZ } } - unsafe readonly struct StringParams(byte* input, int inputLength, int leadingZeros, bool withZeroX) + readonly unsafe struct StringParams(byte* input, int inputLength, int leadingZeros, bool withZeroX) { private readonly byte* _input = input; public readonly int InputLength = inputLength; From b8c5ed008a07564f7db40f1a2f938a591a89835c Mon Sep 17 00:00:00 2001 From: "lukasz.rozmej" Date: Mon, 23 Sep 2024 12:51:32 +0200 Subject: [PATCH 3/3] fix whitespace --- src/Nethermind/Nethermind.Consensus.Clique/Snapshot.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Nethermind/Nethermind.Consensus.Clique/Snapshot.cs b/src/Nethermind/Nethermind.Consensus.Clique/Snapshot.cs index 3725511decd..d2f07492a65 100644 --- a/src/Nethermind/Nethermind.Consensus.Clique/Snapshot.cs +++ b/src/Nethermind/Nethermind.Consensus.Clique/Snapshot.cs @@ -36,7 +36,7 @@ public object Clone() => new SortedList(Signers, AddressComparer.Instance), new Dictionary(Tally)) { - Votes = [..Votes] + Votes = [.. Votes] }; public long SignerLimit => Signers.Count / 2 + 1;