Fixed message serialization following changes in core. Sending of block and transaction.

This commit is contained in:
Ignotus Peverell 2016-11-01 10:42:33 -07:00
parent 1008539048
commit edc6c62577
No known key found for this signature in database
GPG key ID: 99CD25F39F8F8211
6 changed files with 132 additions and 56 deletions

View file

@ -303,6 +303,12 @@ impl<'a> AsFixedBytes for &'a [u8] {
} }
} }
impl<'a> AsFixedBytes for String {
fn as_fixed_bytes(&self) -> &[u8] {
self.as_bytes()
}
}
impl AsFixedBytes for ::core::hash::Hash { impl AsFixedBytes for ::core::hash::Hash {
fn as_fixed_bytes(&self) -> &[u8] { fn as_fixed_bytes(&self) -> &[u8] {
self.to_slice() self.to_slice()

View file

@ -37,16 +37,18 @@ pub enum ErrCodes {
/// Types of messages /// Types of messages
enum_from_primitive! { enum_from_primitive! {
#[derive(Clone, Copy)] #[derive(Clone, Copy)]
pub enum Type { pub enum Type {
Error, Error,
Hand, Hand,
Shake, Shake,
Ping, Ping,
Pong, Pong,
GetPeerAddrs, GetPeerAddrs,
PeerAddrs, PeerAddrs,
} Block,
Transaction,
}
} }
/// Header of any protocol message, used to identify incoming messages. /// Header of any protocol message, used to identify incoming messages.
@ -67,8 +69,10 @@ impl MsgHeader {
Type::from_u8(self.msg_type as u8).is_some() Type::from_u8(self.msg_type as u8).is_some()
} }
/// Serialized length of the header in bytes /// Serialized length of the header in bytes
pub fn serialized_len(&self) -> u64 { 3 } pub fn serialized_len(&self) -> u64 {
3
}
} }
impl Writeable for MsgHeader { impl Writeable for MsgHeader {
@ -86,9 +90,14 @@ impl Readable<MsgHeader> for MsgHeader {
try!(reader.expect_u8(MAGIC[0])); try!(reader.expect_u8(MAGIC[0]));
try!(reader.expect_u8(MAGIC[1])); try!(reader.expect_u8(MAGIC[1]));
let t = try!(reader.read_u8()); let t = try!(reader.read_u8());
match Type::from_u8(t) { match Type::from_u8(t) {
Some(ty) => Ok(MsgHeader {magic: MAGIC, msg_type: ty}), Some(ty) => {
None => Err(ser::Error::CorruptedData) Ok(MsgHeader {
magic: MAGIC,
msg_type: ty,
})
}
None => Err(ser::Error::CorruptedData),
} }
} }
} }
@ -118,7 +127,7 @@ impl Writeable for Hand {
[write_u64, self.nonce]); [write_u64, self.nonce]);
self.sender_addr.write(writer); self.sender_addr.write(writer);
self.receiver_addr.write(writer); self.receiver_addr.write(writer);
writer.write_bytes(self.user_agent.as_bytes()) writer.write_bytes(&self.user_agent)
} }
} }
@ -157,7 +166,7 @@ impl Writeable for Shake {
ser_multiwrite!(writer, ser_multiwrite!(writer,
[write_u32, self.version], [write_u32, self.version],
[write_u32, self.capabilities.bits()], [write_u32, self.capabilities.bits()],
[write_bytes, self.user_agent.as_bytes()]); [write_bytes, &self.user_agent]);
Ok(()) Ok(())
} }
} }
@ -182,7 +191,7 @@ pub struct GetPeerAddrs {
} }
impl Writeable for GetPeerAddrs { impl Writeable for GetPeerAddrs {
fn write(&self, writer: &mut Writer) -> Option<ser::Error> { fn write(&self, writer: &mut Writer) -> Result<(), ser::Error> {
writer.write_u32(self.capabilities.bits()) writer.write_u32(self.capabilities.bits())
} }
} }
@ -202,12 +211,12 @@ pub struct PeerAddrs {
} }
impl Writeable for PeerAddrs { impl Writeable for PeerAddrs {
fn write(&self, writer: &mut Writer) -> Option<ser::Error> { fn write(&self, writer: &mut Writer) -> Result<(), ser::Error> {
try_o!(writer.write_u32(self.peers.len() as u32)); try!(writer.write_u32(self.peers.len() as u32));
for p in &self.peers { for p in &self.peers {
p.write(writer); p.write(writer);
} }
None Ok(())
} }
} }
@ -234,9 +243,7 @@ pub struct PeerError {
impl Writeable for PeerError { impl Writeable for PeerError {
fn write(&self, writer: &mut Writer) -> Result<(), ser::Error> { fn write(&self, writer: &mut Writer) -> Result<(), ser::Error> {
ser_multiwrite!(writer, ser_multiwrite!(writer, [write_u32, self.code], [write_bytes, &self.message]);
[write_u32, self.code],
[write_bytes, self.message.as_bytes()]);
Ok(()) Ok(())
} }
} }

View file

@ -14,6 +14,7 @@
use mioco::tcp::TcpStream; use mioco::tcp::TcpStream;
use core::core;
use core::ser::Error; use core::ser::Error;
use handshake::Handshake; use handshake::Handshake;
use types::*; use types::*;
@ -43,14 +44,24 @@ impl Peer {
}) })
} }
pub fn run(&self, na: &NetAdapter) -> Option<Error> { pub fn run(&self, na: &NetAdapter) -> Result<(), Error> {
self.proto.handle(na) self.proto.handle(na)
} }
pub fn send_ping(&self) -> Option<Error> { pub fn send_ping(&self) -> Result<(), Error> {
self.proto.send_ping() self.proto.send_ping()
} }
pub fn send_block(&self, b: &core::Block) -> Result<(), Error> {
// TODO don't send if we already got the block from peer
self.proto.send_block(b)
}
pub fn send_transaction(&self, tx: &core::Transaction) -> Result<(), Error> {
// TODO don't relay if we already got the tx from peer
self.proto.send_transaction(tx)
}
pub fn transmitted_bytes(&self) -> (u64, u64) { pub fn transmitted_bytes(&self) -> (u64, u64) {
self.proto.transmitted_bytes() self.proto.transmitted_bytes()
} }

