cs_mwc_bch/messages/
version.rs

1use byteorder::{LittleEndian, ReadBytesExt, WriteBytesExt};
2use messages::message::Payload;
3use messages::node_addr::NodeAddr;
4use std::io;
5use std::io::{Read, Write};
6use std::time::UNIX_EPOCH;
7use util::{secs_since, var_int, Error, Result, Serializable};
8
9/// Protocol version supported by this library
10pub const PROTOCOL_VERSION: u32 = 70015;
11
12/// Minimum protocol version supported by this library
13pub const MIN_SUPPORTED_PROTOCOL_VERSION: u32 = 70001;
14
15/// Unknown IP address to use as a default
16pub const UNKNOWN_IP: [u8; 16] = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 255, 255, 127, 0, 0, 1];
17
18/// Service flag that node is not a full node. Used for SPV wallets.
19pub const NODE_NONE: u64 = 0;
20
21/// Service flag that node is a full node and implements all protocol features
22pub const NODE_NETWORK: u64 = 1;
23
24/// Service flag that node is a full node and implements all protocol features
25pub const NODE_BITCOIN_CASH: u64 = 1 << 5;
26
27/// Version payload defining a node's capabilities
28#[derive(Debug, Default, PartialEq, Eq, Hash, Clone)]
29pub struct Version {
30    /// The protocol version being used by the node
31    pub version: u32,
32    /// Bitfield of features to be enabled for this connection
33    pub services: u64,
34    /// Time since the Unix epoch in seconds
35    pub timestamp: i64,
36    /// Network address of the node receiving this message
37    pub recv_addr: NodeAddr,
38    /// Network address of the node emitting this message
39    pub tx_addr: NodeAddr,
40    /// A random nonce which can help a node detect a connection to itself
41    pub nonce: u64,
42    /// User agent string
43    pub user_agent: String,
44    /// Height of the transmiting node's best block chain, or in the case of SPV wallets, block header chain
45    pub start_height: i32,
46    /// Whether the client wants to receive broadcast transactions before a filter is set
47    pub relay: bool,
48}
49
50impl Version {
51    /// Checks if the version message is valid
52    pub fn validate(&self) -> Result<()> {
53        if self.version < MIN_SUPPORTED_PROTOCOL_VERSION {
54            let msg = format!("Unsupported protocol version: {}", self.version);
55            return Err(Error::BadData(msg));
56        }
57        let now = secs_since(UNIX_EPOCH) as i64;
58        if (self.timestamp - now).abs() > 2 * 60 * 60 {
59            let msg = format!("Timestamp too old: {}", self.timestamp);
60            return Err(Error::BadData(msg));
61        }
62        Ok(())
63    }
64}
65
66impl Serializable<Version> for Version {
67    fn read(reader: &mut dyn Read) -> Result<Version> {
68        let mut ret = Version {
69            ..Default::default()
70        };
71        ret.version = reader.read_u32::<LittleEndian>()?;
72        ret.services = reader.read_u64::<LittleEndian>()?;
73        ret.timestamp = reader.read_i64::<LittleEndian>()?;
74        ret.recv_addr = NodeAddr::read(reader)?;
75        ret.tx_addr = NodeAddr::read(reader)?;
76        ret.nonce = reader.read_u64::<LittleEndian>()?;
77        let user_agent_size = var_int::read(reader)? as usize;
78        let mut user_agent_bytes = vec![0; user_agent_size];
79        reader.read(&mut user_agent_bytes)?;
80        ret.user_agent = String::from_utf8(user_agent_bytes)?;
81        ret.start_height = reader.read_i32::<LittleEndian>()?;
82        ret.relay = reader.read_u8()? == 0x01;
83        Ok(ret)
84    }
85
86    fn write(&self, writer: &mut dyn Write) -> io::Result<()> {
87        writer.write_u32::<LittleEndian>(self.version)?;
88        writer.write_u64::<LittleEndian>(self.services)?;
89        writer.write_i64::<LittleEndian>(self.timestamp)?;
90        self.recv_addr.write(writer)?;
91        self.tx_addr.write(writer)?;
92        writer.write_u64::<LittleEndian>(self.nonce)?;
93        var_int::write(self.user_agent.as_bytes().len() as u64, writer)?;
94        writer.write(&self.user_agent.as_bytes())?;
95        writer.write_i32::<LittleEndian>(self.start_height)?;
96        writer.write_u8(if self.relay { 0x01 } else { 0x00 })?;
97        Ok(())
98    }
99}
100
101impl Payload<Version> for Version {
102    fn size(&self) -> usize {
103        33 + self.recv_addr.size()
104            + self.tx_addr.size()
105            + var_int::size(self.user_agent.as_bytes().len() as u64)
106            + self.user_agent.as_bytes().len()
107    }
108}
109
110#[cfg(test)]
111mod tests {
112    use super::*;
113    use hex;
114    use std::io::Cursor;
115
116    #[test]
117    fn read_bytes() {
118        let b = hex::decode("7f1101002500000000000000f2d2d25a00000000000000000000000000000000000000000000ffff2d32bffbdd1725000000000000000000000000000000000000000000000000008d501d3bb5369deb242f426974636f696e204142433a302e31362e30284542382e303b20626974636f7265292f6606080001".as_bytes()).unwrap();
119        let v = Version::read(&mut Cursor::new(&b)).unwrap();
120        assert!(v.version == 70015);
121        assert!(v.services == 37);
122        assert!(v.timestamp == 1523766002);
123        assert!(v.recv_addr.services == 0);
124        assert!(
125            v.recv_addr.ip.octets() == [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 255, 255, 45, 50, 191, 251]
126        );
127        assert!(v.recv_addr.port == 56599);
128        assert!(v.tx_addr.services == 37);
129        assert!(v.tx_addr.ip.octets() == [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]);
130        assert!(v.tx_addr.port == 0);
131        assert!(v.nonce == 16977786322265395341);
132        assert!(v.user_agent == "/Bitcoin ABC:0.16.0(EB8.0; bitcore)/");
133        assert!(v.start_height == 525926);
134        assert!(v.relay == true);
135    }
136
137    #[test]
138    fn write_read() {
139        let mut v = Vec::new();
140        let m = Version {
141            version: MIN_SUPPORTED_PROTOCOL_VERSION,
142            services: 77,
143            timestamp: 1234,
144            recv_addr: NodeAddr {
145                ..Default::default()
146            },
147            tx_addr: NodeAddr {
148                ..Default::default()
149            },
150            nonce: 99,
151            user_agent: "dummy".to_string(),
152            start_height: 22,
153            relay: true,
154        };
155        m.write(&mut v).unwrap();
156        assert!(v.len() == m.size());
157        assert!(Version::read(&mut Cursor::new(&v)).unwrap() == m);
158    }
159
160    #[test]
161    fn validate() {
162        let m = Version {
163            version: MIN_SUPPORTED_PROTOCOL_VERSION,
164            services: 77,
165            timestamp: secs_since(UNIX_EPOCH) as i64,
166            recv_addr: NodeAddr {
167                ..Default::default()
168            },
169            tx_addr: NodeAddr {
170                ..Default::default()
171            },
172            nonce: 99,
173            user_agent: "dummy".to_string(),
174            start_height: 22,
175            relay: true,
176        };
177        // Valid
178        assert!(m.validate().is_ok());
179        // Unsupported version
180        let m2 = Version {
181            version: 0,
182            ..m.clone()
183        };
184        assert!(m2.validate().is_err());
185        // Bad timestamp
186        let m3 = Version {
187            timestamp: 0,
188            ..m.clone()
189        };
190        assert!(m3.validate().is_err());
191    }
192}