basic serialization
This commit is contained in:
parent
9c29e35f92
commit
b51f3b4c6b
|
@ -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
|
||||
|
|
|
@ -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"
|
|
@ -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);
|
||||
}
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
}
|
|
@ -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() {
|
||||
}
|
||||
}
|
|
@ -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());
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue