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); }
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); }
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()); }
/// <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); }
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)); }
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)); } }
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); } }
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); }
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); }
/// <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 }); }
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; }
//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)); }