/// <summary>
        /// Response to indexing request from main 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 IndexServerStreaming(RequestBlockInfo request,
                                                        IServerStreamWriter <ResponseSideChainBlockInfo> responseStream, ServerCallContext context)
        {
            // TODO: verify the from address and the chain
            _logger?.Debug("Side Chain Server received IndexedInfo message.");

            try
            {
                var height = request.NextHeight;
                while (height <= await LightChain.GetCurrentBlockHeightAsync())
                {
                    var blockHeader = await LightChain.GetHeaderByHeightAsync(height);

                    var res = new ResponseSideChainBlockInfo
                    {
                        Success   = blockHeader != null,
                        BlockInfo = blockHeader == null ? null : new SideChainBlockInfo
                        {
                            Height            = height,
                            BlockHeaderHash   = blockHeader.GetHash(),
                            TransactionMKRoot = blockHeader.MerkleTreeRootOfTransactions,
                            ChainId           = blockHeader.ChainId
                        }
                    };
                    //_logger?.Log(LogLevel.Debug, $"Side Chain Server responsed IndexedInfo message of height {height}");
                    await responseStream.WriteAsync(res);

                    height++;
                }
            }
            catch (Exception e)
            {
                _logger?.Error(e, "Exception while index server streaming.");
            }
        }
Ejemplo n.º 2
0
        /// <summary>
        /// Start to request only once but response many (one by one)
        /// </summary>
        /// <param name="next"></param>
        /// <returns></returns>
        public async Task StartServerStreamingCall(ulong next)
        {
            _next = Math.Max(next, ToBeIndexedInfoQueue.Last()?.Height ?? -1 + 1);
            try
            {
                var request = new RequestBlockInfo
                {
                    ChainId    = Hash.LoadHex(ChainConfig.Instance.ChainId),
                    NextHeight = ToBeIndexedInfoQueue.Count == 0 ? _next : ToBeIndexedInfoQueue.Last().Height + 1
                };

                using (var call = Call(request))
                {
                    while (await call.ResponseStream.MoveNext())
                    {
                        var response = call.ResponseStream.Current;

                        // request failed or useless response
                        if (!response.Success || response.Height != _next)
                        {
                            continue;
                        }
                        if (ToBeIndexedInfoQueue.TryAdd(response.BlockInfoResult))
                        {
                            _next++;
                        }
                    }
                }
            }
            catch (RpcException e)
            {
                _logger.Error(e);
                throw;
            }
        }
        /// <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.");
            }
        }
Ejemplo n.º 4
0
        /// <summary>
        /// Task to create request in loop.
        /// </summary>
        /// <param name="call"></param>
        /// <param name="cancellationToken"></param>
        /// <returns></returns>
        private async Task RequestLoop(AsyncDuplexStreamingCall <RequestBlockInfo, TResponse> call,
                                       CancellationToken cancellationToken)
        {
            while (!cancellationToken.IsCancellationRequested)
            {
                var request = new RequestBlockInfo
                {
                    ChainId    = Hash.LoadHex(ChainConfig.Instance.ChainId),
                    NextHeight = ToBeIndexedInfoQueue.Count == 0 ? _next : ToBeIndexedInfoQueue.Last().Height + 1
                };
                //_logger.Trace($"New request for height {request.NextHeight} to chain {_targetChainId.DumpHex()}");
                await call.RequestStream.WriteAsync(request);

                await Task.Delay(_realInterval);
            }
        }
Ejemplo n.º 5
0
 protected override AsyncServerStreamingCall <ResponseParentChainBlockInfo> Call(RequestBlockInfo requestBlockInfo)
 {
     return(_client.RecordServerStreaming(requestBlockInfo));
 }
Ejemplo n.º 6
0
 protected abstract AsyncServerStreamingCall <TResponse> Call(RequestBlockInfo requestBlockInfo);
Ejemplo n.º 7
0
 protected override AsyncServerStreamingCall <ResponseSideChainBlockInfo> Call(RequestBlockInfo requestBlockInfo)
 {
     return(_client.IndexServerStreaming(requestBlockInfo));
 }