/// <summary> /// Response to recording request from side chain node. /// One request to many responses. /// </summary> /// <param name="request"></param> /// <param name="responseStream"></param> /// <param name="context"></param> /// <returns></returns> public override async Task RecordServerStreaming(RequestBlockInfo request, IServerStreamWriter <ResponseParentChainBlockInfo> responseStream, ServerCallContext context) { _logger?.Trace("Parent Chain Server received IndexedInfo message."); try { var height = request.NextHeight; var sideChainId = request.ChainId; while (height <= await BlockChain.GetCurrentBlockHeightAsync()) { IBlock block = await BlockChain.GetBlockByHeightAsync(height); BlockHeader header = block?.Header; BlockBody body = block?.Body; var res = new ResponseParentChainBlockInfo { Success = block != null }; if (res.Success) { res.BlockInfo = new ParentChainBlockInfo { Root = new ParentChainBlockRootInfo { Height = height, SideChainBlockHeadersRoot = header?.SideChainBlockHeadersRoot, SideChainTransactionsRoot = header?.SideChainTransactionsRoot, ChainId = header?.ChainId } }; var tree = await _binaryMerkleTreeManager .GetSideChainTransactionRootsMerkleTreeByHeightAsync(header?.ChainId, height); //Todo: this is to tell side chain the height of side chain block in this main chain block, which could be removed with subsequent improvement. body?.IndexedInfo.Where(predicate: i => i.ChainId.Equals(sideChainId)) .Select((info, index) => new KeyValuePair <ulong, MerklePath>(info.Height, tree.GenerateMerklePath(index))) .ForEach(kv => res.BlockInfo.IndexedBlockInfo.Add(kv.Key, kv.Value)); } //_logger?.Log(LogLevel.Trace, $"Parent Chain Server responsed IndexedInfo message of height {height}"); await responseStream.WriteAsync(res); height++; } } catch (Exception e) { _logger?.Error(e, "Miner server RecordDuplexStreaming failed."); } }
/// <summary> /// Response to recording request from side chain node. /// Many requests to many responses. /// </summary> /// <param name="requestStream"></param> /// <param name="responseStream"></param> /// <param name="context"></param> /// <returns></returns> public override async Task RecordDuplexStreaming(IAsyncStreamReader <RequestBlockInfo> requestStream, IServerStreamWriter <ResponseParentChainBlockInfo> responseStream, ServerCallContext context) { _logger?.Debug("Parent Chain Server received IndexedInfo message."); try { while (await requestStream.MoveNext()) { var requestInfo = requestStream.Current; var requestedHeight = requestInfo.NextHeight; var sideChainId = requestInfo.ChainId; var currentHeight = await BlockChain.GetCurrentBlockHeightAsync(); if (currentHeight - requestedHeight < (ulong)GlobalConfig.InvertibleChainHeight) { await responseStream.WriteAsync(new ResponseParentChainBlockInfo { Success = false }); continue; } IBlock block = await BlockChain.GetBlockByHeightAsync(requestedHeight); BlockHeader header = block?.Header; BlockBody body = block?.Body; var res = new ResponseParentChainBlockInfo { Success = block != null }; if (res.Success) { res.BlockInfo = new ParentChainBlockInfo { Root = new ParentChainBlockRootInfo { Height = requestedHeight, SideChainBlockHeadersRoot = header?.SideChainBlockHeadersRoot, SideChainTransactionsRoot = header?.SideChainTransactionsRoot, ChainId = header?.ChainId } }; var tree = await _binaryMerkleTreeManager .GetSideChainTransactionRootsMerkleTreeByHeightAsync(header?.ChainId, requestedHeight); if (tree != null) { //Todo: this is to tell side chain the merkle path for one side chain block, which could be removed with subsequent improvement. /*body?.IndexedInfo.Where(predicate: i => i.ChainId.Equals(sideChainId)) * .Select((info, index) => * new KeyValuePair<ulong, MerklePath>(info.Height, tree.GenerateMerklePath(index))) * .ForEach(kv => res.BlockInfo.IndexedBlockInfo.Add(kv.Key, kv.Value));*/ for (int i = 0; i < body?.IndexedInfo.Count; i++) { var info = body.IndexedInfo[i]; if (!info.ChainId.Equals(sideChainId)) { continue; } var merklePath = tree.GenerateMerklePath(i); if (merklePath == null) { _logger?.Trace($"tree.Root == null: {tree.Root == null}"); _logger?.Trace($"tree.LeafCount = {tree.LeafCount}, index = {i}"); } res.BlockInfo.IndexedBlockInfo.Add(info.Height, merklePath); } } } await responseStream.WriteAsync(res); } } catch (Exception e) { _logger?.Error(e, "Miner server RecordDuplexStreaming failed."); } }