예제 #1
0
        public async Task Get_Block_By_BlockHash_Success()
        {
            var chain = await _blockchainService.GetChainAsync();

            var transactions = new List <Transaction>();

            for (int i = 0; i < 3; i++)
            {
                transactions.Add(await _osTestHelper.GenerateTransferTransaction());
            }

            await _osTestHelper.BroadcastTransactions(transactions);

            var block = await _osTestHelper.MinedOneBlock();

            var response =
                await GetResponseAsObjectAsync <BlockDto>(
                    $"/api/blockChain/block?blockHash={block.GetHash().ToHex()}&includeTransactions=true");

            response.BlockHash.ShouldBe(block.GetHash().ToHex());
            response.Header.PreviousBlockHash.ShouldBe(block.Header.PreviousBlockHash.ToHex());
            response.Header.MerkleTreeRootOfTransactions.ShouldBe(block.Header.MerkleTreeRootOfTransactions.ToHex());
            response.Header.MerkleTreeRootOfWorldState.ShouldBe(block.Header.MerkleTreeRootOfWorldState.ToHex());
            response.Header.Height.ShouldBe(block.Height);
            response.Header.Time.ShouldBe(block.Header.Time.ToDateTime());
            response.Header.ChainId.ShouldBe(ChainHelpers.ConvertChainIdToBase58(chain.Id));
            response.Header.Bloom.ShouldBe(block.Header.Bloom.ToByteArray().ToHex());
            response.Body.TransactionsCount.ShouldBe(3);

            var responseTransactions = response.Body.Transactions;

            responseTransactions.Count.ShouldBe(3);
        }
예제 #2
0
        public async Task <bool> StartIndexingRequest(int chainId, long targetHeight,
                                                      ICrossChainDataProducer crossChainDataProducer)
        {
            var requestData = new RequestCrossChainBlockData
            {
                FromChainId = LocalChainId,
                NextHeight  = targetHeight
            };

            using (var serverStream = RequestIndexing(requestData))
            {
                while (await serverStream.ResponseStream.MoveNext())
                {
                    var response = serverStream.ResponseStream.Current;

                    // requestCrossChain failed or useless response
                    if (!response.Success || !crossChainDataProducer.AddNewBlockInfo(response.BlockInfoResult))
                    {
                        break;
                    }

                    crossChainDataProducer.Logger.LogTrace(
                        $"Received response from chain {ChainHelpers.ConvertChainIdToBase58(response.BlockInfoResult.ChainId)} at height {response.Height}");
                }
            }

            return(true);
        }
예제 #3
0
        public async Task <List <SideChainBlockData> > GetSideChainBlockDataAsync(Hash currentBlockHash, long currentBlockHeight)
        {
            var sideChainBlockData = new List <SideChainBlockData>();
            var dict = await _crossChainContractReader.GetSideChainIdAndHeightAsync(currentBlockHash,
                                                                                    currentBlockHeight);

            foreach (var idHeight in dict)
            {
                var i            = 0;
                var targetHeight = idHeight.Value + 1;
                while (i < CrossChainConstants.MaximalCountForIndexingSideChainBlock)
                {
                    var blockInfo = _crossChainDataConsumer.TryTake <SideChainBlockData>(idHeight.Key, targetHeight, true);
                    if (blockInfo == null)
                    {
                        // no more available parent chain block info
                        break;
                    }
                    sideChainBlockData.Add(blockInfo);
                    Logger.LogTrace($"Got height {blockInfo.Height} of side chain  {ChainHelpers.ConvertChainIdToBase58(idHeight.Key)}");
                    targetHeight++;
                    i++;
                }
            }

            Logger.LogTrace($"Side chain block data count {sideChainBlockData.Count}");
            return(sideChainBlockData);
        }
        public long GetNeededChainHeightForCache(int chainId)
        {
            var blockInfoCache = _multiChainBlockInfoCacheProvider.GetBlockInfoCache(chainId);

            if (blockInfoCache == null)
            {
                throw new ChainCacheNotFoundException($"Chain {ChainHelpers.ConvertChainIdToBase58(chainId)} cache not found.");
            }
            return(blockInfoCache.TargetChainHeight());
        }
