Initial import.
This commit is contained in:
@@ -0,0 +1,133 @@
|
||||
//! Base types that the block chain pipeline requires.
|
||||
|
||||
use core::core::{Hash, Block};
|
||||
use core::ser;
|
||||
|
||||
/// The lineage of a fork, defined as a series of numbers. Each new branch gets
|
||||
/// a new number that gets added to a fork's ancestry to form a new fork.
|
||||
/// Example:
|
||||
/// head [1] -> fork1 [1, 2]
|
||||
/// fork2 [1, 3]
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct Lineage(Vec<u32>);
|
||||
|
||||
impl Lineage {
|
||||
/// New lineage initialized just with branch 0
|
||||
pub fn new() -> Lineage {
|
||||
Lineage(vec![0])
|
||||
}
|
||||
/// The last branch that was added to the lineage. Also the only branch
|
||||
/// that's
|
||||
/// unique to this lineage.
|
||||
pub fn last_branch(&self) -> u32 {
|
||||
*self.0.last().unwrap()
|
||||
}
|
||||
}
|
||||
|
||||
/// Serialization for lineage, necessary to serialize fork tips.
|
||||
impl ser::Writeable for Lineage {
|
||||
fn write(&self, writer: &mut ser::Writer) -> Option<ser::Error> {
|
||||
try_m!(writer.write_u32(self.0.len() as u32));
|
||||
for num in &self.0 {
|
||||
try_m!(writer.write_u32(*num));
|
||||
}
|
||||
None
|
||||
}
|
||||
}
|
||||
/// Deserialization for lineage, necessary to deserialize fork tips.
|
||||
impl ser::Readable<Lineage> for Lineage {
|
||||
fn read(reader: &mut ser::Reader) -> Result<Lineage, ser::Error> {
|
||||
let len = try!(reader.read_u32());
|
||||
let mut branches = Vec::with_capacity(len as usize);
|
||||
for _ in 0..len {
|
||||
branches.push(try!(reader.read_u32()));
|
||||
}
|
||||
Ok(Lineage(branches))
|
||||
}
|
||||
}
|
||||
|
||||
/// The tip of a fork. A handle to the fork ancestry from its leaf in the
|
||||
/// blockchain tree. References both the lineage of the fork as well as its max
|
||||
/// height and its latest and previous blocks for convenience.
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct Tip {
|
||||
/// Height of the tip (max height of the fork)
|
||||
pub height: u64,
|
||||
/// Last block pushed to the fork
|
||||
pub last_block_h: Hash,
|
||||
/// Block previous to last
|
||||
pub prev_block_h: Hash,
|
||||
/// Lineage in branch numbers of the fork
|
||||
pub lineage: Lineage,
|
||||
}
|
||||
|
||||
impl Tip {
|
||||
/// Creates a new tip at height zero and the provided genesis hash.
|
||||
pub fn new(gbh: Hash) -> Tip {
|
||||
Tip {
|
||||
height: 0,
|
||||
last_block_h: gbh,
|
||||
prev_block_h: gbh,
|
||||
lineage: Lineage::new(),
|
||||
}
|
||||
}
|
||||
|
||||
/// Append a new block hash to this tip, returning a new updated tip.
|
||||
pub fn append(&self, bh: Hash) -> Tip {
|
||||
Tip {
|
||||
height: self.height + 1,
|
||||
last_block_h: bh,
|
||||
prev_block_h: self.last_block_h,
|
||||
lineage: self.lineage.clone(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Serialization of a tip, required to save to datastore.
|
||||
impl ser::Writeable for Tip {
|
||||
fn write(&self, writer: &mut ser::Writer) -> Option<ser::Error> {
|
||||
try_m!(writer.write_u64(self.height));
|
||||
try_m!(writer.write_fixed_bytes(&self.last_block_h));
|
||||
try_m!(writer.write_fixed_bytes(&self.prev_block_h));
|
||||
self.lineage.write(writer)
|
||||
}
|
||||
}
|
||||
|
||||
impl ser::Readable<Tip> for Tip {
|
||||
fn read(reader: &mut ser::Reader) -> Result<Tip, ser::Error> {
|
||||
let height = try!(reader.read_u64());
|
||||
let last = try!(reader.read_fixed_bytes(32));
|
||||
let prev = try!(reader.read_fixed_bytes(32));
|
||||
let line = try!(Lineage::read(reader));
|
||||
Ok(Tip {
|
||||
height: height,
|
||||
last_block_h: Hash::from_vec(last),
|
||||
prev_block_h: Hash::from_vec(prev),
|
||||
lineage: line,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub enum Error {
|
||||
/// Couldn't find what we were looking for
|
||||
NotFoundErr,
|
||||
/// Error generated by the underlying storage layer
|
||||
StorageErr(String),
|
||||
}
|
||||
|
||||
/// Trait the chain pipeline requires an implementor for in order to process
|
||||
/// blocks.
|
||||
pub trait ChainStore {
|
||||
/// Get the tip that's also the head of the chain
|
||||
fn head(&self) -> Result<Tip, Error>;
|
||||
|
||||
/// Save the provided block in store
|
||||
fn save_block(&self, b: &Block) -> Option<Error>;
|
||||
|
||||
/// Save the provided tip as the current head of our chain
|
||||
fn save_head(&self, t: &Tip) -> Option<Error>;
|
||||
|
||||
/// Save the provided tip without setting it as head
|
||||
fn save_tip(&self, t: &Tip) -> Option<Error>;
|
||||
}
|
||||
Reference in New Issue
Block a user