/// <summary> /// Checks a version payload from a peer against the requirements. /// </summary> /// <param name="version">Version payload to check.</param> /// <returns><c>true</c> if the version payload satisfies the protocol requirements, <c>false</c> otherwise.</returns> public virtual bool Check(VersionPayload version) { if (this.MinVersion != null) { if (version.Version < this.MinVersion.Value) { return(false); } } if ((this.RequiredServices & version.Services) != this.RequiredServices) { return(false); } if (this.SupportSPV) { if (version.Version < ProtocolVersion.MEMPOOL_GD_VERSION) { return(false); } if ((ProtocolVersion.NO_BLOOM_VERSION <= version.Version) && ((version.Services & NetworkPeerServices.NODE_BLOOM) == 0)) { return(false); } } return(true); }
/// <summary> /// Processes a "version" message received from a peer. /// </summary> /// <param name="version">Version message received from a peer.</param> /// <param name="cancellation">Cancellation token to abort message processing.</param> private async Task ProcessVersionMessageAsync(VersionPayload version, CancellationToken cancellation) { this.logger.LogTrace("Peer's state is {0}.", this.State); switch (this.State) { case NetworkPeerState.Connected: if (this.Inbound) { await this.ProcessInitialVersionPayloadAsync(version, cancellation).ConfigureAwait(false); } break; case NetworkPeerState.HandShaked: if (this.Version >= ProtocolVersion.REJECT_VERSION) { var rejectPayload = new RejectPayload() { Code = RejectCode.DUPLICATE }; await this.SendMessageAsync(rejectPayload, cancellation).ConfigureAwait(false); } break; } this.TimeOffset = this.dateTimeProvider.GetTimeOffset() - version.Timestamp; if ((version.Services & NetworkPeerServices.NODE_WITNESS) != 0) { this.SupportedTransactionOptions |= TransactionOptions.Witness; } }
private void OnVersionMessageReceived(VersionPayload payload) { version = payload; Context.Parent.Tell(new SetVersion { Version = payload }); }
public async Task Can_activate_peer_on_verack_receiving() { // Arrange var blockchain = new NullBlockchain(); AutoMockContainer.Register <IBlockchain>(blockchain); var verAckMessage = new VerAckMessage(); var version = new VersionPayload(); var peerMock = AutoMockContainer.GetMock <IPeer>(); peerMock.SetupProperty(x => x.IsReady, false); peerMock.SetupProperty(x => x.Version, version); blockchain.LastBlockHeader.Index = 1; version.CurrentBlockIndex = 1; var messageHandler = AutoMockContainer.Get <VerAckMessageHandler>(); // Act await messageHandler.Handle(verAckMessage, peerMock.Object); // Assert peerMock.Object.IsReady.Should().BeTrue(); }
public void RemoteNode_Test_Accept_IfSameMagic() { var connectionTestProbe = CreateTestProbe(); var remoteNodeActor = ActorOfAsTestActorRef(() => new RemoteNode(testBlockchain, connectionTestProbe, null, null)); connectionTestProbe.ExpectMsg <Tcp.Write>(); var payload = new VersionPayload() { UserAgent = "Unit Test".PadLeft(1024, '0'), Nonce = 1, Magic = ProtocolSettings.Default.Magic, Timestamp = 5, Version = 6, Capabilities = new NodeCapability[] { new ServerCapability(NodeCapabilityType.TcpServer, 25) } }; var testProbe = CreateTestProbe(); testProbe.Send(remoteNodeActor, payload); var verackMessage = connectionTestProbe.ExpectMsg <Tcp.Write>(); //Verack verackMessage.Data.Count.Should().Be(3); }
public RemoteNode(LyraSystem system, object connection, IPEndPoint remote, IPEndPoint local) : base(connection, remote, local) { _log = new SimpleLogger("RemoteNode").Logger; this.system = system; this.protocol = Context.ActorOf(ProtocolHandler.Props(system)); LocalNode.Singleton.RemoteNodes.TryAdd(Self, this); while (BlockChain.Singleton == null) { Task.Delay(100).Wait(); } var capabilities = new List <NodeCapability> { new FullNodeCapability(BlockChain.Singleton.Height) }; if (LocalNode.Singleton.ListenerTcpPort > 0) { capabilities.Add(new ServerCapability(NodeCapabilityType.TcpServer, (ushort)LocalNode.Singleton.ListenerTcpPort)); } if (LocalNode.Singleton.ListenerWsPort > 0) { capabilities.Add(new ServerCapability(NodeCapabilityType.WsServer, (ushort)LocalNode.Singleton.ListenerWsPort)); } SendMessage(Message.Create(MessageCommand.Version, VersionPayload.Create(LocalNode.Nonce, LocalNode.UserAgent, capabilities.ToArray()))); }
private void OnVersionPayload(VersionPayload version) { Version = version; foreach (NodeCapability capability in version.Capabilities) { switch (capability) { case FullNodeCapability fullNodeCapability: IsFullNode = true; LastBlockIndex = fullNodeCapability.StartHeight; break; case ServerCapability serverCapability: if (serverCapability.Type == NodeCapabilityType.TcpServer) { ListenerTcpPort = serverCapability.Port; } break; } } if (version.Nonce == LocalNode.Nonce || version.Magic != ProtocolSettings.Default.Magic) { Disconnect(true); return; } if (LocalNode.Singleton.RemoteNodes.Values.Where(p => p != this).Any(p => p.Remote.Address.Equals(Remote.Address) && p.Version?.Nonce == version.Nonce)) { Disconnect(true); return; } SendMessage(Message.Create(MessageCommand.Verack)); }
public void RemoteNode_Test_Abort_DifferentMagic() { var connectionTestProbe = CreateTestProbe(); var remoteNodeActor = ActorOfAsTestActorRef(() => new RemoteNode(testBlockchain, connectionTestProbe, null, null)); connectionTestProbe.ExpectMsg <Tcp.Write>(); var payload = new VersionPayload() { UserAgent = "".PadLeft(1024, '0'), Nonce = 1, Magic = 2, Timestamp = 5, Version = 6, Capabilities = new NodeCapability[] { new ServerCapability(NodeCapabilityType.TcpServer, 25) } }; var testProbe = CreateTestProbe(); testProbe.Send(remoteNodeActor, payload); connectionTestProbe.ExpectMsg <Tcp.Abort>(); }
/// <summary>Creates a peer with extended puller behavior.</summary> public Mock <INetworkPeer> CreatePeerMock(out ExtendedBlockPullerBehavior mockedBehavior, bool notSupportedVersion = false) { var peer = new Mock <INetworkPeer>(); var connection = new NetworkPeerConnection(KnownNetworks.StratisMain, peer.Object, new TcpClient(), this.currentPeerId, (message, token) => Task.CompletedTask, new DateTimeProvider(), this.loggerFactory, new PayloadProvider()); this.currentPeerId++; peer.SetupGet(networkPeer => networkPeer.Connection).Returns(connection); var connectionParameters = new NetworkPeerConnectionParameters(); VersionPayload version = connectionParameters.CreateVersion(new IPEndPoint(1, 1), new IPEndPoint(1, 1), KnownNetworks.StratisMain, new DateTimeProvider().GetTimeOffset()); if (notSupportedVersion) { version.Version = ProtocolVersion.NOBLKS_VERSION_START; } else { version.Services = NetworkPeerServices.Network; } peer.SetupGet(x => x.PeerVersion).Returns(version); peer.SetupGet(x => x.State).Returns(NetworkPeerState.HandShaked); peer.SetupGet(x => x.MessageReceived).Returns(new AsyncExecutionEvent <INetworkPeer, IncomingMessage>()); ExtendedBlockPullerBehavior behavior = this.CreateBlockPullerBehavior(); behavior.Attach(peer.Object); peer.Setup(x => x.Behavior <IBlockPullerBehavior>()).Returns(() => behavior); mockedBehavior = behavior; return(peer); }
private Mock <INetworkPeer> CreatePeerMock() { var peer = new Mock <INetworkPeer>(); var connection = new NetworkPeerConnection(this.Network, peer.Object, new TcpClient(), 0, (message, token) => Task.CompletedTask, DateTimeProvider.Default, this.extendedLoggerFactory, new PayloadProvider(), this.asyncProvider); peer.SetupGet(networkPeer => networkPeer.Connection).Returns(connection); var connectionParameters = new NetworkPeerConnectionParameters(); VersionPayload version = connectionParameters.CreateVersion(new IPEndPoint(1, 1), new IPEndPoint(1, 1), this.Network, DateTimeProvider.Default.GetTimeOffset()); version.Services = NetworkPeerServices.Network; peer.SetupGet(x => x.PeerVersion).Returns(version); peer.SetupGet(x => x.State).Returns(NetworkPeerState.HandShaked); var stateChanged = new AsyncExecutionEvent <INetworkPeer, NetworkPeerState>(); var messageReceived = new AsyncExecutionEvent <INetworkPeer, IncomingMessage>(); peer.Setup(x => x.StateChanged).Returns(() => stateChanged); peer.Setup(x => x.MessageReceived).Returns(() => messageReceived); var connectionManagerBehaviorMock = new Mock <IConnectionManagerBehavior>(); peer.Setup(x => x.Behavior <IConnectionManagerBehavior>()).Returns(() => connectionManagerBehaviorMock.Object); peer.SetupGet(x => x.PeerEndPoint).Returns(new IPEndPoint(1, 1)); return(peer); }
/// <summary> /// Event handler that is called when the attached node receives a network message. /// </summary> /// <param name="node">Node that received the message.</param> /// <param name="message">Received message.</param> /// <remarks> /// This handler only cares about "verack" messages, which are only sent once per node /// and at the time they are sent the time offset information is parsed by underlaying logic. /// <para> /// Note that it is not possible to use "version" message here as <see cref="Node"/> /// does not deliver this message for inbound peers to node behaviors. /// </para> /// </remarks> private void AttachedNode_MessageReceived(Node node, IncomingMessage message) { this.logger.LogTrace("({0}:'{1}',{2}:'{3}')", nameof(node), node.RemoteSocketEndpoint, nameof(message), message.Message.Command); VerAckPayload verack = message.Message.Payload as VerAckPayload; if (verack != null) { IPAddress address = node.RemoteSocketAddress; if (address != null) { VersionPayload version = node.PeerVersion; if (version != null) { TimeSpan timeOffset = version.Timestamp - this.dateTimeProvider.GetUtcNow(); if (timeOffset != null) { this.state.AddTimeData(address, timeOffset, node.Inbound); } } else { this.logger.LogTrace("Node '{0}' does not have an initialized time offset.", node.RemoteSocketEndpoint); } } else { this.logger.LogTrace("Message received from unknown node's address."); } } this.logger.LogTrace("(-)"); }
/// <summary> /// Event handler that is called when the node receives a network message from the attached peer. /// </summary> /// <param name="peer">Peer that sent us the message.</param> /// <param name="message">Received message.</param> /// <remarks> /// This handler only cares about "verack" messages, which are only sent once per node /// and at the time they are sent the time offset information is parsed by underlaying logic. /// <para> /// Note that it is not possible to use "version" message here as <see cref="INetworkPeer"/> /// does not deliver this message for inbound peers to node behaviors. /// </para> /// </remarks> private Task OnMessageReceivedAsync(INetworkPeer peer, IncomingMessage message) { this.logger.LogTrace("({0}:'{1}',{2}:'{3}')", nameof(peer), peer.RemoteSocketEndpoint, nameof(message), message.Message.Command); if (message.Message.Payload is VerAckPayload verack) { IPAddress address = peer.RemoteSocketAddress; if (address != null) { VersionPayload version = peer.PeerVersion; if (version != null) { TimeSpan timeOffset = version.Timestamp - this.dateTimeProvider.GetTimeOffset(); if (timeOffset != null) { this.state.AddTimeData(address, timeOffset, peer.Inbound); } } else { this.logger.LogTrace("Node '{0}' does not have an initialized time offset.", peer.RemoteSocketEndpoint); } } else { this.logger.LogTrace("Message received from unknown node's address."); } } this.logger.LogTrace("(-)"); return(Task.CompletedTask); }
public TaskSession(IActorRef node, VersionPayload version) { this.RemoteNode = node; this.Version = version; this.StartHeight = version.Capabilities .OfType <FullNodeCapability>() .FirstOrDefault()?.StartHeight ?? 0; }
public RemoteNode(CamSystem system, object connection, IPEndPoint remote, IPEndPoint local) : base(connection, remote, local) { this.system = system; this.protocol = Context.ActorOf(ProtocolHandler.Props(system)); LocalNode.Singleton.RemoteNodes.TryAdd(Self, this); SendMessage(Message.Create("version", VersionPayload.Create(LocalNode.Singleton.ListenerPort, LocalNode.Nonce, LocalNode.UserAgent, Blockchain.Singleton.Height))); }
public static byte[] EncodeVersionPayload(VersionPayload versionPayload, bool withRelay) { using (var stream = new MemoryStream()) { EncodeVersionPayload(stream, versionPayload, withRelay); return(stream.ToArray()); } }
private void OnRegister(VersionPayload version) { Context.Watch(Sender); TaskSession session = new TaskSession(Sender, version); sessions.Add(Sender, session); RequestTasks(session); }
public void TestVersoinPayload() { VersionPayload payload; byte[] expected; payload = new VersionPayload( version: 70001, services: 0x01, timeStamp: new DateTime(1000), addressTo: new IPAddressPayload( timeStamp: new DateTime(), services: (UInt64)1, address: IPAddress.Parse("10.0.0.2"), port: (UInt16)9911 ), addressFrom: new IPAddressPayload( timeStamp: new DateTime(), services: (UInt64)1, address: IPAddress.Parse("10.0.0.1"), port: (UInt16)9911 ), nonce: 0, userAgent: new StringPayload("/UnitTest-v0.0.1/"), startHeight: 1000, relay: true ); expected = new byte[] { 0x71, 0x11, 0x01, 0x00, // Version 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // Services 0xE8, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // TimeStamp // AddressTo 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // Services 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // Address... 0x00, 0x00, 0xFF, 0xFF, 0x0A, 0x00, 0x00, 0x02, // ... 0x26, 0xB7, // Port // AddressFrom 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // Services 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // Address... 0x00, 0x00, 0xFF, 0xFF, 0x0A, 0x00, 0x00, 0x01, // ... 0x26, 0xB7, // Port 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // Nonce // UserAgent 17, // UserAgent byte count 0x2F, 0x55, 0x6E, 0x69, 0x74, 0x54, 0x65, 0x73, // "/UnitTest-v0.0.1/"... 0x74, 0x2D, 0x76, 0x30, 0x2E, 0x30, 0x2E, 0x31, // ... 0x2F, // ... 0xE8, 0x03, 0x00, 0x00, // StartHeight 0x01 // Relay }; AssertBytesEqual(expected, payload.ToBytes()); AssertVersionPayloadsEqual(payload, new VersionPayload(expected)); }
private bool DoesPeerSupportsPH(VersionPayload peerVersion) { if (peerVersion == null) { return(false); } return(peerVersion.Version >= NBitcoin.Protocol.ProtocolVersion.PROVEN_HEADER_VERSION); }
private void OnRegister(VersionPayload version) { Context.Watch(Sender); TaskSession session = new TaskSession(version); if (session.IsFullNode) session.InvTasks.TryAdd(MemPoolTaskHash, TimeProvider.Current.UtcNow); sessions.TryAdd(Sender, session); RequestTasks(); }
public TaskSession(IActorRef node, VersionPayload version) { var fullNode = version.Capabilities.OfType <FullNodeCapability>().FirstOrDefault(); this.IsFullNode = fullNode != null; this.RemoteNode = node; this.Version = version; this.StartHeight = fullNode?.StartHeight ?? 0; this.LastBlockIndex = this.StartHeight; }
public void TryDeserializeTest() { var pl = new VersionPayload(); byte[] data = Helper.HexToBytes("721101000100000000000000bc8f5e5400000000010000000000000000000000000000000000ffffc61b6409208d010000000000000000000000000000000000ffffcb0071c0208d128035cbc97953f80f2f5361746f7368693a302e392e332fcf05050001"); bool b = pl.TryDeserialize(new FastStreamReader(data), out string error); Assert.True(b, error); Assert.Null(error); }
public MockNodeStatus(VersionPayload pl) { _protVer = pl.Version; _servs = pl.Services; _nonce = pl.Nonce; _agent = pl.UserAgent; _height = pl.StartHeight; _relayToReturn = pl.Relay; _relayToSet = pl.Relay; }
/// <summary> /// Processes an initial "version" message received from a peer. /// </summary> /// <param name="version">Version message received from a peer.</param> /// <param name="cancellation">Cancellation token to abort message processing.</param> /// <exception cref="OperationCanceledException">Thrown if the response to our "version" message is not received on time.</exception> async Task ProcessInitialVersionPayloadAsync(VersionPayload version, CancellationToken cancellation) { this.PeerVersion = version; var connectedToSelf = version.Nonce == this.ConnectionParameters.Nonce; this.logger.LogDebug("First message received from peer '{0}'.", version.AddressFrom); if (connectedToSelf) { this.logger.LogDebug("Connection to self detected, disconnecting."); Disconnect("Connected to self"); this.selfEndpointTracker.Add(version.AddressReceiver); this.logger.LogTrace("(-)[CONNECTED_TO_SELF]"); throw new OperationCanceledException(); } using (var cancellationSource = CancellationTokenSource.CreateLinkedTokenSource(this.Connection.CancellationSource.Token, cancellation)) { cancellationSource.CancelAfter(TimeSpan.FromSeconds(10.0)); try { await RespondToHandShakeAsync(cancellationSource.Token).ConfigureAwait(false); } catch (OperationCanceledException ex) { if (ex.CancellationToken == cancellationSource.Token) { this.logger.LogDebug( "Remote peer hasn't responded within 10 seconds of the handshake completion, dropping connection."); Disconnect("Handshake timeout"); } else { this.logger.LogDebug("Handshake problem, dropping connection. Problem: '{0}'.", ex.Message); Disconnect($"Handshake problem, reason: '{ex.Message}'."); } this.logger.LogTrace("(-)[HANDSHAKE_TIMEDOUT]"); throw; } catch (Exception ex) { this.logger.LogDebug("Exception occurred: {0}", ex.ToString()); Disconnect("Handshake exception", ex); this.logger.LogTrace("(-)[HANDSHAKE_EXCEPTION]"); throw; } } }
private void OnRegister(VersionPayload version) { Context.Watch(Sender); TaskSession session = new TaskSession(Sender, version); if (session.IsFullNode) { session.AvailableTasks.Add(TaskManager.MemPoolTaskHash); } sessions.Add(Sender, session); RequestTasks(session); }
public void SizeAndEndPoint_Get() { var test = new VersionPayload() { Capabilities = new NodeCapability[0], UserAgent = "neo3" }; test.Size.Should().Be(22); test = VersionPayload.Create(123, "neo3", new NodeCapability[] { new ServerCapability(NodeCapabilityType.TcpServer, 22) }); test.Size.Should().Be(25); }
void AssertVersionPayloadsEqual(VersionPayload expected, VersionPayload actual) { Assert.AreEqual(expected.Version, actual.Version); Assert.AreEqual(expected.Services, actual.Services); Assert.AreEqual(expected.TimeStamp, actual.TimeStamp); AssertIPAddressPayloadsEqual(expected.AddressFrom, actual.AddressFrom); AssertIPAddressPayloadsEqual(expected.AddressTo, actual.AddressTo); Assert.AreEqual(expected.Nonce, actual.Nonce); AssertStringPayloadsEqual(expected.UserAgent, actual.UserAgent); Assert.AreEqual(expected.StartHeight, actual.StartHeight); Assert.AreEqual(expected.Relay, actual.Relay); }
public void SizeAndEndPoint_Get() { var test = new VersionPayload() { Capabilities = Array.Empty <NodeCapability>(), UserAgent = "Vauth3" }; test.Size.Should().Be(22); test = VersionPayload.Create(123, 456, "Vauth3", new NodeCapability[] { new ServerCapability(NodeCapabilityType.TcpServer, 22) }); test.Size.Should().Be(25); }
public NetworkPeerConnectionParameters() { this.TemplateBehaviors.Add(new PingPongBehavior()); this.Version = ProtocolVersion.PROTOCOL_VERSION; this.IsRelay = true; this.Services = NetworkPeerServices.Nothing; this.ConnectCancellation = default(CancellationToken); this.ReceiveBufferSize = 1000 * 5000; this.SendBufferSize = 1000 * 1000; this.UserAgent = VersionPayload.GetNBitcoinUserAgent(); this.PreferredTransactionOptions = NetworkOptions.TemporaryOptions; }
public NodeConnectionParameters() { ReuseBuffer = true; TemplateBehaviors.Add(new PingPongBehavior()); Version = ProtocolVersion.PROTOCOL_VERSION; IsRelay = true; Services = NodeServices.Nothing; ConnectCancellation = default(CancellationToken); ReceiveBufferSize = 1000 * 5000; SendBufferSize = 1000 * 1000; UserAgent = VersionPayload.GetNBitcoinUserAgent(); PreferredTransactionOptions = TransactionOptions.All; }
/// <summary> /// Processes an initial "version" message received from a peer. /// </summary> /// <param name="version">Version message received from a peer.</param> /// <exception cref="OperationCanceledException">Thrown if the response to our "version" message is not received on time.</exception> private async Task ProcessInitialVersionPayloadAsync(VersionPayload version) { this.logger.LogTrace("({0}:'{1}')", nameof(version), version); this.PeerVersion = version; bool connectedToSelf = version.Nonce == this.Parameters.Nonce; this.logger.LogDebug("First message received from peer '{0}'.", version.AddressFrom); if (connectedToSelf) { this.logger.LogDebug("Connection to self detected and will be aborted."); VersionPayload versionPayload = this.Parameters.CreateVersion(this.PeerAddress.Endpoint, this.Network, this.dateTimeProvider.GetTimeOffset()); await this.SendMessageAsync(versionPayload); this.Disconnect("Connected to self"); this.logger.LogTrace("(-)[CONNECTED_TO_SELF]"); return; } using (CancellationTokenSource cancellationSource = CancellationTokenSource.CreateLinkedTokenSource(this.Connection.CancellationSource.Token)) { cancellationSource.CancelAfter(TimeSpan.FromSeconds(10.0)); try { await this.RespondToHandShakeAsync(cancellationSource.Token).ConfigureAwait(false); } catch (OperationCanceledException) { this.logger.LogTrace("Remote peer haven't responded within 10 seconds of the handshake completion, dropping connection."); this.Disconnect("Handshake timeout"); this.logger.LogTrace("(-)[HANDSHAKE_TIMEDOUT]"); throw; } catch (Exception ex) { this.logger.LogTrace("Exception occurred: {0}", ex.ToString()); this.Disconnect("Handshake exception", ex); this.logger.LogTrace("(-)[HANDSHAKE_EXCEPTION]"); throw; } } this.logger.LogTrace("(-)"); }
public static VersionPayload DecodeVersionPayload(BinaryReader reader, int payloadLength) { var position = reader.BaseStream.Position; var versionPayload = new VersionPayload ( ProtocolVersion: reader.ReadUInt32(), ServicesBitfield: reader.ReadUInt64(), Time: DateTimeOffset.FromUnixTimeSeconds((long)reader.ReadUInt64()), RemoteAddress: DecodeNetworkAddress(reader), LocalAddress: DecodeNetworkAddress(reader), Nonce: reader.ReadUInt64(), UserAgent: reader.ReadVarString(), StartBlockHeight: reader.ReadUInt32(), Relay: false ); var readCount = reader.BaseStream.Position - position; if (versionPayload.ProtocolVersion >= VersionPayload.RELAY_VERSION && payloadLength - readCount == 1) versionPayload = versionPayload.With(Relay: reader.ReadBool()); return versionPayload; }
public static void EncodeVersionPayload(BinaryWriter writer, VersionPayload versionPayload, bool withRelay) { writer.WriteUInt32(versionPayload.ProtocolVersion); writer.WriteUInt64(versionPayload.ServicesBitfield); writer.WriteUInt64((ulong)versionPayload.Time.ToUnixTimeSeconds()); EncodeNetworkAddress(writer, versionPayload.RemoteAddress); EncodeNetworkAddress(writer, versionPayload.LocalAddress); writer.WriteUInt64(versionPayload.Nonce); writer.WriteVarString(versionPayload.UserAgent); writer.WriteUInt32(versionPayload.StartBlockHeight); if (withRelay) writer.WriteBool(versionPayload.Relay); }
public static byte[] EncodeVersionPayload(VersionPayload versionPayload, bool withRelay) { using (var stream = new MemoryStream()) using (var writer = new BinaryWriter(stream)) { EncodeVersionPayload(writer, versionPayload, withRelay); return stream.ToArray(); } }