예제 #5
0
        /// <summary>
        /// Get information about a given block by block hash. Otionally with the list of its transactions.
        /// </summary>
        /// <param name="blockHash">block hash</param>
        /// <param name="includeTransactions">include transactions or not</param>
        /// <returns></returns>
        public async Task <BlockDto> GetBlock(string blockHash, bool includeTransactions = false)
        {
            Hash realBlockHash;

            try
            {
                realBlockHash = Hash.LoadHex(blockHash);
            }
            catch
            {
                throw new UserFriendlyException(Error.Message[Error.InvalidBlockHash], Error.InvalidBlockHash.ToString());
            }

            var block = await GetBlock(realBlockHash);

            if (block == null)
            {
                throw new UserFriendlyException(Error.Message[Error.NotFound], Error.NotFound.ToString());
            }

            var blockDto = new BlockDto
            {
                BlockHash = block.GetHash().ToHex(),
                Header    = new BlockHeaderDto
                {
                    PreviousBlockHash            = block.Header.PreviousBlockHash.ToHex(),
                    MerkleTreeRootOfTransactions = block.Header.MerkleTreeRootOfTransactions.ToHex(),
                    MerkleTreeRootOfWorldState   = block.Header.MerkleTreeRootOfWorldState.ToHex(),
                    Extra   = block.Header.BlockExtraDatas.ToString(),
                    Height  = block.Header.Height,
                    Time    = block.Header.Time.ToDateTime(),
                    ChainId = ChainHelpers.ConvertChainIdToBase58(block.Header.ChainId),
                    Bloom   = block.Header.Bloom.ToByteArray().ToHex()
                },
                Body = new BlockBodyDto()
                {
                    TransactionsCount = block.Body.TransactionsCount,
                    Transactions      = new List <string>()
                }
            };

            if (includeTransactions)
            {
                var transactions = block.Body.Transactions;
                var txs          = new List <string>();
                foreach (var txHash in transactions)
                {
                    txs.Add(txHash.ToHex());
                }

                blockDto.Body.Transactions = txs;
            }

            return(blockDto);
        }
예제 #6
0
        public Task <JObject> GetChainInformation()
        {
            var map = SmartContractAddressService.GetSystemContractNameToAddressMapping();
            var basicContractZero = SmartContractAddressService.GetZeroSmartContractAddress();
            var response          = new JObject
            {
                ["GenesisContractAddress"] = basicContractZero?.GetFormatted(),
                ["ChainId"] = ChainHelpers.ConvertChainIdToBase58(BlockchainService.GetChainId())
            };

            return(Task.FromResult(response));
        }
예제 #7
0
        public void RequestCrossChainIndexing()
        {
            //Logger.LogTrace("Request cross chain indexing ..");
            var chainIds = _crossChainMemoryCacheService.GetCachedChainIds();

            foreach (var chainId in chainIds)
            {
                if (!_grpcCrossChainClients.TryGetValue(chainId, out var client))
                {
                    continue;
                }
                Logger.LogTrace($"Request chain {ChainHelpers.ConvertChainIdToBase58(chainId)}");
                var targetHeight = _crossChainMemoryCacheService.GetNeededChainHeightForCache(chainId);
                var task         = TryRequest(client, c => c.StartIndexingRequest(chainId, targetHeight, _crossChainDataProducer));
            }
        }
예제 #8
0
 public void GetChainId_By_SerialNumber()
 {
     // Have tested all the conditions (195112UL ~ 11316496UL), To save time, just do some random test
     //var base58HashSet = new HashSet<string>();
     //var intHashSet = new HashSet<int>();
     // for (var i = ; i < 11316496UL; i++)
     for (var i = 0; i < 1000; i++)
     {
         var chainId      = 2111;
         var base58String = ChainHelpers.ConvertChainIdToBase58(chainId);
         base58String.Length.ShouldBe(4);
         var newChainId = ChainHelpers.ConvertBase58ToChainId(base58String);
         newChainId.ShouldBe(chainId);
         // Uncomment this for go through all conditions
         // base58HashSet.Add(base58String).ShouldBe(true);
         // intHashSet.Add(newChainId).ShouldBe(true);
     }
 }
