Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Optimism CL P2P #7297

Merged
merged 39 commits into from
Jan 2, 2025
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
Show all changes
39 commits
Select commit Hold shift + click to select a range
be22107
P2P
deffrian Jul 30, 2024
f7266d0
Blob support
deffrian Sep 4, 2024
7e78b03
Add decoders
deffrian Oct 28, 2024
d58ffef
Merge branch 'master' into feature/op-cl
deffrian Oct 28, 2024
702bad1
nuget libp2p
deffrian Oct 28, 2024
af7dcb2
Delete submodule
deffrian Oct 28, 2024
52446cf
Span batch decoder
deffrian Nov 18, 2024
3b08e35
Merge branch 'master' into feature/op-cl
deffrian Nov 18, 2024
50c6309
Fix decoding
deffrian Nov 20, 2024
fe7868f
Merge branch 'master' into feature/op-cl
deffrian Nov 20, 2024
a0da6fc
Fix build
deffrian Nov 20, 2024
a507ee4
Fix p2p
deffrian Nov 20, 2024
f48b495
More derivation
deffrian Nov 29, 2024
0c35f65
Merge branch 'master' into feature/op-cl
deffrian Nov 29, 2024
9086435
Add pubKey verification
deffrian Nov 29, 2024
971386d
Fix payload decoder & peers
deffrian Dec 3, 2024
e962edf
Change signature validation
deffrian Dec 4, 2024
eecb968
Add peers
deffrian Dec 4, 2024
8baef3e
sequencerP2PAddress
deffrian Dec 5, 2024
2f05fe1
Merge branch 'master' into feature/op-cl
deffrian Dec 6, 2024
3a94ced
Fix formatting
deffrian Dec 6, 2024
8230d31
Fix formatting
deffrian Dec 6, 2024
1b8000e
Remove derivation
deffrian Dec 6, 2024
9b669d4
Cleanup
deffrian Dec 18, 2024
aaf2f44
Merge branch 'master' into feature/op-cl
deffrian Dec 18, 2024
e51e2bc
Limit decoded data size
deffrian Dec 18, 2024
4a19925
Fix suggestions
deffrian Dec 19, 2024
e1f9b9d
Merge branch 'master' into feature/op-cl
deffrian Dec 19, 2024
dc2d0de
Fix formating
deffrian Dec 19, 2024
9c30ea4
Merge remote-tracking branch 'origin/feature/op-cl' into feature/op-cl
deffrian Dec 19, 2024
9275b17
Add payload decoder tests
deffrian Dec 19, 2024
bf593a7
Fix suggestions
deffrian Dec 26, 2024
543584f
Merge branch 'master' into feature/op-cl
deffrian Dec 26, 2024
85670e9
Fix suggestions
deffrian Dec 30, 2024
68e0aaa
Add catch on async void to avoid process crash + refactors
LukaszRozmej Jan 2, 2025
da337da
Use channels
deffrian Jan 2, 2025
8343884
Close channel
deffrian Jan 2, 2025
c04d17c
Minor adjustments
deffrian Jan 2, 2025
2b46ff9
Merge branch 'master' into feature/op-cl
deffrian Jan 2, 2025
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 @@ -11,6 +11,7 @@ public interface IP2PBlockValidator
{
ValidityStatus Validate(ExecutionPayloadV3 payload, P2PTopic topic);
ValidityStatus ValidateSignature(ReadOnlySpan<byte> payloadData, Span<byte> signature);
ValidityStatus IsBlockNumberPerHeightLimitReached(ExecutionPayloadV3 payload);
}

public enum ValidityStatus
Expand Down
54 changes: 43 additions & 11 deletions src/Nethermind/Nethermind.Optimism/CL/P2P/OptimismCLP2P.cs
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
using System.Security.Cryptography;
using System.Text;
using System.Threading;
using System.Threading.Channels;
using System.Threading.Tasks;
using Microsoft.Extensions.DependencyInjection;
using Multiformats.Address;
Expand Down Expand Up @@ -40,6 +41,7 @@ public class OptimismCLP2P : IDisposable
private readonly Multiaddress[] _staticPeerList;
private readonly ICLConfig _config;
private ILocalPeer? _localPeer;
private readonly Task _mainLoopTask;

private readonly string _blocksV2TopicId;

Expand Down Expand Up @@ -67,38 +69,62 @@ public OptimismCLP2P(ulong chainId, string[] staticPeerList, ICLConfig config, A
})
.AddSingleton(new Settings())
.BuildServiceProvider();

_mainLoopTask = new(async () =>
{
await MainLoop();
});
}

private ulong _headPayloadNumber = 0;
private readonly SemaphoreSlim _semaphore = new(1);
private ulong _headPayloadNumber;
private readonly Channel<ExecutionPayloadV3> _blocksP2PMessageChannel = Channel.CreateBounded<ExecutionPayloadV3>(10); // for safety add capacity

private async void OnMessage(byte[] msg)
{
await _semaphore.WaitAsync();
try
{
if (TryValidateAndDecodePayload(msg, out var payload))
{
if (_logger.IsTrace) _logger.Trace($"Received payload prom p2p: {payload}");
await _blocksP2PMessageChannel.Writer.WriteAsync(payload, _cancellationTokenSource.Token);
}
}
catch (Exception e)
{
if (e is not OperationCanceledException && _logger.IsError) _logger.Error("Unhandled exception in Optimism CL P2P:", e);
}
}

