private void Handle(GetBlockHeadersMessage getBlockHeadersMessage)
        {
            if (Logger.IsTrace)
            {
                Logger.Trace($"GetBlockHeaders.MaxHeaders: {getBlockHeadersMessage.MaxHeaders}");
                Logger.Trace($"GetBlockHeaders.Reverse: {getBlockHeadersMessage.Reverse}");
                Logger.Trace($"GetBlockHeaders.Skip: {getBlockHeadersMessage.Skip}");
                Logger.Trace($"GetBlockHeaders.StartingBlockhash: {getBlockHeadersMessage.StartingBlockHash}");
                Logger.Trace($"GetBlockHeaders.StartingBlockNumber: {getBlockHeadersMessage.StartingBlockNumber}");
            }

            Keccak startingHash = getBlockHeadersMessage.StartingBlockHash;

            if (startingHash == null)
            {
                startingHash = SyncManager.Find(getBlockHeadersMessage.StartingBlockNumber)?.Hash;
            }

            Block[] blocks =
                startingHash == null
                    ? new Block[0]
                    : SyncManager.Find(startingHash, (int)getBlockHeadersMessage.MaxHeaders, (int)getBlockHeadersMessage.Skip, getBlockHeadersMessage.Reverse == 1);

            BlockHeader[] headers = new BlockHeader[blocks.Length];
            for (int i = 0; i < blocks.Length; i++)
            {
                headers[i] = blocks[i]?.Header;
            }

            Send(new BlockHeadersMessage(headers));
        }
Example #2
0
        async Task <BlockHeader[]> ISyncPeer.GetBlockHeaders(long number, int maxBlocks, int skip, CancellationToken token)
        {
            if (maxBlocks == 0)
            {
                return(new BlockHeader[0]);
            }

            var msg = new GetBlockHeadersMessage();

            msg.MaxHeaders          = maxBlocks;
            msg.Reverse             = 0;
            msg.Skip                = skip;
            msg.StartingBlockNumber = number;

            // Logger.Info($"Sending headers request ({number}, {maxBlocks}, {skip}) to {this}");

            BlockHeader[] headers = await SendRequest(msg, token);

            // int nonNullCount = 0;
            // for (int i = 0; i < headers.Length; i++)
            // {
            //     if (headers[i] != null)
            //     {
            //         nonNullCount++;
            //     }
            // }

            // Logger.Info($"Sent headers request ({number}, {maxBlocks}, {skip}) to {this} - received {headers.Length}, out of which {nonNullCount} non null");
            return(headers);
        }
Example #3
0
        private void Handle(GetBlockHeadersMessage getBlockHeadersMessage)
        {
            if (Logger.IsTrace)
            {
                Logger.Trace($"GetBlockHeaders.MaxHeaders: {getBlockHeadersMessage.MaxHeaders}");
                Logger.Trace($"GetBlockHeaders.Reverse: {getBlockHeadersMessage.Reverse}");
                Logger.Trace($"GetBlockHeaders.Skip: {getBlockHeadersMessage.Skip}");
                Logger.Trace($"GetBlockHeaders.StartingBlockhash: {getBlockHeadersMessage.StartingBlockHash}");
                Logger.Trace($"GetBlockHeaders.StartingBlockNumber: {getBlockHeadersMessage.StartingBlockNumber}");
            }

            Keccak startingHash = getBlockHeadersMessage.StartingBlockHash;

            if (startingHash == null)
            {
                startingHash = SyncServer.Find(getBlockHeadersMessage.StartingBlockNumber)?.Hash;
            }

            BlockHeader[] headers =
                startingHash == null
                    ? new BlockHeader[0]
                    : SyncServer.FindHeaders(startingHash, (int)getBlockHeadersMessage.MaxHeaders, (int)getBlockHeadersMessage.Skip, getBlockHeadersMessage.Reverse == 1);

            Send(new BlockHeadersMessage(headers));
        }
        async Task <BlockHeader> ISynchronizationPeer.GetHeadBlockHeader(CancellationToken token)
        {
            var msg = new GetBlockHeadersMessage();

            msg.StartingBlockHash = _remoteHeadBlockHash;
            msg.MaxHeaders        = 1;
            msg.Reverse           = 0;
            msg.Skip = 0;

            BlockHeader[] headers = await SendRequest(msg, token);

            return(headers.Length > 0 ? headers[0] : null);
        }
        async Task <BlockHeader[]> ISynchronizationPeer.GetBlockHeaders(UInt256 number, int maxBlocks, int skip, CancellationToken token)
        {
            var msg = new GetBlockHeadersMessage();

            msg.MaxHeaders          = maxBlocks;
            msg.Reverse             = 0;
            msg.Skip                = skip;
            msg.StartingBlockNumber = number;

            BlockHeader[] headers = await SendRequest(msg, token);

            return(headers);
        }
