Exemplo n.º 1
0
        private void RecordCrossChainData(IEnumerable <int> chainIdList)
        {
            var indexedSideChainBlockData = new IndexedSideChainBlockData();

            foreach (var chainId in chainIdList)
            {
                var pendingProposalExists = TryGetIndexingProposalWithStatus(chainId,
                                                                             CrossChainIndexingProposalStatus.Pending,
                                                                             out var pendingCrossChainIndexingProposal);
                Assert(pendingProposalExists, "Chain indexing not proposed.");

                if (chainId == State.ParentChainId.Value)
                {
                    IndexParentChainBlockData(pendingCrossChainIndexingProposal.ProposedCrossChainBlockData
                                              .ParentChainBlockDataList);
                }
                else
                {
                    indexedSideChainBlockData.SideChainBlockDataList.Add(IndexSideChainBlockData(
                                                                             pendingCrossChainIndexingProposal.ProposedCrossChainBlockData.SideChainBlockDataList,
                                                                             pendingCrossChainIndexingProposal.Proposer, chainId));
                }

                SetCrossChainIndexingProposalStatus(pendingCrossChainIndexingProposal,
                                                    CrossChainIndexingProposalStatus.Accepted);
            }

            if (indexedSideChainBlockData.SideChainBlockDataList.Count > 0)
            {
                State.IndexedSideChainBlockData.Set(Context.CurrentHeight, indexedSideChainBlockData);
                Context.Fire(new SideChainBlockDataIndexed());
            }
        }
Exemplo n.º 2
0
        /// <summary>
        /// Index side chain block data.
        /// </summary>
        /// <param name="sideChainBlockData">Side chain block data to be indexed.</param>
        /// <returns>Valid side chain block data which are indexed.</returns>
        private IndexedSideChainBlockData IndexSideChainBlockData(IList <SideChainBlockData> sideChainBlockData)
        {
            // only miner can do this.
//            Api.IsMiner("Not authorized to do this.");

            var indexedSideChainBlockData = new IndexedSideChainBlockData();

            foreach (var blockInfo in sideChainBlockData)
            {
                var chainId = blockInfo.ChainId;
                var info    = State.SideChainInfo[chainId];
                if (info == null || info.SideChainStatus != SideChainStatus.Active)
                {
                    continue;
                }
                var currentSideChainHeight = State.CurrentSideChainHeight[chainId];

                var target = currentSideChainHeight != 0
                    ? currentSideChainHeight + 1
                    : Constants.GenesisBlockHeight;
                long sideChainHeight = blockInfo.Height;
                if (target != sideChainHeight)
                {
                    continue;
                }

                // indexing fee
                var indexingPrice = info.SideChainCreationRequest.IndexingPrice;
                var lockedToken   = State.IndexingBalance[chainId];

                lockedToken -= indexingPrice;
                State.IndexingBalance[chainId] = lockedToken;

                if (lockedToken < indexingPrice)
                {
                    info.SideChainStatus = SideChainStatus.Terminated;
                }

                State.SideChainInfo[chainId] = info;

                if (indexingPrice > 0)
                {
                    Transfer(new TransferInput
                    {
                        To     = Context.Sender,
                        Symbol = Context.Variables.NativeSymbol,
                        Amount = indexingPrice,
                        Memo   = "Index fee."
                    });
                }

                State.CurrentSideChainHeight[chainId] = sideChainHeight;
                indexedSideChainBlockData.SideChainBlockData.Add(blockInfo);
            }

            return(indexedSideChainBlockData);
        }
Exemplo n.º 3
0
        public static ByteString ExtractCrossChainExtraDataFromCrossChainBlockData(
            this IndexedSideChainBlockData indexedSideChainBlockData)
        {
            var txRootHashList = indexedSideChainBlockData.SideChainBlockDataList
                                 .Select(scb => scb.TransactionStatusMerkleTreeRoot).ToList();

            var calculatedSideChainTransactionsRoot = BinaryMerkleTree.FromLeafNodes(txRootHashList).Root;

            return(new CrossChainExtraData
            {
                TransactionStatusMerkleTreeRoot = calculatedSideChainTransactionsRoot
            }
                   .ToByteString());
        }
