parent
851e012c6c
commit
fa72160c95
|
@ -1670,8 +1670,12 @@ mod tests {
|
||||||
let zero = Hash::default();
|
let zero = Hash::default();
|
||||||
let one = hash(&zero.as_ref());
|
let one = hash(&zero.as_ref());
|
||||||
writer
|
writer
|
||||||
.write_entries(&vec![Entry::new_tick(0, &zero), Entry::new_tick(0, &one)].to_vec())
|
.write_entries(
|
||||||
.unwrap();
|
&vec![
|
||||||
|
Entry::new_tick(&zero, 0, &zero),
|
||||||
|
Entry::new_tick(&one, 0, &one),
|
||||||
|
].to_vec(),
|
||||||
|
).unwrap();
|
||||||
path
|
path
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
36
src/entry.rs
36
src/entry.rs
|
@ -33,6 +33,9 @@ pub type EntryReceiver = Receiver<Vec<Entry>>;
|
||||||
|
|
||||||
#[derive(Serialize, Deserialize, Debug, PartialEq, Eq, Clone)]
|
#[derive(Serialize, Deserialize, Debug, PartialEq, Eq, Clone)]
|
||||||
pub struct Entry {
|
pub struct Entry {
|
||||||
|
/// The the previous Entry ID.
|
||||||
|
pub prev_id: Hash,
|
||||||
|
|
||||||
/// The number of hashes since the previous Entry ID.
|
/// The number of hashes since the previous Entry ID.
|
||||||
pub num_hashes: u64,
|
pub num_hashes: u64,
|
||||||
|
|
||||||
|
@ -47,19 +50,21 @@ pub struct Entry {
|
||||||
|
|
||||||
impl Entry {
|
impl Entry {
|
||||||
/// Creates the next Entry `num_hashes` after `start_hash`.
|
/// Creates the next Entry `num_hashes` after `start_hash`.
|
||||||
pub fn new(start_hash: &Hash, num_hashes: u64, transactions: Vec<Transaction>) -> Self {
|
pub fn new(prev_id: &Hash, num_hashes: u64, transactions: Vec<Transaction>) -> Self {
|
||||||
let entry = {
|
let entry = {
|
||||||
if num_hashes == 0 && transactions.is_empty() {
|
if num_hashes == 0 && transactions.is_empty() {
|
||||||
Entry {
|
Entry {
|
||||||
|
prev_id: *prev_id,
|
||||||
num_hashes: 0,
|
num_hashes: 0,
|
||||||
id: *start_hash,
|
id: *prev_id,
|
||||||
transactions,
|
transactions,
|
||||||
}
|
}
|
||||||
} else if num_hashes == 0 {
|
} else if num_hashes == 0 {
|
||||||
// If you passed in transactions, but passed in num_hashes == 0, then
|
// If you passed in transactions, but passed in num_hashes == 0, then
|
||||||
// next_hash will generate the next hash and set num_hashes == 1
|
// next_hash will generate the next hash and set num_hashes == 1
|
||||||
let id = next_hash(start_hash, 1, &transactions);
|
let id = next_hash(prev_id, 1, &transactions);
|
||||||
Entry {
|
Entry {
|
||||||
|
prev_id: *prev_id,
|
||||||
num_hashes: 1,
|
num_hashes: 1,
|
||||||
id,
|
id,
|
||||||
transactions,
|
transactions,
|
||||||
|
@ -68,8 +73,9 @@ impl Entry {
|
||||||
// Otherwise, the next Entry `num_hashes` after `start_hash`.
|
// Otherwise, the next Entry `num_hashes` after `start_hash`.
|
||||||
// If you wanted a tick for instance, then pass in num_hashes = 1
|
// If you wanted a tick for instance, then pass in num_hashes = 1
|
||||||
// and transactions = empty
|
// and transactions = empty
|
||||||
let id = next_hash(start_hash, num_hashes, &transactions);
|
let id = next_hash(prev_id, num_hashes, &transactions);
|
||||||
Entry {
|
Entry {
|
||||||
|
prev_id: *prev_id,
|
||||||
num_hashes,
|
num_hashes,
|
||||||
id,
|
id,
|
||||||
transactions,
|
transactions,
|
||||||
|
@ -121,7 +127,10 @@ impl Entry {
|
||||||
/// Estimate serialized_size of Entry without creating an Entry.
|
/// Estimate serialized_size of Entry without creating an Entry.
|
||||||
pub fn serialized_size(transactions: &[Transaction]) -> u64 {
|
pub fn serialized_size(transactions: &[Transaction]) -> u64 {
|
||||||
let txs_size = serialized_size(transactions).unwrap();
|
let txs_size = serialized_size(transactions).unwrap();
|
||||||
size_of::<u64>() as u64 + size_of::<Hash>() as u64 + txs_size
|
|
||||||
|
// num_hashes + id + prev_id + txs
|
||||||
|
|
||||||
|
(size_of::<u64>() + 2 * size_of::<Hash>()) as u64 + txs_size
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn num_will_fit(transactions: &[Transaction]) -> usize {
|
pub fn num_will_fit(transactions: &[Transaction]) -> usize {
|
||||||
|
@ -175,14 +184,19 @@ impl Entry {
|
||||||
|
|
||||||
/// Creates a Entry from the number of hashes `num_hashes` since the previous transaction
|
/// Creates a Entry from the number of hashes `num_hashes` since the previous transaction
|
||||||
/// and that resulting `id`.
|
/// and that resulting `id`.
|
||||||
pub fn new_tick(num_hashes: u64, id: &Hash) -> Self {
|
pub fn new_tick(prev_id: &Hash, num_hashes: u64, id: &Hash) -> Self {
|
||||||
Entry {
|
Entry {
|
||||||
|
prev_id: *prev_id,
|
||||||
num_hashes,
|
num_hashes,
|
||||||
id: *id,
|
id: *id,
|
||||||
transactions: vec![],
|
transactions: vec![],
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn verify_self(&self) -> bool {
|
||||||
|
self.id == next_hash(&self.prev_id, self.num_hashes, &self.transactions)
|
||||||
|
}
|
||||||
|
|
||||||
/// Verifies self.id is the result of hashing a `start_hash` `self.num_hashes` times.
|
/// Verifies self.id is the result of hashing a `start_hash` `self.num_hashes` times.
|
||||||
/// If the transaction is not a Tick, then hash that as well.
|
/// If the transaction is not a Tick, then hash that as well.
|
||||||
pub fn verify(&self, start_hash: &Hash) -> bool {
|
pub fn verify(&self, start_hash: &Hash) -> bool {
|
||||||
|
@ -225,11 +239,12 @@ fn next_hash(start_hash: &Hash, num_hashes: u64, transactions: &[Transaction]) -
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Creates the next Tick or Transaction Entry `num_hashes` after `start_hash`.
|
/// Creates the next Tick or Transaction Entry `num_hashes` after `start_hash`.
|
||||||
pub fn next_entry(start_hash: &Hash, num_hashes: u64, transactions: Vec<Transaction>) -> Entry {
|
pub fn next_entry(prev_id: &Hash, num_hashes: u64, transactions: Vec<Transaction>) -> Entry {
|
||||||
assert!(num_hashes > 0 || transactions.is_empty());
|
assert!(num_hashes > 0 || transactions.is_empty());
|
||||||
Entry {
|
Entry {
|
||||||
|
prev_id: *prev_id,
|
||||||
num_hashes,
|
num_hashes,
|
||||||
id: next_hash(start_hash, num_hashes, &transactions),
|
id: next_hash(prev_id, num_hashes, &transactions),
|
||||||
transactions,
|
transactions,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -249,9 +264,10 @@ mod tests {
|
||||||
fn test_entry_verify() {
|
fn test_entry_verify() {
|
||||||
let zero = Hash::default();
|
let zero = Hash::default();
|
||||||
let one = hash(&zero.as_ref());
|
let one = hash(&zero.as_ref());
|
||||||
assert!(Entry::new_tick(0, &zero).verify(&zero)); // base case
|
assert!(Entry::new_tick(&zero, 0, &zero).verify(&zero)); // base case, never used
|
||||||
assert!(!Entry::new_tick(0, &zero).verify(&one)); // base case, bad
|
assert!(!Entry::new_tick(&zero, 0, &zero).verify(&one)); // base case, bad
|
||||||
assert!(next_entry(&zero, 1, vec![]).verify(&zero)); // inductive step
|
assert!(next_entry(&zero, 1, vec![]).verify(&zero)); // inductive step
|
||||||
|
assert!(next_entry(&zero, 1, vec![]).verify_self()); // also inductive step
|
||||||
assert!(!next_entry(&zero, 1, vec![]).verify(&one)); // inductive step, bad
|
assert!(!next_entry(&zero, 1, vec![]).verify(&one)); // inductive step, bad
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -463,7 +463,7 @@ pub trait Block {
|
||||||
|
|
||||||
impl Block for [Entry] {
|
impl Block for [Entry] {
|
||||||
fn verify(&self, start_hash: &Hash) -> bool {
|
fn verify(&self, start_hash: &Hash) -> bool {
|
||||||
let genesis = [Entry::new_tick(0, start_hash)];
|
let genesis = [Entry::new_tick(start_hash, 0, start_hash)];
|
||||||
let entry_pairs = genesis.par_iter().chain(self).zip(self);
|
let entry_pairs = genesis.par_iter().chain(self).zip(self);
|
||||||
entry_pairs.all(|(x0, x1)| {
|
entry_pairs.all(|(x0, x1)| {
|
||||||
let r = x1.verify(&x0.id);
|
let r = x1.verify(&x0.id);
|
||||||
|
@ -710,8 +710,8 @@ mod tests {
|
||||||
let zero = Hash::default();
|
let zero = Hash::default();
|
||||||
let one = hash(&zero.as_ref());
|
let one = hash(&zero.as_ref());
|
||||||
assert!(vec![][..].verify(&zero)); // base case
|
assert!(vec![][..].verify(&zero)); // base case
|
||||||
assert!(vec![Entry::new_tick(0, &zero)][..].verify(&zero)); // singleton case 1
|
assert!(vec![Entry::new_tick(&zero, 0, &zero)][..].verify(&zero)); // singleton case 1
|
||||||
assert!(!vec![Entry::new_tick(0, &zero)][..].verify(&one)); // singleton case 2, bad
|
assert!(!vec![Entry::new_tick(&zero, 0, &zero)][..].verify(&one)); // singleton case 2, bad
|
||||||
assert!(vec![next_entry(&zero, 0, vec![]); 2][..].verify(&zero)); // inductive step
|
assert!(vec![next_entry(&zero, 0, vec![]); 2][..].verify(&zero)); // inductive step
|
||||||
|
|
||||||
let mut bad_ticks = vec![next_entry(&zero, 0, vec![]); 2];
|
let mut bad_ticks = vec![next_entry(&zero, 0, vec![]); 2];
|
||||||
|
@ -781,6 +781,7 @@ mod tests {
|
||||||
let tx_small_size = serialized_size(&tx_small).unwrap() as usize;
|
let tx_small_size = serialized_size(&tx_small).unwrap() as usize;
|
||||||
let tx_large_size = serialized_size(&tx_large).unwrap() as usize;
|
let tx_large_size = serialized_size(&tx_large).unwrap() as usize;
|
||||||
let entry_size = serialized_size(&Entry {
|
let entry_size = serialized_size(&Entry {
|
||||||
|
prev_id: Hash::default(),
|
||||||
num_hashes: 0,
|
num_hashes: 0,
|
||||||
id: Hash::default(),
|
id: Hash::default(),
|
||||||
transactions: vec![],
|
transactions: vec![],
|
||||||
|
|
46
src/poh.rs
46
src/poh.rs
|
@ -3,40 +3,48 @@
|
||||||
use hash::{hash, hashv, Hash};
|
use hash::{hash, hashv, Hash};
|
||||||
|
|
||||||
pub struct Poh {
|
pub struct Poh {
|
||||||
last_hash: Hash,
|
prev_id: Hash,
|
||||||
|
id: Hash,
|
||||||
num_hashes: u64,
|
num_hashes: u64,
|
||||||
pub tick_height: u64,
|
pub tick_height: u64,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct PohEntry {
|
pub struct PohEntry {
|
||||||
|
pub prev_id: Hash,
|
||||||
pub num_hashes: u64,
|
pub num_hashes: u64,
|
||||||
pub id: Hash,
|
pub id: Hash,
|
||||||
pub mixin: Option<Hash>,
|
pub mixin: Option<Hash>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Poh {
|
impl Poh {
|
||||||
pub fn new(last_hash: Hash, tick_height: u64) -> Self {
|
pub fn new(prev_id: Hash, tick_height: u64) -> Self {
|
||||||
Poh {
|
Poh {
|
||||||
last_hash,
|
prev_id,
|
||||||
num_hashes: 0,
|
num_hashes: 0,
|
||||||
|
id: prev_id,
|
||||||
tick_height,
|
tick_height,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn hash(&mut self) {
|
pub fn hash(&mut self) {
|
||||||
self.last_hash = hash(&self.last_hash.as_ref());
|
self.id = hash(&self.id.as_ref());
|
||||||
self.num_hashes += 1;
|
self.num_hashes += 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn record(&mut self, mixin: Hash) -> PohEntry {
|
pub fn record(&mut self, mixin: Hash) -> PohEntry {
|
||||||
let num_hashes = self.num_hashes + 1;
|
self.id = hashv(&[&self.id.as_ref(), &mixin.as_ref()]);
|
||||||
self.last_hash = hashv(&[&self.last_hash.as_ref(), &mixin.as_ref()]);
|
|
||||||
|
|
||||||
|
let prev_id = self.prev_id;
|
||||||
|
self.prev_id = self.id;
|
||||||
|
|
||||||
|
let num_hashes = self.num_hashes + 1;
|
||||||
self.num_hashes = 0;
|
self.num_hashes = 0;
|
||||||
|
|
||||||
PohEntry {
|
PohEntry {
|
||||||
|
prev_id,
|
||||||
num_hashes,
|
num_hashes,
|
||||||
id: self.last_hash,
|
id: self.id,
|
||||||
mixin: Some(mixin),
|
mixin: Some(mixin),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -48,11 +56,16 @@ impl Poh {
|
||||||
|
|
||||||
let num_hashes = self.num_hashes;
|
let num_hashes = self.num_hashes;
|
||||||
self.num_hashes = 0;
|
self.num_hashes = 0;
|
||||||
|
|
||||||
|
let prev_id = self.prev_id;
|
||||||
|
self.prev_id = self.id;
|
||||||
|
|
||||||
self.tick_height += 1;
|
self.tick_height += 1;
|
||||||
|
|
||||||
PohEntry {
|
PohEntry {
|
||||||
|
prev_id,
|
||||||
num_hashes,
|
num_hashes,
|
||||||
id: self.last_hash,
|
id: self.id,
|
||||||
mixin: None,
|
mixin: None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -60,21 +73,22 @@ impl Poh {
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
pub fn verify(initial: Hash, entries: &[PohEntry]) -> bool {
|
pub fn verify(initial: Hash, entries: &[PohEntry]) -> bool {
|
||||||
let mut last_hash = initial;
|
let mut prev_id = initial;
|
||||||
|
|
||||||
for entry in entries {
|
for entry in entries {
|
||||||
assert!(entry.num_hashes != 0);
|
assert!(entry.num_hashes != 0);
|
||||||
|
assert!(prev_id == entry.prev_id);
|
||||||
|
|
||||||
for _ in 1..entry.num_hashes {
|
for _ in 1..entry.num_hashes {
|
||||||
last_hash = hash(&last_hash.as_ref());
|
prev_id = hash(&prev_id.as_ref());
|
||||||
}
|
}
|
||||||
let id = match entry.mixin {
|
prev_id = match entry.mixin {
|
||||||
Some(mixin) => hashv(&[&last_hash.as_ref(), &mixin.as_ref()]),
|
Some(mixin) => hashv(&[&prev_id.as_ref(), &mixin.as_ref()]),
|
||||||
None => hash(&last_hash.as_ref()),
|
None => hash(&prev_id.as_ref()),
|
||||||
};
|
};
|
||||||
if id != entry.id {
|
if prev_id != entry.id {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
last_hash = id;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
true
|
true
|
||||||
|
@ -91,10 +105,12 @@ mod tests {
|
||||||
poh::verify(
|
poh::verify(
|
||||||
Hash::default(),
|
Hash::default(),
|
||||||
&[PohEntry {
|
&[PohEntry {
|
||||||
|
prev_id: Hash::default(),
|
||||||
num_hashes: 0,
|
num_hashes: 0,
|
||||||
id: Hash::default(),
|
id: Hash::default(),
|
||||||
mixin: None,
|
mixin: None,
|
||||||
}],
|
}],
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -80,15 +80,6 @@ impl PohRecorder {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn generate_tick_entry(&self, poh: &mut Poh) -> Entry {
|
|
||||||
let tick = poh.tick();
|
|
||||||
Entry {
|
|
||||||
num_hashes: tick.num_hashes,
|
|
||||||
id: tick.id,
|
|
||||||
transactions: vec![],
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn is_max_tick_height_reached(&self, poh: &Poh) -> bool {
|
fn is_max_tick_height_reached(&self, poh: &Poh) -> bool {
|
||||||
if let Some(max_tick_height) = self.max_tick_height {
|
if let Some(max_tick_height) = self.max_tick_height {
|
||||||
poh.tick_height >= max_tick_height
|
poh.tick_height >= max_tick_height
|
||||||
|
@ -98,11 +89,12 @@ impl PohRecorder {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn record_and_send_txs(&self, poh: &mut Poh, mixin: Hash, txs: Vec<Transaction>) -> Result<()> {
|
fn record_and_send_txs(&self, poh: &mut Poh, mixin: Hash, txs: Vec<Transaction>) -> Result<()> {
|
||||||
let tick = poh.record(mixin);
|
let entry = poh.record(mixin);
|
||||||
assert!(!txs.is_empty(), "Entries without transactions are used to track real-time passing in the ledger and can only be generated with PohRecorder::tick function");
|
assert!(!txs.is_empty(), "Entries without transactions are used to track real-time passing in the ledger and can only be generated with PohRecorder::tick function");
|
||||||
let entry = Entry {
|
let entry = Entry {
|
||||||
num_hashes: tick.num_hashes,
|
prev_id: entry.prev_id,
|
||||||
id: tick.id,
|
num_hashes: entry.num_hashes,
|
||||||
|
id: entry.id,
|
||||||
transactions: txs,
|
transactions: txs,
|
||||||
};
|
};
|
||||||
self.sender.send(vec![entry])?;
|
self.sender.send(vec![entry])?;
|
||||||
|
@ -110,9 +102,15 @@ impl PohRecorder {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn register_and_send_tick(&self, poh: &mut Poh) -> Result<()> {
|
fn register_and_send_tick(&self, poh: &mut Poh) -> Result<()> {
|
||||||
let tick_entry = self.generate_tick_entry(poh);
|
let tick = poh.tick();
|
||||||
self.bank.register_tick(&tick_entry.id);
|
let tick = Entry {
|
||||||
self.sender.send(vec![tick_entry])?;
|
prev_id: tick.prev_id,
|
||||||
|
num_hashes: tick.num_hashes,
|
||||||
|
id: tick.id,
|
||||||
|
transactions: vec![],
|
||||||
|
};
|
||||||
|
self.bank.register_tick(&tick.id);
|
||||||
|
self.sender.send(vec![tick])?;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -130,9 +128,9 @@ mod tests {
|
||||||
fn test_poh() {
|
fn test_poh() {
|
||||||
let mint = Mint::new(1);
|
let mint = Mint::new(1);
|
||||||
let bank = Arc::new(Bank::new(&mint));
|
let bank = Arc::new(Bank::new(&mint));
|
||||||
let last_id = bank.last_id();
|
let prev_id = bank.last_id();
|
||||||
let (entry_sender, entry_receiver) = channel();
|
let (entry_sender, entry_receiver) = channel();
|
||||||
let mut poh_recorder = PohRecorder::new(bank, entry_sender, last_id, None);
|
let mut poh_recorder = PohRecorder::new(bank, entry_sender, prev_id, None);
|
||||||
|
|
||||||
//send some data
|
//send some data
|
||||||
let h1 = hash(b"hello world!");
|
let h1 = hash(b"hello world!");
|
||||||
|
|
Loading…
Reference in New Issue