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); }
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); }
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)); }