예제 #9
0
        public async Task <JObject> GetBlockInfo(long blockHeight, bool includeTransactions = false)
        {
            var blockInfo = await this.GetBlockAtHeight(blockHeight);

            if (blockInfo == null)
            {
                throw new JsonRpcServiceException(Error.NotFound, Error.Message[Error.NotFound]);
            }

            // TODO: Create DTO Exntension for Block
            var response = new JObject
            {
                ["BlockHash"] = blockInfo.GetHash().ToHex(),
                ["Header"]    = new JObject
                {
                    ["PreviousBlockHash"]            = blockInfo.Header.PreviousBlockHash.ToHex(),
                    ["MerkleTreeRootOfTransactions"] = blockInfo.Header.MerkleTreeRootOfTransactions.ToHex(),
                    ["MerkleTreeRootOfWorldState"]   = blockInfo.Header.MerkleTreeRootOfWorldState.ToHex(),
                    ["Extra"]   = blockInfo.Header.BlockExtraDatas.ToString(),
                    ["Height"]  = blockInfo.Header.Height.ToString(),
                    ["Time"]    = blockInfo.Header.Time.ToDateTime(),
                    ["ChainId"] = ChainHelpers.ConvertChainIdToBase58(blockInfo.Header.ChainId),
                    ["Bloom"]   = blockInfo.Header.Bloom.ToByteArray().ToHex()
                },
                ["Body"] = new JObject
                {
                    ["TransactionsCount"] = blockInfo.Body.TransactionsCount,
                }
            };

            if (includeTransactions)
            {
                var transactions = blockInfo.Body.Transactions;
                var txs          = new List <string>();
                foreach (var txHash in transactions)
                {
                    txs.Add(txHash.ToHex());
                }

                response["Body"]["Transactions"] = JArray.FromObject(txs);
            }

            return(response);
        }
예제 #10
0
        public async Task Get_BlockInfo_Success()
        {
            var chain = await _blockchainService.GetChainAsync();

            var transactions = new List <Transaction>();

            for (int i = 0; i < 3; i++)
            {
                transactions.Add(await _osTestHelper.GenerateTransferTransaction());
            }

            await _osTestHelper.BroadcastTransactions(transactions);

            var block = await _osTestHelper.MinedOneBlock();

            var response = await JsonCallAsJObject("/chain", "GetBlockInfo",
                                                   new { blockHeight = 12, includeTransactions = true });

            var responseResult = response["result"];

            responseResult["BlockHash"].ToString().ShouldBe(block.GetHash().ToHex());
            responseResult["Header"]["PreviousBlockHash"].ToString()
            .ShouldBe(block.Header.PreviousBlockHash.ToHex());
            responseResult["Header"]["MerkleTreeRootOfTransactions"].ToString().ShouldBe(
                block.Header.MerkleTreeRootOfTransactions.ToHex
                    ());
            responseResult["Header"]["MerkleTreeRootOfWorldState"].ToString()
            .ShouldBe(block.Header.MerkleTreeRootOfWorldState.ToHex());
            ((long)responseResult["Header"]["Height"]).ShouldBe(block.Height);
            Convert.ToDateTime(responseResult["Header"]["Time"]).ShouldBe(block.Header.Time.ToDateTime());
            responseResult["Header"]["ChainId"].ToString().ShouldBe(ChainHelpers.ConvertChainIdToBase58(chain.Id));
            responseResult["Header"]["Bloom"].ToString().ShouldBe(block.Header.Bloom.ToByteArray().ToHex());
            ((int)responseResult["Body"]["TransactionsCount"]).ShouldBe(3);

            var responseTransactions = responseResult["Body"]["Transactions"].ToList();

            responseTransactions.Count.ShouldBe(3);
        }
예제 #11
0
        /// <summary>
        /// Get the current status of the block chain.
        /// </summary>
        /// <returns></returns>
        public async Task <ChainStatusDto> GetChainStatus()
        {
            var basicContractZero = _smartContractAddressService.GetZeroSmartContractAddress();

            var chain = await _blockchainService.GetChainAsync();

            var branches = JsonConvert.DeserializeObject <Dictionary <string, long> >(chain.Branches.ToString());
            var formattedNotLinkedBlocks = new List <NotLinkedBlockDto>();

            foreach (var notLinkedBlock in chain.NotLinkedBlocks)
            {
                var block = await GetBlock(Hash.LoadBase64(notLinkedBlock.Value));

                formattedNotLinkedBlocks.Add(new NotLinkedBlockDto
                {
                    BlockHash         = block.GetHash().ToHex(),
                    Height            = block.Height,
                    PreviousBlockHash = block.Header.PreviousBlockHash.ToHex()
                }
                                             );
            }

            return(new ChainStatusDto()
            {
                ChainId = ChainHelpers.ConvertChainIdToBase58(chain.Id),
                GenesisContractAddress = basicContractZero?.GetFormatted(),
                Branches = branches,
                NotLinkedBlocks = formattedNotLinkedBlocks,
                LongestChainHeight = chain.LongestChainHeight,
                LongestChainHash = chain.LongestChainHash?.ToHex(),
                GenesisBlockHash = chain.GenesisBlockHash.ToHex(),
                LastIrreversibleBlockHash = chain.LastIrreversibleBlockHash?.ToHex(),
                LastIrreversibleBlockHeight = chain.LastIrreversibleBlockHeight,
                BestChainHash = chain.BestChainHash?.ToHex(),
                BestChainHeight = chain.BestChainHeight
            });
        }
