Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Verkle sync devnet 6 #54

Open
wants to merge 68 commits into
base: verkle/sync
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
68 commits
Select commit Hold shift + click to select a range
a1d6755
fix witness gas
tanishqjasoria May 9, 2024
e9e7402
make other fields visible
tanishqjasoria May 9, 2024
4ba3488
fix gas consumption
tanishqjasoria May 9, 2024
ebf6029
storage saving when origional value is zero
tanishqjasoria May 9, 2024
c77618c
enable verkle sync
tanishqjasoria May 9, 2024
15dc322
no need to use journal set here
tanishqjasoria May 13, 2024
63f2e80
remove unecessary tests
tanishqjasoria May 10, 2024
f44d435
fix issues
tanishqjasoria May 17, 2024
de9154c
logs
tanishqjasoria May 17, 2024
75ec75e
Add test
tanishqjasoria May 17, 2024
412eed9
TEMP - disable stateless verification during sync
tanishqjasoria May 17, 2024
aa6d9fc
Add node for testingA
tanishqjasoria May 17, 2024
c48bda4
add state check
tanishqjasoria May 17, 2024
ed6b5ed
rename
tanishqjasoria May 23, 2024
68164e2
Add state root to execution witness
tanishqjasoria May 23, 2024
3050be7
fix create gas
tanishqjasoria May 23, 2024
15a3c54
add another fix
tanishqjasoria May 23, 2024
b3383a8
add new function and commit while inserting in the stateless manner
tanishqjasoria May 28, 2024
384629b
refac
tanishqjasoria May 28, 2024
22fc2d0
add the parent state root to the execution witness when new payload
tanishqjasoria May 28, 2024
2ee9ab5
Add some comments
tanishqjasoria May 29, 2024
69abc8b
Add flag for statless processing
tanishqjasoria May 29, 2024
902db97
force processing
tanishqjasoria May 29, 2024
0beba93
enable all things from flags
tanishqjasoria May 29, 2024
9ba2fc8
fix benchmarks
tanishqjasoria May 31, 2024
9a0543a
small changes
tanishqjasoria May 31, 2024
c5f254a
fix stateless insertion
tanishqjasoria May 31, 2024
6c00f86
add leaf table to exec witness - temp - poc
tanishqjasoria May 31, 2024
05ec07b
temp solution
tanishqjasoria May 31, 2024
b3f39f9
enable stateless from config
tanishqjasoria May 31, 2024
4269118
add todo
tanishqjasoria May 31, 2024
126715e
Add another overload
tanishqjasoria Jun 3, 2024
75341dc
stupid comments
tanishqjasoria Jun 6, 2024
00190bf
add another condition
tanishqjasoria Jun 13, 2024
f3ce0d3
another fix
tanishqjasoria Jun 13, 2024
23dd826
Add another thing
tanishqjasoria Jun 13, 2024
dcfd383
serve logs
tanishqjasoria Jun 13, 2024
d12f1a5
update
tanishqjasoria Jun 13, 2024
e14791c
make function virtual
tanishqjasoria Jun 13, 2024
a063689
add checks
tanishqjasoria Jun 14, 2024
cea62c5
updates
tanishqjasoria Jun 14, 2024
616c811
add checks
tanishqjasoria Jun 14, 2024
d5af026
Add tests
tanishqjasoria Jun 14, 2024
bf6b981
fix things
tanishqjasoria Jun 14, 2024
4fd7f87
fix things
tanishqjasoria Jun 14, 2024
144e26d
add try log
tanishqjasoria Jun 14, 2024
aa07ec3
fix
tanishqjasoria Jun 14, 2024
67751da
logs
tanishqjasoria Jun 18, 2024
c8ac195
fix stupid mistakes
tanishqjasoria Jun 18, 2024
065d778
fix sync init
tanishqjasoria Jun 19, 2024
6daf422
update server
tanishqjasoria Jun 19, 2024
acef62f
Add another test
tanishqjasoria Jun 19, 2024
59ef4d5
debug
tanishqjasoria Jun 19, 2024
40d587c
remove stupid comments
tanishqjasoria Jun 19, 2024
e40d3ba
update config
tanishqjasoria Jun 24, 2024
c1d0422
Add temp event to block tree
tanishqjasoria Jun 25, 2024
3d4b1be
add more nodes
tanishqjasoria Jun 25, 2024
6d2cce4
use new events
tanishqjasoria Jun 25, 2024
0202600
generate events on stateless block procesing
tanishqjasoria Jun 25, 2024
31e2799
remove redundant flags
tanishqjasoria Jun 25, 2024
c0cbaa2
refactor
tanishqjasoria Jun 25, 2024
75ad082
quick fix
tanishqjasoria Jul 2, 2024
f2b65cf
add more run configuration
tanishqjasoria Jul 2, 2024
c217ae9
update pivot to use stateless header
tanishqjasoria Jul 2, 2024
3ed5dcd
update to fix the healing
tanishqjasoria Jul 2, 2024
ca5b279
fix stateless processing
tanishqjasoria Jul 2, 2024
71acee5
merge statelss block processor
tanishqjasoria Jul 2, 2024
aea7c78
final fix the sync - things work here
tanishqjasoria Jul 2, 2024
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
2 changes: 1 addition & 1 deletion src/Nethermind/Directory.Packages.props
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@
<PackageVersion Include="Nethermind.DotNetty.Transport" Version="1.0.1" />
<PackageVersion Include="Nethermind.Gmp" Version="1.0.1" />
<PackageVersion Include="Nethermind.Numerics.Int256" Version="1.2.0" />
<PackageVersion Include="Nethermind.Verkle" Version="0.2.3-alpha"/>
<PackageVersion Include="Nethermind.Verkle" Version="0.2.5-alpha" />
<PackageVersion Include="Nito.Collections.Deque" Version="1.2.1" />
<PackageVersion Include="NLog" Version="5.2.8" />
<PackageVersion Include="NLog.Targets.Seq" Version="3.1.0" />
Expand Down
1 change: 0 additions & 1 deletion src/Nethermind/Nethermind.Api/IApiWithNetwork.cs
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,5 @@ public interface IApiWithNetwork : IApiWithBlockchain
ISyncServer? SyncServer { get; set; }
IWebSocketsManager WebSocketsManager { get; set; }
ISubscriptionFactory? SubscriptionFactory { get; set; }
VerkleSyncServer? VerkleSyncServer { get; set; }
}
}
1 change: 0 additions & 1 deletion src/Nethermind/Nethermind.Api/NethermindApi.cs
Original file line number Diff line number Diff line change
Expand Up @@ -233,7 +233,6 @@ public ISealEngine SealEngine
public CompositePruningTrigger PruningTrigger { get; } = new();
public IProcessExitSource? ProcessExit { get; set; }
public CompositeTxGossipPolicy TxGossipPolicy { get; } = new();
public VerkleSyncServer? VerkleSyncServer { get; set; }
public IVerkleTreeStore? VerkleTreeStore { get; set; }
public IReadOnlyVerkleTreeStore? ReadOnlyVerkleTrieStore { get; set; }
public VerkleArchiveStore? VerkleArchiveStore { get; set; }
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -293,7 +293,7 @@ public void InsertAndCommitRepeatedlyTimes()
{
if (slot == null)
{
worldState.GetAccount(address);
worldState.TryGetAccount(address, out _);
}
else
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -117,6 +117,7 @@ public Block[] Process(Hash256 newBranchStateRoot, List<Block> suggestedBlocks,
}
}