Example #6
0
        async Task <BlockHeader[]> ISyncPeer.GetBlockHeaders(Keccak blockHash, int maxBlocks, int skip, CancellationToken token)
        {
            var msg = new GetBlockHeadersMessage();

            msg.MaxHeaders        = maxBlocks;
            msg.Reverse           = 0;
            msg.Skip              = skip;
            msg.StartingBlockHash = blockHash;

            BlockHeader[] headers = await SendRequest(msg, token);

            return(headers);
        }
Example #7
0
        async Task <UInt256> ISynchronizationPeer.GetHeadDifficulty(CancellationToken token)
        {
            var msg = new GetBlockHeadersMessage();

            msg.StartingBlockHash = _remoteHeadBlockHash;
            msg.MaxHeaders        = 1;
            msg.Reverse           = 0;
            msg.Skip = 0;

            BlockHeader[] headers = await SendRequest(msg, token);

            return(headers[0]?.Difficulty ?? 0);
        }
Example #8
0
        private async Task <BlockHeader[]> SendRequest(GetBlockHeadersMessage message, CancellationToken token)
        {
            if (_headersRequests.IsAddingCompleted || _isDisposed)
            {
                throw new TimeoutException("Session disposed");
            }

            if (Logger.IsTrace)
            {
                Logger.Trace($"Sending headers request to {Session.Node:c}:");
                Logger.Trace($"  Starting blockhash: {message.StartingBlockHash}");
                Logger.Trace($"  Starting number: {message.StartingBlockNumber}");
                Logger.Trace($"  Skip: {message.Skip}");
                Logger.Trace($"  Reverse: {message.Reverse}");
                Logger.Trace($"  Max headers: {message.MaxHeaders}");
            }

            var request = new Request <GetBlockHeadersMessage, BlockHeader[]>(message);

            _headersRequests.Add(request, token);
            request.StartMeasuringTime();

            Send(request.Message);
            Task <BlockHeader[]> task = request.CompletionSource.Task;

            using CancellationTokenSource delayCancellation     = new CancellationTokenSource();
            using CancellationTokenSource compositeCancellation = CancellationTokenSource.CreateLinkedTokenSource(token, delayCancellation.Token);
            var firstTask = await Task.WhenAny(task, Task.Delay(Timeouts.Eth, compositeCancellation.Token));

            if (firstTask.IsCanceled)
            {
                token.ThrowIfCancellationRequested();
            }

            if (firstTask == task)
            {
                delayCancellation.Cancel();
                long elapsed             = request.FinishMeasuringTime();
                long bytesPerMillisecond = (long)((decimal)request.ResponseSize / Math.Max(1, elapsed));
                if (Logger.IsTrace)
                {
                    Logger.Trace($"{this} speed is {request.ResponseSize}/{elapsed} = {bytesPerMillisecond}");
                }

                StatsManager.ReportTransferSpeedEvent(Session.Node, bytesPerMillisecond);
                return(task.Result);
            }

            StatsManager.ReportTransferSpeedEvent(Session.Node, 0);
            throw new TimeoutException($"{Session} Request timeout in {nameof(GetBlockHeadersMessage)} with {message.MaxHeaders} max headers");
        }
        private async Task <BlockHeader[]> SendRequest(GetBlockHeadersMessage message, CancellationToken token)
        {
            if (_headersRequests.IsAddingCompleted || _isDisposed)
            {
                throw new TimeoutException("Session disposed");
            }

            if (Logger.IsTrace)
            {
                Logger.Trace($"Sending headers request to {Session.Node:c}:");
                Logger.Trace($"  Starting blockhash: {message.StartingBlockHash}");
                Logger.Trace($"  Starting number: {message.StartingBlockNumber}");
                Logger.Trace($"  Skip: {message.Skip}");
                Logger.Trace($"  Reverse: {message.Reverse}");
                Logger.Trace($"  Max headers: {message.MaxHeaders}");
            }

            var request = new Request <GetBlockHeadersMessage, BlockHeader[]>(message);

            _headersRequests.Add(request, token);

            var perfCalcId = _perfService.StartPerfCalc();

            Send(request.Message);
            Task <BlockHeader[]>    task = request.CompletionSource.Task;
            CancellationTokenSource delayCancellation     = new CancellationTokenSource();
            CancellationTokenSource compositeCancellation = CancellationTokenSource.CreateLinkedTokenSource(token, delayCancellation.Token);
            var firstTask = await Task.WhenAny(task, Task.Delay(Timeouts.Eth, compositeCancellation.Token));

            if (firstTask.IsCanceled)
            {
                token.ThrowIfCancellationRequested();
            }

            if (firstTask == task)
            {
                delayCancellation.Cancel();
                var latency = _perfService.EndPerfCalc(perfCalcId);
                if (latency.HasValue)
                {
                    StatsManager.ReportLatencyCaptureEvent(Session.Node, NodeLatencyStatType.BlockHeaders, latency.Value);
                }

                return(task.Result);
            }

            _perfService.EndPerfCalc(perfCalcId);
            throw new TimeoutException($"{Session} Request timeout in {nameof(GetBlockHeadersMessage)} with {message.MaxHeaders} max headers");
        }
