mwc_bch/messages/
block_locator.rs

1use byteorder::{LittleEndian, ReadBytesExt, WriteBytesExt};
2use messages::message::Payload;
3use messages::version::MIN_SUPPORTED_PROTOCOL_VERSION;
4use std::io;
5use std::io::{Read, Write};
6use util::{var_int, Error, Hash256, Result, Serializable};
7
8/// Return results until either there are 2000 for getheaders or 500 or getblocks, or no more left
9pub const NO_HASH_STOP: Hash256 = Hash256([0; 32]);
10
11/// Specifies which blocks to return
12#[derive(Debug, Default, PartialEq, Eq, Hash, Clone)]
13pub struct BlockLocator {
14    /// Protocol version of this node
15    pub version: u32,
16    /// Block hash to start after. First found will be used.
17    pub block_locator_hashes: Vec<Hash256>,
18    /// Block hash to stop at, or none if NO_HASH_STOP.
19    pub hash_stop: Hash256,
20}
21
22impl BlockLocator {
23    /// Checks if the message is valid
24    pub fn validate(&self) -> Result<()> {
25        if self.version < MIN_SUPPORTED_PROTOCOL_VERSION as u32 {
26            let msg = format!("Unsupported protocol version: {}", self.version);
27            return Err(Error::BadData(msg));
28        }
29        Ok(())
30    }
31}
32
33impl Serializable<BlockLocator> for BlockLocator {
34    fn read(reader: &mut dyn Read) -> Result<BlockLocator> {
35        let version = reader.read_u32::<LittleEndian>()?;
36        let num_hashes = var_int::read(reader)?;
37        let mut block_locator_hashes = Vec::new();
38        for _i in 0..num_hashes {
39            block_locator_hashes.push(Hash256::read(reader)?);
40        }
41        let hash_stop = Hash256::read(reader)?;
42        Ok(BlockLocator {
43            version,
44            block_locator_hashes,
45            hash_stop,
46        })
47    }
48
49    fn write(&self, writer: &mut dyn Write) -> io::Result<()> {
50        writer.write_u32::<LittleEndian>(self.version)?;
51        var_int::write(self.block_locator_hashes.len() as u64, writer)?;
52        for hash in self.block_locator_hashes.iter() {
53            hash.write(writer)?;
54        }
55        self.hash_stop.write(writer)?;
56        Ok(())
57    }
58}
59
60impl Payload<BlockLocator> for BlockLocator {
61    fn size(&self) -> usize {
62        4 + var_int::size(self.block_locator_hashes.len() as u64)
63            + self.block_locator_hashes.len() * 32
64            + 32
65    }
66}
67
68#[cfg(test)]
69mod tests {
70    use super::*;
71    use std::io::Cursor;
72
73    #[test]
74    fn write_read() {
75        let mut v = Vec::new();
76        let p = BlockLocator {
77            version: 12345,
78            block_locator_hashes: vec![
79                NO_HASH_STOP,
80                Hash256::decode("6677889900667788990066778899006677889900667788990066778899006677")
81                    .unwrap(),
82            ],
83            hash_stop: Hash256::decode(
84                "1122334455112233445511223344551122334455112233445511223344551122",
85            ).unwrap(),
86        };
87        p.write(&mut v).unwrap();
88        assert!(v.len() == p.size());
89        assert!(BlockLocator::read(&mut Cursor::new(&v)).unwrap() == p);
90    }
91}