protected override async Task ProcessItemAsync(RpcMessage <BeaconBlocksByRange> rpcMessage)
        {
            try
            {
                if (rpcMessage.Direction == RpcDirection.Request)
                {
                    if (_logger.IsDebug())
                    {
                        LogDebug.ProcessBeaconBlocksByRange(_logger, rpcMessage.Content, null);
                    }

                    // TODO: Add some sanity checks on request to prevent DoS
                    // TODO: Maybe add limit on number of blocks (as allowed by spec)

                    Slot slot = new Slot(rpcMessage.Content.StartSlot +
                                         rpcMessage.Content.Step * (rpcMessage.Content.Count - 1));
                    Stack <(Root root, SignedBeaconBlock signedBlock)> signedBlocks =
                        new Stack <(Root, SignedBeaconBlock)>();
                    // Search backwards from head for the requested slots
                    Root root = rpcMessage.Content.HeadBlockRoot;
                    while (slot >= rpcMessage.Content.StartSlot)
                    {
                        root = await _forkChoice.GetAncestorAsync(_store, root, slot);

                        SignedBeaconBlock signedBlock = await _store.GetSignedBlockAsync(root);

                        if (signedBlock.Message.Slot == slot)
                        {
                            signedBlocks.Push((root, signedBlock));
                        }
                        else
                        {
                            // block is skipped
                            if (_logger.IsWarn())
                            {
                                Log.RequestedBlockSkippedSlot(_logger, slot, rpcMessage.Content.HeadBlockRoot, null);
                            }
                        }

                        // If they requested for slot 0, then include it (anchor block is usually null), but don't underflow
                        if (slot == Slot.Zero)
                        {
                            break;
                        }
                        slot = slot - Slot.One;
                    }

                    // Send each block in a response chunk, in slot order
                    foreach (var data in signedBlocks)
                    {
                        if (_logger.IsDebug())
                        {
                            LogDebug.SendingRequestBlocksByRangeResponse(_logger, data.signedBlock.Message, data.root,
                                                                         null);
                        }

                        await _networkPeering.SendBlockAsync(rpcMessage.PeerId, data.signedBlock);
                    }
                }
                else
                {
                    throw new Exception($"Unexpected direction {rpcMessage.Direction}");
                }
            }
            catch (Exception ex)
            {
                if (_logger.IsError())
                {
                    Log.HandleRpcStatusError(_logger, rpcMessage.PeerId, ex.Message, ex);
                }
            }
        }
Example #2
0
        private void OnRpcReceived(ReadOnlySpan <byte> methodUtf8, int requestResponseFlag, ReadOnlySpan <byte> peerUtf8,
                                   ReadOnlySpan <byte> data)
        {
            Activity activity = new Activity("rpc-received");

            activity.Start();
            try
            {
                string       peerId       = Encoding.UTF8.GetString(peerUtf8);
                RpcDirection rpcDirection = requestResponseFlag == 0 ? RpcDirection.Request : RpcDirection.Response;

                // Even though the value '/eth2/beacon_chain/req/status/1/' is sent, when Mothra calls the received event it is 'HELLO'
                // if (methodUtf8.SequenceEqual(MethodUtf8.Status)
                //     || methodUtf8.SequenceEqual(MethodUtf8.StatusMothraAlternative))
                if (data.Length == Ssz.Ssz.PeeringStatusLength)
                {
                    if (_logger.IsDebug())
                    {
                        LogDebug.RpcReceived(_logger, rpcDirection, requestResponseFlag,
                                             Encoding.UTF8.GetString(methodUtf8),
                                             peerId, data.Length, nameof(MethodUtf8.Status), null);
                    }

                    PeeringStatus peeringStatus = Ssz.Ssz.DecodePeeringStatus(data);
                    RpcMessage <PeeringStatus> statusRpcMessage =
                        new RpcMessage <PeeringStatus>(peerId, rpcDirection, peeringStatus);
                    _rpcPeeringStatusProcessor.Enqueue(statusRpcMessage);
                }
                //else if (methodUtf8.SequenceEqual(MethodUtf8.BeaconBlocksByRange))
                else if (data.Length == Ssz.Ssz.BeaconBlocksByRangeLength ||
                         data.Length >= _minimumSignedBeaconBlockLength)
                {
                    if (_logger.IsDebug())
                    {
                        LogDebug.RpcReceived(_logger, rpcDirection, requestResponseFlag,
                                             Encoding.UTF8.GetString(methodUtf8),
                                             peerId, data.Length, nameof(MethodUtf8.BeaconBlocksByRange), null);
                    }

                    //if (rpcDirection == RpcDirection.Request)
                    if (data.Length == Ssz.Ssz.BeaconBlocksByRangeLength)
                    {
                        BeaconBlocksByRange beaconBlocksByRange     = Ssz.Ssz.DecodeBeaconBlocksByRange(data);
                        RpcMessage <BeaconBlocksByRange> rpcMessage =
                            new RpcMessage <BeaconBlocksByRange>(peerId, rpcDirection, beaconBlocksByRange);
                        _rpcBeaconBlocksByRangeProcessor.Enqueue(rpcMessage);
                    }
                    else
                    {
                        SignedBeaconBlock signedBeaconBlock = Ssz.Ssz.DecodeSignedBeaconBlock(data);
                        _signedBeaconBlockProcessor.Enqueue(signedBeaconBlock, peerId);
                    }
                }
                else
                {
                    // TODO: handle other RPC
                    if (_logger.IsWarn())
                    {
                        Log.UnknownRpcReceived(_logger, rpcDirection, requestResponseFlag,
                                               Encoding.UTF8.GetString(methodUtf8), peerId,
                                               data.Length, null);
                    }
                }
            }
            catch (Exception ex)
            {
                if (_logger.IsError())
                {
                    Log.RpcReceivedError(_logger, Encoding.UTF8.GetString(methodUtf8), ex.Message, ex);
                }
            }
            finally
            {
                activity.Stop();
            }
        }
 public void Enqueue(RpcMessage <BeaconBlocksByRange> rpcMessage)
 {
     EnqueueItem(rpcMessage);
 }
 public void Enqueue(RpcMessage <PeeringStatus> statusRpcMessage)
 {
     EnqueueItem(statusRpcMessage);
 }