public bool CanProcessStatelessBlock { get; } = false;
public event EventHandler<BlocksProcessingEventArgs>? BlocksProcessing;

public event EventHandler<BlockProcessedEventArgs>? BlockProcessed;
Expand Down
19 changes: 17 additions & 2 deletions src/Nethermind/Nethermind.Blockchain/BlockTree.cs
Original file line number Diff line number Diff line change
Expand Up @@ -59,8 +59,15 @@ public partial class BlockTree : IBlockTree
public Block? Head { get; private set; }

public BlockHeader? BestSuggestedHeader { get; private set; }

public Block? BestSuggestedBody { get; private set; }

// for stateless chain
public BlockHeader? BestProcessedStatelessHeader { get; private set; }
public Block? BestProcessedStatelessBlock { get; private set; }

public BlockHeader? BestSuggestedStatelessHeader { get; private set; }
public Block? BestSuggestedStatelessBlock { get; private set; }

public BlockHeader? LowestInsertedHeader { get; private set; }
public BlockHeader? BestSuggestedBeaconHeader { get; private set; }

Expand Down Expand Up @@ -1483,16 +1490,24 @@ void SetTotalDifficultyDeep(BlockHeader current)
public event EventHandler<BlockReplacementEventArgs>? BlockAddedToMain;

