public Task RequestBlocksAsync(string peerId, Root peerHeadRoot, Slot finalizedSlot, Slot peerHeadSlot)
        {
            // NOTE: Currently just requests entire range, one at a time, to get small testnet working.
            // Will need more sophistication in future, e.g. request interleaved blocks and stuff.

            // Start with the block for the next slot after our finalized state
            Slot  startSlot = finalizedSlot + Slot.One;
            ulong count     = peerHeadSlot - finalizedSlot;
            ulong step      = 1;
            BeaconBlocksByRange beaconBlocksByRange = new BeaconBlocksByRange(peerHeadRoot, startSlot, count, step);

            byte[]      peerUtf8 = Encoding.UTF8.GetBytes(peerId);
            Span <byte> encoded  = new byte[Ssz.Ssz.BeaconBlocksByRangeLength];

            Ssz.Ssz.Encode(encoded, beaconBlocksByRange);

            if (_logger.IsDebug())
            {
                LogDebug.RpcSend(_logger, RpcDirection.Request, nameof(MethodUtf8.BeaconBlocksByRange), peerId,
                                 encoded.Length, null);
            }

            if (!_mothraLibp2p.SendRpcRequest(MethodUtf8.BeaconBlocksByRange, peerUtf8, encoded))
            {
                if (_logger.IsWarn())
                {
                    Log.RpcRequestNotSentAsPeeeringNotStarted(_logger, nameof(MethodUtf8.BeaconBlocksByRange), null);
                }
            }

            return(Task.CompletedTask);
        }
Esempio n. 2
0
        public static void Encode(Span <byte> span, BeaconBlocksByRange container)
        {
            if (span.Length != BeaconBlocksByRangeLength)
            {
                ThrowTargetLength <BeaconBlocksByRange>(span.Length, BeaconBlocksByRangeLength);
            }
            int offset = 0;

            Encode(span, container.HeadBlockRoot, ref offset);
            Encode(span, container.StartSlot, ref offset);
            Encode(span, container.Count, ref offset);
            Encode(span, container.Step, ref offset);
        }
Esempio n. 3
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 async Task BlocksByRangeRequestShouldCreateResponse()
        {
            // arrange
            Root root6       = new Root(Enumerable.Repeat((byte)0x67, 32).ToArray());
            Root root4       = new Root(Enumerable.Repeat((byte)0x45, 32).ToArray());
            Root root2       = new Root(Enumerable.Repeat((byte)0x23, 32).ToArray());
            Root requestRoot = root6;

            SignedBeaconBlock block6 = new SignedBeaconBlock(new BeaconBlock(new Slot(6), root4, Root.Zero, BeaconBlockBody.Zero),
                                                             BlsSignature.Zero);
            SignedBeaconBlock block4 = new SignedBeaconBlock(new BeaconBlock(new Slot(4), root2, Root.Zero, BeaconBlockBody.Zero),
                                                             BlsSignature.Zero);
            SignedBeaconBlock block2 = new SignedBeaconBlock(new BeaconBlock(new Slot(2), Root.Zero, Root.Zero, BeaconBlockBody.Zero),
                                                             BlsSignature.Zero);

            _mockForkChoice.GetAncestorAsync(Arg.Any <IStore>(), Arg.Any <Root>(), Arg.Any <Slot>()).Returns(Root.Zero);
            _mockForkChoice.GetAncestorAsync(Arg.Any <IStore>(), Arg.Any <Root>(), new Slot(6)).Returns(root6);
            _mockForkChoice.GetAncestorAsync(Arg.Any <IStore>(), Arg.Any <Root>(), new Slot(5)).Returns(root4);
            _mockForkChoice.GetAncestorAsync(Arg.Any <IStore>(), Arg.Any <Root>(), new Slot(4)).Returns(root4);
            _mockForkChoice.GetAncestorAsync(Arg.Any <IStore>(), Arg.Any <Root>(), new Slot(3)).Returns(root2);

            _mockStore.GetSignedBlockAsync(root6).Returns(block6);
            _mockStore.GetSignedBlockAsync(root4).Returns(block4);
            _mockStore.GetSignedBlockAsync(root2).Returns(block2);

            MothraPeeringWorker peeringWorker = new MothraPeeringWorker(
                _loggerFactory.CreateLogger <MothraPeeringWorker>(),
                _mockMothraConfigurationMonitor,
                Substitute.For <IHostEnvironment>(),
                Substitute.For <IClientVersion>(),
                _mockStore,
                _mockMothra,
                _dataDirectory,
                _peerManager,
                _peerDiscoveredProcessor,
                _rpcPeeringStatusProcessor,
                _rpcBeaconBlocksByRangeProcessor,
                _signedBeaconBlockProcessor
                );

            // act - start worker
            await peeringWorker.StartAsync(CancellationToken.None);

            await Task.Delay(TimeSpan.FromMilliseconds(100));

            // - request for 4 blocks: 3, 4, 5, 6
            BeaconBlocksByRange request = new BeaconBlocksByRange(
                requestRoot,
                new Slot(3),
                4,
                1);

            byte[] data = new Byte[Ssz.Ssz.BeaconBlocksByRangeLength];
            Ssz.Ssz.Encode(data, request);
            _mockMothra.RaiseRpcReceived(
                Encoding.UTF8.GetBytes("/eth2/beacon_chain/req/beacon_blocks_by_range/1/"),
                0,
                Encoding.UTF8.GetBytes("peer1"),
                data);
            // - wait for event to be handled
            await Task.Delay(TimeSpan.FromMilliseconds(100));

            // - finish
            await peeringWorker.StopAsync(CancellationToken.None);

            // assert - should receive in slot order
            var receivedCalls = _mockNetworkPeering.ReceivedCalls().ToList();

            receivedCalls.Count.ShouldBe(2);

            receivedCalls[0].GetMethodInfo().Name.ShouldBe(nameof(_mockNetworkPeering.SendBlockAsync));
            SignedBeaconBlock response0 = receivedCalls[0].GetArguments()[1].ShouldBeOfType <SignedBeaconBlock>();

            response0.Message.Slot.ShouldBe(new Slot(4));

            SignedBeaconBlock response1 = receivedCalls[1].GetArguments()[1].ShouldBeOfType <SignedBeaconBlock>();

            response1.Message.Slot.ShouldBe(new Slot(6));
        }