Try writing message headers.

This commit is contained in:
Henry de Valence 2019-09-13 05:29:17 -07:00 committed by Deirdre Connolly
parent cf63f00171
commit 50f749a817
2 changed files with 77 additions and 9 deletions

View File

@ -7,5 +7,7 @@ edition = "2018"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]
zebra-chain = { path = "../zebra-chain" }
byteorder = "1.3"
chrono = "0.4"
failure = "0.1"
zebra-chain = { path = "../zebra-chain" }

View File

@ -1,7 +1,11 @@
//! Definitions of network messages.
use std::io;
use chrono::{DateTime, Utc};
use zebra_chain::types::Sha256dChecksum;
use crate::meta_addr::MetaAddr;
use crate::types::*;
@ -232,14 +236,6 @@ pub enum Message {
MerkleBlock {/* XXX add fields */},
}
// Q: how do we want to implement serialization, exactly? do we want to have
// something generic over stdlib Read and Write traits, or over async versions
// of those traits?
//
// Note: because of the way the message structure is defined (checksum comes
// first) we can't write the message headers before collecting the whole body
// into a buffer
/// Reject Reason CCodes
///
/// [Bitcoin reference](https://en.bitcoin.it/wiki/Protocol_documentation#reject)
@ -255,3 +251,73 @@ pub enum RejectReason {
InsufficientFee = 0x42,
Checkpoint = 0x43,
}
// Q: how do we want to implement serialization, exactly? do we want to have
// something generic over stdlib Read and Write traits, or over async versions
// of those traits?
//
// Note: because of the way the message structure is defined (checksum comes
// first) we can't write the message headers before collecting the whole body
// into a buffer
//
// Maybe just write some functions and refactor later?
impl Message {
/// Serialize `self` into the given writer.
pub fn write<W: io::Write>(&self, mut writer: W, magic: Magic) -> io::Result<()> {
use byteorder::{LittleEndian, WriteBytesExt};
// Because the header contains a checksum of
// the body data, it must be written first.
let mut body = Vec::new();
self.write_body(&mut body)?;
use Message::*;
// Note: because all match arms must have
// the same type, and the array length is
// part of the type, having at least one
// of length 12 checks that they are all
// of length 12, as they must be &[u8; 12].
let command = match *self {
Version { .. } => b"version\0\0\0\0\0",
Verack { .. } => b"verack\0\0\0\0\0\0",
Ping { .. } => b"ping\0\0\0\0\0\0\0\0",
Pong { .. } => b"pong\0\0\0\0\0\0\0\0",
Reject { .. } => b"reject\0\0\0\0\0\0",
Addr { .. } => b"addr\0\0\0\0\0\0\0\0",
GetAddr { .. } => b"getaddr\0\0\0\0\0",
Block { .. } => b"block\0\0\0\0\0\0\0",
GetBlocks { .. } => b"getblocks\0\0\0",
Headers { .. } => b"headers\0\0\0\0\0",
GetHeaders { .. } => b"getheaders\0\0",
Inventory { .. } => b"inv\0\0\0\0\0\0\0\0\0",
GetData { .. } => b"getdata\0\0\0\0\0",
NotFound { .. } => b"notfound\0\0\0\0",
Tx { .. } => b"tx\0\0\0\0\0\0\0\0\0\0",
Mempool { .. } => b"mempool\0\0\0\0\0",
FilterLoad { .. } => b"filterload\0\0",
FilterAdd { .. } => b"filteradd\0\0\0",
FilterClear { .. } => b"filterclear\0",
MerkleBlock { .. } => b"merkleblock\0",
};
// Write the header and then the body.
writer.write_u32::<LittleEndian>(magic.0)?;
writer.write_all(command)?;
writer.write_u32::<LittleEndian>(body.len() as u32)?;
writer.write_all(&Sha256dChecksum::from(&body[..]).0)?;
writer.write_all(&body)
}
/// Write the body of the message into the given writer. This allows writing
/// the message body prior to writing the header, so that the header can
/// contain a checksum of the message body.
fn write_body<W: io::Write>(&self, _writer: W) -> io::Result<()> {
unimplemented!()
}
/// Try to deserialize a [`Message`] from the given reader.
pub fn try_read<R: io::Read>(_reader: R) -> Result<Self, String> {
unimplemented!()
}
}