Example #10
0
        private void Handle(GetBlockHeadersMessage getBlockHeadersMessage)
        {
            Stopwatch stopwatch = Stopwatch.StartNew();

            if (Logger.IsTrace)
            {
                Logger.Trace($"Received headers request from {Session.Node:c}:");
                Logger.Trace($"  MaxHeaders: {getBlockHeadersMessage.MaxHeaders}");
                Logger.Trace($"  Reverse: {getBlockHeadersMessage.Reverse}");
                Logger.Trace($"  Skip: {getBlockHeadersMessage.Skip}");
                Logger.Trace($"  StartingBlockhash: {getBlockHeadersMessage.StartingBlockHash}");
                Logger.Trace($"  StartingBlockNumber: {getBlockHeadersMessage.StartingBlockNumber}");
            }

            Interlocked.Increment(ref Counter);

            // to clearly state that this client is an ETH client and not ETC (and avoid disconnections on reversed sync)
            // also to improve performance as this is the most common request
//            if (getBlockHeadersMessage.StartingBlockNumber == 1920000 && getBlockHeadersMessage.MaxHeaders == 1)
//            {
//                // hardcoded response
//                Packet packet = new Packet(ProtocolCode, Eth62MessageCode.BlockHeaders, Bytes.FromHexString("f90210f9020da0a218e2c611f21232d857e3c8cecdcdf1f65f25a4477f98f6f47e4063807f2308a01dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d4934794bcdfc35b86bedf72f0cda046a3c16829a2ef41d1a0c5e389416116e3696cce82ec4533cce33efccb24ce245ae9546a4b8f0d5e9a75a07701df8e07169452554d14aadd7bfa256d4a1d0355c1d174ab373e3e2d0a3743a026cf9d9422e9dd95aedc7914db690b92bab6902f5221d62694a2fa5d065f534bb90100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008638c3bf2616aa831d4c008347e7c08301482084578f7aa88d64616f2d686172642d666f726ba05b5acbf4bf305f948bd7be176047b20623e1417f75597341a059729165b9239788bede87201de42426"));
//                Session.DeliverMessage(packet);
//                if (Logger.IsTrace) Logger.Trace($"OUT {_counter:D5} hardcoded 1920000 BlockHeaders to {Node:c}");
//                return;
//            }

            Keccak startingHash = getBlockHeadersMessage.StartingBlockHash;

            if (startingHash == null)
            {
                startingHash = SyncServer.FindHash(getBlockHeadersMessage.StartingBlockNumber);
            }

            BlockHeader[] headers =
                startingHash == null
                    ? Array.Empty <BlockHeader>()
                    : SyncServer.FindHeaders(startingHash, (int)getBlockHeadersMessage.MaxHeaders, (int)getBlockHeadersMessage.Skip, getBlockHeadersMessage.Reverse == 1);

            headers = FixHeadersForGeth(headers);

            Send(new BlockHeadersMessage(headers));
            stopwatch.Stop();
            if (Logger.IsTrace)
            {
                Logger.Trace($"OUT {Counter:D5} BlockHeaders to {Node:c} in {stopwatch.Elapsed.TotalMilliseconds}ms");
            }
        }