View file

@ -13,17 +13,16 @@
// limitations under the License. // limitations under the License.
use std::cell::RefCell; use std::cell::RefCell;
use std::io::{Read, Write}; use std::io::Write;
use std::ops::{Deref, DerefMut}; use std::ops::{Deref, DerefMut};
use std::rc::Rc;
use std::sync::Mutex; use std::sync::Mutex;
use mioco; use mioco;
use mioco::sync::mpsc::{sync_channel, SyncSender}; use mioco::sync::mpsc::{sync_channel, SyncSender};
use mioco::tcp::{TcpStream, Shutdown}; use mioco::tcp::{TcpStream, Shutdown};
use core::core;
use core::ser; use core::ser;
use handshake::Handshake;
use msg::*; use msg::*;
use types::*; use types::*;
@ -39,12 +38,12 @@ pub struct ProtocolV1 {
// Used both to count the amount of data sent and lock writing to the conn. We can't wrap conn with // Used both to count the amount of data sent and lock writing to the conn. We can't wrap conn with
// the lock as we're always listening to receive. // the lock as we're always listening to receive.
sent_bytes: Mutex<u64>, sent_bytes: Mutex<u64>,
// Bytes we've received. // Bytes we've received.
received_bytes: Mutex<u64>, received_bytes: Mutex<u64>,
} }
impl ProtocolV1 { impl ProtocolV1 {
/// Creates a new protocol v1 /// Creates a new protocol v1
pub fn new(conn: TcpStream) -> ProtocolV1 { pub fn new(conn: TcpStream) -> ProtocolV1 {
ProtocolV1 { ProtocolV1 {
conn: RefCell::new(conn), conn: RefCell::new(conn),
@ -62,7 +61,7 @@ impl Protocol for ProtocolV1 {
/// to send. Must be called before any interaction with a protocol instance /// to send. Must be called before any interaction with a protocol instance
/// and should only be called once. Will block so also needs to be called /// and should only be called once. Will block so also needs to be called
/// within a coroutine. /// within a coroutine.
fn handle(&self, server: &NetAdapter) -> Option<ser::Error> { fn handle(&self, server: &NetAdapter) -> Result<(), ser::Error> {
// setup channels so we can switch between reads, writes and close // setup channels so we can switch between reads, writes and close
let (msg_send, msg_recv) = sync_channel(10); let (msg_send, msg_recv) = sync_channel(10);
let (stop_send, stop_recv) = sync_channel(1); let (stop_send, stop_recv) = sync_channel(1);
@ -75,23 +74,23 @@ impl Protocol for ProtocolV1 {
let mut conn = self.conn.borrow_mut(); let mut conn = self.conn.borrow_mut();
loop { loop {
// main select loop, switches between listening, sending or stopping // main select loop, switches between listening, sending or stopping
select!( select!(
r:conn => { r:conn => {
// deser the header ot get the message type // deser the header ot get the message type
let header = try_to_o!(ser::deserialize::<MsgHeader>(conn.deref_mut())); let header = try!(ser::deserialize::<MsgHeader>(conn.deref_mut()));
if !header.acceptable() { if !header.acceptable() {
continue; continue;
} }
let recv = header.serialized_len(); let recv = header.serialized_len();
// check the message and hopefully do what's expected // check the message and hopefully do what's expected
match header.msg_type { match header.msg_type {
Type::Ping => { Type::Ping => {
// respond with pong // respond with pong
let data = try_to_o!(ser::ser_vec(&MsgHeader::new(Type::Pong))); let data = try!(ser::ser_vec(&MsgHeader::new(Type::Pong)));
let mut sent_bytes = self.sent_bytes.lock().unwrap(); let mut sent_bytes = self.sent_bytes.lock().unwrap();
*sent_bytes += data.len() as u64; *sent_bytes += data.len() as u64;
try_to_o!(conn.deref_mut().write_all(&data[..]).map_err(&ser::Error::IOErr)); try!(conn.deref_mut().write_all(&data[..]).map_err(&ser::Error::IOErr));
}, },
Type::Pong => {}, Type::Pong => {},
_ => error!("uncaught unknown"), _ => error!("uncaught unknown"),
@ -100,17 +99,17 @@ impl Protocol for ProtocolV1 {
*received += recv; *received += recv;
}, },
r:msg_recv => { r:msg_recv => {
// relay a message originated from the rest of the local system // relay a message originated from the rest of the local system
let data = &msg_recv.recv().unwrap()[..]; let data = &msg_recv.recv().unwrap()[..];
let mut sent_bytes = self.sent_bytes.lock().unwrap(); let mut sent_bytes = self.sent_bytes.lock().unwrap();
*sent_bytes += data.len() as u64; *sent_bytes += data.len() as u64;
try_to_o!(conn.deref_mut().write_all(data).map_err(&ser::Error::IOErr)); try!(conn.deref_mut().write_all(data).map_err(&ser::Error::IOErr));
}, },
r:stop_recv => { r:stop_recv => {
// shuts the connection don and end the loop // shuts the connection don and end the loop
stop_recv.recv(); stop_recv.recv();
conn.shutdown(Shutdown::Both); conn.shutdown(Shutdown::Both);
return None; return Ok(());
} }
); );
} }
@ -118,17 +117,25 @@ impl Protocol for ProtocolV1 {
/// Sends a ping message to the remote peer. Will panic if handle has never /// Sends a ping message to the remote peer. Will panic if handle has never
/// been called on this protocol. /// been called on this protocol.
fn send_ping(&self) -> Option<ser::Error> { fn send_ping(&self) -> Result<(), ser::Error> {
let data = try_to_o!(ser::ser_vec(&MsgHeader::new(Type::Ping))); let data = try!(ser::ser_vec(&MsgHeader::new(Type::Ping)));
let msg_send = self.msg_send.borrow(); let msg_send = self.msg_send.borrow();
msg_send.as_ref().unwrap().send(data); msg_send.as_ref().unwrap().send(data);
None Ok(())
}
fn send_block(&self, b: &core::Block) -> Result<(), ser::Error> {
self.send_msg(Type::Block, b)
}
fn send_transaction(&self, tx: &core::Transaction) -> Result<(), ser::Error> {
self.send_msg(Type::Transaction, tx)
} }
fn transmitted_bytes(&self) -> (u64, u64) { fn transmitted_bytes(&self) -> (u64, u64) {
let sent = *self.sent_bytes.lock().unwrap().deref(); let sent = *self.sent_bytes.lock().unwrap().deref();
let received = *self.received_bytes.lock().unwrap().deref(); let received = *self.received_bytes.lock().unwrap().deref();
(sent, received) (sent, received)
} }
fn close(&self) { fn close(&self) {
@ -136,3 +143,16 @@ impl Protocol for ProtocolV1 {
stop_send.as_ref().unwrap().send(0); stop_send.as_ref().unwrap().send(0);
} }
} }
impl ProtocolV1 {
/// Helper function to avoid boilerplate, builds a header followed by the
/// Writeable body and send the whole thing.
fn send_msg(&self, t: Type, body: &ser::Writeable) -> Result<(), ser::Error> {
let mut data = Vec::new();
try!(ser::serialize(&mut data, &MsgHeader::new(t)));
try!(ser::serialize(&mut data, body));
let msg_send = self.msg_send.borrow();
msg_send.as_ref().unwrap().send(data);
Ok(())
}
}

View file

@ -26,11 +26,14 @@ use mioco;
use mioco::sync::mpsc::{sync_channel, SyncSender}; use mioco::sync::mpsc::{sync_channel, SyncSender};
use mioco::tcp::{TcpListener, TcpStream}; use mioco::tcp::{TcpListener, TcpStream};
use core::core;
use core::ser::Error; use core::ser::Error;
use handshake::Handshake; use handshake::Handshake;
use peer::Peer; use peer::Peer;
use types::*; use types::*;
/// Default address for peer-to-peer connections, placeholder until better
/// configuration is in place.
pub const DEFAULT_LISTEN_ADDR: &'static str = "127.0.0.1:3414"; pub const DEFAULT_LISTEN_ADDR: &'static str = "127.0.0.1:3414";
// replace with some config lookup or something // replace with some config lookup or something
@ -53,7 +56,7 @@ unsafe impl Send for Server {}
// TODO TLS // TODO TLS
impl Server { impl Server {
/// Creates a new idle p2p server with no peers /// Creates a new idle p2p server with no peers
pub fn new() -> Server { pub fn new() -> Server {
Server { Server {
peers: RwLock::new(Vec::new()), peers: RwLock::new(Vec::new()),
@ -89,7 +92,7 @@ impl Server {
} }
mioco::spawn(move || -> io::Result<()> { mioco::spawn(move || -> io::Result<()> {
if let Some(err) = wpeer.run(&DummyAdapter{}) { if let Err(err) = wpeer.run(&DummyAdapter{}) {
error!("{:?}", err); error!("{:?}", err);
} }
Ok(()) Ok(())
@ -103,7 +106,29 @@ impl Server {
} }
} }
/// Stops the server. Disconnect from all peers at the same time. /// Asks all the peers to relay the provided block. A peer may choose to
/// ignore the relay request if it has knowledge that the remote peer
/// already knows the block.
pub fn relay_block(&self, b: &core::Block) -> Result<(), Error> {
let peers = self.peers.write().unwrap();
for p in peers.deref() {
try!(p.send_block(b));
}
Ok(())
}
/// Asks all the peers to relay the provided transaction. A peer may choose
/// to ignore the relay request if it has knowledge that the remote peer
/// already knows the transaction.
pub fn relay_transaction(&self, tx: &core::Transaction) -> Result<(), Error> {
let peers = self.peers.write().unwrap();
for p in peers.deref() {
try!(p.send_transaction(tx));
}
Ok(())
}
/// Stops the server. Disconnect from all peers at the same time.
pub fn stop(&self) { pub fn stop(&self) {
let peers = self.peers.write().unwrap(); let peers = self.peers.write().unwrap();
for p in peers.deref() { for p in peers.deref() {
@ -120,7 +145,7 @@ impl Server {
Peer::accept(tcp_client, &Handshake::new()) Peer::accept(tcp_client, &Handshake::new())
} }
pub fn peers_count(&self) -> u32 { pub fn peers_count(&self) -> u32 {
self.peers.read().unwrap().len() as u32 self.peers.read().unwrap().len() as u32
} }
} }

View file

@ -13,6 +13,7 @@
// limitations under the License. // limitations under the License.
use std::net::SocketAddr; use std::net::SocketAddr;
use core::core;
use core::ser::Error; use core::ser::Error;
bitflags! { bitflags! {
@ -42,13 +43,19 @@ pub trait Protocol {
/// be known already, usually passed during construction. Will typically /// be known already, usually passed during construction. Will typically
/// block so needs to be called withing a coroutine. Should also be called /// block so needs to be called withing a coroutine. Should also be called
/// only once. /// only once.
fn handle(&self, na: &NetAdapter) -> Option<Error>; fn handle(&self, na: &NetAdapter) -> Result<(), Error>;
/// Sends a ping message to the remote peer. /// Sends a ping message to the remote peer.
fn send_ping(&self) -> Option<Error>; fn send_ping(&self) -> Result<(), Error>;
/// Relays a block to the remote peer.
fn send_block(&self, b: &core::Block) -> Result<(), Error>;
/// Relays a transaction to the remote peer.
fn send_transaction(&self, tx: &core::Transaction) -> Result<(), Error>;
/// How many bytes have been sent/received to/from the remote peer. /// How many bytes have been sent/received to/from the remote peer.
fn transmitted_bytes(&self) -> (u64, u64); fn transmitted_bytes(&self) -> (u64, u64);
/// Close the connection to the remote peer. /// Close the connection to the remote peer.
fn close(&self); fn close(&self);