2014-07-18 13:56:17 +00:00
|
|
|
// Rust Bitcoin Library
|
|
|
|
// Written in 2014 by
|
2015-04-07 22:51:57 +00:00
|
|
|
// Andrew Poelstra <apoelstra@wpsoftware.net>
|
2014-07-18 13:56:17 +00:00
|
|
|
//
|
|
|
|
// To the extent possible under law, the author(s) have dedicated all
|
|
|
|
// copyright and related and neighboring rights to this software to
|
|
|
|
// the public domain worldwide. This software is distributed without
|
|
|
|
// any warranty.
|
|
|
|
//
|
|
|
|
// You should have received a copy of the CC0 Public Domain Dedication
|
|
|
|
// along with this software.
|
|
|
|
// If not, see <http://creativecommons.org/publicdomain/zero/1.0/>.
|
|
|
|
//
|
|
|
|
|
2018-08-08 21:38:50 +00:00
|
|
|
//! Blockdata network messages
|
2014-07-18 13:56:17 +00:00
|
|
|
//!
|
|
|
|
//! This module describes network messages which are used for passing
|
|
|
|
//! Bitcoin data (blocks and transactions) around.
|
|
|
|
//!
|
|
|
|
|
|
|
|
use network::constants;
|
2019-07-11 17:06:42 +00:00
|
|
|
use consensus::encode::{self, Decodable, Encodable};
|
2019-01-16 20:45:31 +00:00
|
|
|
use bitcoin_hashes::sha256d;
|
2014-07-18 13:56:17 +00:00
|
|
|
|
2019-07-11 14:56:37 +00:00
|
|
|
use std::io;
|
|
|
|
|
2015-03-26 15:35:31 +00:00
|
|
|
#[derive(PartialEq, Eq, Clone, Debug)]
|
2014-07-18 13:56:17 +00:00
|
|
|
/// The type of an inventory object
|
|
|
|
pub enum InvType {
|
2015-04-07 22:51:57 +00:00
|
|
|
/// Error --- these inventories can be ignored
|
|
|
|
Error,
|
|
|
|
/// Transaction
|
|
|
|
Transaction,
|
|
|
|
/// Block
|
2018-05-28 13:24:35 +00:00
|
|
|
Block,
|
|
|
|
/// Witness Block
|
|
|
|
WitnessBlock,
|
|
|
|
/// Witness Transaction
|
|
|
|
WitnessTransaction
|
2014-07-18 13:56:17 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// Some simple messages
|
|
|
|
|
|
|
|
/// The `getblocks` message
|
2015-03-26 15:35:31 +00:00
|
|
|
#[derive(PartialEq, Eq, Clone, Debug)]
|
2014-07-18 13:56:17 +00:00
|
|
|
pub struct GetBlocksMessage {
|
2015-04-07 22:51:57 +00:00
|
|
|
/// The protocol version
|
|
|
|
pub version: u32,
|
|
|
|
/// Locator hashes --- ordered newest to oldest. The remote peer will
|
|
|
|
/// reply with its longest known chain, starting from a locator hash
|
|
|
|
/// if possible and block 1 otherwise.
|
2019-01-16 20:45:31 +00:00
|
|
|
pub locator_hashes: Vec<sha256d::Hash>,
|
2015-04-07 22:51:57 +00:00
|
|
|
/// References the block to stop at, or zero to just fetch the maximum 500 blocks
|
2019-01-16 20:45:31 +00:00
|
|
|
pub stop_hash: sha256d::Hash,
|
2014-07-18 13:56:17 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/// The `getheaders` message
|
2015-03-26 15:35:31 +00:00
|
|
|
#[derive(PartialEq, Eq, Clone, Debug)]
|
2014-07-18 13:56:17 +00:00
|
|
|
pub struct GetHeadersMessage {
|
2015-04-07 22:51:57 +00:00
|
|
|
/// The protocol version
|
|
|
|
pub version: u32,
|
|
|
|
/// Locator hashes --- ordered newest to oldest. The remote peer will
|
|
|
|
/// reply with its longest known chain, starting from a locator hash
|
|
|
|
/// if possible and block 1 otherwise.
|
2019-01-16 20:45:31 +00:00
|
|
|
pub locator_hashes: Vec<sha256d::Hash>,
|
2015-04-07 22:51:57 +00:00
|
|
|
/// References the header to stop at, or zero to just fetch the maximum 2000 headers
|
2019-01-16 20:45:31 +00:00
|
|
|
pub stop_hash: sha256d::Hash
|
2014-07-18 13:56:17 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/// An inventory object --- a reference to a Bitcoin object
|
2015-03-26 15:35:31 +00:00
|
|
|
#[derive(PartialEq, Eq, Clone, Debug)]
|
2014-07-18 13:56:17 +00:00
|
|
|
pub struct Inventory {
|
2015-04-07 22:51:57 +00:00
|
|
|
/// The type of object that is referenced
|
|
|
|
pub inv_type: InvType,
|
|
|
|
/// The object's hash
|
2019-01-16 20:45:31 +00:00
|
|
|
pub hash: sha256d::Hash
|
2014-07-18 13:56:17 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
impl GetBlocksMessage {
|
2015-04-07 22:51:57 +00:00
|
|
|
/// Construct a new `getblocks` message
|
2019-01-16 20:45:31 +00:00
|
|
|
pub fn new(locator_hashes: Vec<sha256d::Hash>, stop_hash: sha256d::Hash) -> GetBlocksMessage {
|
2015-04-07 22:51:57 +00:00
|
|
|
GetBlocksMessage {
|
|
|
|
version: constants::PROTOCOL_VERSION,
|
|
|
|
locator_hashes: locator_hashes.clone(),
|
|
|
|
stop_hash: stop_hash
|
|
|
|
}
|
2014-07-18 13:56:17 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-01-18 18:16:01 +00:00
|
|
|
impl_consensus_encoding!(GetBlocksMessage, version, locator_hashes, stop_hash);
|
2014-07-18 13:56:17 +00:00
|
|
|
|
|
|
|
impl GetHeadersMessage {
|
2015-04-07 22:51:57 +00:00
|
|
|
/// Construct a new `getheaders` message
|
2019-01-16 20:45:31 +00:00
|
|
|
pub fn new(locator_hashes: Vec<sha256d::Hash>, stop_hash: sha256d::Hash) -> GetHeadersMessage {
|
2015-04-07 22:51:57 +00:00
|
|
|
GetHeadersMessage {
|
|
|
|
version: constants::PROTOCOL_VERSION,
|
|
|
|
locator_hashes: locator_hashes,
|
|
|
|
stop_hash: stop_hash
|
|
|
|
}
|
2014-07-18 13:56:17 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-01-18 18:16:01 +00:00
|
|
|
impl_consensus_encoding!(GetHeadersMessage, version, locator_hashes, stop_hash);
|
2014-07-18 13:56:17 +00:00
|
|
|
|
2019-07-11 14:56:37 +00:00
|
|
|
impl Encodable for Inventory {
|
2015-04-07 22:51:57 +00:00
|
|
|
#[inline]
|
2019-07-11 14:56:37 +00:00
|
|
|
fn consensus_encode<S: io::Write>(
|
|
|
|
&self,
|
|
|
|
mut s: S,
|
|
|
|
) -> Result<usize, encode::Error> {
|
2019-05-23 20:28:10 +00:00
|
|
|
let inv_len = match self.inv_type {
|
2019-07-11 14:56:37 +00:00
|
|
|
InvType::Error => 0u32,
|
2015-04-07 22:51:57 +00:00
|
|
|
InvType::Transaction => 1,
|
2018-05-28 13:24:35 +00:00
|
|
|
InvType::Block => 2,
|
|
|
|
InvType::WitnessBlock => 0x40000002,
|
|
|
|
InvType::WitnessTransaction => 0x40000001
|
2019-07-11 14:56:37 +00:00
|
|
|
}.consensus_encode(&mut s)?;
|
|
|
|
Ok(inv_len + self.hash.consensus_encode(&mut s)?)
|
2015-04-07 22:51:57 +00:00
|
|
|
}
|
2014-08-01 16:01:39 +00:00
|
|
|
}
|
2014-07-18 13:56:17 +00:00
|
|
|
|
2019-07-11 17:06:42 +00:00
|
|
|
impl Decodable for Inventory {
|
2015-04-07 22:51:57 +00:00
|
|
|
#[inline]
|
2019-07-11 17:06:42 +00:00
|
|
|
fn consensus_decode<D: io::Read>(mut d: D) -> Result<Self, encode::Error> {
|
|
|
|
let int_type: u32 = Decodable::consensus_decode(&mut d)?;
|
2015-04-07 22:51:57 +00:00
|
|
|
Ok(Inventory {
|
|
|
|
inv_type: match int_type {
|
|
|
|
0 => InvType::Error,
|
|
|
|
1 => InvType::Transaction,
|
|
|
|
2 => InvType::Block,
|
|
|
|
// TODO do not fail here
|
|
|
|
_ => { panic!("bad inventory type field") }
|
|
|
|
},
|
Move relevant names into consensus::encode
- Move network::encodable::* to consensus::encode::*
- Rename Consensus{En,De}codable to {En,De}codable (now under
consensus::encode)
- Move network::serialize::Error to consensus::encode::Error
- Remove Raw{En,De}coder, implement {En,De}coder for T: {Write,Read}
instead
- Move network::serialize::Simple{En,De}coder to
consensus::encode::{En,De}coder
- Rename util::Error::Serialize to util::Error::Encode
- Modify comments to refer to new names
- Modify files to refer to new names
- Expose {En,De}cod{able,er}, {de,}serialize, Params
- Do not return Result for serialize{,_hex} as serializing to a Vec
should never fail
2018-09-20 10:15:45 +00:00
|
|
|
hash: Decodable::consensus_decode(d)?
|
2015-04-07 22:51:57 +00:00
|
|
|
})
|
|
|
|
}
|
2014-07-18 13:56:17 +00:00
|
|
|
}
|
|
|
|
|
2014-08-01 16:01:39 +00:00
|
|
|
#[cfg(test)]
|
|
|
|
mod tests {
|
2015-04-07 22:51:57 +00:00
|
|
|
use super::{GetHeadersMessage, GetBlocksMessage};
|
|
|
|
|
2018-07-24 18:43:03 +00:00
|
|
|
use hex::decode as hex_decode;
|
2015-04-07 22:51:57 +00:00
|
|
|
|
Move relevant names into consensus::encode
- Move network::encodable::* to consensus::encode::*
- Rename Consensus{En,De}codable to {En,De}codable (now under
consensus::encode)
- Move network::serialize::Error to consensus::encode::Error
- Remove Raw{En,De}coder, implement {En,De}coder for T: {Write,Read}
instead
- Move network::serialize::Simple{En,De}coder to
consensus::encode::{En,De}coder
- Rename util::Error::Serialize to util::Error::Encode
- Modify comments to refer to new names
- Modify files to refer to new names
- Expose {En,De}cod{able,er}, {de,}serialize, Params
- Do not return Result for serialize{,_hex} as serializing to a Vec
should never fail
2018-09-20 10:15:45 +00:00
|
|
|
use consensus::encode::{deserialize, serialize};
|
2015-04-07 22:51:57 +00:00
|
|
|
use std::default::Default;
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn getblocks_message_test() {
|
2018-07-24 18:43:03 +00:00
|
|
|
let from_sat = hex_decode("72110100014a5e1e4baab89f3a32518a88c31bc87f618f76673e2cc77ab2127b7afdeda33b0000000000000000000000000000000000000000000000000000000000000000").unwrap();
|
|
|
|
let genhash = hex_decode("4a5e1e4baab89f3a32518a88c31bc87f618f76673e2cc77ab2127b7afdeda33b").unwrap();
|
2015-04-07 22:51:57 +00:00
|
|
|
|
2015-04-08 22:23:45 +00:00
|
|
|
let decode: Result<GetBlocksMessage, _> = deserialize(&from_sat);
|
2015-04-07 22:51:57 +00:00
|
|
|
assert!(decode.is_ok());
|
|
|
|
let real_decode = decode.unwrap();
|
|
|
|
assert_eq!(real_decode.version, 70002);
|
|
|
|
assert_eq!(real_decode.locator_hashes.len(), 1);
|
Move relevant names into consensus::encode
- Move network::encodable::* to consensus::encode::*
- Rename Consensus{En,De}codable to {En,De}codable (now under
consensus::encode)
- Move network::serialize::Error to consensus::encode::Error
- Remove Raw{En,De}coder, implement {En,De}coder for T: {Write,Read}
instead
- Move network::serialize::Simple{En,De}coder to
consensus::encode::{En,De}coder
- Rename util::Error::Serialize to util::Error::Encode
- Modify comments to refer to new names
- Modify files to refer to new names
- Expose {En,De}cod{able,er}, {de,}serialize, Params
- Do not return Result for serialize{,_hex} as serializing to a Vec
should never fail
2018-09-20 10:15:45 +00:00
|
|
|
assert_eq!(serialize(&real_decode.locator_hashes[0]), genhash);
|
2015-04-07 22:51:57 +00:00
|
|
|
assert_eq!(real_decode.stop_hash, Default::default());
|
|
|
|
|
Move relevant names into consensus::encode
- Move network::encodable::* to consensus::encode::*
- Rename Consensus{En,De}codable to {En,De}codable (now under
consensus::encode)
- Move network::serialize::Error to consensus::encode::Error
- Remove Raw{En,De}coder, implement {En,De}coder for T: {Write,Read}
instead
- Move network::serialize::Simple{En,De}coder to
consensus::encode::{En,De}coder
- Rename util::Error::Serialize to util::Error::Encode
- Modify comments to refer to new names
- Modify files to refer to new names
- Expose {En,De}cod{able,er}, {de,}serialize, Params
- Do not return Result for serialize{,_hex} as serializing to a Vec
should never fail
2018-09-20 10:15:45 +00:00
|
|
|
assert_eq!(serialize(&real_decode), from_sat);
|
2015-04-07 22:51:57 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn getheaders_message_test() {
|
2018-07-24 18:43:03 +00:00
|
|
|
let from_sat = hex_decode("72110100014a5e1e4baab89f3a32518a88c31bc87f618f76673e2cc77ab2127b7afdeda33b0000000000000000000000000000000000000000000000000000000000000000").unwrap();
|
|
|
|
let genhash = hex_decode("4a5e1e4baab89f3a32518a88c31bc87f618f76673e2cc77ab2127b7afdeda33b").unwrap();
|
2015-04-07 22:51:57 +00:00
|
|
|
|
2015-04-08 22:23:45 +00:00
|
|
|
let decode: Result<GetHeadersMessage, _> = deserialize(&from_sat);
|
2015-04-07 22:51:57 +00:00
|
|
|
assert!(decode.is_ok());
|
|
|
|
let real_decode = decode.unwrap();
|
|
|
|
assert_eq!(real_decode.version, 70002);
|
|
|
|
assert_eq!(real_decode.locator_hashes.len(), 1);
|
Move relevant names into consensus::encode
- Move network::encodable::* to consensus::encode::*
- Rename Consensus{En,De}codable to {En,De}codable (now under
consensus::encode)
- Move network::serialize::Error to consensus::encode::Error
- Remove Raw{En,De}coder, implement {En,De}coder for T: {Write,Read}
instead
- Move network::serialize::Simple{En,De}coder to
consensus::encode::{En,De}coder
- Rename util::Error::Serialize to util::Error::Encode
- Modify comments to refer to new names
- Modify files to refer to new names
- Expose {En,De}cod{able,er}, {de,}serialize, Params
- Do not return Result for serialize{,_hex} as serializing to a Vec
should never fail
2018-09-20 10:15:45 +00:00
|
|
|
assert_eq!(serialize(&real_decode.locator_hashes[0]), genhash);
|
2015-04-07 22:51:57 +00:00
|
|
|
assert_eq!(real_decode.stop_hash, Default::default());
|
|
|
|
|
Move relevant names into consensus::encode
- Move network::encodable::* to consensus::encode::*
- Rename Consensus{En,De}codable to {En,De}codable (now under
consensus::encode)
- Move network::serialize::Error to consensus::encode::Error
- Remove Raw{En,De}coder, implement {En,De}coder for T: {Write,Read}
instead
- Move network::serialize::Simple{En,De}coder to
consensus::encode::{En,De}coder
- Rename util::Error::Serialize to util::Error::Encode
- Modify comments to refer to new names
- Modify files to refer to new names
- Expose {En,De}cod{able,er}, {de,}serialize, Params
- Do not return Result for serialize{,_hex} as serializing to a Vec
should never fail
2018-09-20 10:15:45 +00:00
|
|
|
assert_eq!(serialize(&real_decode), from_sat);
|
2015-04-07 22:51:57 +00:00
|
|
|
}
|
2014-07-18 13:56:17 +00:00
|
|
|
}
|
|
|
|
|