예제 #12
0
        public async Task CreateClient(ICrossChainCommunicationContext crossChainCommunicationContext)
        {
            if (_grpcCrossChainClients.ContainsKey(crossChainCommunicationContext.RemoteChainId))
            {
                return;
            }
            if (crossChainCommunicationContext.RemoteIsSideChain &&
                !_crossChainMemoryCacheService.GetCachedChainIds().Contains(crossChainCommunicationContext.RemoteChainId))
            {
                return; // dont create client for not cached remote side chain
            }
            var client = CreateGrpcClient((GrpcCrossChainCommunicationContext)crossChainCommunicationContext);

            Logger.LogTrace(
                $"Try shake with chain {ChainHelpers.ConvertChainIdToBase58(crossChainCommunicationContext.RemoteChainId)}");
            var reply = await TryRequest(client, c => c.TryHandShakeAsync(crossChainCommunicationContext.LocalChainId,
                                                                          ((GrpcCrossChainCommunicationContext)crossChainCommunicationContext).LocalListeningPort));

            if (reply == null || !reply.Result)
            {
                return;
            }
            _grpcCrossChainClients[crossChainCommunicationContext.RemoteChainId] = client;
        }
예제 #13
0
        //TODO: for testnet we only have a single chain, thus grouper only take care of txList in one chain (hence Process has chainId as parameter)
        public async Task <Tuple <List <List <Transaction> >, Dictionary <Transaction, Exception> > > ProcessNaive(int chainId, List <Transaction> transactions)
        {
            var txResourceHandle = new Dictionary <Transaction, string>();
            var failedTxs        = new Dictionary <Transaction, Exception>();

            if (transactions.Count == 0)
            {
                return(new Tuple <List <List <Transaction> >, Dictionary <Transaction, Exception> >(new List <List <Transaction> >(), failedTxs));
            }

            Dictionary <string, UnionFindNode> resourceUnionSet = new Dictionary <string, UnionFindNode>();

            //set up the union find set as the representation of graph and the connected components will be the resulting groups
            foreach (var tx in transactions)
            {
                UnionFindNode first = null;
                List <string> resources;
                try
                {
                    resources = (await _resourceUsageDetectionService.GetResources(tx)).ToList();
                }
                catch (Exception e)
                {
                    failedTxs.Add(tx, e);
                    continue;
                }

                //Logger.LogDebug(string.Format("tx {0} have resource [{1}]", tx.From, string.Join(" ||| ", resources)));
                foreach (var resource in resources)
                {
                    if (!resourceUnionSet.TryGetValue(resource, out var node))
                    {
                        node = new UnionFindNode();
                        resourceUnionSet.Add(resource, node);
                    }
                    if (first == null)
                    {
                        first = node;
                        txResourceHandle.Add(tx, resource);
                    }
                    else
                    {
                        node.Union(first);
                    }
                }
            }

            Dictionary <int, List <Transaction> > grouped = new Dictionary <int, List <Transaction> >();
            List <List <Transaction> >            result  = new List <List <Transaction> >();

            foreach (var tx in transactions)
            {
                if (txResourceHandle.TryGetValue(tx, out var firstResource))
                {
                    int nodeId = resourceUnionSet[firstResource].Find().NodeId;
                    if (!grouped.TryGetValue(nodeId, out var group))
                    {
                        group = new List <Transaction>();
                        grouped.Add(nodeId, group);
                    }
                    group.Add(tx);
                }
                else
                {
                    if (!failedTxs.ContainsKey(tx))
                    {
                        //each "resource-free" transaction have its own group
                        result.Add(new List <Transaction>()
                        {
                            tx
                        });
                    }
                }
            }
            result.AddRange(grouped.Values);

            Logger.LogInformation(string.Format(
                                      "Grouper on chainId \"{0}\" group [{1}] transactions into [{2}] groups with sizes [{3}], There are also {4} transactions failed retriving resource", ChainHelpers.ConvertChainIdToBase58(chainId),
                                      transactions.Count, result.Count, string.Join(", ", result.Select(a => a.Count)), failedTxs.Count));

            return(new Tuple <List <List <Transaction> >, Dictionary <Transaction, Exception> >(result, failedTxs));
        }