forked from NethermindEth/nethermind
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathBlockTree.AcceptVisitor.cs
More file actions
141 lines (122 loc) · 5.86 KB
/
BlockTree.AcceptVisitor.cs
File metadata and controls
141 lines (122 loc) · 5.86 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
// SPDX-FileCopyrightText: 2022 Demerzel Solutions Limited
// SPDX-License-Identifier: LGPL-3.0-only
using System.Threading;
using System.Threading.Tasks;
using Nethermind.Blockchain.Visitors;
using Nethermind.Core;
using Nethermind.Core.Crypto;
namespace Nethermind.Blockchain
{
public partial class BlockTree
{
public async Task Accept(IBlockTreeVisitor visitor, CancellationToken cancellationToken)
{
if (visitor.PreventsAcceptingNewBlocks)
{
BlockAcceptingNewBlocks();
}
try
{
long levelNumber = visitor.StartLevelInclusive;
long blocksToVisit = visitor.EndLevelExclusive - visitor.StartLevelInclusive;
for (long i = 0; i < blocksToVisit; i++)
{
if (cancellationToken.IsCancellationRequested)
{
break;
}
ChainLevelInfo level = LoadLevel(levelNumber);
LevelVisitOutcome visitOutcome = await visitor.VisitLevelStart(level, levelNumber, cancellationToken);
if ((visitOutcome & LevelVisitOutcome.DeleteLevel) == LevelVisitOutcome.DeleteLevel)
{
_chainLevelInfoRepository.Delete(levelNumber);
level = null;
}
if ((visitOutcome & LevelVisitOutcome.StopVisiting) == LevelVisitOutcome.StopVisiting)
{
break;
}
int numberOfBlocksAtThisLevel = level?.BlockInfos.Length ?? 0;
for (int blockIndex = 0; blockIndex < numberOfBlocksAtThisLevel; blockIndex++)
{
// if we delete blocks during the process then the number of blocks at this level will be falling and we need to adjust the index
Hash256 hash = level!.BlockInfos[blockIndex - (numberOfBlocksAtThisLevel - level.BlockInfos.Length)].BlockHash;
Block block = FindBlock(hash, BlockTreeLookupOptions.None);
if (block is null)
{
BlockHeader header = FindHeader(hash, BlockTreeLookupOptions.None);
if (header is null)
{
if (await VisitMissing(visitor, hash, cancellationToken)) break;
}
else
{
if (await VisitHeader(visitor, header, cancellationToken)) break;
}
}
else
{
if (visitor.CalculateTotalDifficultyIfMissing && (block.TotalDifficulty is null || block.TotalDifficulty == 0))
{
if (Logger.IsTrace) Logger.Trace($"Setting TD for block {block.Number}. Old TD: {block.TotalDifficulty}.");
SetTotalDifficulty(block.Header);
if (Logger.IsTrace) Logger.Trace($"Setting TD for block {block.Number}. New TD: {block.TotalDifficulty}.");
}
if (await VisitBlock(visitor, block, cancellationToken)) break;
}
}
visitOutcome = await visitor.VisitLevelEnd(level, levelNumber, cancellationToken);
if ((visitOutcome & LevelVisitOutcome.DeleteLevel) == LevelVisitOutcome.DeleteLevel)
{
_chainLevelInfoRepository.Delete(levelNumber);
}
levelNumber++;
}
RecalculateTreeLevels();
string resultWord = cancellationToken.IsCancellationRequested ? "Canceled" : "Completed";
if (Logger.IsDebug) Logger.Debug($"{resultWord} visiting blocks in DB at level {levelNumber} - best known {BestKnownNumber}");
}
finally
{
if (visitor.PreventsAcceptingNewBlocks)
{
ReleaseAcceptingNewBlocks();
}
}
}
private static async Task<bool> VisitMissing(IBlockTreeVisitor visitor, Hash256 hash, CancellationToken cancellationToken)
{
bool shouldContinue = await visitor.VisitMissing(hash, cancellationToken);
if (!shouldContinue)
{
return true;
}
return false;
}
private static async Task<bool> VisitHeader(IBlockTreeVisitor visitor, BlockHeader header, CancellationToken cancellationToken)
{
HeaderVisitOutcome outcome = await visitor.VisitHeader(header, cancellationToken);
if (outcome == HeaderVisitOutcome.StopVisiting)
{
return true;
}
return false;
}
private async Task<bool> VisitBlock(IBlockTreeVisitor visitor, Block block, CancellationToken cancellationToken)
{
BlockVisitOutcome blockVisitOutcome = await visitor.VisitBlock(block, cancellationToken);
if ((blockVisitOutcome & BlockVisitOutcome.Suggest) == BlockVisitOutcome.Suggest)
{
// remnant after previous approach - we want to skip standard suggest processing and just invoke processor
BestSuggestedHeader = block.Header;
BestSuggestedBody = block;
NewBestSuggestedBlock?.Invoke(this, new BlockEventArgs(block));
}
if ((blockVisitOutcome & BlockVisitOutcome.StopVisiting) == BlockVisitOutcome.StopVisiting)
{
return true;
}
return false;
}
}
}