use std::iter;
use std::io::Cursor;
use std::sync::mpsc::Sender;
use blockdata::block;
use blockdata::transaction;
use network::address::Address;
use network::message_network;
use network::message_blockdata;
use consensus::encode::{Decodable, Encodable};
use consensus::encode::CheckedData;
use consensus::encode::{self, serialize, Encoder, Decoder};
use util;
#[derive(PartialEq, Eq, Clone, Debug)]
pub struct CommandString(pub String);
impl<S: Encoder> Encodable<S> for CommandString {
#[inline]
fn consensus_encode(&self, s: &mut S) -> Result<(), encode::Error> {
let &CommandString(ref inner_str) = self;
let mut rawbytes = [0u8; 12];
let strbytes = inner_str.as_bytes();
if strbytes.len() > 12 {
panic!("Command string longer than 12 bytes");
}
for x in 0..strbytes.len() {
rawbytes[x] = strbytes[x];
}
rawbytes.consensus_encode(s)
}
}
impl<D: Decoder> Decodable<D> for CommandString {
#[inline]
fn consensus_decode(d: &mut D) -> Result<CommandString, encode::Error> {
let rawbytes: [u8; 12] = Decodable::consensus_decode(d)?;
let rv = iter::FromIterator::from_iter(rawbytes.iter().filter_map(|&u| if u > 0 { Some(u as char) } else { None }));
Ok(CommandString(rv))
}
}
pub struct RawNetworkMessage {
pub magic: u32,
pub payload: NetworkMessage
}
pub enum SocketResponse {
MessageReceived(NetworkMessage),
ConnectionFailed(util::Error, Sender<()>)
}
#[derive(Clone, PartialEq, Eq, Debug)]
pub enum NetworkMessage {
Version(message_network::VersionMessage),
Verack,
Addr(Vec<(u32, Address)>),
Inv(Vec<message_blockdata::Inventory>),
GetData(Vec<message_blockdata::Inventory>),
NotFound(Vec<message_blockdata::Inventory>),
GetBlocks(message_blockdata::GetBlocksMessage),
GetHeaders(message_blockdata::GetHeadersMessage),
MemPool,
Tx(transaction::Transaction),
Block(block::Block),
Headers(Vec<block::LoneBlockHeader>),
GetAddr,
Ping(u64),
Pong(u64),
Alert(Vec<u8>)
}
impl RawNetworkMessage {
pub fn command(&self) -> String {
match self.payload {
NetworkMessage::Version(_) => "version",
NetworkMessage::Verack => "verack",
NetworkMessage::Addr(_) => "addr",
NetworkMessage::Inv(_) => "inv",
NetworkMessage::GetData(_) => "getdata",
NetworkMessage::NotFound(_) => "notfound",
NetworkMessage::GetBlocks(_) => "getblocks",
NetworkMessage::GetHeaders(_) => "getheaders",
NetworkMessage::MemPool => "mempool",
NetworkMessage::Tx(_) => "tx",
NetworkMessage::Block(_) => "block",
NetworkMessage::Headers(_) => "headers",
NetworkMessage::GetAddr => "getaddr",
NetworkMessage::Ping(_) => "ping",
NetworkMessage::Pong(_) => "pong",
NetworkMessage::Alert(_) => "alert",
}.to_owned()
}
}
impl<S: Encoder> Encodable<S> for RawNetworkMessage {
fn consensus_encode(&self, s: &mut S) -> Result<(), encode::Error> {
self.magic.consensus_encode(s)?;
CommandString(self.command()).consensus_encode(s)?;
CheckedData(match self.payload {
NetworkMessage::Version(ref dat) => serialize(dat),
NetworkMessage::Addr(ref dat) => serialize(dat),
NetworkMessage::Inv(ref dat) => serialize(dat),
NetworkMessage::GetData(ref dat) => serialize(dat),
NetworkMessage::NotFound(ref dat) => serialize(dat),
NetworkMessage::GetBlocks(ref dat) => serialize(dat),
NetworkMessage::GetHeaders(ref dat) => serialize(dat),
NetworkMessage::Tx(ref dat) => serialize(dat),
NetworkMessage::Block(ref dat) => serialize(dat),
NetworkMessage::Headers(ref dat) => serialize(dat),
NetworkMessage::Ping(ref dat) => serialize(dat),
NetworkMessage::Pong(ref dat) => serialize(dat),
NetworkMessage::Alert(ref dat) => serialize(dat),
NetworkMessage::Verack
| NetworkMessage::MemPool
| NetworkMessage::GetAddr => vec![],
}).consensus_encode(s)
}
}
impl<D: Decoder> Decodable<D> for RawNetworkMessage {
fn consensus_decode(d: &mut D) -> Result<RawNetworkMessage, encode::Error> {
let magic = Decodable::consensus_decode(d)?;
let CommandString(cmd): CommandString= Decodable::consensus_decode(d)?;
let CheckedData(raw_payload): CheckedData = Decodable::consensus_decode(d)?;
let mut mem_d = Cursor::new(raw_payload);
let payload = match &cmd[..] {
"version" => NetworkMessage::Version(Decodable::consensus_decode(&mut mem_d)?),
"verack" => NetworkMessage::Verack,
"addr" => NetworkMessage::Addr(Decodable::consensus_decode(&mut mem_d)?),
"inv" => NetworkMessage::Inv(Decodable::consensus_decode(&mut mem_d)?),
"getdata" => NetworkMessage::GetData(Decodable::consensus_decode(&mut mem_d)?),
"notfound" => NetworkMessage::NotFound(Decodable::consensus_decode(&mut mem_d)?),
"getblocks" => NetworkMessage::GetBlocks(Decodable::consensus_decode(&mut mem_d)?),
"getheaders" => NetworkMessage::GetHeaders(Decodable::consensus_decode(&mut mem_d)?),
"mempool" => NetworkMessage::MemPool,
"block" => NetworkMessage::Block(Decodable::consensus_decode(&mut mem_d)?),
"headers" => NetworkMessage::Headers(Decodable::consensus_decode(&mut mem_d)?),
"getaddr" => NetworkMessage::GetAddr,
"ping" => NetworkMessage::Ping(Decodable::consensus_decode(&mut mem_d)?),
"pong" => NetworkMessage::Pong(Decodable::consensus_decode(&mut mem_d)?),
"tx" => NetworkMessage::Tx(Decodable::consensus_decode(&mut mem_d)?),
"alert" => NetworkMessage::Alert(Decodable::consensus_decode(&mut mem_d)?),
_ => return Err(encode::Error::UnrecognizedNetworkCommand(cmd)),
};
Ok(RawNetworkMessage {
magic: magic,
payload: payload
})
}
}
#[cfg(test)]
mod test {
use super::{RawNetworkMessage, NetworkMessage, CommandString};
use consensus::encode::{deserialize, serialize};
#[test]
fn serialize_commandstring_test() {
let cs = CommandString("Andrew".to_owned());
assert_eq!(serialize(&cs), vec![0x41u8, 0x6e, 0x64, 0x72, 0x65, 0x77, 0, 0, 0, 0, 0, 0]);
}
#[test]
fn deserialize_commandstring_test() {
let cs: Result<CommandString, _> = deserialize(&[0x41u8, 0x6e, 0x64, 0x72, 0x65, 0x77, 0, 0, 0, 0, 0, 0]);
assert!(cs.is_ok());
assert_eq!(cs.unwrap(), CommandString("Andrew".to_owned()));
let short_cs: Result<CommandString, _> = deserialize(&[0x41u8, 0x6e, 0x64, 0x72, 0x65, 0x77, 0, 0, 0, 0, 0]);
assert!(short_cs.is_err());
}
#[test]
fn serialize_verack_test() {
assert_eq!(serialize(&RawNetworkMessage { magic: 0xd9b4bef9, payload: NetworkMessage::Verack }),
vec![0xf9, 0xbe, 0xb4, 0xd9, 0x76, 0x65, 0x72, 0x61,
0x63, 0x6B, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x5d, 0xf6, 0xe0, 0xe2]);
}
#[test]
fn serialize_ping_test() {
assert_eq!(serialize(&RawNetworkMessage { magic: 0xd9b4bef9, payload: NetworkMessage::Ping(100) }),
vec![0xf9, 0xbe, 0xb4, 0xd9, 0x70, 0x69, 0x6e, 0x67,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x08, 0x00, 0x00, 0x00, 0x24, 0x67, 0xf1, 0x1d,
0x64, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]);
}
#[test]
fn serialize_mempool_test() {
assert_eq!(serialize(&RawNetworkMessage { magic: 0xd9b4bef9, payload: NetworkMessage::MemPool }),
vec![0xf9, 0xbe, 0xb4, 0xd9, 0x6d, 0x65, 0x6d, 0x70,
0x6f, 0x6f, 0x6c, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x5d, 0xf6, 0xe0, 0xe2]);
}
#[test]
fn serialize_getaddr_test() {
assert_eq!(serialize(&RawNetworkMessage { magic: 0xd9b4bef9, payload: NetworkMessage::GetAddr }),
vec![0xf9, 0xbe, 0xb4, 0xd9, 0x67, 0x65, 0x74, 0x61,
0x64, 0x64, 0x72, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x5d, 0xf6, 0xe0, 0xe2]);
}
}