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
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,8 @@ private static ISpecProvider MakeSpecProvider(bool isAmsterdam)
new object[] { /* isAmsterdam */ true, /* withSlot */ true, /* fcu */ PayloadAttributesVersions.V4,
PayloadAttributesValidationResult.Success, null!, null! },
new object[] { /* isAmsterdam */ false, /* withSlot */ true, /* fcu */ PayloadAttributesVersions.V3,
PayloadAttributesValidationResult.InvalidPayloadAttributes, null!, null! },
new object[] { /* isAmsterdam */ true, /* withSlot */ false, /* fcu */ PayloadAttributesVersions.V3,
PayloadAttributesValidationResult.UnsupportedFork, null!, null! },
];

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -163,9 +163,11 @@ private static PayloadAttributesValidationResult ValidateVersion(
if (actualVersion != timestampVersion)
{
error = $"{methodName}{timestampVersion} expected";
// FCU also doesn't support this fork → UnsupportedFork (post-Paris only)
bool unsupportedFork = timestampVersion >= PayloadAttributesVersions.V2 &&
(actualVersion > timestampVersion || fcuVersion != timestampVersion);
bool unsupportedFork = timestampVersion >= PayloadAttributesVersions.V2 && (
// attrs from a newer fork AND FCU version is also too new for this timestamp
actualVersion > timestampVersion ? fcuVersion > timestampVersion
// attrs from an older fork AND the FCU version doesn't match either
: fcuVersion != timestampVersion);
return unsupportedFork
? PayloadAttributesValidationResult.UnsupportedFork
: PayloadAttributesValidationResult.InvalidPayloadAttributes;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -856,7 +856,7 @@ public static IEnumerable<TestCaseData> ForkchoiceUpdatedV3DeclinedTestCaseSourc
yield return new TestCaseData(Shanghai.Instance, nameof(IEngineRpcModule.engine_forkchoiceUpdatedV2), true)
{
TestName = "ForkchoiceUpdatedV2 To Request Shanghai Payload, Zero Beacon Root",
ExpectedResult = MergeErrorCodes.UnsupportedFork,
ExpectedResult = MergeErrorCodes.InvalidPayloadAttributes,
};
yield return new TestCaseData(Cancun.Instance, nameof(IEngineRpcModule.engine_forkchoiceUpdatedV2), true)
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,12 @@ public ValidationResult ValidateParams(IReleaseSpec spec, int version, out strin
return result;
}

if (blobVersionedHashes is null)
{
error = "Blob versioned hashes must not be null";
Comment thread
DarkLord017 marked this conversation as resolved.
return ValidationResult.Fail;
}

Result<Transaction[]> transactionDecodingResult = executionPayload.TryGetTransactions();
if (transactionDecodingResult.IsError)
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -130,7 +130,7 @@ public async Task<ResultWrapper<PayloadStatusV1>> HandleAsync(ExecutionPayload r
if (!HeaderValidator.ValidateHash(block!.Header, out Hash256 actualHash))
{
if (_logger.IsWarn) _logger.Warn(InvalidBlockHelper.GetMessage(block, "invalid block hash"));
RecordBadBlock(block);
Nethermind.Blockchain.Metrics.BadBlocks++;
return NewPayloadV1Result.Invalid(null, $"Invalid block hash {request.BlockHash} does not match calculated hash {actualHash}.");
}

Expand Down
7 changes: 7 additions & 0 deletions src/Nethermind/Nethermind.Network/NodeFilter.cs
Original file line number Diff line number Diff line change
Expand Up @@ -105,6 +105,13 @@ public void Touch(IPAddress ipAddress, bool exactOnly = false)
_cache.Set(GetKey(ipAddress, exactOnly), Environment.TickCount64);
}

/// <summary>
/// Removes a previously recorded address so that the next <see cref="TryAccept"/> call for the
/// same address succeeds. Used to permit reconnection after a session ends.
/// </summary>
public void Remove(IPAddress ipAddress, bool exactOnly = false)
=> _cache?.Delete(GetKey(ipAddress, exactOnly));

[MethodImpl(MethodImplOptions.AggressiveInlining)]
private IpSubnetKey GetKey(IPAddress ipAddress, bool exactOnly)
=> _exactMatchOnly || exactOnly
Expand Down
8 changes: 7 additions & 1 deletion src/Nethermind/Nethermind.Network/PeerManager.cs
Original file line number Diff line number Diff line change
Expand Up @@ -925,8 +925,14 @@ void TraceHardLimitDisconnect()
=> _logger.Trace($"Initiating disconnect with {session} {DisconnectReason.HardLimitTooManyPeers} {DisconnectType.Local}");
}

/// <remarks>
/// Static and bootnode peers bypass the IP filter so that a single failed attempt does not block reconnection
/// for the full filter timeout window. Their retry cadence is governed by <see cref="IsConnectionDelayed"/>
/// and the outgoing rate-limiter instead.
/// </remarks>
private bool ShouldContactPeer(Peer peer)
=> _rlpxHost.ShouldContact(peer.Node.Address.Address, exactOnly: peer.Node.IsStatic || peer.Node.IsBootnode);
=> peer.Node.IsStatic || peer.Node.IsBootnode
|| _rlpxHost.ShouldContact(peer.Node.Address.Address);

/// <summary>
/// Fast-path guard for the peer-added event: checks throttle before the IP filter
Expand Down
9 changes: 9 additions & 0 deletions src/Nethermind/Nethermind.Network/Rlpx/RlpxHost.cs
Original file line number Diff line number Diff line change
Expand Up @@ -501,6 +501,15 @@ private void OnSessionDisconnected(ISession session, DisconnectEventArgs args)
return;
}

// Release the peer's IP from the filter so it can reconnect immediately.
// For inbound sessions the filter entry was created by ShouldRejectInbound; clearing it here
// prevents the 5-minute window from blocking legitimate reconnection after a dropped session.
if (session.Node?.Address?.Address is { } remoteIp)
{
bool exactOnly = session.Node.IsStatic || session.Node.IsBootnode;
_nodeFilter.Remove(remoteIp, exactOnly);
}

subscription.DetachSession();
_sessionMonitor.RemoveSession(session);
try
Expand Down
Loading