Example #1
0
        public async Task MergeBlockStateAsync(long lastIrreversibleBlockHeight, Hash lastIrreversibleBlockHash)
        {
            var chainStateInfo = await _blockStateSetManger.GetChainStateInfoAsync();

            var firstHeightToMerge = chainStateInfo.BlockHeight == 0L
                ? AElfConstants.GenesisBlockHeight
                : chainStateInfo.BlockHeight + 1;
            var mergeCount = lastIrreversibleBlockHeight - firstHeightToMerge;

            if (mergeCount < 0)
            {
                Logger.LogWarning(
                    $"Last merge height: {chainStateInfo.BlockHeight}, lib height: {lastIrreversibleBlockHeight}, needn't merge");
                return;
            }

            var blockIndexes = new List <IBlockIndex>();

            if (chainStateInfo.Status == ChainStateMergingStatus.Merged)
            {
                blockIndexes.Add(new BlockIndex(chainStateInfo.MergingBlockHash, -1));
            }

            var reversedBlockIndexes =
                await _blockchainService.GetReversedBlockIndexes(lastIrreversibleBlockHash, (int)mergeCount);

            reversedBlockIndexes.Reverse();

            blockIndexes.AddRange(reversedBlockIndexes);

            blockIndexes.Add(new BlockIndex(lastIrreversibleBlockHash, lastIrreversibleBlockHeight));

            Logger.LogDebug(
                $"Start merge lib height: {lastIrreversibleBlockHeight}, lib block hash: {lastIrreversibleBlockHash}, merge count: {blockIndexes.Count}");

            foreach (var blockIndex in blockIndexes)
            {
                try
                {
                    Logger.LogTrace($"Merging state {chainStateInfo} for block {blockIndex}");
                    await _blockStateSetManger.MergeBlockStateAsync(chainStateInfo, blockIndex.BlockHash);
                }
                catch (Exception e)
                {
                    Logger.LogError(e,
                                    $"Exception while merge state {chainStateInfo} for block {blockIndex}");
                    throw;
                }
            }
        }
        public async Task AddBlockStateSet_Test()
        {
            // one level tests without best chain state
            await _blockStateSetManger.SetBlockStateSetAsync(new BlockStateSet()
            {
                BlockHash    = _tv[1].BlockHash,
                BlockHeight  = _tv[1].BlockHeight,
                PreviousHash = null,
                Changes      =
                {
                    {
                        _tv[1].Key,
                        _tv[1].Value
                    },
                    {
                        _tv[2].Key,
                        _tv[2].Value
                    },
                }
            });


            var check1 = new Func <Task>(async() =>
            {
                (await _blockchainStateManager.GetStateAsync(_tv[1].Key, _tv[1].BlockHeight, _tv[1].BlockHash))
                .ShouldBe(_tv[1].Value);

                (await _blockchainStateManager.GetStateAsync(_tv[2].Key, _tv[1].BlockHeight, _tv[1].BlockHash))
                .ShouldBe(_tv[2].Value);
            });

            await check1();

            //two level tests without best chain state

            await _blockStateSetManger.SetBlockStateSetAsync(new BlockStateSet()
            {
                BlockHash    = _tv[2].BlockHash,
                BlockHeight  = _tv[2].BlockHeight,
                PreviousHash = _tv[1].BlockHash,
                Changes      =
                {
                    //override key 1
                    {
                        _tv[1].Key,
                        _tv[2].Value
                    },
                }
            });

            var check2 = new Func <Task>(async() =>
            {
                //key 1 was changed, value was changed to value 2
                (await _blockchainStateManager.GetStateAsync(_tv[1].Key, _tv[2].BlockHeight, _tv[2].BlockHash))
                .ShouldBe(_tv[2].Value);

                (await _blockchainStateManager.GetStateAsync(_tv[2].Key, _tv[2].BlockHeight, _tv[2].BlockHash))
                .ShouldBe(_tv[2].Value);
            });

            await check2();

            //but when we we can get value at the height of block height 1, also block hash 1
            await check1();

            await _blockStateSetManger.SetBlockStateSetAsync(new BlockStateSet()
            {
                BlockHash    = _tv[3].BlockHash,
                BlockHeight  = _tv[3].BlockHeight,
                PreviousHash = _tv[2].BlockHash,
                Changes      =
                {
                    //override key 2 at height 3
                    {
                        _tv[2].Key,
                        _tv[4].Value
                    },
                }
            });

            var check3_1 = new Func <Task>(async() =>
            {
                (await _blockchainStateManager.GetStateAsync(_tv[2].Key, _tv[3].BlockHeight, _tv[3].BlockHash))
                .ShouldBe(_tv[4].Value);
            });


            await check1();
            await check2();
            await check3_1();

            await _blockStateSetManger.SetBlockStateSetAsync(new BlockStateSet()
            {
                BlockHash    = _tv[4].BlockHash,
                BlockHeight  = _tv[3].BlockHeight, // it's a branch
                PreviousHash = _tv[2].BlockHash,
                Changes      =
                {
                    //override key 2 at height 3
                    {
                        _tv[2].Key,
                        _tv[5].Value
                    },
                }
            });

            var check3_2 = new Func <Task>(async() =>
            {
                (await _blockchainStateManager.GetStateAsync(_tv[2].Key, _tv[3].BlockHeight, _tv[4].BlockHash))
                .ShouldBe(_tv[5].Value);
            });

            await check1();
            await check2();
            await check3_2();

            var chainStateInfo = await _blockStateSetManger.GetChainStateInfoAsync();

            await _blockStateSetManger.MergeBlockStateAsync(chainStateInfo, _tv[1].BlockHash);

            await check1();
            await check2();
            await check3_1();
            await check3_2();

            await Assert.ThrowsAsync <InvalidOperationException>(async() =>
                                                                 await _blockStateSetManger.MergeBlockStateAsync(chainStateInfo, _tv[3].BlockHash));

            await _blockStateSetManger.MergeBlockStateAsync(chainStateInfo, _tv[2].BlockHash);

            await Assert.ThrowsAsync <InvalidOperationException>(async() =>
                                                                 await check1());

            await check2();

            //test failed merge recover
            chainStateInfo.Status           = ChainStateMergingStatus.Merging;
            chainStateInfo.MergingBlockHash = _tv[4].BlockHash;

            //merge best to second branch
            await _blockStateSetManger.MergeBlockStateAsync(chainStateInfo, _tv[4].BlockHash);

            await Assert.ThrowsAsync <InvalidOperationException>(async() =>
                                                                 await check1());

            await Assert.ThrowsAsync <InvalidOperationException>(async() =>
                                                                 await check2());

            await Assert.ThrowsAsync <InvalidOperationException>(async() =>
                                                                 await check3_1());

            await check3_2();

            //test failed merge recover
            chainStateInfo.Status           = ChainStateMergingStatus.Merged;
            chainStateInfo.MergingBlockHash = _tv[4].BlockHash;
            await _blockStateSetManger.MergeBlockStateAsync(chainStateInfo, _tv[4].BlockHash);
        }