using System; using System.Net; using System.Reflection; using NBitcoin; using NBitcoin.DataEncoders; using NBitcoin.Protocol; namespace Stratis.Bitcoin.P2P.Protocol.Payloads { [Flags] public enum NetworkPeerServices : ulong { Nothing = 0, /// <summary> /// NODE_NETWORK means that the node is capable of serving the block chain. It is currently /// set by all Bitcoin Core nodes, and is unset by SPV clients or other peers that just want /// network services but don't provide them. /// </summary> Network = (1 << 0), /// <summary> /// NODE_GETUTXO means the node is capable of responding to the getutxo protocol request. /// Bitcoin Core does not support this but a patch set called Bitcoin XT does. /// See BIP 64 for details on how this is implemented. /// </summary> GetUTXO = (1 << 1), /// <summary> NODE_BLOOM means the node is capable and willing to handle bloom-filtered connections. /// Bitcoin Core nodes used to support this by default, without advertising this bit, /// but no longer do as of protocol version 70011 (= NO_BLOOM_VERSION) /// </summary> NODE_BLOOM = (1 << 2), /// <summary> Indicates that a node can be asked for blocks and transactions including /// witness data. /// </summary> NODE_WITNESS = (1 << 3), } [Payload("version")] public class VersionPayload : Payload, IBitcoinSerializable { private const int MaxSubversionLength = 256; private static string userAgent; private uint version; public ProtocolVersion Version { get { // A version number of 10300 is converted to 300 before being processed. if (this.version == 10300) return (ProtocolVersion)(300); //https://en.bitcoin.it/wiki/Version_Handshake return (ProtocolVersion)this.version; } set { if (value == (ProtocolVersion)10300) value = (ProtocolVersion)300; this.version = (uint)value; } } private ulong services; public NetworkPeerServices Services { get { return (NetworkPeerServices)this.services; } set { this.services = (ulong)value; } } private long timestamp; public DateTimeOffset Timestamp { get { return Utils.UnixTimeToDateTime((uint)this.timestamp); } set { this.timestamp = Utils.DateTimeToUnixTime(value); } } private NetworkAddress addr_recv = new NetworkAddress(); public IPEndPoint AddressReceiver { get { return this.addr_recv.Endpoint; } set { this.addr_recv.Endpoint = value; } } private NetworkAddress addr_from = new NetworkAddress(); public IPEndPoint AddressFrom { get { return this.addr_from.Endpoint; } set { this.addr_from.Endpoint = value; } } private ulong nonce; public ulong Nonce { get { return this.nonce; } set { this.nonce = value; } } private int start_height; public int StartHeight { get { return this.start_height; } set { this.start_height = value; } } private bool relay = true; public bool Relay { get { return this.relay; } set { this.relay = value; } } private VarString user_agent; public string UserAgent { get { return Encoders.ASCII.EncodeData(this.user_agent.GetString()); } set { if (value.Length > MaxSubversionLength) value = value.Substring(0, MaxSubversionLength); this.user_agent = new VarString(Encoders.ASCII.DecodeData(value)); } } public static string GetNBitcoinUserAgent() { if (userAgent == null) { Version version = typeof(VersionPayload).GetTypeInfo().Assembly.GetName().Version; userAgent = "/NBitcoin:" + version.Major + "." + version.MajorRevision + "." + version.Build + "/"; } return userAgent; } public override void ReadWriteCore(BitcoinStream stream) { stream.ReadWrite(ref this.version); using (stream.ProtocolVersionScope((ProtocolVersion)this.version)) { stream.ReadWrite(ref this.services); stream.ReadWrite(ref this.timestamp); // No time field in version message. using (stream.ProtocolVersionScope(ProtocolVersion.CADDR_TIME_VERSION - 1)) { stream.ReadWrite(ref this.addr_recv); } if (this.version >= 106) { // No time field in version message. using (stream.ProtocolVersionScope(ProtocolVersion.CADDR_TIME_VERSION - 1)) { stream.ReadWrite(ref this.addr_from); } stream.ReadWrite(ref this.nonce); stream.ReadWrite(ref this.user_agent); if (this.version < 60002) { if (this.user_agent.Length != 0) throw new FormatException("Should not find user agent for current version " + this.version); } stream.ReadWrite(ref this.start_height); if (this.version >= 70001) stream.ReadWrite(ref this.relay); } } } public override string ToString() { return this.Version.ToString(); } } }