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 {
fn as_fixed_bytes(&self) -> &[u8] {
self.to_slice()

View file

@ -37,8 +37,8 @@ pub enum ErrCodes {
/// Types of messages
enum_from_primitive! {
#[derive(Clone, Copy)]
pub enum Type {
#[derive(Clone, Copy)]
pub enum Type {
Error,
Hand,
Shake,
@ -46,7 +46,9 @@ pub enum Type {
Pong,
GetPeerAddrs,
PeerAddrs,
}
Block,
Transaction,
}
}
/// Header of any protocol message, used to identify incoming messages.
@ -68,7 +70,9 @@ impl MsgHeader {
}
/// 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 {
@ -87,8 +91,13 @@ impl Readable<MsgHeader> for MsgHeader {
try!(reader.expect_u8(MAGIC[1]));
let t = try!(reader.read_u8());
match Type::from_u8(t) {
Some(ty) => Ok(MsgHeader {magic: MAGIC, msg_type: ty}),
None => Err(ser::Error::CorruptedData)
Some(ty) => {
Ok(MsgHeader {
magic: MAGIC,
msg_type: ty,
})
}
None => Err(ser::Error::CorruptedData),
}
}
}
@ -118,7 +127,7 @@ impl Writeable for Hand {
[write_u64, self.nonce]);
self.sender_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,
[write_u32, self.version],
[write_u32, self.capabilities.bits()],
[write_bytes, self.user_agent.as_bytes()]);
[write_bytes, &self.user_agent]);
Ok(())
}
}
@ -182,7 +191,7 @@ pub struct 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())
}
}
@ -202,12 +211,12 @@ pub struct PeerAddrs {
}
impl Writeable for PeerAddrs {
fn write(&self, writer: &mut Writer) -> Option<ser::Error> {
try_o!(writer.write_u32(self.peers.len() as u32));
fn write(&self, writer: &mut Writer) -> Result<(), ser::Error> {
try!(writer.write_u32(self.peers.len() as u32));
for p in &self.peers {
p.write(writer);
}
None
Ok(())
}
}
@ -234,9 +243,7 @@ pub struct PeerError {
impl Writeable for PeerError {
fn write(&self, writer: &mut Writer) -> Result<(), ser::Error> {
ser_multiwrite!(writer,
[write_u32, self.code],
[write_bytes, self.message.as_bytes()]);
ser_multiwrite!(writer, [write_u32, self.code], [write_bytes, &self.message]);
Ok(())
}
}

View file

@ -14,6 +14,7 @@
use mioco::tcp::TcpStream;
use core::core;
use core::ser::Error;
use handshake::Handshake;
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)
}
pub fn send_ping(&self) -> Option<Error> {
pub fn send_ping(&self) -> Result<(), Error> {
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) {
self.proto.transmitted_bytes()
}

View file

@ -13,17 +13,16 @@
// limitations under the License.
use std::cell::RefCell;
use std::io::{Read, Write};
use std::io::Write;
use std::ops::{Deref, DerefMut};
use std::rc::Rc;
use std::sync::Mutex;
use mioco;
use mioco::sync::mpsc::{sync_channel, SyncSender};
use mioco::tcp::{TcpStream, Shutdown};
use core::core;
use core::ser;
use handshake::Handshake;
use msg::*;
use types::*;
@ -62,7 +61,7 @@ impl Protocol for ProtocolV1 {
/// 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
/// 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
let (msg_send, msg_recv) = sync_channel(10);
let (stop_send, stop_recv) = sync_channel(1);
@ -79,7 +78,7 @@ impl Protocol for ProtocolV1 {
select!(
r:conn => {
// 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() {
continue;
}
@ -88,10 +87,10 @@ impl Protocol for ProtocolV1 {
match header.msg_type {
Type::Ping => {
// 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();
*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 => {},
_ => error!("uncaught unknown"),
@ -104,13 +103,13 @@ impl Protocol for ProtocolV1 {
let data = &msg_recv.recv().unwrap()[..];
let mut sent_bytes = self.sent_bytes.lock().unwrap();
*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 => {
// shuts the connection don and end the loop
stop_recv.recv();
conn.shutdown(Shutdown::Both);
return None;
return Ok(());
}
);
}
@ -118,11 +117,19 @@ impl Protocol for ProtocolV1 {
/// Sends a ping message to the remote peer. Will panic if handle has never
/// been called on this protocol.
fn send_ping(&self) -> Option<ser::Error> {
let data = try_to_o!(ser::ser_vec(&MsgHeader::new(Type::Ping)));
fn send_ping(&self) -> Result<(), ser::Error> {
let data = try!(ser::ser_vec(&MsgHeader::new(Type::Ping)));
let msg_send = self.msg_send.borrow();
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) {
@ -136,3 +143,16 @@ impl Protocol for ProtocolV1 {
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::tcp::{TcpListener, TcpStream};
use core::core;
use core::ser::Error;
use handshake::Handshake;
use peer::Peer;
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";
// replace with some config lookup or something
@ -89,7 +92,7 @@ impl Server {
}
mioco::spawn(move || -> io::Result<()> {
if let Some(err) = wpeer.run(&DummyAdapter{}) {
if let Err(err) = wpeer.run(&DummyAdapter{}) {
error!("{:?}", err);
}
Ok(())
@ -103,6 +106,28 @@ impl Server {
}
}
/// 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) {
let peers = self.peers.write().unwrap();

View file

@ -13,6 +13,7 @@
// limitations under the License.
use std::net::SocketAddr;
use core::core;
use core::ser::Error;
bitflags! {
@ -42,10 +43,16 @@ pub trait Protocol {
/// be known already, usually passed during construction. Will typically
/// block so needs to be called withing a coroutine. Should also be called
/// only once.
fn handle(&self, na: &NetAdapter) -> Option<Error>;
fn handle(&self, na: &NetAdapter) -> Result<(), Error>;
/// 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.
fn transmitted_bytes(&self) -> (u64, u64);