Merge pull request #357 from stevenroose/command-str
Various optimizations of the network code
This commit is contained in:
commit
024557fe47
|
@ -29,11 +29,8 @@
|
||||||
//! big-endian decimals, etc.)
|
//! big-endian decimals, etc.)
|
||||||
//!
|
//!
|
||||||
|
|
||||||
use std::{mem, u32};
|
use std::{fmt, error, io, mem, u32};
|
||||||
|
use std::borrow::Cow;
|
||||||
use std::error;
|
|
||||||
use std::fmt;
|
|
||||||
use std::io;
|
|
||||||
use std::io::{Cursor, Read, Write};
|
use std::io::{Cursor, Read, Write};
|
||||||
use hashes::hex::ToHex;
|
use hashes::hex::ToHex;
|
||||||
|
|
||||||
|
@ -483,6 +480,26 @@ impl Decodable for String {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Cow<'static, str>
|
||||||
|
impl Encodable for Cow<'static, str> {
|
||||||
|
#[inline]
|
||||||
|
fn consensus_encode<S: io::Write>(&self, mut s: S) -> Result<usize, Error> {
|
||||||
|
let b = self.as_bytes();
|
||||||
|
let vi_len = VarInt(b.len() as u64).consensus_encode(&mut s)?;
|
||||||
|
s.emit_slice(&b)?;
|
||||||
|
Ok(vi_len + b.len())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Decodable for Cow<'static, str> {
|
||||||
|
#[inline]
|
||||||
|
fn consensus_decode<D: io::Read>(d: D) -> Result<Cow<'static, str>, Error> {
|
||||||
|
String::from_utf8(Decodable::consensus_decode(d)?)
|
||||||
|
.map_err(|_| self::Error::ParseFailed("String was not valid UTF8"))
|
||||||
|
.map(Cow::Owned)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
// Arrays
|
// Arrays
|
||||||
macro_rules! impl_array {
|
macro_rules! impl_array {
|
||||||
|
@ -894,6 +911,10 @@ mod tests {
|
||||||
#[test]
|
#[test]
|
||||||
fn deserialize_strbuf_test() {
|
fn deserialize_strbuf_test() {
|
||||||
assert_eq!(deserialize(&[6u8, 0x41, 0x6e, 0x64, 0x72, 0x65, 0x77]).ok(), Some("Andrew".to_string()));
|
assert_eq!(deserialize(&[6u8, 0x41, 0x6e, 0x64, 0x72, 0x65, 0x77]).ok(), Some("Andrew".to_string()));
|
||||||
|
assert_eq!(
|
||||||
|
deserialize(&[6u8, 0x41, 0x6e, 0x64, 0x72, 0x65, 0x77]).ok(),
|
||||||
|
Some(::std::borrow::Cow::Borrowed("Andrew"))
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
|
|
@ -19,7 +19,8 @@
|
||||||
//! also defines (de)serialization routines for many primitives.
|
//! also defines (de)serialization routines for many primitives.
|
||||||
//!
|
//!
|
||||||
|
|
||||||
use std::{io, iter, mem};
|
use std::{io, iter, mem, fmt};
|
||||||
|
use std::borrow::Cow;
|
||||||
use std::io::Cursor;
|
use std::io::Cursor;
|
||||||
|
|
||||||
use blockdata::block;
|
use blockdata::block;
|
||||||
|
@ -34,7 +35,31 @@ use consensus::encode::MAX_VEC_SIZE;
|
||||||
|
|
||||||
/// Serializer for command string
|
/// Serializer for command string
|
||||||
#[derive(PartialEq, Eq, Clone, Debug)]
|
#[derive(PartialEq, Eq, Clone, Debug)]
|
||||||
pub struct CommandString(pub String);
|
pub struct CommandString(Cow<'static, str>);
|
||||||
|
|
||||||
|
impl fmt::Display for CommandString {
|
||||||
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||||
|
f.write_str(self.0.as_ref())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<&'static str> for CommandString {
|
||||||
|
fn from(f: &'static str) -> Self {
|
||||||
|
CommandString(f.into())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<String> for CommandString {
|
||||||
|
fn from(f: String) -> Self {
|
||||||
|
CommandString(f.into())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl AsRef<str> for CommandString {
|
||||||
|
fn as_ref(&self) -> &str {
|
||||||
|
self.0.as_ref()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl Encodable for CommandString {
|
impl Encodable for CommandString {
|
||||||
#[inline]
|
#[inline]
|
||||||
|
@ -42,11 +67,10 @@ impl Encodable for CommandString {
|
||||||
&self,
|
&self,
|
||||||
s: S,
|
s: S,
|
||||||
) -> Result<usize, encode::Error> {
|
) -> Result<usize, encode::Error> {
|
||||||
let &CommandString(ref inner_str) = self;
|
|
||||||
let mut rawbytes = [0u8; 12];
|
let mut rawbytes = [0u8; 12];
|
||||||
let strbytes = inner_str.as_bytes();
|
let strbytes = self.0.as_bytes();
|
||||||
if strbytes.len() > 12 {
|
if strbytes.len() > 12 {
|
||||||
panic!("Command string longer than 12 bytes");
|
return Err(encode::Error::UnrecognizedNetworkCommand(self.0.clone().into_owned()));
|
||||||
}
|
}
|
||||||
for x in 0..strbytes.len() {
|
for x in 0..strbytes.len() {
|
||||||
rawbytes[x] = strbytes[x];
|
rawbytes[x] = strbytes[x];
|
||||||
|
@ -116,7 +140,6 @@ pub enum NetworkMessage {
|
||||||
Ping(u64),
|
Ping(u64),
|
||||||
/// `pong`
|
/// `pong`
|
||||||
Pong(u64),
|
Pong(u64),
|
||||||
// TODO: reject,
|
|
||||||
// TODO: bloom filtering
|
// TODO: bloom filtering
|
||||||
/// BIP157 getcfilters
|
/// BIP157 getcfilters
|
||||||
GetCFilters(message_filter::GetCFilters),
|
GetCFilters(message_filter::GetCFilters),
|
||||||
|
@ -136,10 +159,10 @@ pub enum NetworkMessage {
|
||||||
Reject(message_network::Reject)
|
Reject(message_network::Reject)
|
||||||
}
|
}
|
||||||
|
|
||||||
impl RawNetworkMessage {
|
impl NetworkMessage {
|
||||||
/// Return the message command. This is useful for debug outputs.
|
/// Return the message command. This is useful for debug outputs.
|
||||||
pub fn command(&self) -> String {
|
pub fn cmd(&self) -> &'static str {
|
||||||
match self.payload {
|
match *self {
|
||||||
NetworkMessage::Version(_) => "version",
|
NetworkMessage::Version(_) => "version",
|
||||||
NetworkMessage::Verack => "verack",
|
NetworkMessage::Verack => "verack",
|
||||||
NetworkMessage::Addr(_) => "addr",
|
NetworkMessage::Addr(_) => "addr",
|
||||||
|
@ -164,7 +187,24 @@ impl RawNetworkMessage {
|
||||||
NetworkMessage::CFCheckpt(_) => "cfcheckpt",
|
NetworkMessage::CFCheckpt(_) => "cfcheckpt",
|
||||||
NetworkMessage::Alert(_) => "alert",
|
NetworkMessage::Alert(_) => "alert",
|
||||||
NetworkMessage::Reject(_) => "reject",
|
NetworkMessage::Reject(_) => "reject",
|
||||||
}.to_owned()
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Return the CommandString for the message command.
|
||||||
|
pub fn command(&self) -> CommandString {
|
||||||
|
self.cmd().into()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl RawNetworkMessage {
|
||||||
|
/// Return the message command. This is useful for debug outputs.
|
||||||
|
pub fn cmd(&self) -> &'static str {
|
||||||
|
self.payload.cmd()
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Return the CommandString for the message command.
|
||||||
|
pub fn command(&self) -> CommandString {
|
||||||
|
self.payload.command()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -193,7 +233,7 @@ impl Encodable for RawNetworkMessage {
|
||||||
) -> Result<usize, encode::Error> {
|
) -> Result<usize, encode::Error> {
|
||||||
let mut len = 0;
|
let mut len = 0;
|
||||||
len += self.magic.consensus_encode(&mut s)?;
|
len += self.magic.consensus_encode(&mut s)?;
|
||||||
len += CommandString(self.command()).consensus_encode(&mut s)?;
|
len += self.command().consensus_encode(&mut s)?;
|
||||||
len += CheckedData(match self.payload {
|
len += CheckedData(match self.payload {
|
||||||
NetworkMessage::Version(ref dat) => serialize(dat),
|
NetworkMessage::Version(ref dat) => serialize(dat),
|
||||||
NetworkMessage::Addr(ref dat) => serialize(dat),
|
NetworkMessage::Addr(ref dat) => serialize(dat),
|
||||||
|
@ -281,7 +321,7 @@ impl Decodable for RawNetworkMessage {
|
||||||
"cfcheckpt" => NetworkMessage::CFCheckpt(Decodable::consensus_decode(&mut mem_d)?),
|
"cfcheckpt" => NetworkMessage::CFCheckpt(Decodable::consensus_decode(&mut mem_d)?),
|
||||||
"reject" => NetworkMessage::Reject(Decodable::consensus_decode(&mut mem_d)?),
|
"reject" => NetworkMessage::Reject(Decodable::consensus_decode(&mut mem_d)?),
|
||||||
"alert" => NetworkMessage::Alert(Decodable::consensus_decode(&mut mem_d)?),
|
"alert" => NetworkMessage::Alert(Decodable::consensus_decode(&mut mem_d)?),
|
||||||
_ => return Err(encode::Error::UnrecognizedNetworkCommand(cmd)),
|
_ => return Err(encode::Error::UnrecognizedNetworkCommand(cmd.into_owned())),
|
||||||
};
|
};
|
||||||
Ok(RawNetworkMessage {
|
Ok(RawNetworkMessage {
|
||||||
magic: magic,
|
magic: magic,
|
||||||
|
@ -292,20 +332,26 @@ impl Decodable for RawNetworkMessage {
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod test {
|
mod test {
|
||||||
|
use std::io;
|
||||||
use super::{RawNetworkMessage, NetworkMessage, CommandString};
|
use super::{RawNetworkMessage, NetworkMessage, CommandString};
|
||||||
use consensus::encode::{deserialize, deserialize_partial, serialize};
|
use consensus::encode::{Encodable, deserialize, deserialize_partial, serialize};
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn serialize_commandstring_test() {
|
fn serialize_commandstring_test() {
|
||||||
let cs = CommandString("Andrew".to_owned());
|
let cs = CommandString("Andrew".into());
|
||||||
assert_eq!(serialize(&cs), vec![0x41u8, 0x6e, 0x64, 0x72, 0x65, 0x77, 0, 0, 0, 0, 0, 0]);
|
assert_eq!(serialize(&cs), vec![0x41u8, 0x6e, 0x64, 0x72, 0x65, 0x77, 0, 0, 0, 0, 0, 0]);
|
||||||
|
|
||||||
|
// Test oversized one.
|
||||||
|
let mut encoder = io::Cursor::new(vec![]);
|
||||||
|
assert!(CommandString("AndrewAndrewA".into()).consensus_encode(&mut encoder).is_err());
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn deserialize_commandstring_test() {
|
fn deserialize_commandstring_test() {
|
||||||
let cs: Result<CommandString, _> = deserialize(&[0x41u8, 0x6e, 0x64, 0x72, 0x65, 0x77, 0, 0, 0, 0, 0, 0]);
|
let cs: Result<CommandString, _> = deserialize(&[0x41u8, 0x6e, 0x64, 0x72, 0x65, 0x77, 0, 0, 0, 0, 0, 0]);
|
||||||
assert!(cs.is_ok());
|
assert!(cs.is_ok());
|
||||||
assert_eq!(cs.unwrap(), CommandString("Andrew".to_owned()));
|
assert_eq!(cs.as_ref().unwrap().to_string(), "Andrew".to_owned());
|
||||||
|
assert_eq!(cs.unwrap(), "Andrew".into());
|
||||||
|
|
||||||
let short_cs: Result<CommandString, _> = deserialize(&[0x41u8, 0x6e, 0x64, 0x72, 0x65, 0x77, 0, 0, 0, 0, 0]);
|
let short_cs: Result<CommandString, _> = deserialize(&[0x41u8, 0x6e, 0x64, 0x72, 0x65, 0x77, 0, 0, 0, 0, 0]);
|
||||||
assert!(short_cs.is_err());
|
assert!(short_cs.is_err());
|
||||||
|
|
|
@ -24,7 +24,7 @@ use hashes::sha256d;
|
||||||
|
|
||||||
use std::io;
|
use std::io;
|
||||||
|
|
||||||
#[derive(PartialEq, Eq, Clone, Debug)]
|
#[derive(PartialEq, Eq, Clone, Debug, Copy)]
|
||||||
/// The type of an inventory object
|
/// The type of an inventory object
|
||||||
pub enum InvType {
|
pub enum InvType {
|
||||||
/// Error --- these inventories can be ignored
|
/// Error --- these inventories can be ignored
|
||||||
|
|
|
@ -18,12 +18,14 @@
|
||||||
//! capabilities
|
//! capabilities
|
||||||
//!
|
//!
|
||||||
|
|
||||||
|
use std::io;
|
||||||
|
use std::borrow::Cow;
|
||||||
|
|
||||||
use network::address::Address;
|
use network::address::Address;
|
||||||
use network::constants::{self, ServiceFlags};
|
use network::constants::{self, ServiceFlags};
|
||||||
use consensus::{Encodable, Decodable, ReadExt};
|
use consensus::{Encodable, Decodable, ReadExt};
|
||||||
use consensus::encode;
|
use consensus::encode;
|
||||||
use std::io;
|
use network::message::CommandString;
|
||||||
use network::message_network::RejectReason::{MALFORMED, INVALID, OBSOLETE, DUPLICATE, NONSTANDARD, DUST, CHECKPOINT, FEE};
|
|
||||||
use hashes::sha256d;
|
use hashes::sha256d;
|
||||||
|
|
||||||
/// Some simple messages
|
/// Some simple messages
|
||||||
|
@ -87,21 +89,21 @@ impl_consensus_encoding!(VersionMessage, version, services, timestamp,
|
||||||
/// message rejection reason as a code
|
/// message rejection reason as a code
|
||||||
pub enum RejectReason {
|
pub enum RejectReason {
|
||||||
/// malformed message
|
/// malformed message
|
||||||
MALFORMED = 0x01,
|
Malformed = 0x01,
|
||||||
/// invalid message
|
/// invalid message
|
||||||
INVALID = 0x10,
|
Invalid = 0x10,
|
||||||
/// obsolete message
|
/// obsolete message
|
||||||
OBSOLETE = 0x11,
|
Obsolete = 0x11,
|
||||||
/// duplicate message
|
/// duplicate message
|
||||||
DUPLICATE = 0x12,
|
Duplicate = 0x12,
|
||||||
/// nonstandard transaction
|
/// nonstandard transaction
|
||||||
NONSTANDARD = 0x40,
|
NonStandard = 0x40,
|
||||||
/// an output is below dust limit
|
/// an output is below dust limit
|
||||||
DUST = 0x41,
|
Dust = 0x41,
|
||||||
/// insufficient fee
|
/// insufficient fee
|
||||||
FEE = 0x42,
|
Fee = 0x42,
|
||||||
/// checkpoint
|
/// checkpoint
|
||||||
CHECKPOINT = 0x43
|
Checkpoint = 0x43
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Encodable for RejectReason {
|
impl Encodable for RejectReason {
|
||||||
|
@ -114,14 +116,14 @@ impl Encodable for RejectReason {
|
||||||
impl Decodable for RejectReason {
|
impl Decodable for RejectReason {
|
||||||
fn consensus_decode<D: io::Read>(mut d: D) -> Result<Self, encode::Error> {
|
fn consensus_decode<D: io::Read>(mut d: D) -> Result<Self, encode::Error> {
|
||||||
Ok(match d.read_u8()? {
|
Ok(match d.read_u8()? {
|
||||||
0x01 => MALFORMED,
|
0x01 => RejectReason::Malformed,
|
||||||
0x10 => INVALID,
|
0x10 => RejectReason::Invalid,
|
||||||
0x11 => OBSOLETE,
|
0x11 => RejectReason::Obsolete,
|
||||||
0x12 => DUPLICATE,
|
0x12 => RejectReason::Duplicate,
|
||||||
0x40 => NONSTANDARD,
|
0x40 => RejectReason::NonStandard,
|
||||||
0x41 => DUST,
|
0x41 => RejectReason::Dust,
|
||||||
0x42 => FEE,
|
0x42 => RejectReason::Fee,
|
||||||
0x43 => CHECKPOINT,
|
0x43 => RejectReason::Checkpoint,
|
||||||
_ => return Err(encode::Error::ParseFailed("unknown reject code"))
|
_ => return Err(encode::Error::ParseFailed("unknown reject code"))
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
@ -131,11 +133,11 @@ impl Decodable for RejectReason {
|
||||||
#[derive(PartialEq, Eq, Clone, Debug)]
|
#[derive(PartialEq, Eq, Clone, Debug)]
|
||||||
pub struct Reject {
|
pub struct Reject {
|
||||||
/// message type rejected
|
/// message type rejected
|
||||||
pub message: String,
|
pub message: CommandString,
|
||||||
/// reason of rejection as code
|
/// reason of rejection as code
|
||||||
pub ccode: RejectReason,
|
pub ccode: RejectReason,
|
||||||
/// reason of rejectection
|
/// reason of rejectection
|
||||||
pub reason: String,
|
pub reason: Cow<'static, str>,
|
||||||
/// reference to rejected item
|
/// reference to rejected item
|
||||||
pub hash: sha256d::Hash
|
pub hash: sha256d::Hash
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue