Skip to content

Commit

Permalink
add beacon pointer test
Browse files Browse the repository at this point in the history
  • Loading branch information
avalonche committed May 18, 2022
1 parent ec5c74e commit a15a721
Show file tree
Hide file tree
Showing 2 changed files with 125 additions and 44 deletions.
101 changes: 66 additions & 35 deletions src/Nethermind/Nethermind.Blockchain/BlockTree.cs
Original file line number Diff line number Diff line change
Expand Up @@ -348,32 +348,28 @@ private bool BodyExists(long blockNumber, bool findBeacon = false)
return false;
}

private void LoadBestKnown(bool findBeacon = false)
private void LoadBestKnown()
{
long lowestInserted =
findBeacon ? (LowestInsertedBeaconHeader?.Number ?? 0) : (LowestInsertedHeader?.Number ?? 0);
long left = (Head?.Number ?? 0) == 0
? Math.Max(_syncConfig.PivotNumberParsed, lowestInserted) - 1
? Math.Max(_syncConfig.PivotNumberParsed, LowestInsertedHeader?.Number ?? 0) - 1
: Head.Number;

long right = Math.Max(0, left) + BestKnownSearchLimit;

long bestKnownNumberFound =
BinarySearchBlockNumber(1, left, LevelExists, findBeacon: findBeacon) ?? 0;
BinarySearchBlockNumber(1, left, LevelExists) ?? 0;
long bestKnownNumberAlternative =
BinarySearchBlockNumber(left, right, LevelExists, findBeacon: findBeacon) ?? 0;
BinarySearchBlockNumber(left, right, LevelExists) ?? 0;

long bestSuggestedHeaderNumber =
BinarySearchBlockNumber(1, left, HeaderExists, findBeacon: findBeacon) ?? 0;
BinarySearchBlockNumber(1, left, HeaderExists) ?? 0;
long bestSuggestedHeaderNumberAlternative
= BinarySearchBlockNumber(left, right, HeaderExists, findBeacon: findBeacon) ?? 0;
= BinarySearchBlockNumber(left, right, HeaderExists) ?? 0;

long? beaconPivotNumber = _metadataDb.Get(MetadataDbKeys.BeaconSyncPivotNumber)?.AsRlpValueContext().DecodeLong();
long leftForBody = (findBeacon && beaconPivotNumber.HasValue) ? beaconPivotNumber.Value : left;
long bestSuggestedBodyNumber
= BinarySearchBlockNumber(1, leftForBody, BodyExists, findBeacon: findBeacon) ?? 0;
= BinarySearchBlockNumber(1, left, BodyExists) ?? 0;
long bestSuggestedBodyNumberAlternative
= BinarySearchBlockNumber(leftForBody, right, BodyExists, findBeacon: findBeacon) ?? 0;
= BinarySearchBlockNumber(left, right, BodyExists) ?? 0;

if (_logger.IsInfo)
_logger.Info("Numbers resolved, " +
Expand Down Expand Up @@ -406,32 +402,61 @@ long bestSuggestedBodyNumberAlternative
$"best body: {bestSuggestedBodyNumber}|");
}
}

if (findBeacon)
{
BestKnownBeaconNumber = Math.Max(bestKnownNumberFound, bestKnownNumberAlternative);
BestSuggestedBeaconHeader = FindHeader(bestSuggestedHeaderNumber, BlockTreeLookupOptions.TotalDifficultyNotNeeded);
BlockHeader? bestSuggestedBodyHeader = FindHeader(bestSuggestedBodyNumber, BlockTreeLookupOptions.TotalDifficultyNotNeeded);
BestSuggestedBeaconBody = bestSuggestedBodyHeader is null
? null
: FindBlock(bestSuggestedBodyHeader.Hash, BlockTreeLookupOptions.TotalDifficultyNotNeeded);
}
else
{
BestKnownNumber = Math.Max(bestKnownNumberFound, bestKnownNumberAlternative);
BestSuggestedHeader = FindHeader(bestSuggestedHeaderNumber, BlockTreeLookupOptions.None);
BlockHeader? bestSuggestedBodyHeader = FindHeader(bestSuggestedBodyNumber, BlockTreeLookupOptions.None);
BestSuggestedBody = bestSuggestedBodyHeader is null
? null
: FindBlock(bestSuggestedBodyHeader.Hash, BlockTreeLookupOptions.None);
}

BestKnownNumber = Math.Max(bestKnownNumberFound, bestKnownNumberAlternative);
BestSuggestedHeader = FindHeader(bestSuggestedHeaderNumber, BlockTreeLookupOptions.None);
BlockHeader? bestSuggestedBodyHeader = FindHeader(bestSuggestedBodyNumber, BlockTreeLookupOptions.None);
BestSuggestedBody = bestSuggestedBodyHeader is null
? null
: FindBlock(bestSuggestedBodyHeader.Hash, BlockTreeLookupOptions.None);
}

private void LoadBeaconBestKnown()
{
long left = Math.Max(Head?.Number ?? 0, (LowestInsertedBeaconHeader?.Number ?? 0) - 1);
long right = Math.Max(0, left) + BestKnownSearchLimit;

long bestKnownNumberFound = BinarySearchBlockNumber(left, right, LevelExists, findBeacon: true) ?? 0;
long bestBeaconHeaderNumber = BinarySearchBlockNumber(left, right, HeaderExists, findBeacon: true) ?? 0;

long? beaconPivotNumber = _metadataDb.Get(MetadataDbKeys.BeaconSyncPivotNumber)?.AsRlpValueContext().DecodeLong();
long bestBeaconBodyNumber = BinarySearchBlockNumber(
beaconPivotNumber.HasValue ? beaconPivotNumber.Value : left, right, BodyExists, findBeacon: true) ?? 0;

if (_logger.IsInfo)
_logger.Info("Finding beacon block best pointers");
LoadBestKnown(true);
_logger.Info("Beacon Numbers resolved, " +
$"level = {bestKnownNumberFound}, " +
$"header = {bestBeaconHeaderNumber}, " +
$"body = {bestBeaconBodyNumber}");

if (bestKnownNumberFound < 0 ||
bestBeaconHeaderNumber < 0 ||
bestBeaconBodyNumber < 0 ||
bestBeaconHeaderNumber < bestBeaconBodyNumber)
{
if (_logger.IsWarn)
_logger.Warn(
$"Detected corrupted block tree data ({bestBeaconHeaderNumber} < {bestBeaconBodyNumber}) (possibly due to an unexpected shutdown). Attempting to fix by moving head backwards. This may fail and you may need to resync the node.");
if (bestBeaconHeaderNumber < bestBeaconBodyNumber)
{
bestBeaconBodyNumber = bestBeaconHeaderNumber;
_tryToRecoverFromHeaderBelowBodyCorruption = true;
}
else
{
throw new InvalidDataException("Invalid initial block tree state loaded - " +
$"best known: {bestKnownNumberFound}|" +
$"best header: {bestBeaconHeaderNumber}|" +
$"best body: {bestBeaconBodyNumber}|");
}
}

BestKnownBeaconNumber = bestKnownNumberFound;
BestSuggestedBeaconHeader = FindHeader(bestBeaconHeaderNumber, BlockTreeLookupOptions.TotalDifficultyNotNeeded);
BlockHeader? bestBeaconBodyHeader = FindHeader(bestBeaconBodyNumber, BlockTreeLookupOptions.TotalDifficultyNotNeeded);
BestSuggestedBeaconBody = bestBeaconBodyHeader is null
? null
: FindBlock(bestBeaconBodyHeader.Hash, BlockTreeLookupOptions.TotalDifficultyNotNeeded);
}

private enum BinarySearchDirection
Expand Down Expand Up @@ -1582,7 +1607,10 @@ public bool IsKnownBlock(long number, Keccak blockHash)
}

ChainLevelInfo level = LoadLevel(number);
return level is not null && FindIndex(blockHash, level).HasValue;
if (level is null)
return false;
int? index = FindIndex(blockHash, level);
return index.HasValue && level.HasNonBeaconBlocks;
}

public bool IsKnownBeaconBlock(long number, Keccak blockHash)
Expand All @@ -1598,7 +1626,10 @@ public bool IsKnownBeaconBlock(long number, Keccak blockHash)
}

ChainLevelInfo level = LoadLevel(number);
return level is not null && FindIndex(blockHash, level).HasValue;
if (level is null)
return false;
int? index = FindIndex(blockHash, level);
return index.HasValue && level.HasBeaconBlocks;
}

private void UpdateDeletePointer(Keccak? hash)
Expand Down
68 changes: 59 additions & 9 deletions src/Nethermind/Nethermind.Merge.Plugin.Test/BlockTreeTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -20,10 +20,12 @@
using Nethermind.Blockchain.Synchronization;
using Nethermind.Core;
using Nethermind.Core.Test.Builders;
using Nethermind.Db;
using Nethermind.Db.Blooms;
using Nethermind.Int256;
using Nethermind.Logging;
using Nethermind.Merge.Plugin.Synchronization;
using Nethermind.Serialization.Rlp;
using Nethermind.Specs;
using NUnit.Framework;

Expand Down Expand Up @@ -198,10 +200,19 @@ private void OnNewBestSuggestedBlock(object? sender, BlockEventArgs e)

public ScenarioBuilder InsertBeaconPivot(long num)
{
Block? beaconBlock = SyncedTree!.FindBlock(num, BlockTreeLookupOptions.None);
AddBlockResult insertResult = NotSyncedTree!.Insert(beaconBlock!, true,
Block? beaconBlock = SyncedTree.FindBlock(num, BlockTreeLookupOptions.None);
AddBlockResult insertResult = NotSyncedTree.Insert(beaconBlock!, true,
BlockTreeInsertOptions.BeaconBlockInsert);
Assert.AreEqual(AddBlockResult.Added, insertResult);
NotSyncedTreeBuilder.MetadataDb.Set(MetadataDbKeys.LowestInsertedBeaconHeaderHash, Rlp.Encode(beaconBlock!.Hash).Bytes);
NotSyncedTreeBuilder.MetadataDb.Set(MetadataDbKeys.BeaconSyncPivotNumber, Rlp.Encode(beaconBlock.Number ).Bytes);
return this;
}

public ScenarioBuilder ClearBeaconPivot()
{
NotSyncedTreeBuilder.MetadataDb.Delete(MetadataDbKeys.BeaconSyncPivotNumber);

return this;
}

Expand Down Expand Up @@ -320,6 +331,22 @@ public ScenarioBuilder AssertLowestInsertedBeaconHeader(long expected)
Console.WriteLine("LowestInsertedBeaconHeader:"+NotSyncedTree!.LowestInsertedBeaconHeader!.Number);
return this;
}

public ScenarioBuilder AssertBestBeaconHeader(long expected)
{
Assert.IsNotNull(NotSyncedTree);
Assert.IsNotNull(NotSyncedTree.BestSuggestedBeaconHeader);
Assert.AreEqual(expected, NotSyncedTree.BestSuggestedBeaconHeader?.Number);
return this;
}

public ScenarioBuilder AssertBestBeaconBody(long expected)
{
Assert.IsNotNull(NotSyncedTree);
Assert.IsNotNull(NotSyncedTree.BestSuggestedBeaconBody);
Assert.AreEqual(expected, NotSyncedTree.BestSuggestedBeaconBody?.Number);
return this;
}

public ScenarioBuilder AssertChainLevel(int startNumber, int finalNumber)
{
Expand Down Expand Up @@ -369,6 +396,8 @@ public void Best_pointers_are_set_on_restart_with_gap()
.WithBlockTrees(10, 20)
.InsertBeaconPivot(14)
.Restart()
.AssertBestBeaconBody(14)
.AssertBestBeaconHeader(14)
.AssertBestKnownNumber(9)
.AssertBestSuggestedHeader(9)
.AssertBestSuggestedBody(9);
Expand All @@ -382,7 +411,12 @@ public void pointers_are_set_on_restart_during_header_sync()
.InsertBeaconPivot(7)
.InsertHeaders(6, 6)
.Restart()
.AssertLowestInsertedBeaconHeader(6);
.AssertBestBeaconBody(7)
.AssertBestBeaconHeader(7)
.AssertLowestInsertedBeaconHeader(6)
.AssertBestKnownNumber(4)
.AssertBestSuggestedHeader(4)
.AssertBestSuggestedBody(4);
}

[Test]
Expand All @@ -393,20 +427,28 @@ public void pointers_are_set_on_restart_after_header_sync_finished()
.InsertBeaconPivot(7)
.InsertHeaders(4, 6)
.Restart()
.AssertLowestInsertedBeaconHeader(4);
.AssertBestBeaconBody(7)
.AssertBestBeaconHeader(7)
.AssertLowestInsertedBeaconHeader(4)
.AssertBestKnownNumber(3)
.AssertBestSuggestedHeader(3)
.AssertBestSuggestedBody(3);
}

[Test]
public void pointers_are_set_on_restart_during_filling_block_gap()
{
BlockTreeTestScenario.ScenarioBuilder scenario = BlockTreeTestScenario.GoesLikeThis()
BlockTreeTestScenario.ScenarioBuilder scenario = BlockTreeTestScenario.GoesLikeThis()
.WithBlockTrees(4, 10)
.InsertBeaconPivot(7)
.InsertHeaders(4, 6)
.SuggestBlocks(4, 4)
.Restart()
.AssertBestSuggestedBody(4)
.AssertLowestInsertedBeaconHeader(4);
.AssertBestBeaconBody(7)
.AssertBestBeaconHeader(7)
.AssertLowestInsertedBeaconHeader(4)
.AssertBestSuggestedHeader(4)
.AssertBestSuggestedBody(4);
}

[Test]
Expand All @@ -416,9 +458,14 @@ public void pointers_are_set_on_restart_after_filling_block_gap_finished()
.WithBlockTrees(4, 10)
.InsertBeaconPivot(7)
.InsertHeaders(4, 6)
.SuggestBlocks(4, 6)
.SuggestBlocks(4, 7)
.ClearBeaconPivot()
.Restart()
.AssertBestSuggestedBody(6)
.AssertBestBeaconBody(0)
.AssertBestBeaconHeader(0)
.AssertLowestInsertedBeaconHeader(4)
.AssertBestSuggestedHeader(7)
.AssertBestSuggestedBody(7)
.AssertLowestInsertedBeaconHeader(4);
}

Expand All @@ -431,6 +478,9 @@ public void Best_pointers_should_not_move_if_sync_is_not_finished()
.InsertHeaders(5, 6)
.InsertBeaconBlocks(7, 9)
.Restart()
.AssertBestBeaconBody(9)
.AssertBestBeaconHeader(9)
.AssertLowestInsertedBeaconHeader(5)
.AssertBestKnownNumber(3)
.AssertBestSuggestedHeader(3)
.AssertBestSuggestedBody(3);
Expand Down

0 comments on commit a15a721

Please sign in to comment.