Skip to content
This repository was archived by the owner on Jan 22, 2025. It is now read-only.
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 6 additions & 2 deletions src/cluster_info.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1670,8 +1670,12 @@ mod tests {
let zero = Hash::default();
let one = hash(&zero.as_ref());
writer
.write_entries(&vec![Entry::new_tick(0, &zero), Entry::new_tick(0, &one)].to_vec())
.unwrap();
.write_entries(
&vec![
Entry::new_tick(&zero, 0, &zero),
Entry::new_tick(&one, 0, &one),
].to_vec(),
).unwrap();
path
}

Expand Down
36 changes: 26 additions & 10 deletions src/entry.rs
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,9 @@ pub type EntryReceiver = Receiver<Vec<Entry>>;

#[derive(Serialize, Deserialize, Debug, PartialEq, Eq, Clone)]
pub struct Entry {
/// The the previous Entry ID.
pub prev_id: Hash,

/// The number of hashes since the previous Entry ID.
pub num_hashes: u64,

Expand All @@ -47,19 +50,21 @@ pub struct Entry {

impl Entry {
/// 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 = {
if num_hashes == 0 && transactions.is_empty() {
Entry {
prev_id: *prev_id,
num_hashes: 0,
id: *start_hash,
id: *prev_id,
transactions,
}
} else if num_hashes == 0 {
// If you passed in transactions, but passed in num_hashes == 0, then
// 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 {
prev_id: *prev_id,
num_hashes: 1,
id,
transactions,
Expand All @@ -68,8 +73,9 @@ impl Entry {
// Otherwise, the next Entry `num_hashes` after `start_hash`.
// If you wanted a tick for instance, then pass in num_hashes = 1
// and transactions = empty
let id = next_hash(start_hash, num_hashes, &transactions);
let id = next_hash(prev_id, num_hashes, &transactions);
Entry {
prev_id: *prev_id,
num_hashes,
id,
transactions,
Expand Down Expand Up @@ -121,7 +127,10 @@ impl Entry {
/// Estimate serialized_size of Entry without creating an Entry.
pub fn serialized_size(transactions: &[Transaction]) -> u64 {
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 {
Expand Down Expand Up @@ -175,14 +184,19 @@ impl Entry {

/// Creates a Entry from the number of hashes `num_hashes` since the previous transaction
/// 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 {
prev_id: *prev_id,
num_hashes,
id: *id,
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.
/// If the transaction is not a Tick, then hash that as well.
pub fn verify(&self, start_hash: &Hash) -> bool {
Expand Down Expand Up @@ -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`.
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());
Entry {
prev_id: *prev_id,
num_hashes,
id: next_hash(start_hash, num_hashes, &transactions),
id: next_hash(prev_id, num_hashes, &transactions),
transactions,
}
}
Expand All @@ -249,9 +264,10 @@ mod tests {
fn test_entry_verify() {
let zero = Hash::default();
let one = hash(&zero.as_ref());
assert!(Entry::new_tick(0, &zero).verify(&zero)); // base case
assert!(!Entry::new_tick(0, &zero).verify(&one)); // base case, bad
assert!(Entry::new_tick(&zero, 0, &zero).verify(&zero)); // base case, never used
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_self()); // also inductive step
assert!(!next_entry(&zero, 1, vec![]).verify(&one)); // inductive step, bad
}

Expand Down
7 changes: 4 additions & 3 deletions src/ledger.rs
Original file line number Diff line number Diff line change
Expand Up @@ -463,7 +463,7 @@ pub trait Block {

impl Block for [Entry] {
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);
entry_pairs.all(|(x0, x1)| {
let r = x1.verify(&x0.id);
Expand Down Expand Up @@ -710,8 +710,8 @@ mod tests {
let zero = Hash::default();
let one = hash(&zero.as_ref());
assert!(vec![][..].verify(&zero)); // base case
assert!(vec![Entry::new_tick(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(&zero)); // singleton case 1
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

let mut bad_ticks = vec![next_entry(&zero, 0, vec![]); 2];
Expand Down Expand Up @@ -781,6 +781,7 @@ mod tests {
let tx_small_size = serialized_size(&tx_small).unwrap() as usize;
let tx_large_size = serialized_size(&tx_large).unwrap() as usize;
let entry_size = serialized_size(&Entry {
prev_id: Hash::default(),
num_hashes: 0,
id: Hash::default(),
transactions: vec![],
Expand Down
46 changes: 31 additions & 15 deletions src/poh.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,40 +3,48 @@
use hash::{hash, hashv, Hash};

pub struct Poh {
last_hash: Hash,
prev_id: Hash,
id: Hash,
num_hashes: u64,
pub tick_height: u64,
}

#[derive(Debug)]
pub struct PohEntry {
pub prev_id: Hash,
pub num_hashes: u64,
pub id: Hash,
pub mixin: Option<Hash>,
}

impl Poh {
pub fn new(last_hash: Hash, tick_height: u64) -> Self {
pub fn new(prev_id: Hash, tick_height: u64) -> Self {
Poh {
last_hash,
prev_id,
num_hashes: 0,
id: prev_id,
tick_height,
}
}

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;
}

pub fn record(&mut self, mixin: Hash) -> PohEntry {
let num_hashes = self.num_hashes + 1;
self.last_hash = hashv(&[&self.last_hash.as_ref(), &mixin.as_ref()]);
self.id = hashv(&[&self.id.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;

PohEntry {
prev_id,
num_hashes,
id: self.last_hash,
id: self.id,
mixin: Some(mixin),
}
}
Expand All @@ -48,33 +56,39 @@ impl Poh {

let num_hashes = self.num_hashes;
self.num_hashes = 0;

let prev_id = self.prev_id;
self.prev_id = self.id;

self.tick_height += 1;

PohEntry {
prev_id,
num_hashes,
id: self.last_hash,
id: self.id,
mixin: None,
}
}
}

#[cfg(test)]
pub fn verify(initial: Hash, entries: &[PohEntry]) -> bool {
let mut last_hash = initial;
let mut prev_id = initial;

for entry in entries {
assert!(entry.num_hashes != 0);
assert!(prev_id == entry.prev_id);

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 {
Some(mixin) => hashv(&[&last_hash.as_ref(), &mixin.as_ref()]),
None => hash(&last_hash.as_ref()),
prev_id = match entry.mixin {
Some(mixin) => hashv(&[&prev_id.as_ref(), &mixin.as_ref()]),
None => hash(&prev_id.as_ref()),
};
if id != entry.id {
if prev_id != entry.id {
return false;
}
last_hash = id;
}

true
Expand All @@ -91,10 +105,12 @@ mod tests {
poh::verify(
Hash::default(),
&[PohEntry {
prev_id: Hash::default(),
num_hashes: 0,
id: Hash::default(),
mixin: None,
}],
);
}

}
32 changes: 15 additions & 17 deletions src/poh_recorder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
if let Some(max_tick_height) = self.max_tick_height {
poh.tick_height >= max_tick_height
Expand All @@ -98,21 +89,28 @@ impl PohRecorder {
}

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");
let entry = Entry {
num_hashes: tick.num_hashes,
id: tick.id,
prev_id: entry.prev_id,
num_hashes: entry.num_hashes,
id: entry.id,
transactions: txs,
};
self.sender.send(vec![entry])?;
Ok(())
}

fn register_and_send_tick(&self, poh: &mut Poh) -> Result<()> {
let tick_entry = self.generate_tick_entry(poh);
self.bank.register_tick(&tick_entry.id);
self.sender.send(vec![tick_entry])?;
let tick = poh.tick();
let 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(())
}
}
Expand All @@ -130,9 +128,9 @@ mod tests {
fn test_poh() {
let mint = Mint::new(1);
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 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
let h1 = hash(b"hello world!");
Expand Down