Example #11
0
        async Task <BlockHeader[]> ISyncPeer.GetBlockHeaders(long number, int maxBlocks, int skip, CancellationToken token)
        {
            if (maxBlocks == 0)
            {
                return(new BlockHeader[0]);
            }

            var msg = new GetBlockHeadersMessage();

            msg.MaxHeaders          = maxBlocks;
            msg.Reverse             = 0;
            msg.Skip                = skip;
            msg.StartingBlockNumber = number;

            BlockHeader[] headers = await SendRequest(msg, token);

            return(headers);
        }
        private async Task <BlockHeader[]> SendRequest(GetBlockHeadersMessage message, CancellationToken token)
        {
            if (Logger.IsTrace)
            {
                Logger.Trace("Sending headers request:");
                Logger.Trace($"Starting blockhash: {message.StartingBlockHash}");
                Logger.Trace($"Starting number: {message.StartingBlockNumber}");
                Logger.Trace($"Skip: {message.Skip}");
                Logger.Trace($"Reverse: {message.Reverse}");
                Logger.Trace($"Max headers: {message.MaxHeaders}");
            }

            var request = new Request <GetBlockHeadersMessage, BlockHeader[]>(message);

            _headersRequests.Add(request, token);
            var perfCalcId = _perfService.StartPerfCalc();

            Send(request.Message);
            Task <BlockHeader[]> task = request.CompletionSource.Task;
            var firstTask             = await Task.WhenAny(task, Task.Delay(Timeouts.Eth, token));

            if (firstTask.IsCanceled)
            {
                token.ThrowIfCancellationRequested();
            }

            if (firstTask == task)
            {
                var latency = _perfService.EndPerfCalc(perfCalcId);
                if (latency.HasValue)
                {
                    P2PSession?.NodeStats.AddLatencyCaptureEvent(NodeLatencyStatType.BlockHeaders, latency.Value);
                }

                return(task.Result);
            }

            throw new TimeoutException($"{P2PSession.RemoteNodeId} Request timeout in {nameof(GetBlockHeadersMessage)}");
        }
        public virtual void HandleMessage(ZeroPacket message)
        {
            if (Logger.IsTrace)
            {
                Logger.Trace($"Handling {message} message from {Session.Node:c}.");
            }

            if (message.PacketType != Eth62MessageCode.Status && !_statusReceived)
            {
                throw new SubprotocolException($"No {nameof(StatusMessage)} received prior to communication with {Session.Node:c}.");
            }

            int size = message.Content.ReadableBytes;

            // Logger.Warn($"Received a message {message.Protocol}.{Enum.GetName(typeof(Eth62MessageCode), message.PacketType)} of size {size/1024}kb");

            switch (message.PacketType)
            {
            case Eth62MessageCode.Status:
                StatusMessage statusMessage = Deserialize <StatusMessage>(message.Content);
                if (NetworkDiagTracer.IsEnabled)
                {
                    NetworkDiagTracer.ReportIncomingMessage(Session.Node.Host, Name, statusMessage.ToString());
                }
                Handle(statusMessage);
                break;

            case Eth62MessageCode.NewBlockHashes:
                if (NetworkDiagTracer.IsEnabled)
                {
                    NetworkDiagTracer.ReportIncomingMessage(Session.Node.Host, Name, nameof(NewBlockHashesMessage));
                }
                Interlocked.Increment(ref Counter);
                if (Logger.IsTrace)
                {
                    Logger.Trace($"{Counter:D5} NewBlockHashes from {Node:c}");
                }
                Metrics.Eth62NewBlockHashesReceived++;
                Handle(Deserialize <NewBlockHashesMessage>(message.Content));
                break;

            case Eth62MessageCode.Transactions:
                Interlocked.Increment(ref Counter);
                Metrics.Eth62TransactionsReceived++;
                TransactionsMessage transactionsMessage = Deserialize <TransactionsMessage>(message.Content);
                if (NetworkDiagTracer.IsEnabled)
                {
                    NetworkDiagTracer.ReportIncomingMessage(Session.Node.Host, Name, $"{nameof(TransactionsMessage)}({transactionsMessage.Transactions.Length})");
                }
                if (!_isDowngradedDueToTxFlooding || 10 > _random.Next(0, 99))     // TODO: disable that when IsMining is set to true
                {
                    Handle(transactionsMessage);
                }

                break;

            case Eth62MessageCode.GetBlockHeaders:
                Interlocked.Increment(ref Counter);
                if (Logger.IsTrace)
                {
                    Logger.Trace($"{Counter:D5} GetBlockHeaders from {Node:c}");
                }
                Metrics.Eth62GetBlockHeadersReceived++;
                GetBlockHeadersMessage getBlockHeadersMessage = Deserialize <GetBlockHeadersMessage>(message.Content);
                if (NetworkDiagTracer.IsEnabled)
                {
                    NetworkDiagTracer.ReportIncomingMessage(Session.Node.Host, Name, $"{nameof(GetBlockHeadersMessage)}({getBlockHeadersMessage.StartingBlockNumber}|{getBlockHeadersMessage.StartingBlockHash}, {getBlockHeadersMessage.MaxHeaders})");
                }
                Handle(getBlockHeadersMessage);
                break;

            case Eth62MessageCode.BlockHeaders:
                Interlocked.Increment(ref Counter);
                if (Logger.IsTrace)
                {
                    Logger.Trace($"{Counter:D5} BlockHeaders from {Node:c}");
                }
                Metrics.Eth62BlockHeadersReceived++;
                BlockHeadersMessage blockHeadersMessage = Deserialize <BlockHeadersMessage>(message.Content);
                if (NetworkDiagTracer.IsEnabled)
                {
                    NetworkDiagTracer.ReportIncomingMessage(Session.Node.Host, Name, $"{nameof(BlockHeadersMessage)}({blockHeadersMessage.BlockHeaders.Length})");
                }
                Handle(blockHeadersMessage, size);
                break;

            case Eth62MessageCode.GetBlockBodies:
                Interlocked.Increment(ref Counter);
                if (Logger.IsTrace)
                {
                    Logger.Trace($"{Counter:D5} GetBlockBodies from {Node:c}");
                }
                Metrics.Eth62GetBlockBodiesReceived++;
                GetBlockBodiesMessage getBlockBodiesMessage = Deserialize <GetBlockBodiesMessage>(message.Content);
                if (NetworkDiagTracer.IsEnabled)
                {
                    NetworkDiagTracer.ReportIncomingMessage(Session.Node.Host, Name, $"{nameof(GetBlockBodiesMessage)}({getBlockBodiesMessage.BlockHashes.Count})");
                }
                Handle(getBlockBodiesMessage);
                break;

            case Eth62MessageCode.BlockBodies:
                Interlocked.Increment(ref Counter);
                if (Logger.IsTrace)
                {
                    Logger.Trace($"{Counter:D5} BlockBodies from {Node:c}");
                }
                Metrics.Eth62BlockBodiesReceived++;
                BlockBodiesMessage blockBodiesMessage = Deserialize <BlockBodiesMessage>(message.Content);
                if (NetworkDiagTracer.IsEnabled)
                {
                    NetworkDiagTracer.ReportIncomingMessage(Session.Node.Host, Name, $"{nameof(BlockBodiesMessage)}({blockBodiesMessage.Bodies.Length})");
                }
                Handle(blockBodiesMessage, size);
                break;

            case Eth62MessageCode.NewBlock:
                Interlocked.Increment(ref Counter);
                if (Logger.IsTrace)
                {
                    Logger.Trace($"{Counter:D5} NewBlock from {Node:c}");
                }
                Metrics.Eth62NewBlockReceived++;
                NewBlockMessage newBlockMessage = Deserialize <NewBlockMessage>(message.Content);
                if (NetworkDiagTracer.IsEnabled)
                {
                    NetworkDiagTracer.ReportIncomingMessage(Session.Node.Host, Name, $"{nameof(NewBlockMessage)}({newBlockMessage.Block.Number})");
                }
                Handle(newBlockMessage);
                break;
            }
        }