Exemplo n.º 4
0
        public static ByteString ExtractCrossChainExtraDataFromCrossChainBlockData(this CrossChainBlockData crossChainBlockData)
        {
            if (crossChainBlockData.IsNullOrEmpty() || crossChainBlockData.SideChainBlockDataList.Count == 0)
            {
                return(ByteString.Empty);
            }

            var indexedSideChainBlockData = new IndexedSideChainBlockData
            {
                SideChainBlockDataList = { crossChainBlockData.SideChainBlockDataList }
            };

            return(indexedSideChainBlockData.ExtractCrossChainExtraDataFromCrossChainBlockData());
        }
        public override void ConfigureServices(ServiceConfigurationContext context)
        {
            base.ConfigureServices(context);

            var dictionary = new Dictionary <long, Hash>
            {
                { 1, Hash.FromString("1") },
                { 2, Hash.FromString("2") },
                { 3, Hash.FromString("3") }
            };

            Configure <GrpcCrossChainConfigOption>(option =>
            {
                option.ListeningPort         = 5001;
                option.ParentChainServerIp   = "127.0.0.1";
                option.ParentChainServerPort = 5000;
            });

            Configure <CrossChainConfigOptions>(option =>
            {
                option.ParentChainId = ChainHelper.ConvertChainIdToBase58(ChainHelper.GetChainId(1));
            });

            context.Services.AddTransient(provider =>
            {
                var kernelTestHelper      = context.Services.GetRequiredServiceLazy <KernelTestHelper>();
                var mockBlockChainService = new Mock <IBlockchainService>();
                mockBlockChainService.Setup(m => m.GetChainAsync()).Returns(() =>
                {
                    var chain = new Chain {
                        LastIrreversibleBlockHeight = 10
                    };
                    return(Task.FromResult(chain));
                });
                mockBlockChainService.Setup(m =>
                                            m.GetBlockHashByHeightAsync(It.IsAny <Chain>(), It.IsAny <long>(), It.IsAny <Hash>()))
                .Returns <Chain, long, Hash>((chain, height, hash) =>
                {
                    if (height > 0 && height <= 3)
                    {
                        return(Task.FromResult(dictionary[height]));
                    }
                    return(Task.FromResult <Hash>(null));
                });
                mockBlockChainService.Setup(m => m.GetBlockByHashAsync(It.IsAny <Hash>())).Returns <Hash>(hash =>
                {
                    foreach (var kv in dictionary)
                    {
                        if (kv.Value.Equals(hash))
                        {
                            var block = kernelTestHelper.Value.GenerateBlock(kv.Key - 1, dictionary[kv.Key - 1]);
                            return(Task.FromResult(block));
                        }
                    }

                    return(Task.FromResult <Block>(null));
                });
                return(mockBlockChainService.Object);
            });

            context.Services.AddTransient(provider =>
            {
                var mockBlockExtraDataService = new Mock <IBlockExtraDataService>();
                mockBlockExtraDataService
                .Setup(m => m.GetExtraDataFromBlockHeader(It.IsAny <string>(), It.IsAny <BlockHeader>())).Returns(
                    () =>
                {
                    var crossExtraData = new CrossChainExtraData()
                    {
                        TransactionStatusMerkleTreeRoot = Hash.FromString("SideChainBlockHeadersRoot"),
                    };
                    return(ByteString.CopyFrom(crossExtraData.ToByteArray()));
                });
                return(mockBlockExtraDataService.Object);
            });

            context.Services.AddTransient(provider =>
            {
                var mockCrossChainIndexingDataService = new Mock <ICrossChainIndexingDataService>();
                mockCrossChainIndexingDataService
                .Setup(m => m.GetIndexedCrossChainBlockDataAsync(It.IsAny <Hash>(), It.IsAny <long>()))
                .Returns(() =>
                {
                    var crossChainBlockData = new CrossChainBlockData
                    {
                        SideChainBlockDataList =
                        {
                            new SideChainBlockData
                            {
                                ChainId = 123, Height = 1,
                                TransactionStatusMerkleTreeRoot = Hash.FromString("fakeTransactionMerkleTree")
                            }
                        }
                    };
                    return(Task.FromResult(crossChainBlockData));
                });
                mockCrossChainIndexingDataService
                .Setup(m => m.GetIndexedSideChainBlockDataAsync(It.IsAny <Hash>(), It.IsAny <long>())).Returns(
                    () =>
                {
                    var indexedSideChainBlockData = new IndexedSideChainBlockData
                    {
                        SideChainBlockDataList =
                        {
                            new SideChainBlockData
                            {
                                ChainId = 123, Height = 1,
                                TransactionStatusMerkleTreeRoot = Hash.FromString("fakeTransactionMerkleTree")
                            }
                        }
                    };
                    return(Task.FromResult(indexedSideChainBlockData));
                });
                return(mockCrossChainIndexingDataService.Object);
            });

            context.Services.AddTransient(provider =>
            {
                var mockCrossChainClientProvider = new Mock <ICrossChainClientProvider>();
                mockCrossChainClientProvider.Setup(m => m.CreateCrossChainClient(It.IsAny <CrossChainClientDto>()))
                .Returns(() =>
                {
                    var mockCrossChainClient = new Mock <ICrossChainClient>();
                    mockCrossChainClient.Setup(m => m.RequestChainInitializationDataAsync(It.IsAny <int>())).Returns(
                        () =>
                    {
                        var chainInitialization = new ChainInitializationData
                        {
                            CreationHeightOnParentChain = 1
                        };
                        return(Task.FromResult(chainInitialization));
                    });
                    mockCrossChainClient.Setup(m =>
                                               m.RequestCrossChainDataAsync(It.IsAny <long>(),
                                                                            It.IsAny <Func <IBlockCacheEntity, bool> >()))
                    .Returns(() =>
                    {
                        var chainInitialization = new ChainInitializationData
                        {
                            CreationHeightOnParentChain = 1
                        };
                        return(Task.FromResult(chainInitialization));
                    });
                    return(mockCrossChainClient.Object);
                });
                return(mockCrossChainClientProvider.Object);
            });

            context.Services.AddSingleton <CrossChainPlugin>();

            context.Services.AddSingleton <IConsensusExtraDataNameProvider, MockConsensusExtraDataProvider>();
        }
