basic serialization

This commit is contained in:
debris 2016-08-15 14:50:20 +02:00
parent 9c29e35f92
commit b51f3b4c6b
6 changed files with 245 additions and 0 deletions

2
.gitignore vendored
View File

@ -5,3 +5,5 @@
# Remove Cargo.lock from gitignore if creating an executable, leave it for libraries
# More information here http://doc.crates.io/guide.html#cargotoml-vs-cargolock
Cargo.lock
*.swp

8
Cargo.toml Normal file
View File

@ -0,0 +1,8 @@
[package]
name = "pbtc"
version = "0.1.0"
authors = ["debris <marek.kotewicz@gmail.com>"]
[dependencies]
byteorder = "0.5"
rustc-serialize = "0.3"

55
src/block_header.rs Normal file
View File

@ -0,0 +1,55 @@
use stream::{Serializable, Stream};
pub struct BlockHeader {
version: u32,
previous_header_hash: [u8; 32],
merkle_root_hash: [u8; 32],
time: u32,
nbits: u32,
nonce: u32,
}
impl Serializable for BlockHeader {
fn serialize(&self, stream: &mut Stream) {
stream
.append(&self.version)
.append_bytes(&self.previous_header_hash)
.append_bytes(&self.merkle_root_hash)
.append(&self.time)
.append(&self.nbits)
.append(&self.nonce);
}
}
#[cfg(test)]
mod tests {
use stream::Stream;
use super::BlockHeader;
#[test]
fn test_block_header_stream() {
let block_header = BlockHeader {
version: 1,
previous_header_hash: [2; 32],
merkle_root_hash: [3; 32],
time: 4,
nbits: 5,
nonce: 6,
};
let mut stream = Stream::default();
stream.append(&block_header);
let expected = vec![
1, 0, 0, 0,
2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
4, 0, 0, 0,
5, 0, 0, 0,
6, 0, 0, 0,
];
assert_eq!(stream.out(), expected);
}
}

77
src/compact_integer.rs Normal file
View File

@ -0,0 +1,77 @@
//! A type of variable-length integer commonly used in the Bitcoin P2P protocol and Bitcoin serialized data structures.
//! https://bitcoin.org/en/developer-reference#compactsize-unsigned-integers
use stream::{Serializable, Stream};
/// A type of variable-length integer commonly used in the Bitcoin P2P protocol and Bitcoin serialized data structures.
#[derive(Default, Debug, Clone, Copy, PartialEq)]
pub struct CompactInteger(u64);
impl From<CompactInteger> for u64 {
fn from(i: CompactInteger) -> Self {
i.0
}
}
impl From<u64> for CompactInteger {
fn from(i: u64) -> Self {
CompactInteger(i)
}
}
impl Serializable for CompactInteger {
fn serialize(&self, stream: &mut Stream) {
match self.0 {
0...0xfc => {
stream.append(&(self.0 as u8));
},
0xfd...0xffff => {
stream
.append(&0xfdu8)
.append(&(self.0 as u16));
},
0x10000...0xffff_ffff => {
stream
.append(&0xfeu8)
.append(&(self.0 as u32));
},
_ => {
stream
.append(&0xffu8)
.append(&self.0);
}
}
}
}
#[cfg(test)]
mod tests {
use stream::Stream;
use super::CompactInteger;
#[test]
fn test_compact_integer_stream() {
let mut stream = Stream::default();
stream
.append(&CompactInteger::from(0))
.append(&CompactInteger::from(0xfc))
.append(&CompactInteger::from(0xfd))
.append(&CompactInteger::from(0xffff))
.append(&CompactInteger::from(0x10000))
.append(&CompactInteger::from(0xffff_ffff))
.append(&CompactInteger::from(0x1_0000_0000));
let expected = vec![
0,
0xfc,
0xfd, 0xfd, 0x00,
0xfd, 0xff, 0xff,
0xfe, 0x00, 0x00, 0x01, 0x00,
0xfe, 0xff, 0xff, 0xff, 0xff,
0xff, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
];
assert_eq!(stream.out(), expected);
}
}

16
src/lib.rs Normal file
View File

@ -0,0 +1,16 @@
//! Ethcore's bitcoin library.
extern crate byteorder;
extern crate rustc_serialize;
pub mod block_header;
pub mod compact_integer;
pub mod stream;
#[cfg(test)]
mod tests {
#[test]
fn it_works() {
}
}

87
src/stream.rs Normal file
View File

@ -0,0 +1,87 @@
//! Stream used for serialization.
use std::io::Write;
use byteorder::{LittleEndian, WriteBytesExt};
pub trait Serializable {
/// Serialize the struct and appends it to the end of stream.
fn serialize(&self, s: &mut Stream);
}
/// Stream used for serialization.
#[derive(Default)]
pub struct Stream {
buffer: Vec<u8>,
}
impl Stream {
/// Serializes the struct and appends it to the end of stream.
pub fn append(&mut self, t: &Serializable) -> &mut Self {
t.serialize(self);
self
}
/// Appends raw bytes to the end of the stream.
pub fn append_bytes(&mut self, bytes: &[u8]) -> &mut Self {
// discard error for now, since we write to sinple vector
self.buffer.write(bytes).unwrap();
self
}
/// Full stream.
pub fn out(self) -> Vec<u8> {
self.buffer
}
}
impl Serializable for u8 {
#[inline]
fn serialize(&self, s: &mut Stream) {
s.buffer.write_u8(*self).unwrap();
}
}
impl Serializable for u16 {
#[inline]
fn serialize(&self, s: &mut Stream) {
s.buffer.write_u16::<LittleEndian>(*self).unwrap();
}
}
impl Serializable for u32 {
#[inline]
fn serialize(&self, s: &mut Stream) {
s.buffer.write_u32::<LittleEndian>(*self).unwrap();
}
}
impl Serializable for u64 {
#[inline]
fn serialize(&self, s: &mut Stream) {
s.buffer.write_u64::<LittleEndian>(*self).unwrap();
}
}
#[cfg(test)]
mod tests {
use super::Stream;
#[test]
fn test_stream_append() {
let mut stream = Stream::default();
stream
.append(&1u8)
.append(&2u16)
.append(&3u32)
.append(&4u64);
let expected = vec![
1u8,
2, 0,
3, 0, 0, 0,
4, 0, 0, 0, 0, 0, 0, 0,
];
assert_eq!(expected, stream.out());
}
}