diff --git a/src/Nethermind/Nethermind.Consensus.AuRa/Validators/ContractBasedValidator.cs b/src/Nethermind/Nethermind.Consensus.AuRa/Validators/ContractBasedValidator.cs
index d4b2f9f057e..297996c5e81 100644
--- a/src/Nethermind/Nethermind.Consensus.AuRa/Validators/ContractBasedValidator.cs
+++ b/src/Nethermind/Nethermind.Consensus.AuRa/Validators/ContractBasedValidator.cs
@@ -1,21 +1,20 @@
// Copyright (c) 2021 Demerzel Solutions Limited
// This file is part of the Nethermind library.
-//
+//
// The Nethermind library is free software: you can redistribute it and/or modify
// it under the terms of the GNU Lesser General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
-//
+//
// The Nethermind library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Lesser General Public License for more details.
-//
+//
// You should have received a copy of the GNU Lesser General Public License
// along with the Nethermind. If not, see .
using System;
-using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using Nethermind.Abi;
@@ -24,15 +23,9 @@
using Nethermind.Blockchain.Receipts;
using Nethermind.Consensus.AuRa.Contracts;
using Nethermind.Consensus.Processing;
-using Nethermind.Consensus.Transactions;
using Nethermind.Core;
using Nethermind.Core.Crypto;
-using Nethermind.Evm;
-using Nethermind.Evm.Tracing;
using Nethermind.Logging;
-using Nethermind.Specs.ChainSpecStyle;
-using Nethermind.State;
-using Nethermind.Db.Blooms;
namespace Nethermind.Consensus.AuRa.Validators
{
@@ -47,7 +40,6 @@ public partial class ContractBasedValidator : AuRaValidatorBase, IDisposable
private readonly IReceiptFinder _receiptFinder;
internal IValidatorContract ValidatorContract { get; }
- private PendingValidators CurrentPendingValidators => _currentPendingValidators;
public ContractBasedValidator(
IValidatorContract validatorContract,
@@ -67,7 +59,7 @@ public ContractBasedValidator(
_posdaoTransition = posdaoTransition;
_logger = logManager?.GetClassLogger() ?? throw new ArgumentNullException(nameof(logManager));
ValidatorContract = validatorContract ?? throw new ArgumentNullException(nameof(validatorContract));
- SetPendingValidators(LoadPendingValidators());
+ _currentPendingValidators = ValidatorStore.PendingValidators;
SetFinalizationManager(finalizationManager, parentHeader ?? BlockTree.Head?.Header);
}
@@ -99,74 +91,66 @@ public override void OnBlockProcessingStart(Block block, ProcessingOptions optio
return;
}
- var isProducingBlock = options.ContainsFlag(ProcessingOptions.ProducingBlock);
- var isProcessingBlock = !isProducingBlock;
- var isInitBlock = InitBlockNumber == block.Number;
- var notConsecutiveBlock = block.Number - 1 > _lastProcessedBlockNumber || _lastProcessedBlockNumber == 0;
- var shouldLoadValidators = Validators == null || notConsecutiveBlock || isProducingBlock;
- var mainChainProcessing = !ForSealing && isProcessingBlock;
+ bool isInitBlock = InitBlockNumber == block.Number;
+ bool isProducingBlock = options.ContainsFlag(ProcessingOptions.ProducingBlock);
+ bool isMainChainProcessing = !ForSealing && !isProducingBlock;
+ bool isConsecutiveBlock = block.Number - 1 == _lastProcessedBlockNumber && _lastProcessedBlockNumber != 0;
- if (shouldLoadValidators)
+ if (Validators == null || !isConsecutiveBlock || isProducingBlock)
{
- Validators = isInitBlock || notConsecutiveBlock
- ? LoadValidatorsFromContract(BlockTree.FindParentHeader(block.Header, BlockTreeLookupOptions.None))
- : ValidatorStore.GetValidators();
+ var parentHeader = BlockTree.FindParentHeader(block.Header, BlockTreeLookupOptions.None);
+ Validators = isInitBlock || !isConsecutiveBlock ? LoadValidatorsFromContract(parentHeader) : ValidatorStore.GetValidators();
- if (mainChainProcessing)
+ if (isMainChainProcessing)
{
- if (_logger.IsInfo) _logger.Info($"{(isInitBlock ? "Initial" : "Current")} contract validators ({Validators.Length}): [{string.Join(", ", Validators)}].");
+ if (_logger.IsInfo)
+ _logger.Info($"{(isInitBlock ? "Initial" : "Current")} contract validators ({Validators.Length}): [{string.Join(", ", Validators)}].");
}
}
if (isInitBlock)
{
- if (mainChainProcessing)
+ if (isMainChainProcessing)
{
ValidatorStore.SetValidators(InitBlockNumber, Validators);
}
-
- InitiateChange(block, Validators.ToArray(), isProcessingBlock, true);
}
else
{
- if (mainChainProcessing && notConsecutiveBlock)
+ if (!isConsecutiveBlock)// either reorg or blocks skipped (like fast sync)
{
- bool loadedValidatorsAreSameInStore = (ValidatorStore.GetValidators()?.SequenceEqual(Validators) == true);
- if (!loadedValidatorsAreSameInStore)
+ if (isMainChainProcessing)
{
- ValidatorStore.SetValidators(_blockFinalizationManager.GetLastLevelFinalizedBy(block.ParentHash), Validators);
+ bool loadedValidatorsAreSameInStore = (ValidatorStore.GetValidators()?.SequenceEqual(Validators) == true);
+ if (!loadedValidatorsAreSameInStore)
+ {
+ ValidatorStore.SetValidators(_blockFinalizationManager.GetLastLevelFinalizedBy(block.ParentHash), Validators);
+ }
}
- }
-
- if (isProcessingBlock)
- {
- bool reorganisationHappened = block.Number <= _lastProcessedBlockNumber;
- if (reorganisationHappened)
- {
- var reorganisationToBlockBeforePendingValidatorsInitChange = block.Number <= CurrentPendingValidators?.BlockNumber;
- SetPendingValidators(reorganisationToBlockBeforePendingValidatorsInitChange ? null : LoadPendingValidators(), reorganisationToBlockBeforePendingValidatorsInitChange);
- }
- else if (block.Number > _lastProcessedBlockNumber + 1) // blocks skipped, like fast sync
+ if (!isProducingBlock)
{
- SetPendingValidators(TryGetInitChangeFromPastBlocks(block.ParentHash), true);
+ _currentPendingValidators = ValidatorStore.PendingValidators = TryGetInitChangeFromPastBlocks(block.ParentHash);
}
}
- else
+
+ if (isProducingBlock)
{
- // if we are not processing blocks we are not on consecutive blocks.
- // We need to initialize pending validators from db on each block being produced.
- SetPendingValidators(LoadPendingValidators());
+ // if we are producing blocks we are not on consecutive blocks.
+ // We need to initialize pending validators from db on each block being produced.
+ _currentPendingValidators = ValidatorStore.PendingValidators;
}
}
+
base.OnBlockProcessingStart(block, options);
- FinalizePendingValidatorsIfNeeded(block.Header, isProcessingBlock);
+ FinalizePendingValidatorsIfNeeded(block.Header, isProducingBlock);
_lastProcessedBlockNumber = block.Number;
}
+ // FIXME
private PendingValidators TryGetInitChangeFromPastBlocks(Keccak blockHash)
{
PendingValidators pendingValidators = null;
@@ -202,40 +186,36 @@ public override void OnBlockProcessingEnd(Block block, TxReceipt[] receipts, Pro
if (ValidatorContract.CheckInitiateChangeEvent(block.Header, receipts, out var potentialValidators))
{
- bool isProcessingBlock = !options.ContainsFlag(ProcessingOptions.ProducingBlock);
- InitiateChange(block, potentialValidators, isProcessingBlock, Validators.Length == 1);
- if (_logger.IsInfo && isProcessingBlock) _logger.Info($"Signal for transition within contract at block {block.ToString(Block.Format.Short)}. New list of {potentialValidators.Length} : [{string.Join(", ", potentialValidators)}].");
- }
- }
+ bool isProducingBlock = options.ContainsFlag(ProcessingOptions.ProducingBlock);
- private void FinalizePendingValidatorsIfNeeded(BlockHeader block, bool isProcessingBlock)
- {
- if (CurrentPendingValidators?.AreFinalized == true)
- {
- if (_logger.IsInfo && isProcessingBlock) _logger.Info($"Applying validator set change signalled at block {CurrentPendingValidators.BlockNumber} before block {block.ToString(BlockHeader.Format.Short)}.");
- if (block.Number == InitBlockNumber)
+ // We are ignoring the signal if there are already pending validators.
+ // This replicates openethereum's behaviour which can be seen as a bug.
+ if (_currentPendingValidators == null && potentialValidators.Length > 0)
{
- ValidatorContract.EnsureSystemAccount();
- ValidatorContract.FinalizeChange(block);
- }
- else
- {
- ValidatorContract.FinalizeChange(block);
+ _currentPendingValidators = new PendingValidators(block.Number, block.Hash, potentialValidators);
+ if (!isProducingBlock)
+ {
+ ValidatorStore.PendingValidators = _currentPendingValidators;
+
+ if (_logger.IsInfo)
+ _logger.Info($"Signal for transition within contract at block {block.ToString(Block.Format.Short)}. New list of {potentialValidators.Length} : [{string.Join(", ", potentialValidators)}].");
+ }
}
- SetPendingValidators(null, isProcessingBlock);
}
}
- private void InitiateChange(Block block, Address[] potentialValidators, bool isProcessingBlock, bool initiateChangeIsImmediatelyFinalized = false)
+ private void FinalizePendingValidatorsIfNeeded(BlockHeader block, bool isProducingBlock)
{
- // We are ignoring the signal if there are already pending validators. This replicates Parity behaviour which can be seen as a bug.
- if (CurrentPendingValidators == null && potentialValidators.Length > 0)
+ var validatorsInfo = ValidatorStore.GetValidatorsInfo(block.Number);
+ if (block.Number == InitBlockNumber || validatorsInfo.FinalizingBlockNumber == block.Number - 1)
{
- SetPendingValidators(new PendingValidators(block.Number, block.Hash, potentialValidators)
- {
- AreFinalized = initiateChangeIsImmediatelyFinalized
- },
- !initiateChangeIsImmediatelyFinalized && isProcessingBlock);
+ if (_logger.IsInfo && !isProducingBlock)
+ _logger.Info($"Applying validator set change before block {block.ToString(BlockHeader.Format.Short)}.");
+
+ if (block.Number == InitBlockNumber)
+ ValidatorContract.EnsureSystemAccount();
+
+ ValidatorContract.FinalizeChange(block);
}
}
@@ -254,48 +234,20 @@ private Address[] LoadValidatorsFromContract(BlockHeader parentHeader)
}
catch (AbiException e)
{
- throw new AuRaException($"Failed to initialize validators list on block {parentHeader.ToString(BlockHeader.Format.FullHashAndNumber)} {new StackTrace()}.", e);
+ throw new AuRaException($"Failed to initialize validators list on block {parentHeader.ToString(BlockHeader.Format.FullHashAndNumber)}\n{new StackTrace()}.", e);
}
}
+ // NOTE: this is only added to `_blockFinalizationManager.BlocksFinalized` when `!ForSealing`
private void OnBlocksFinalized(object sender, FinalizeEventArgs e)
{
- if (CurrentPendingValidators != null)
- {
- // .Any equivalent with for
- var currentPendingValidatorsBlockGotFinalized = false;
- for (int i = 0; i < e.FinalizedBlocks.Count && !currentPendingValidatorsBlockGotFinalized; i++)
- {
- currentPendingValidatorsBlockGotFinalized = e.FinalizedBlocks[i].Hash == CurrentPendingValidators.BlockHash;
- }
-
- if (currentPendingValidatorsBlockGotFinalized)
- {
- CurrentPendingValidators.AreFinalized = true;
- Validators = CurrentPendingValidators.Addresses;
- SetPendingValidators(CurrentPendingValidators, true);
- if (!ForSealing)
- {
- ValidatorStore.SetValidators(e.FinalizingBlock.Number, Validators);
- if (_logger.IsInfo) _logger.Info($"Finalizing validators for transition within contract signalled at block {CurrentPendingValidators.BlockNumber}. after block {e.FinalizingBlock.ToString(BlockHeader.Format.Short)}.");
- }
- }
- }
- }
-
- private PendingValidators LoadPendingValidators() => ValidatorStore.PendingValidators;
-
- private void SetPendingValidators(PendingValidators validators, bool canSave = false)
- {
- _currentPendingValidators = validators;
-
- // We don't want to save to db when:
- // * We are producing block
- // * We will save later on processing same block (stateDb ignores consecutive calls with same key!)
- // * We are loading validators from db.
- if (canSave)
+ if (e.FinalizedBlocks.Any(header => header.Hash == _currentPendingValidators?.BlockHash))
{
- ValidatorStore.PendingValidators = validators;
+ Validators = _currentPendingValidators.Addresses;
+ ValidatorStore.SetValidators(e.FinalizingBlock.Number, Validators);
+ if (_logger.IsInfo)
+ _logger.Info($"Finalizing validators for transition signalled within contract at block {_currentPendingValidators.BlockNumber} after block {e.FinalizingBlock.ToString(BlockHeader.Format.Short)}.");
+ _currentPendingValidators = ValidatorStore.PendingValidators = null;
}
}
diff --git a/src/Nethermind/Nethermind.Consensus.AuRa/Validators/IValidatorStore.cs b/src/Nethermind/Nethermind.Consensus.AuRa/Validators/IValidatorStore.cs
index 40074c465da..de766e58059 100644
--- a/src/Nethermind/Nethermind.Consensus.AuRa/Validators/IValidatorStore.cs
+++ b/src/Nethermind/Nethermind.Consensus.AuRa/Validators/IValidatorStore.cs
@@ -1,16 +1,16 @@
// Copyright (c) 2021 Demerzel Solutions Limited
// This file is part of the Nethermind library.
-//
+//
// The Nethermind library is free software: you can redistribute it and/or modify
// it under the terms of the GNU Lesser General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
-//
+//
// The Nethermind library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Lesser General Public License for more details.
-//
+//
// You should have received a copy of the GNU Lesser General Public License
// along with the Nethermind. If not, see .
@@ -21,7 +21,10 @@ namespace Nethermind.Consensus.AuRa.Validators
public interface IValidatorStore
{
void SetValidators(long finalizingBlockNumber, Address[] validators);
- Address[] GetValidators(long? blockNumber = null);
+
+ Address[] GetValidators(in long? blockNumber = null);
+ ValidatorInfo GetValidatorsInfo(in long? blockNumber = null);
+
PendingValidators PendingValidators { get; set; }
}
}
diff --git a/src/Nethermind/Nethermind.Consensus.AuRa/Validators/ValidatorStore.cs b/src/Nethermind/Nethermind.Consensus.AuRa/Validators/ValidatorStore.cs
index 3fb875783d6..16f78d8529e 100644
--- a/src/Nethermind/Nethermind.Consensus.AuRa/Validators/ValidatorStore.cs
+++ b/src/Nethermind/Nethermind.Consensus.AuRa/Validators/ValidatorStore.cs
@@ -1,16 +1,16 @@
// Copyright (c) 2021 Demerzel Solutions Limited
// This file is part of the Nethermind library.
-//
+//
// The Nethermind library is free software: you can redistribute it and/or modify
// it under the terms of the GNU Lesser General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
-//
+//
// The Nethermind library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Lesser General Public License for more details.
-//
+//
// You should have received a copy of the GNU Lesser General Public License
// along with the Nethermind. If not, see .
@@ -34,6 +34,7 @@ public class ValidatorStore : IValidatorStore
private ValidatorInfo _latestValidatorInfo;
private static readonly int EmptyBlockNumber = -1;
private static readonly ValidatorInfo EmptyValidatorInfo = new ValidatorInfo(-1, -1, Array.Empty());
+ private static Keccak GetKey(in long blockNumber) => Keccak.Compute("Validators" + blockNumber);
public ValidatorStore(IDb db)
{
@@ -55,12 +56,19 @@ public void SetValidators(long finalizingBlockNumber, Address[] validators)
}
}
- private Keccak GetKey(in long blockNumber) => Keccak.Compute("Validators" + blockNumber);
+ public Address[] GetValidators(in long? blockNumber = null)
+ {
+ return blockNumber == null || blockNumber > _latestFinalizedValidatorsBlockNumber
+ ? GetLatestValidatorInfo().Validators
+ : FindValidatorInfo(blockNumber.Value).Validators;
+ }
- public Address[] GetValidators(long? blockNumber = null)
+ public ValidatorInfo GetValidatorsInfo(in long? blockNumber = null)
{
- return blockNumber == null || blockNumber > _latestFinalizedValidatorsBlockNumber ? GetLatestValidatorInfo().Validators : FindValidatorInfo(blockNumber.Value);
+ return blockNumber == null || blockNumber > _latestFinalizedValidatorsBlockNumber
+ ? GetLatestValidatorInfo()
+ : FindValidatorInfo(blockNumber.Value);
}
public PendingValidators PendingValidators
@@ -73,7 +81,7 @@ public PendingValidators PendingValidators
set => _db.Set(PendingValidatorsKey, PendingValidatorsDecoder.Encode(value).Bytes);
}
- private Address[] FindValidatorInfo(in long blockNumber)
+ private ValidatorInfo FindValidatorInfo(in long blockNumber)
{
var currentValidatorInfo = GetLatestValidatorInfo();
while (currentValidatorInfo.FinalizingBlockNumber >= blockNumber)
@@ -81,7 +89,7 @@ private Address[] FindValidatorInfo(in long blockNumber)
currentValidatorInfo = LoadValidatorInfo(currentValidatorInfo.PreviousFinalizingBlockNumber);
}
- return currentValidatorInfo.Validators;
+ return currentValidatorInfo;
}
private ValidatorInfo GetLatestValidatorInfo()