Exemplo n.º 6
0
 public static bool IsNullOrEmpty(this IndexedSideChainBlockData indexedSideChainBlockData)
 {
     return(indexedSideChainBlockData == null || indexedSideChainBlockData.SideChainBlockDataList.Count == 0);
 }
Exemplo n.º 7
0
        /// <summary>
        /// Index side chain block data.
        /// </summary>
        /// <param name="sideChainBlockDataList">Side chain block data to be indexed.</param>
        /// <param name="proposer">Charge indexing fee for the one who proposed side chain block data.</param>
        /// <returns>Valid side chain block data which are indexed.</returns>
        private IndexedSideChainBlockData IndexSideChainBlockData(IList <SideChainBlockData> sideChainBlockDataList,
                                                                  Address proposer)
        {
            var  indexedSideChainBlockData = new IndexedSideChainBlockData();
            long indexingFeeAmount         = 0;
            var  groupResult = sideChainBlockDataList.GroupBy(data => data.ChainId, data => data);
            var  formattedProposerAddress = proposer.ToByteString().ToBase64();

            foreach (var group in groupResult)
            {
                var chainId = group.Key;

                var sideChainInfo = State.SideChainInfo[chainId];
                if (sideChainInfo == null)
                {
                    continue;
                }
                var  currentSideChainHeight = State.CurrentSideChainHeight[chainId];
                long arrearsAmount          = 0;
                foreach (var sideChainBlockData in group)
                {
                    var target = currentSideChainHeight != 0
                        ? currentSideChainHeight + 1
                        : Constants.GenesisBlockHeight;
                    var sideChainHeight = sideChainBlockData.Height;
                    if (target != sideChainHeight)
                    {
                        break;
                    }

                    // indexing fee
                    var indexingPrice = sideChainInfo.IndexingPrice;
                    var lockedToken   = State.IndexingBalance[chainId];

                    lockedToken -= indexingPrice;
                    State.IndexingBalance[chainId] = lockedToken;

                    if (lockedToken < 0)
                    {
                        // record arrears
                        arrearsAmount += indexingPrice;
                    }
                    else
                    {
                        indexingFeeAmount += indexingPrice;
                        if (lockedToken < indexingPrice)
                        {
                            sideChainInfo.SideChainStatus = SideChainStatus.InsufficientBalance;
                        }
                    }

                    currentSideChainHeight++;
                    indexedSideChainBlockData.SideChainBlockDataList.Add(sideChainBlockData);
                }

                Context.LogDebug(() =>
                                 $"## [ {State.CurrentSideChainHeight[chainId]} - {currentSideChainHeight} ] from side chain {chainId} indexed by {proposer}, index blocks {currentSideChainHeight - State.CurrentSideChainHeight[chainId] + 1} ");

                if (arrearsAmount > 0)
                {
                    if (sideChainInfo.ArrearsInfo.TryGetValue(formattedProposerAddress, out var amount))
                    {
                        sideChainInfo.ArrearsInfo[formattedProposerAddress] = amount + arrearsAmount;
                    }
                    else
                    {
                        sideChainInfo.ArrearsInfo[formattedProposerAddress] = arrearsAmount;
                    }
                }

                State.SideChainInfo[chainId]          = sideChainInfo;
                State.CurrentSideChainHeight[chainId] = currentSideChainHeight;
            }

            if (indexingFeeAmount > 0)
            {
                Transfer(new TransferInput
                {
                    To     = proposer,
                    Symbol = Context.Variables.NativeSymbol,
                    Amount = indexingFeeAmount,
                    Memo   = "Index fee."
                });
            }

            return(indexedSideChainBlockData);
        }
