bitcoin/network/
message.rs

1// Rust Bitcoin Library
2// Written in 2014 by
3//     Andrew Poelstra <apoelstra@wpsoftware.net>
4//
5// To the extent possible under law, the author(s) have dedicated all
6// copyright and related and neighboring rights to this software to
7// the public domain worldwide. This software is distributed without
8// any warranty.
9//
10// You should have received a copy of the CC0 Public Domain Dedication
11// along with this software.
12// If not, see <http://creativecommons.org/publicdomain/zero/1.0/>.
13//
14
15//! Network message
16//!
17//! This module defines the `Message` traits which are used
18//! for (de)serializing Bitcoin objects for transmission on the network. It
19//! also defines (de)serialization routines for many primitives.
20//!
21
22use std::iter;
23use std::io::Cursor;
24use std::sync::mpsc::Sender;
25
26use blockdata::block;
27use blockdata::transaction;
28use network::address::Address;
29use network::message_network;
30use network::message_blockdata;
31use consensus::encode::{Decodable, Encodable};
32use consensus::encode::CheckedData;
33use consensus::encode::{self, serialize, Encoder, Decoder};
34use util;
35
36/// Serializer for command string
37#[derive(PartialEq, Eq, Clone, Debug)]
38pub struct CommandString(pub String);
39
40impl<S: Encoder> Encodable<S> for CommandString {
41    #[inline]
42    fn consensus_encode(&self, s: &mut S) -> Result<(), encode::Error> {
43        let &CommandString(ref inner_str) = self;
44        let mut rawbytes = [0u8; 12];
45        let strbytes = inner_str.as_bytes();
46        if strbytes.len() > 12 {
47            panic!("Command string longer than 12 bytes");
48        }
49        for x in 0..strbytes.len() {
50            rawbytes[x] = strbytes[x];
51        }
52        rawbytes.consensus_encode(s)
53    }
54}
55
56impl<D: Decoder> Decodable<D> for CommandString {
57    #[inline]
58    fn consensus_decode(d: &mut D) -> Result<CommandString, encode::Error> {
59        let rawbytes: [u8; 12] = Decodable::consensus_decode(d)?;
60        let rv = iter::FromIterator::from_iter(rawbytes.iter().filter_map(|&u| if u > 0 { Some(u as char) } else { None }));
61        Ok(CommandString(rv))
62    }
63}
64
65/// A Network message
66pub struct RawNetworkMessage {
67    /// Magic bytes to identify the network these messages are meant for
68    pub magic: u32,
69    /// The actual message data
70    pub payload: NetworkMessage
71}
72
73/// A response from the peer-connected socket
74pub enum SocketResponse {
75    /// A message was received
76    MessageReceived(NetworkMessage),
77    /// An error occurred and the socket needs to close
78    ConnectionFailed(util::Error, Sender<()>)
79}
80
81#[derive(Clone, PartialEq, Eq, Debug)]
82/// A Network message payload. Proper documentation is available on at
83/// [Bitcoin Wiki: Protocol Specification](https://en.bitcoin.it/wiki/Protocol_specification)
84pub enum NetworkMessage {
85    /// `version`
86    Version(message_network::VersionMessage),
87    /// `verack`
88    Verack,
89    /// `addr`
90    Addr(Vec<(u32, Address)>),
91    /// `inv`
92    Inv(Vec<message_blockdata::Inventory>),
93    /// `getdata`
94    GetData(Vec<message_blockdata::Inventory>),
95    /// `notfound`
96    NotFound(Vec<message_blockdata::Inventory>),
97    /// `getblocks`
98    GetBlocks(message_blockdata::GetBlocksMessage),
99    /// `getheaders`
100    GetHeaders(message_blockdata::GetHeadersMessage),
101    /// `mempool`
102    MemPool,
103    /// tx
104    Tx(transaction::Transaction),
105    /// `block`
106    Block(block::Block),
107    /// `headers`
108    Headers(Vec<block::LoneBlockHeader>),
109    /// `getaddr`
110    GetAddr,
111    // TODO: checkorder,
112    // TODO: submitorder,
113    // TODO: reply,
114    /// `ping`
115    Ping(u64),
116    /// `pong`
117    Pong(u64),
118    // TODO: reject,
119    // TODO: bloom filtering
120    // TODO: alert
121    /// `alert`
122    Alert(Vec<u8>)
123}
124
125impl RawNetworkMessage {
126    /// Return the message command. This is useful for debug outputs.
127    pub fn command(&self) -> String {
128        match self.payload {
129            NetworkMessage::Version(_) => "version",
130            NetworkMessage::Verack     => "verack",
131            NetworkMessage::Addr(_)    => "addr",
132            NetworkMessage::Inv(_)     => "inv",
133            NetworkMessage::GetData(_) => "getdata",
134            NetworkMessage::NotFound(_) => "notfound",
135            NetworkMessage::GetBlocks(_) => "getblocks",
136            NetworkMessage::GetHeaders(_) => "getheaders",
137            NetworkMessage::MemPool    => "mempool",
138            NetworkMessage::Tx(_)      => "tx",
139            NetworkMessage::Block(_)   => "block",
140            NetworkMessage::Headers(_) => "headers",
141            NetworkMessage::GetAddr    => "getaddr",
142            NetworkMessage::Ping(_)    => "ping",
143            NetworkMessage::Pong(_)    => "pong",
144            NetworkMessage::Alert(_)    => "alert",
145        }.to_owned()
146    }
147}
148
149impl<S: Encoder> Encodable<S> for RawNetworkMessage {
150    fn consensus_encode(&self, s: &mut S) -> Result<(), encode::Error> {
151        self.magic.consensus_encode(s)?;
152        CommandString(self.command()).consensus_encode(s)?;
153        CheckedData(match self.payload {
154            NetworkMessage::Version(ref dat) => serialize(dat),
155            NetworkMessage::Addr(ref dat)    => serialize(dat),
156            NetworkMessage::Inv(ref dat)     => serialize(dat),
157            NetworkMessage::GetData(ref dat) => serialize(dat),
158            NetworkMessage::NotFound(ref dat) => serialize(dat),
159            NetworkMessage::GetBlocks(ref dat) => serialize(dat),
160            NetworkMessage::GetHeaders(ref dat) => serialize(dat),
161            NetworkMessage::Tx(ref dat)      => serialize(dat),
162            NetworkMessage::Block(ref dat)   => serialize(dat),
163            NetworkMessage::Headers(ref dat) => serialize(dat),
164            NetworkMessage::Ping(ref dat)    => serialize(dat),
165            NetworkMessage::Pong(ref dat)    => serialize(dat),
166            NetworkMessage::Alert(ref dat)    => serialize(dat),
167            NetworkMessage::Verack
168            | NetworkMessage::MemPool
169            | NetworkMessage::GetAddr => vec![],
170        }).consensus_encode(s)
171    }
172}
173
174impl<D: Decoder> Decodable<D> for RawNetworkMessage {
175    fn consensus_decode(d: &mut D) -> Result<RawNetworkMessage, encode::Error> {
176        let magic = Decodable::consensus_decode(d)?;
177        let CommandString(cmd): CommandString= Decodable::consensus_decode(d)?;
178        let CheckedData(raw_payload): CheckedData = Decodable::consensus_decode(d)?;
179
180        let mut mem_d = Cursor::new(raw_payload);
181        let payload = match &cmd[..] {
182            "version" => NetworkMessage::Version(Decodable::consensus_decode(&mut mem_d)?),
183            "verack"  => NetworkMessage::Verack,
184            "addr"    => NetworkMessage::Addr(Decodable::consensus_decode(&mut mem_d)?),
185            "inv"     => NetworkMessage::Inv(Decodable::consensus_decode(&mut mem_d)?),
186            "getdata" => NetworkMessage::GetData(Decodable::consensus_decode(&mut mem_d)?),
187            "notfound" => NetworkMessage::NotFound(Decodable::consensus_decode(&mut mem_d)?),
188            "getblocks" => NetworkMessage::GetBlocks(Decodable::consensus_decode(&mut mem_d)?),
189            "getheaders" => NetworkMessage::GetHeaders(Decodable::consensus_decode(&mut mem_d)?),
190            "mempool" => NetworkMessage::MemPool,
191            "block"   => NetworkMessage::Block(Decodable::consensus_decode(&mut mem_d)?),
192            "headers" => NetworkMessage::Headers(Decodable::consensus_decode(&mut mem_d)?),
193            "getaddr" => NetworkMessage::GetAddr,
194            "ping"    => NetworkMessage::Ping(Decodable::consensus_decode(&mut mem_d)?),
195            "pong"    => NetworkMessage::Pong(Decodable::consensus_decode(&mut mem_d)?),
196            "tx"      => NetworkMessage::Tx(Decodable::consensus_decode(&mut mem_d)?),
197            "alert"   => NetworkMessage::Alert(Decodable::consensus_decode(&mut mem_d)?),
198            _ => return Err(encode::Error::UnrecognizedNetworkCommand(cmd)),
199        };
200        Ok(RawNetworkMessage {
201            magic: magic,
202            payload: payload
203        })
204    }
205}
206
207#[cfg(test)]
208mod test {
209    use super::{RawNetworkMessage, NetworkMessage, CommandString};
210
211    use consensus::encode::{deserialize, serialize};
212
213    #[test]
214    fn serialize_commandstring_test() {
215        let cs = CommandString("Andrew".to_owned());
216        assert_eq!(serialize(&cs), vec![0x41u8, 0x6e, 0x64, 0x72, 0x65, 0x77, 0, 0, 0, 0, 0, 0]);
217    }
218
219    #[test]
220    fn deserialize_commandstring_test() {
221        let cs: Result<CommandString, _> = deserialize(&[0x41u8, 0x6e, 0x64, 0x72, 0x65, 0x77, 0, 0, 0, 0, 0, 0]);
222        assert!(cs.is_ok());
223        assert_eq!(cs.unwrap(), CommandString("Andrew".to_owned()));
224
225        let short_cs: Result<CommandString, _> = deserialize(&[0x41u8, 0x6e, 0x64, 0x72, 0x65, 0x77, 0, 0, 0, 0, 0]);
226        assert!(short_cs.is_err());
227    }
228
229    #[test]
230    fn serialize_verack_test() {
231        assert_eq!(serialize(&RawNetworkMessage { magic: 0xd9b4bef9, payload: NetworkMessage::Verack }),
232                             vec![0xf9, 0xbe, 0xb4, 0xd9, 0x76, 0x65, 0x72, 0x61,
233                                  0x63, 0x6B, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
234                                  0x00, 0x00, 0x00, 0x00, 0x5d, 0xf6, 0xe0, 0xe2]);
235    }
236
237    #[test]
238    fn serialize_ping_test() {
239        assert_eq!(serialize(&RawNetworkMessage { magic: 0xd9b4bef9, payload: NetworkMessage::Ping(100) }),
240                             vec![0xf9, 0xbe, 0xb4, 0xd9, 0x70, 0x69, 0x6e, 0x67,
241                                  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
242                                  0x08, 0x00, 0x00, 0x00, 0x24, 0x67, 0xf1, 0x1d,
243                                  0x64, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]);
244    }
245
246
247    #[test]
248    fn serialize_mempool_test() {
249        assert_eq!(serialize(&RawNetworkMessage { magic: 0xd9b4bef9, payload: NetworkMessage::MemPool }),
250                             vec![0xf9, 0xbe, 0xb4, 0xd9, 0x6d, 0x65, 0x6d, 0x70,
251                                  0x6f, 0x6f, 0x6c, 0x00, 0x00, 0x00, 0x00, 0x00,
252                                  0x00, 0x00, 0x00, 0x00, 0x5d, 0xf6, 0xe0, 0xe2]);
253    }
254
255    #[test]
256    fn serialize_getaddr_test() {
257        assert_eq!(serialize(&RawNetworkMessage { magic: 0xd9b4bef9, payload: NetworkMessage::GetAddr }),
258                             vec![0xf9, 0xbe, 0xb4, 0xd9, 0x67, 0x65, 0x74, 0x61,
259                                  0x64, 0x64, 0x72, 0x00, 0x00, 0x00, 0x00, 0x00,
260                                  0x00, 0x00, 0x00, 0x00, 0x5d, 0xf6, 0xe0, 0xe2]);
261    }
262
263}