public event EventHandler<OnUpdateMainChainArgs>? OnUpdateMainChain;
public event EventHandler<BlockEventArgs>? OnUpdateStatelessChain;

public event EventHandler<BlockEventArgs>? NewBestSuggestedBlock;

public event EventHandler<BlockEventArgs>? NewSuggestedBlock;

public event EventHandler<BlockEventArgs>? NewHeadBlock;

public void UpdateStatelessBlock(Block block)
{
BestProcessedStatelessHeader = block.Header;
BestProcessedStatelessBlock = block;
OnUpdateStatelessChain?.Invoke(this, new BlockEventArgs(block));
}

/// <summary>
/// Can delete a slice of the chain (usually invoked when the chain is corrupted in the DB).
/// This will only allow to delete a slice starting somewhere before the head of the chain
/// This will only allow deleting a slice starting somewhere before the head of the chain
/// and ending somewhere after the head (in case there are some hanging levels later).
/// </summary>
/// <param name="startNumber">Start level of the slice to delete</param>
Expand Down
5 changes: 5 additions & 0 deletions src/Nethermind/Nethermind.Blockchain/IBlockTree.cs
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ public interface IBlockTree : IBlockFinder
/// Best header that has been suggested for processing
/// </summary>
BlockHeader? BestSuggestedHeader { get; }
BlockHeader? BestProcessedStatelessHeader { get; }

/// <summary>
/// Best block that has been suggested for processing
Expand Down Expand Up @@ -178,6 +179,10 @@ AddBlockResult Insert(Block block, BlockTreeInsertBlockOptions insertBlockOption
/// </summary>
event EventHandler<OnUpdateMainChainArgs> OnUpdateMainChain;

event EventHandler<BlockEventArgs> OnUpdateStatelessChain;

public void UpdateStatelessBlock(Block block);

int DeleteChainSlice(in long startNumber, long? endNumber = null, bool force = false);

bool IsBetterThanHead(BlockHeader? header);
Expand Down
9 changes: 9 additions & 0 deletions src/Nethermind/Nethermind.Blockchain/ReadOnlyBlockTree.cs
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ public ReadOnlyBlockTree(IBlockTree wrapped)
public BlockHeader Genesis => _wrapped.Genesis;
public BlockHeader BestSuggestedHeader => _wrapped.BestSuggestedHeader;
public BlockHeader BestSuggestedBeaconHeader => _wrapped.BestSuggestedBeaconHeader;
public BlockHeader BestProcessedStatelessHeader => _wrapped.BestProcessedStatelessHeader;
public BlockHeader LowestInsertedHeader => _wrapped.LowestInsertedHeader;

public long? LowestInsertedBodyNumber
Expand Down Expand Up @@ -152,6 +153,14 @@ public event EventHandler<OnUpdateMainChainArgs>? OnUpdateMainChain
remove { }
}

public event EventHandler<BlockEventArgs>? OnUpdateStatelessChain
{
add { }
remove { }
}

public void UpdateStatelessBlock(Block block) => _wrapped.UpdateStatelessBlock(block);