private async Task MainLoop()
{
while (true)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

maybe await foreach (ExecutionPayloadV3 payload in reader.ReadAllAsync()) instead?

Will we ever close the channel, shouldn't we close it when app close (we have a CancelationToken available for that)?

{
try
{
ExecutionPayloadV3 payload =
await _blocksP2PMessageChannel.Reader.ReadAsync(_cancellationTokenSource.Token);

if (_headPayloadNumber >= (ulong)payload.BlockNumber)
{
// Old payload. skip
return;
}

if (_blockValidator.IsBlockNumberPerHeightLimitReached(payload) is not ValidityStatus.Valid)
{
return;
}

if (await SendNewPayloadToEL(payload) && await SendForkChoiceUpdatedToEL(payload.BlockHash))
{
_headPayloadNumber = (ulong)payload.BlockNumber;
}
}
}
catch (Exception e)
{
if (_logger.IsError) _logger.Error("Unhandled exception in Optimism CL P2P:", e);
}
finally
{
_semaphore.Release();
catch (Exception e)
{
if (_logger.IsError && e is not OperationCanceledException and not ChannelClosedException)
_logger.Error("Unhandled exception in Optimism CL P2P:", e);
}
}
}

Expand Down Expand Up @@ -150,6 +176,8 @@ private async Task<bool> SendNewPayloadToEL(ExecutionPayloadV3 executionPayload)
ResultWrapper<PayloadStatusV1> npResult = await _engineRpcModule.engine_newPayloadV3(executionPayload, Array.Empty<byte[]>(),
executionPayload.ParentBeaconBlockRoot);

_cancellationTokenSource.Token.ThrowIfCancellationRequested();

if (npResult.Result.ResultType == ResultType.Failure)
{
if (_logger.IsError)
Expand All @@ -174,6 +202,8 @@ private async Task<bool> SendForkChoiceUpdatedToEL(Hash256 headBlockHash)
new ForkchoiceStateV1(headBlockHash, headBlockHash, headBlockHash),
null);

_cancellationTokenSource.Token.ThrowIfCancellationRequested();

if (fcuResult.Result.ResultType == ResultType.Failure)
{
if (_logger.IsError)
Expand Down Expand Up @@ -213,6 +243,8 @@ public void Start()
PeerStore peerStore = _serviceProvider.GetService<PeerStore>()!;
peerStore.Discover(_staticPeerList);

_mainLoopTask.Start();

if (_logger.IsInfo) _logger.Info($"Started P2P: {_localPeer.Address}");
}

Expand Down
22 changes: 12 additions & 10 deletions src/Nethermind/Nethermind.Optimism/CL/P2P/P2PBlockValidator.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.Generic;
using Nethermind.Core;
using Nethermind.Core.Crypto;
using Nethermind.Crypto;
Expand All @@ -16,7 +17,7 @@ public class P2PBlockValidator : IP2PBlockValidator
{
private readonly ILogger _logger;
private readonly ITimestamper _timestamper;
private readonly ConcurrentDictionary<long, long> _numberOfBlocksSeen = new();
private readonly Dictionary<long, long> _numberOfBlocksSeen = new();
private readonly Address _sequencerP2PAddress;
private readonly byte[] _chainId;

Expand All @@ -33,14 +34,23 @@ public ValidityStatus Validate(ExecutionPayloadV3 payload, P2PTopic topic)
{
if (!IsTopicValid(topic) || !IsTimestampValid(payload) || !IsBlockHashValid(payload) ||
!IsBlobGasUsedValid(payload, topic) || !IsExcessBlobGasValid(payload, topic) ||
!IsParentBeaconBlockRootValid(payload, topic) || IsBlockNumberPerHeightLimitReached(payload))
!IsParentBeaconBlockRootValid(payload, topic))
{
return ValidityStatus.Reject;
}

return ValidityStatus.Valid;
}

// This method is not thread safe
public ValidityStatus IsBlockNumberPerHeightLimitReached(ExecutionPayloadV3 payload)
{
// [REJECT] if more than 5 different blocks have been seen with the same block height
_numberOfBlocksSeen.TryGetValue(payload.BlockNumber, out var currentCount);
_numberOfBlocksSeen[payload.BlockNumber] = currentCount + 1;
return currentCount > 5 ? ValidityStatus.Reject : ValidityStatus.Valid;
}

public ValidityStatus ValidateSignature(ReadOnlySpan<byte> payloadData, Span<byte> signature)
{
return IsSignatureValid(payloadData, signature) ? ValidityStatus.Valid : ValidityStatus.Reject;
Expand Down Expand Up @@ -129,14 +139,6 @@ private bool IsParentBeaconBlockRootValid(ExecutionPayloadV3 payload, P2PTopic t
return true;
}

private bool IsBlockNumberPerHeightLimitReached(ExecutionPayloadV3 payload)
{
// [REJECT] if more than 5 different blocks have been seen with the same block height
long currentCount = _numberOfBlocksSeen.GetOrAdd(payload.BlockNumber, _ => 0);
_numberOfBlocksSeen[payload.BlockNumber] = currentCount + 1;
return currentCount > 5;
}

private bool IsSignatureValid(ReadOnlySpan<byte> payloadData, Span<byte> signature)
{
if (signature[64] > 3) return false;
Expand Down
Loading