public async Task <ByteString> GetExtraDataForFillingBlockHeaderAsync(BlockHeader blockHeader)
        {
            if (blockHeader.Height == Constants.GenesisBlockHeight)
            {
                return(ByteString.Empty);
            }

            var newCrossChainBlockData =
                await _crossChainIndexingDataService.GetCrossChainBlockDataForNextMiningAsync(blockHeader.PreviousBlockHash,
                                                                                              blockHeader.Height - 1);

            if (newCrossChainBlockData == null || newCrossChainBlockData.SideChainBlockData.Count == 0)
            {
                return(ByteString.Empty);
            }

            var txRootHashList = newCrossChainBlockData.SideChainBlockData.Select(scb => scb.TransactionStatusMerkleTreeRoot).ToList();
            var calculatedSideChainTransactionsRoot = BinaryMerkleTree.FromLeafNodes(txRootHashList).Root;

            Logger.LogTrace("Cross chain extra data generated.");
            return(new CrossChainExtraData {
                TransactionStatusMerkleTreeRoot = calculatedSideChainTransactionsRoot
            }
                   .ToByteString());
        }
        public async Task GetCrossChainBlockDataForNextMining_Test()
        {
            var parentChainId        = 123;
            var sideChainId          = 456;
            var parentBlockInfoCache = new List <IBlockCacheEntity>();
            var cachingCount         = 5;

            for (int i = 0; i < cachingCount + CrossChainConstants.MinimalBlockCacheEntityCount; i++)
            {
                parentBlockInfoCache.Add(new SideChainBlockData()
                {
                    ChainId = sideChainId,
                    Height  = (i + 1),
                });
            }
            _crossChainTestHelper.AddFakeSideChainIdHeight(sideChainId, 1);
            var parentFakeCache = new Dictionary <int, List <IBlockCacheEntity> > {
                { sideChainId, parentBlockInfoCache }
            };

            AddFakeCacheData(parentFakeCache);

            var sideBlockInfoCache = new List <IBlockCacheEntity>();

            for (int i = 0; i < cachingCount + CrossChainConstants.MinimalBlockCacheEntityCount; i++)
            {
                sideBlockInfoCache.Add(new ParentChainBlockData()
                {
                    ChainId = sideChainId,
                    Height  = (i + 1),
                });
            }
            _crossChainTestHelper.AddFakeParentChainIdHeight(sideChainId, 1);
            var sideFakeCache = new Dictionary <int, List <IBlockCacheEntity> > {
                { sideChainId, sideBlockInfoCache }
            };

            AddFakeCacheData(sideFakeCache);

            var res = await _crossChainIndexingDataService.GetCrossChainBlockDataForNextMiningAsync(Hash.Empty, 1);

            Assert.True(res.ParentChainBlockData.Count == 4);
            Assert.True(res.SideChainBlockData.Count == 4);
            Assert.True(res.PreviousBlockHeight == 1);
        }
        public async Task GenerateTransactions_Test()
        {
            var transactions = new List <Transaction>();

            _crossChainIndexingTransactionGenerator.GenerateTransactions(SampleAddress.AddressList[0], 0, Hash.Empty, ref transactions);
            transactions.Count.ShouldBe(0);

            var chainId             = _kernelTestHelper.BestBranchBlockList[0].Header.ChainId;
            var previousBlockHash   = _kernelTestHelper.BestBranchBlockList[3].GetHash();
            var previousBlockHeight = _kernelTestHelper.BestBranchBlockList[3].Height;

            _crossChainTestHelper.AddFakeSideChainIdHeight(chainId, previousBlockHeight);

            var blockInfoCache = new List <IBlockCacheEntity>();
            var cachingCount   = CrossChainConstants.MinimalBlockCacheEntityCount + 1;

            for (var i = 1; i <= cachingCount; i++)
            {
                var sideChainBlockData = new SideChainBlockData
                {
                    ChainId = chainId,
                    Height  = previousBlockHeight + i,
                };
                blockInfoCache.Add(sideChainBlockData);
            }

            var fakeCache = new Dictionary <int, List <IBlockCacheEntity> > {
                { chainId, blockInfoCache }
            };

            AddFakeCacheData(fakeCache);

            var smartContractAddress = SampleAddress.AddressList[0];

            _smartContractAddressService.SetAddress(CrossChainSmartContractAddressNameProvider.Name,
                                                    smartContractAddress);

            await _crossChainIndexingDataService.GetCrossChainBlockDataForNextMiningAsync(previousBlockHash, previousBlockHeight);

            _crossChainIndexingTransactionGenerator.GenerateTransactions(SampleAddress.AddressList[0], previousBlockHeight, previousBlockHash, ref transactions);

            transactions.Count.ShouldBe(1);
            transactions[0].From.ShouldBe(SampleAddress.AddressList[0]);
            transactions[0].To.ShouldBe(smartContractAddress);
            transactions[0].RefBlockNumber.ShouldBe(previousBlockHeight);
            transactions[0].RefBlockPrefix.ShouldBe(ByteString.CopyFrom(previousBlockHash.Value.Take(4).ToArray()));
            transactions[0].MethodName.ShouldBe(CrossChainConstants.CrossChainIndexingMethodName);

            var crossChainBlockData = CrossChainBlockData.Parser.ParseFrom(transactions[0].Params);

            crossChainBlockData.PreviousBlockHeight.ShouldBe(previousBlockHeight);
            crossChainBlockData.ParentChainBlockData.Count.ShouldBe(0);
            crossChainBlockData.SideChainBlockData.Count.ShouldBe(
                cachingCount - CrossChainConstants.MinimalBlockCacheEntityCount);
            crossChainBlockData.SideChainBlockData[0].ChainId.ShouldBe(chainId);
            crossChainBlockData.SideChainBlockData[0].Height.ShouldBe(previousBlockHeight + 1);
        }