public int DeleteChainSlice(in long startNumber, long? endNumber = null, bool force = false)
{
var bestKnownNumber = BestKnownNumber;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -142,7 +142,7 @@ protected TxAction ProcessTransaction(

public IBlockProcessor.IBlockTransactionsExecutor WithNewStateProvider(IWorldState worldState)
{
return new BlockProductionTransactionsExecutor(_transactionProcessor, worldState,
return new BlockProductionTransactionsExecutor(_transactionProcessor.WithNewStateProvider(worldState), worldState,
_blockProductionTransactionPicker, _logManager);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@ private void ProcessTransaction(in BlockExecutionContext blkCtx, Transaction cur

public IBlockProcessor.IBlockTransactionsExecutor WithNewStateProvider(IWorldState worldState)
{
return new BlockValidationTransactionsExecutor(_transactionProcessor, worldState);
return new BlockValidationTransactionsExecutor(_transactionProcessor.WithNewStateProvider(worldState), worldState);
}

[DoesNotReturn]
Expand Down
65 changes: 53 additions & 12 deletions src/Nethermind/Nethermind.Consensus/Processing/BlockProcessor.cs
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
using Nethermind.Core.Specs;
using Nethermind.Core.Verkle;
using Nethermind.Crypto;
using Nethermind.Db;
using Nethermind.Evm;
using Nethermind.Evm.Tracing;
using Nethermind.Evm.Tracing.GethStyle;
Expand All @@ -31,6 +32,7 @@
using Nethermind.Specs.Forks;
using Nethermind.State;
using Nethermind.Verkle.Curve;
using Nethermind.Verkle.Tree.TreeStore;
using Nethermind.Verkle.Tree.Utils;
using Metrics = Nethermind.Blockchain.Metrics;

Expand All @@ -53,6 +55,9 @@ public partial class BlockProcessor : IBlockProcessor
private readonly IBlockTree _blockTree;
private const int MaxUncommittedBlocks = 64;

public bool CanProcessStatelessBlock { get; protected init; }
private readonly VerkleWorldState _statelessWorldState;

// these two are test flags that can be used to test witness generation and verification
public bool ShouldVerifyIncomingWitness { get; set; } = false;
public bool ShouldGenerateWitness { get; set; } = true;
Expand All @@ -74,7 +79,8 @@ public BlockProcessor(
IBlockTree? blockTree,
ILogManager? logManager,
IWithdrawalProcessor? withdrawalProcessor = null,
IReceiptsRootCalculator? receiptsRootCalculator = null)
IReceiptsRootCalculator? receiptsRootCalculator = null,
bool canProcessStatelessBlocks = false)
{
_logger = logManager?.GetClassLogger() ?? throw new ArgumentNullException(nameof(logManager));
_specProvider = specProvider ?? throw new ArgumentNullException(nameof(specProvider));
Expand All @@ -90,6 +96,13 @@ public BlockProcessor(
_blockHashInStateHandlerHandler = new BlockHashInStateHandler();
_blockTree = blockTree ?? throw new ArgumentNullException(nameof(blockTree));

CanProcessStatelessBlock = canProcessStatelessBlocks;
if (CanProcessStatelessBlock)
{
NullVerkleTreeStore stateStore = new();
VerkleStateTree? tree = new(stateStore, logManager);
_statelessWorldState = new VerkleWorldState(tree, new MemDb(), logManager);
}
ExecutionTracer = new BlockExecutionTracer(true, true);
}

Expand All @@ -104,7 +117,8 @@ public event EventHandler<TxProcessedEventArgs> TransactionProcessed
// TODO: move to branch processor
public Block[] Process(Hash256 newBranchStateRoot, List<Block> suggestedBlocks, ProcessingOptions options, IBlockTracer blockTracer)
{
if (suggestedBlocks.Count == 0) return Array.Empty<Block>();
bool shouldProcessStateless = options.ContainsFlag(ProcessingOptions.StatelessProcessing);
if (suggestedBlocks.Count == 0) return [];

TxHashCalculator.CalculateInBackground(suggestedBlocks);
BlocksProcessing?.Invoke(this, new BlocksProcessingEventArgs(suggestedBlocks));
Expand All @@ -113,11 +127,11 @@ public Block[] Process(Hash256 newBranchStateRoot, List<Block> suggestedBlocks,
In case of invalid blocks on the new branch we will discard the entire branch and come back to
the previous head state.*/
Hash256 previousBranchStateRoot = CreateCheckpoint();
InitBranch(newBranchStateRoot);
InitBranch(newBranchStateRoot, shouldProcessStateless);

bool notReadOnly = !options.ContainsFlag(ProcessingOptions.ReadOnlyChain);
int blocksCount = suggestedBlocks.Count;
Block[] processedBlocks = new Block[blocksCount];
var processedBlocks = new Block[blocksCount];
using IDisposable tracker = _witnessCollector.TrackOnThisThread();
try
{
Expand All @@ -133,14 +147,14 @@ the previous head state.*/
processedBlocks[i] = processedBlock;

// be cautious here as AuRa depends on processing
PreCommitBlock(newBranchStateRoot, suggestedBlocks[i].Number);
if(!options.ContainsFlag(ProcessingOptions.StatelessProcessing)) PreCommitBlock(newBranchStateRoot, suggestedBlocks[i].Number);
if (notReadOnly)
{
_witnessCollector.Persist(processedBlock.Hash!);
BlockProcessed?.Invoke(this, new BlockProcessedEventArgs(processedBlock, receipts));
}

// CommitBranch in parts if we have long running branch
// CommitBranch in parts if we have long-running branch
bool isFirstInBatch = i == 0;
bool isLastInBatch = i == blocksCount - 1;
bool isNotAtTheEdge = !isFirstInBatch && !isLastInBatch;
Expand All @@ -150,7 +164,7 @@ the previous head state.*/
if (_logger.IsInfo) _logger.Info($"Commit part of a long blocks branch {i}/{blocksCount}");
previousBranchStateRoot = CreateCheckpoint();
Hash256? newStateRoot = suggestedBlocks[i].StateRoot;
InitBranch(newStateRoot, false);
InitBranch(newStateRoot, shouldProcessStateless, false);
}
}

Expand All @@ -173,8 +187,9 @@ the previous head state.*/
public event EventHandler<BlocksProcessingEventArgs>? BlocksProcessing;

// TODO: move to branch processor
protected virtual void InitBranch(Hash256 branchStateRoot, bool incrementReorgMetric = true)
protected virtual void InitBranch(Hash256 branchStateRoot, bool processStateless, bool incrementReorgMetric = true)
{
if (processStateless) return;
/* Please note that we do not reset the state if branch state root is null.
That said, I do not remember in what cases we receive null here.*/
if (branchStateRoot is not null && _stateProvider.StateRoot != branchStateRoot)
Expand Down Expand Up @@ -278,9 +293,27 @@ private void VerifyIncomingWitness(Block block)
}
}

protected virtual (IBlockProcessor.IBlockTransactionsExecutor, IWorldState) GetOrCreateExecutorAndState(Block block)
protected virtual (IBlockProcessor.IBlockTransactionsExecutor, IWorldState) GetOrCreateExecutorAndState(Block block, bool processStateless)
{
return (_blockTransactionsExecutor, _stateProvider);
IBlockProcessor.IBlockTransactionsExecutor? blockTransactionsExecutor;
IWorldState worldState;

if (block.IsGenesis || !processStateless)
{
blockTransactionsExecutor = _blockTransactionsExecutor;
worldState = _stateProvider;
}
else
{
_logger.Info($"Getting stateless providers");
Banderwagon stateRoot = Banderwagon.FromBytes(block.ExecutionWitness!.StateRoot!.Bytes.ToArray())!.Value;
_statelessWorldState.Reset();
_statelessWorldState.InsertExecutionWitness(block.ExecutionWitness!, stateRoot);
worldState = _statelessWorldState;
blockTransactionsExecutor = _blockTransactionsExecutor.WithNewStateProvider(worldState);
}

return (blockTransactionsExecutor, worldState);
}

// TODO: block processor pipeline
Expand All @@ -289,9 +322,8 @@ protected virtual TxReceipt[] ProcessBlock(
IBlockTracer blockTracer,
ProcessingOptions options)
{

(IBlockProcessor.IBlockTransactionsExecutor? blockTransactionsExecutor, IWorldState worldState) =
GetOrCreateExecutorAndState(block);
GetOrCreateExecutorAndState(block, options.ContainsFlag(ProcessingOptions.StatelessProcessing));

IReleaseSpec spec = _specProvider.GetSpec(block.Header);

Expand Down Expand Up @@ -355,6 +387,15 @@ protected virtual TxReceipt[] ProcessBlock(
}
else
{
// we dont store the execution witness on disk so when we run blocks after restart, this fails
if (!block.IsGenesis && block.Body.ExecutionWitness is not null)
{
var verkleWorldState = worldState as VerkleWorldState;
ExecutionWitness? witness = block.Body.ExecutionWitness;
verkleWorldState?.UpdateWithPostStateValues(witness);
block.Body.ExecutionWitness = witness;
}

worldState.Commit(spec);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -407,13 +407,17 @@ private void FireProcessingQueueEmpty()
if (_logger.IsDebug) _logger.Debug($"Skipped processing of {suggestedBlock.ToString(Block.Format.FullHashAndNumber)}, last processed is null: {true}, processedBlocks.Length: {processedBlocks.Length}");
}

bool updateHead = !options.ContainsFlag(ProcessingOptions.DoNotUpdateHead);
if (updateHead)
bool updateHead = processingBranch.Blocks.Count != 0 &&
!options.ContainsFlag(ProcessingOptions.DoNotUpdateHead);
if (updateHead) _blockTree.UpdateMainChain(processingBranch.Blocks, true);

if (options.ContainsFlag(ProcessingOptions.StatelessProcessing))
{
if (_logger.IsTrace) _logger.Trace($"Updating main chain: {lastProcessed}, blocks count: {processedBlocks.Length}");
_blockTree.UpdateMainChain(processingBranch.Blocks, true);
foreach (Block? block in processedBlocks)
{
_blockTree.UpdateStatelessBlock(block);
}
}

bool readonlyChain = options.ContainsFlag(ProcessingOptions.ReadOnlyChain);
long blockProcessingTimeInMs = _stopwatch.ElapsedMilliseconds;
if (!readonlyChain)
Expand Down Expand Up @@ -608,7 +612,7 @@ private void PrepareBlocksToProcess(Block suggestedBlock, ProcessingOptions opti
private ProcessingBranch PrepareProcessingBranch(Block suggestedBlock, ProcessingOptions options)
{
BlockHeader branchingPoint = null;
List<Block> blocksToBeAddedToMain = new();
List<Block> blocksToBeAddedToMain = [];

bool branchingCondition;
bool suggestedBlockIsPostMerge = suggestedBlock.IsPostMerge;
Expand Down Expand Up @@ -730,7 +734,7 @@ private ProcessingBranch PrepareProcessingBranch(Block suggestedBlock, Processin
private bool RunSimpleChecksAheadOfProcessing(Block suggestedBlock, ProcessingOptions options)
{
/* a bit hacky way to get the invalid branch out of the processing loop */
if (suggestedBlock.Number != 0 &&
if (!options.ContainsFlag(ProcessingOptions.StatelessProcessing) && suggestedBlock.Number != 0 &&
!_blockTree.IsKnownBlock(suggestedBlock.Number - 1, suggestedBlock.ParentHash))
{
if (_logger.IsDebug)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ Block[] Process(
ProcessingOptions processingOptions,
IBlockTracer blockTracer);

public bool CanProcessStatelessBlock => false;
public bool CanProcessStatelessBlock { get; }

/// <summary>
/// Fired when a branch is being processed.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@ private NullBlockProcessor() { }

public static IBlockProcessor Instance { get; } = new NullBlockProcessor();

public bool CanProcessStatelessBlock { get; } = false;

public Block[] Process(Hash256 newBranchStateRoot, List<Block> suggestedBlocks, ProcessingOptions processingOptions, IBlockTracer blockTracer)
{
return suggestedBlocks.ToArray();
Expand Down
Loading