public void correctly_de_finalizes_blocks_on_block_reprocessing(int chainLength, int rerun, int validatorCount, bool twoThirdsMajorityTransition)
        {
            Address[] blockCreators = TestItem.Addresses.Take(validatorCount).ToArray();
            _validatorStore.GetValidators(Arg.Any <long?>()).Returns(blockCreators);

            BlockTreeBuilder             blockTreeBuilder    = Build.A.BlockTree();
            AuRaBlockFinalizationManager finalizationManager = new(
                blockTreeBuilder.TestObject,
                blockTreeBuilder.ChainLevelInfoRepository,
                _blockProcessor,
                _validatorStore,
                _validSealerStrategy,
                _logManager,
                twoThirdsMajorityTransition ? 0 : long.MaxValue);

            blockTreeBuilder.OfChainLength(chainLength, 0, 0, blockCreators);
            FinalizeToLevel(chainLength, blockTreeBuilder.ChainLevelInfoRepository);

            List <Block> blocks = Enumerable.Range(1, rerun)
                                  .Select(i => blockTreeBuilder.TestObject.FindBlock(chainLength - i, BlockTreeLookupOptions.None))
                                  .Reverse()
                                  .ToList();

            _blockProcessor.BlocksProcessing += Raise.EventWith(new BlocksProcessingEventArgs(blocks));

            int majority = (twoThirdsMajorityTransition ? (validatorCount - 1) * 2 / 3 : (validatorCount - 1) / 2) + 1;

            for (int i = 1; i < rerun + majority; i++)
            {
                blockTreeBuilder.ChainLevelInfoRepository.LoadLevel(chainLength - i).MainChainBlock.IsFinalized.Should().BeFalse();
            }

            blockTreeBuilder.ChainLevelInfoRepository.LoadLevel(chainLength - rerun - majority - 1).MainChainBlock.IsFinalized.Should().BeTrue();
        }
        public void correctly_finalizes_blocks_in_chain(int chainLength, long twoThirdsMajorityTransition, Address[] blockCreators, int notFinalizedExpectedCount)
        {
            _validatorStore.GetValidators(Arg.Any <long?>()).Returns(blockCreators);

            BlockTreeBuilder      blockTreeBuilder = Build.A.BlockTree();
            HashSet <BlockHeader> finalizedBlocks  = new();

            AuRaBlockFinalizationManager finalizationManager = new(blockTreeBuilder.TestObject, blockTreeBuilder.ChainLevelInfoRepository, _blockProcessor, _validatorStore, _validSealerStrategy, _logManager, twoThirdsMajorityTransition);

            finalizationManager.BlocksFinalized += (sender, args) =>
            {
                foreach (BlockHeader block in args.FinalizedBlocks)
                {
                    finalizedBlocks.Add(block);
                }
            };

            blockTreeBuilder.OfChainLength(chainLength, 0, 0, blockCreators);

            int start = 0;

            for (int i = start; i < chainLength; i++)
            {
                Keccak blockHash = blockTreeBuilder.ChainLevelInfoRepository.LoadLevel(i).MainChainBlock.BlockHash;
                Block? block     = blockTreeBuilder.TestObject.FindBlock(blockHash, BlockTreeLookupOptions.None);
                _blockProcessor.BlockProcessed += Raise.EventWith(new BlockProcessedEventArgs(block, Array.Empty <TxReceipt>()));
            }

            IEnumerable <bool> isBlockFinalized = Enumerable.Range(start, chainLength).Select(i => blockTreeBuilder.ChainLevelInfoRepository.LoadLevel(i).MainChainBlock.IsFinalized);
            IEnumerable <bool> expected         = Enumerable.Range(start, chainLength).Select(i => i < chainLength - notFinalizedExpectedCount);

            finalizedBlocks.Count.Should().Be(chainLength - notFinalizedExpectedCount);
            isBlockFinalized.Should().BeEquivalentTo(expected);
        }