Skip to content

Commit 31a119f

Browse files
flcl42Scooletz
authored andcommitted
Fix wrong parent block due to reorg (#8159)
Co-authored-by: Szymon Kulec <[email protected]>
1 parent 926ca88 commit 31a119f

File tree

3 files changed

+87
-2
lines changed

3 files changed

+87
-2
lines changed

src/Nethermind/Nethermind.Core/ChainLevelInfo.cs

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,8 @@ public ChainLevelInfo(bool hasBlockInMainChain, params BlockInfo[] blockInfos)
1717
BlockInfos = blockInfos;
1818
}
1919

20+
private const int NotFound = -1;
21+
2022
public bool HasNonBeaconBlocks => BlockInfos.Any(static b => (b.Metadata & (BlockMetadata.BeaconHeader | BlockMetadata.BeaconBody)) == 0);
2123
public bool HasBeaconBlocks => BlockInfos.Any(static b => (b.Metadata & (BlockMetadata.BeaconHeader | BlockMetadata.BeaconBody)) != 0);
2224
public bool HasBlockOnMainChain { get; set; }
@@ -72,6 +74,21 @@ public BlockInfo? BeaconMainChainBlock
7274
return null;
7375
}
7476

77+
private bool TryFindBeaconMainChainIndex(out int index)
78+
{
79+
for (int i = 0; i < BlockInfos.Length; i++)
80+
{
81+
if (BlockInfos[i].IsBeaconMainChain)
82+
{
83+
index = i;
84+
return true;
85+
}
86+
}
87+
88+
index = NotFound;
89+
return false;
90+
}
91+
7592
public BlockInfo? FindBlockInfo(Hash256 blockHash)
7693
{
7794
int? index = FindIndex(blockHash);
@@ -103,6 +120,12 @@ public void InsertBlockInfo(Hash256 hash, BlockInfo blockInfo, bool setAsMain)
103120
blockInfos[index] = blockInfos[0];
104121
blockInfos[0] = blockInfo;
105122
}
123+
// prioritise new beacon info from beacon sync over old fcu
124+
else if (blockInfo.IsBeaconMainChain && TryFindBeaconMainChainIndex(out int beaconMainChainIndex))
125+
{
126+
blockInfos[index] = blockInfos[beaconMainChainIndex];
127+
blockInfos[beaconMainChainIndex] = blockInfo;
128+
}
106129
else
107130
{
108131
blockInfos[index] = blockInfo;

src/Nethermind/Nethermind.Merge.Plugin.Test/EngineModuleTests.V3.cs

Lines changed: 64 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,11 +9,14 @@
99
using System.Threading;
1010
using System.Threading.Tasks;
1111
using FluentAssertions;
12+
using Nethermind.Blockchain;
13+
using Nethermind.Blockchain.Synchronization;
1214
using Nethermind.Consensus.Producers;
1315
using Nethermind.Core;
1416
using Nethermind.Core.Crypto;
1517
using Nethermind.Core.Extensions;
1618
using Nethermind.Core.Specs;
19+
using Nethermind.Core.Test;
1720
using Nethermind.Core.Test.Builders;
1821
using Nethermind.Crypto;
1922
using Nethermind.Evm;
@@ -24,9 +27,13 @@
2427
using Nethermind.Merge.Plugin.Data;
2528
using Nethermind.Merge.Plugin.GC;
2629
using Nethermind.Merge.Plugin.Handlers;
30+
using Nethermind.Merge.Plugin.Synchronization;
2731
using Nethermind.Serialization.Json;
2832
using Nethermind.Serialization.Rlp;
2933
using Nethermind.Specs.Forks;
34+
using Nethermind.Stats;
35+
using Nethermind.Synchronization.Peers;
36+
using Nethermind.Synchronization.Peers.AllocationStrategies;
3037
using Nethermind.TxPool;
3138
using NSubstitute;
3239
using NUnit.Framework;
@@ -656,6 +663,60 @@ public async Task GetBlobsV1_should_return_mix_of_blobs_and_nulls([Values(1, 2,
656663
}
657664
}
658665

666+
[Test]
667+
public async Task Sync_proper_chain_when_header_fork_came_from_fcu_and_beacon_sync()
668+
{
669+
// fork A
670+
MergeTestBlockchain chainA = await CreateBlockchain(releaseSpec: Cancun.Instance);
671+
IEngineRpcModule rpcModuleA = CreateEngineModule(chainA, null, TimeSpan.FromDays(1));
672+
await rpcModuleA.engine_forkchoiceUpdatedV3(new(chainA.BlockTree.Head!.Hash!, chainA.BlockTree.Head!.Hash!, chainA.BlockTree.Head!.Hash!), null);
673+
674+
// main fork B
675+
MergeTestBlockchain chainB = await CreateBlockchain(releaseSpec: Cancun.Instance);
676+
IEngineRpcModule rpcModuleB = CreateEngineModule(chainB, null, TimeSpan.FromDays(1));
677+
await rpcModuleB.engine_forkchoiceUpdatedV3(new(chainA.BlockTree.Head!.Hash!, chainA.BlockTree.Head!.Hash!, chainA.BlockTree.Head!.Hash!), null);
678+
679+
// syncing chain
680+
MergeTestBlockchain chainC = await CreateBlockchain(releaseSpec: Cancun.Instance);
681+
IEngineRpcModule rpcModuleC = CreateEngineModule(chainC, null, TimeSpan.FromDays(1));
682+
await rpcModuleC.engine_forkchoiceUpdatedV3(new(chainA.BlockTree.Head!.Hash!, chainA.BlockTree.Head!.Hash!, chainA.BlockTree.Head!.Hash!), null);
683+
684+
ExecutionPayloadV3 payloadResultA1 = await AddNewBlockV3(rpcModuleA, chainA, 1);
685+
ExecutionPayloadV3 payloadResultA2 = await AddNewBlockV3(rpcModuleA, chainA, 1);
686+
687+
ExecutionPayloadV3 payloadResultB1 = await AddNewBlockV3(rpcModuleB, chainB, 1);
688+
// fork
689+
ExecutionPayloadV3 payloadResultB2 = await AddNewBlockV3(rpcModuleB, chainB, 2);
690+
ExecutionPayloadV3 payloadResultB3 = await AddNewBlockV3(rpcModuleB, chainB, 1);
691+
692+
SyncPeerMock chainAPeer = new SyncPeerMock(chainA.BlockTree);
693+
SyncPeerAllocation alloc = new SyncPeerAllocation(new PeerInfo(chainAPeer), AllocationContexts.All);
694+
alloc.AllocateBestPeer(new[] { new PeerInfo(chainAPeer) }, Substitute.For<INodeStatsManager>(), Substitute.For<IBlockTree>());
695+
chainC.SyncPeerPool!.Allocate(
696+
Arg.Any<IPeerAllocationStrategy>(),
697+
Arg.Any<AllocationContexts>(),
698+
Arg.Any<int>(),
699+
Arg.Any<CancellationToken>())!.Returns(Task.FromResult(alloc));
700+
701+
702+
await rpcModuleC.engine_forkchoiceUpdatedV3(new(payloadResultA1.BlockHash, chainC.BlockTree.GenesisHash, chainC.BlockTree.GenesisHash), null);
703+
await rpcModuleC.engine_forkchoiceUpdatedV3(new(payloadResultA2.BlockHash, chainC.BlockTree.GenesisHash, chainC.BlockTree.GenesisHash), null);
704+
await Task.Delay(1000);
705+
706+
await rpcModuleC.engine_newPayloadV3(payloadResultB2, [], TestItem.KeccakE);
707+
await rpcModuleC.engine_newPayloadV3(payloadResultB3, [], TestItem.KeccakE);
708+
709+
await Task.Delay(1000);
710+
AddBlockResult res = chainC.BlockTree.Insert(chainB.BlockTree.FindBlock(2)!.Header, BlockTreeInsertHeaderOptions.BeaconHeaderInsert);
711+
await rpcModuleC.engine_forkchoiceUpdatedV3(new(payloadResultB3.BlockHash, chainC.BlockTree.GenesisHash, chainC.BlockTree.GenesisHash), null);
712+
713+
BlockHeader[]? heads = new ChainLevelHelper(chainC.BlockTree, chainC.BeaconPivot!, new SyncConfig(), chainC.LogManager)
714+
.GetNextHeaders(10, 3);
715+
716+
Assert.That(heads?[2].Hash, Is.EqualTo(payloadResultB2.BlockHash));
717+
Assert.That(heads?[3].Hash, Is.EqualTo(payloadResultB3.BlockHash));
718+
}
719+
659720
public static IEnumerable<TestCaseData> ForkchoiceUpdatedV3DeclinedTestCaseSource
660721
{
661722
get
@@ -808,7 +869,7 @@ public static IEnumerable<TestCaseData> CancunFieldsTestSource
808869
}
809870
}
810871

811-
private async Task AddNewBlockV3(IEngineRpcModule rpcModule, MergeTestBlockchain chain, int transactionCount = 0)
872+
private async Task<ExecutionPayloadV3> AddNewBlockV3(IEngineRpcModule rpcModule, MergeTestBlockchain chain, int transactionCount = 0)
812873
{
813874
Transaction[] txs = BuildTransactions(chain, chain.BlockTree.Head!.Hash!, TestItem.PrivateKeyA, TestItem.AddressB, (uint)transactionCount, 0, out _, out _, 0);
814875
chain.AddTransactions(txs);
@@ -842,6 +903,8 @@ private async Task AddNewBlockV3(IEngineRpcModule rpcModule, MergeTestBlockchain
842903

843904
ForkchoiceStateV1 newForkchoiceState = new(payload.ExecutionPayload.BlockHash, payload.ExecutionPayload.BlockHash, payload.ExecutionPayload.BlockHash);
844905
await rpcModule.engine_forkchoiceUpdatedV3(newForkchoiceState, null);
906+
907+
return payload.ExecutionPayload;
845908
}
846909

847910
private async Task<(IEngineRpcModule, string?, Transaction[], MergeTestBlockchain chain)> BuildAndGetPayloadV3Result(

src/Nethermind/Nethermind.Serialization.Rlp/HeaderDecoder.cs

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@
22
// SPDX-License-Identifier: LGPL-3.0-only
33

44
using System;
5-
using System.Threading;
65
using Nethermind.Core;
76
using Nethermind.Core.Crypto;
87
using Nethermind.Int256;

0 commit comments

Comments
 (0)