Skip to content
Merged
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
39 changes: 39 additions & 0 deletions src/Nethermind/Nethermind.Blockchain.Test/BlockTreeTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2626,6 +2626,45 @@ public void UpdateMainChain_WhenBeaconSyncAndFcuCycleRepeatedTwice_ClearsStaleMa
blockTree.IsMainChain(sibling1.Header).Should().BeFalse("sibling1 must be orphaned");
}

[Test, MaxTime(Timeout.MaxTestTime)]
public void UpdateMainChain_WhenForwardProcessingWithBeaconSyncedDescendants_DoesNotClearMarkers()
{
(BlockTree blockTree, Block genesis) = BuildBlockTreeWithGenesis(forceUpdateHead: true);

Block[] chain = BuildAndSuggestChain(blockTree, genesis, 4);
blockTree.UpdateMainChain(new[] { chain[0] }, wereProcessed: true, forceUpdateHeadBlock: true);
for (int i = 1; i < chain.Length; i++)
blockTree.UpdateMainChain(new[] { chain[i] }, wereProcessed: false);

// Forward processing H=2 (forceUpdateHeadBlock: false) must not clear H=3, H=4
blockTree.UpdateMainChain(new[] { chain[1] }, wereProcessed: true, forceUpdateHeadBlock: false);

blockTree.IsMainChain(chain[2].Header).Should().BeTrue("H=3 marker must survive");
blockTree.IsMainChain(chain[3].Header).Should().BeTrue("H=4 marker must survive");
}

[Test, MaxTime(Timeout.MaxTestTime)]
public void UpdateMainChain_WhenFcuForwardReorgToLongerChain_ClearsStaleMarkersAboveNewHead()
{
(BlockTree blockTree, Block genesis) = BuildBlockTreeWithGenesis(forceUpdateHead: true);

Block[] chainA = BuildAndSuggestChain(blockTree, genesis, 4);
blockTree.UpdateMainChain(new[] { chainA[0] }, wereProcessed: true, forceUpdateHeadBlock: true);
for (int i = 1; i < chainA.Length; i++)
blockTree.UpdateMainChain(new[] { chainA[i] }, wereProcessed: false);

// FCU to chain B at H=3 (forceUpdateHeadBlock: true) must clear A4
Block b1 = Build.A.Block.WithNumber(1).WithParent(genesis).WithExtraData([0xBB]).TestObject;
Block b2 = Build.A.Block.WithNumber(2).WithParent(b1).WithExtraData([0xBB]).TestObject;
Block b3 = Build.A.Block.WithNumber(3).WithParent(b2).WithExtraData([0xBB]).TestObject;
blockTree.SuggestBlock(b1);
blockTree.SuggestBlock(b2);
blockTree.SuggestBlock(b3);
blockTree.UpdateMainChain(new[] { b1, b2, b3 }, wereProcessed: true, forceUpdateHeadBlock: true);

blockTree.IsMainChain(chainA[3].Header).Should().BeFalse("A4 stale marker must be cleared");
}

[Test, MaxTime(Timeout.MaxTestTime)]
public void FindBlock_WhenBlockOrphanedAfterReorgInPoS_ReturnsNull()
{
Expand Down
7 changes: 5 additions & 2 deletions src/Nethermind/Nethermind.Blockchain/BlockTree.cs
Original file line number Diff line number Diff line change
Expand Up @@ -1025,8 +1025,11 @@ public void UpdateMainChain(IReadOnlyList<Block> blocks, bool wereProcessed, boo
}

// Clear stale canonical markers above the new head left by beacon sync.
// Covers both same-height FCU (previousHeadNumber <= lastNumber) and ePBS FCU to ancestor.
ClearStaleMarkersAbove(Math.Max(previousHeadNumber, lastNumber), batch);
// Only needed on FCU reorgs (forceUpdateHeadBlock == true). During forward sync
// (BlockDownloader) and forward processing (BlockchainProcessor), the markers above
// are either not yet set or belong to the same chain and must not be cleared.
if (forceUpdateHeadBlock)
ClearStaleMarkersAbove(Math.Max(previousHeadNumber, lastNumber), batch);

for (int i = 0; i < blocks.Count; i++)
{
Expand Down
Loading