Exemplo n.º 8
0
        private bool ValidateBlockExtraDataAsync(IndexedSideChainBlockData indexedSideChainBlockData, ByteString extraData)
        {
            var expected = indexedSideChainBlockData.ExtractCrossChainExtraDataFromCrossChainBlockData();

            return(expected.Equals(extraData));
        }
        public override void ConfigureServices(ServiceConfigurationContext context)
        {
            context.Services.AddSingleton <CrossChainTestHelper>();
            context.Services.AddTransient(provider =>
            {
                var mockCrossChainRequestService = new Mock <ICrossChainRequestService>();
                mockCrossChainRequestService.Setup(mock => mock.RequestCrossChainDataFromOtherChainsAsync())
                .Returns(Task.CompletedTask);
                return(mockCrossChainRequestService.Object);
            });

            context.Services.AddTransient(provider =>
            {
                var mockCrossChainIndexingDataService = new Mock <ICrossChainIndexingDataService>();
                mockCrossChainIndexingDataService
                .Setup(m => m.GetIndexedSideChainBlockDataAsync(It.IsAny <Hash>(), It.IsAny <long>()))
                .Returns <Hash, long>((blockHash, blockHeight) =>
                {
                    var crossChainTestHelper =
                        context.Services.GetRequiredServiceLazy <CrossChainTestHelper>().Value;
                    var crossChainBlockData       = crossChainTestHelper.GetIndexedCrossChainExtraData(blockHeight);
                    var indexedSideChainBlockData = new IndexedSideChainBlockData
                    {
                        SideChainBlockDataList = { crossChainBlockData.SideChainBlockDataList },
                    };
                    return(Task.FromResult(indexedSideChainBlockData));
                });

                mockCrossChainIndexingDataService.Setup(m =>
                                                        m.GetCrossChainTransactionInputForNextMiningAsync(It.IsAny <Hash>(), It.IsAny <long>()))
                .Returns <Hash, long>(
                    (previousHash, height) =>
                {
                    var crossChainTestHelper =
                        context.Services.GetRequiredServiceLazy <CrossChainTestHelper>().Value;
                    return(Task.FromResult(crossChainTestHelper.GetCrossChainBlockData(previousHash)));
                });

                mockCrossChainIndexingDataService.Setup(m =>
                                                        m.PrepareExtraDataForNextMiningAsync(It.IsAny <Hash>(), It.IsAny <long>()))
                .Returns <Hash, long>(
                    (previousHash, height) =>
                {
                    var crossChainTestHelper =
                        context.Services.GetRequiredServiceLazy <CrossChainTestHelper>().Value;
                    return(Task.FromResult(
                               crossChainTestHelper.GetCrossChainExtraData(previousHash)?.ToByteString() ??
                               ByteString.Empty));
                });

                mockCrossChainIndexingDataService.Setup(m =>
                                                        m.GetAllChainIdHeightPairsAtLibAsync()).Returns(() =>
                {
                    var crossChainTestHelper =
                        context.Services.GetRequiredServiceLazy <CrossChainTestHelper>().Value;
                    return(Task.FromResult(crossChainTestHelper.GetAllIndexedCrossChainExtraData()));
                });

                mockCrossChainIndexingDataService
                .Setup(
                    m => m.CheckExtraDataIsNeededAsync(It.IsAny <Hash>(), It.IsAny <long>(), It.IsAny <Timestamp>()))
                .Returns <Hash, long, Timestamp>((blockHash, height, timeStamp) =>
                {
                    var crossChainTestHelper =
                        context.Services.GetRequiredServiceLazy <CrossChainTestHelper>().Value;
                    return(Task.FromResult(crossChainTestHelper.GetCrossChainExtraData(blockHash) != null));
                });
                return(mockCrossChainIndexingDataService.Object);
            });

            context.Services.AddTransient(provider =>
            {
                var mockService = new Mock <ISmartContractAddressService>();
                mockService.Setup(m => m.GetAddressByContractNameAsync(It.IsAny <IChainContext>(),
                                                                       It.IsAny <string>()))
                .Returns(Task.FromResult(default(Address)));
                return(mockService.Object);
            });

            context.Services.AddSingleton <ITransactionPackingOptionProvider, MockTransactionPackingOptionProvider>();
        }