2018-09-26 05:52:13 -07:00
//! The `poh_recorder` module provides an object for synchronizing with Proof of History.
2018-11-05 09:47:41 -08:00
//! It synchronizes PoH, bank's register_tick and the ledger
2018-09-26 05:52:13 -07:00
//!
2019-02-24 08:59:49 -08:00
//! PohRecorder will send ticks or entries to a WorkingBank, if the current range of ticks is
//! within the specified WorkingBank range.
//!
//! For Ticks:
//! * tick must be > WorkingBank::min_tick_height && tick must be <= WorkingBank::man_tick_height
//!
//! For Entries:
//! * recorded entry must be >= WorkingBank::min_tick_height && entry must be < WorkingBank::man_tick_height
//!
2018-12-07 19:16:27 -08:00
use crate ::entry ::Entry ;
use crate ::poh ::Poh ;
use crate ::result ::{ Error , Result } ;
2019-02-18 22:26:22 -08:00
use solana_runtime ::bank ::Bank ;
2018-11-16 08:04:46 -08:00
use solana_sdk ::hash ::Hash ;
2018-11-29 16:18:47 -08:00
use solana_sdk ::transaction ::Transaction ;
2019-03-03 16:44:06 -08:00
use std ::sync ::mpsc ::{ channel , Receiver , Sender } ;
2019-02-24 08:59:49 -08:00
use std ::sync ::Arc ;
2018-09-26 05:52:13 -07:00
2018-10-18 22:57:48 -07:00
#[ derive(Debug, PartialEq, Eq, Clone) ]
pub enum PohRecorderError {
2018-10-25 14:56:21 -07:00
InvalidCallingObject ,
2018-10-18 22:57:48 -07:00
MaxHeightReached ,
2019-02-19 16:17:36 -08:00
MinHeightNotReached ,
}
2019-03-03 16:44:06 -08:00
pub type WorkingBankEntries = ( Arc < Bank > , Vec < ( Entry , u64 ) > ) ;
2019-02-19 16:17:36 -08:00
#[ derive(Clone) ]
pub struct WorkingBank {
pub bank : Arc < Bank > ,
pub min_tick_height : u64 ,
pub max_tick_height : u64 ,
2018-10-18 22:57:48 -07:00
}
2018-09-26 05:52:13 -07:00
pub struct PohRecorder {
2019-02-26 10:48:18 -08:00
pub poh : Poh ,
2019-02-24 08:59:49 -08:00
tick_cache : Vec < ( Entry , u64 ) > ,
working_bank : Option < WorkingBank > ,
2019-03-03 16:44:06 -08:00
sender : Sender < WorkingBankEntries > ,
2018-09-26 05:52:13 -07:00
}
impl PohRecorder {
2019-02-24 08:59:49 -08:00
pub fn clear_bank ( & mut self ) {
self . working_bank = None ;
}
pub fn hash ( & mut self ) {
2018-09-26 05:52:13 -07:00
// TODO: amortize the cost of this lock by doing the loop in here for
// some min amount of hashes
2019-02-24 08:59:49 -08:00
self . poh . hash ( ) ;
2019-02-19 16:17:36 -08:00
}
2018-12-12 18:52:11 -08:00
2019-03-03 16:44:06 -08:00
pub fn bank ( & self ) -> Option < Arc < Bank > > {
self . working_bank . clone ( ) . map ( | w | w . bank )
}
2019-03-04 07:08:22 -08:00
pub fn tick_height ( & self ) -> u64 {
self . poh . tick_height
}
2019-02-24 08:59:49 -08:00
// synchronize PoH with a bank
2019-03-02 10:25:16 -08:00
pub fn reset ( & mut self , tick_height : u64 , blockhash : Hash ) {
2019-03-04 07:08:22 -08:00
let existing = self . tick_cache . iter ( ) . any ( | ( entry , entry_tick_height ) | {
if entry . hash = = blockhash {
assert_eq! ( * entry_tick_height , tick_height ) ;
}
entry . hash = = blockhash
} ) ;
if existing {
2019-03-03 16:44:06 -08:00
info! (
" reset skipped for: {},{} " ,
self . poh . hash , self . poh . tick_height
) ;
return ;
}
2019-02-19 16:17:36 -08:00
let mut cache = vec! [ ] ;
2019-02-24 08:59:49 -08:00
info! (
" reset poh from: {},{} to: {},{} " ,
2019-03-02 10:25:16 -08:00
self . poh . hash , self . poh . tick_height , blockhash , tick_height ,
2019-02-24 08:59:49 -08:00
) ;
std ::mem ::swap ( & mut cache , & mut self . tick_cache ) ;
2019-03-02 10:25:16 -08:00
self . poh = Poh ::new ( blockhash , tick_height ) ;
2019-02-24 08:59:49 -08:00
}
pub fn set_working_bank ( & mut self , working_bank : WorkingBank ) {
2019-02-26 21:57:45 -08:00
trace! ( " new working bank " ) ;
2019-02-24 08:59:49 -08:00
self . working_bank = Some ( working_bank ) ;
}
2019-03-03 16:44:06 -08:00
pub fn set_bank ( & mut self , bank : & Arc < Bank > ) {
let max_tick_height = ( bank . slot ( ) + 1 ) * bank . ticks_per_slot ( ) - 1 ;
let working_bank = WorkingBank {
bank : bank . clone ( ) ,
min_tick_height : bank . tick_height ( ) ,
max_tick_height ,
} ;
self . set_working_bank ( working_bank ) ;
}
2019-02-24 08:59:49 -08:00
// Flush cache will delay flushing the cache for a bank until it past the WorkingBank::min_tick_height
// On a record flush will flush the cache at the WorkingBank::min_tick_height, since a record
// occurs after the min_tick_height was generated
fn flush_cache ( & mut self , tick : bool ) -> Result < ( ) > {
// check_tick_height is called before flush cache, so it cannot overrun the bank
// so a bank that is so late that it's slot fully generated before it starts recording
// will fail instead of broadcasting any ticks
let working_bank = self
. working_bank
. as_ref ( )
. ok_or ( Error ::PohRecorderError ( PohRecorderError ::MaxHeightReached ) ) ? ;
if self . poh . tick_height < working_bank . min_tick_height {
return Err ( Error ::PohRecorderError (
PohRecorderError ::MinHeightNotReached ,
) ) ;
}
if tick & & self . poh . tick_height = = working_bank . min_tick_height {
return Err ( Error ::PohRecorderError (
PohRecorderError ::MinHeightNotReached ,
) ) ;
}
let cnt = self
. tick_cache
. iter ( )
. take_while ( | x | x . 1 < = working_bank . max_tick_height )
. count ( ) ;
let e = if cnt > 0 {
2019-02-26 21:57:45 -08:00
debug! (
2019-03-04 16:40:28 -08:00
" flush_cache: bank_slot: {} tick_height: {} max: {} sending: {} " ,
2019-02-26 21:57:45 -08:00
working_bank . bank . slot ( ) ,
2019-02-24 08:59:49 -08:00
working_bank . bank . tick_height ( ) ,
working_bank . max_tick_height ,
cnt ,
) ;
2019-02-25 13:50:31 -08:00
let cache = & self . tick_cache [ .. cnt ] ;
for t in cache {
2019-03-01 08:57:42 -08:00
working_bank . bank . register_tick ( & t . 0. hash ) ;
2019-02-19 16:17:36 -08:00
}
2019-03-03 16:44:06 -08:00
self . sender
. send ( ( working_bank . bank . clone ( ) , cache . to_vec ( ) ) )
2019-02-24 08:59:49 -08:00
} else {
Ok ( ( ) )
} ;
if self . poh . tick_height > = working_bank . max_tick_height {
2019-03-03 16:44:06 -08:00
info! (
" poh_record: max_tick_height reached, setting working bank {} to None " ,
working_bank . bank . slot ( )
) ;
2019-02-24 08:59:49 -08:00
self . working_bank = None ;
2019-02-19 16:17:36 -08:00
}
2019-02-24 08:59:49 -08:00
if e . is_err ( ) {
info! ( " WorkingBank::sender disconnected {:?} " , e ) ;
//revert the cache, but clear the working bank
self . working_bank = None ;
} else {
//commit the flush
let _ = self . tick_cache . drain ( .. cnt ) ;
}
2018-12-12 18:52:11 -08:00
Ok ( ( ) )
2018-09-26 05:52:13 -07:00
}
2019-02-24 08:59:49 -08:00
pub fn tick ( & mut self ) {
let tick = self . generate_tick ( ) ;
trace! ( " tick {} " , tick . 1 ) ;
self . tick_cache . push ( tick ) ;
let _ = self . flush_cache ( true ) ;
2018-09-26 05:52:13 -07:00
}
2019-02-24 08:59:49 -08:00
pub fn record ( & mut self , mixin : Hash , txs : Vec < Transaction > ) -> Result < ( ) > {
self . flush_cache ( false ) ? ;
self . record_and_send_txs ( mixin , txs )
2018-10-18 22:57:48 -07:00
}
2019-03-03 16:44:06 -08:00
/// A recorder to synchronize PoH with the following data structures
/// * bank - the LastId's queue is updated on `tick` and `record` events
/// * sender - the Entry channel that outputs to the ledger
pub fn new ( tick_height : u64 , last_entry_hash : Hash ) -> ( Self , Receiver < WorkingBankEntries > ) {
2019-03-01 08:26:47 -08:00
let poh = Poh ::new ( last_entry_hash , tick_height ) ;
2019-03-03 16:44:06 -08:00
let ( sender , receiver ) = channel ( ) ;
(
PohRecorder {
poh ,
tick_cache : vec ! [ ] ,
working_bank : None ,
sender ,
} ,
receiver ,
)
2018-10-18 22:57:48 -07:00
}
2019-02-24 08:59:49 -08:00
fn record_and_send_txs ( & mut self , mixin : Hash , txs : Vec < Transaction > ) -> Result < ( ) > {
let working_bank = self
. working_bank
. as_ref ( )
. ok_or ( Error ::PohRecorderError ( PohRecorderError ::MaxHeightReached ) ) ? ;
2019-03-01 09:21:58 -08:00
let poh_entry = self . poh . record ( mixin ) ;
2018-10-10 17:23:06 -07:00
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 " ) ;
2019-02-25 13:50:31 -08:00
let recorded_entry = Entry {
2019-03-01 09:21:58 -08:00
num_hashes : poh_entry . num_hashes ,
hash : poh_entry . hash ,
2018-09-26 05:52:13 -07:00
transactions : txs ,
} ;
2019-02-25 13:50:31 -08:00
trace! ( " sending entry {} " , recorded_entry . is_tick ( ) ) ;
2019-03-03 16:44:06 -08:00
self . sender . send ( (
working_bank . bank . clone ( ) ,
vec! [ ( recorded_entry , poh_entry . tick_height ) ] ,
) ) ? ;
2018-09-26 05:52:13 -07:00
Ok ( ( ) )
}
2018-10-18 22:57:48 -07:00
2019-02-24 08:59:49 -08:00
fn generate_tick ( & mut self ) -> ( Entry , u64 ) {
let tick = self . poh . tick ( ) ;
assert_ne! ( tick . tick_height , 0 ) ;
(
Entry {
num_hashes : tick . num_hashes ,
2019-03-01 09:21:58 -08:00
hash : tick . hash ,
2019-02-24 08:59:49 -08:00
transactions : vec ! [ ] ,
} ,
tick . tick_height ,
)
2018-10-18 22:57:48 -07:00
}
2018-09-26 05:52:13 -07:00
}
#[ cfg(test) ]
mod tests {
use super ::* ;
2018-12-07 19:16:27 -08:00
use crate ::test_tx ::test_tx ;
2019-02-18 22:26:22 -08:00
use solana_sdk ::genesis_block ::GenesisBlock ;
2018-11-16 08:04:46 -08:00
use solana_sdk ::hash ::hash ;
2018-09-26 05:52:13 -07:00
use std ::sync ::Arc ;
#[ test ]
2019-02-24 08:59:49 -08:00
fn test_poh_recorder_no_zero_tick ( ) {
2019-03-01 08:44:55 -08:00
let prev_hash = Hash ::default ( ) ;
2019-03-03 16:44:06 -08:00
let ( mut poh_recorder , _entry_receiver ) = PohRecorder ::new ( 0 , prev_hash ) ;
2019-02-24 08:59:49 -08:00
poh_recorder . tick ( ) ;
assert_eq! ( poh_recorder . tick_cache . len ( ) , 1 ) ;
assert_eq! ( poh_recorder . tick_cache [ 0 ] . 1 , 1 ) ;
assert_eq! ( poh_recorder . poh . tick_height , 1 ) ;
}
#[ test ]
fn test_poh_recorder_tick_height_is_last_tick ( ) {
2019-03-01 08:44:55 -08:00
let prev_hash = Hash ::default ( ) ;
2019-03-03 16:44:06 -08:00
let ( mut poh_recorder , _entry_receiver ) = PohRecorder ::new ( 0 , prev_hash ) ;
2019-02-24 08:59:49 -08:00
poh_recorder . tick ( ) ;
poh_recorder . tick ( ) ;
assert_eq! ( poh_recorder . tick_cache . len ( ) , 2 ) ;
assert_eq! ( poh_recorder . tick_cache [ 1 ] . 1 , 2 ) ;
assert_eq! ( poh_recorder . poh . tick_height , 2 ) ;
}
#[ test ]
fn test_poh_recorder_reset_clears_cache ( ) {
2019-03-03 16:44:06 -08:00
let ( mut poh_recorder , _entry_receiver ) = PohRecorder ::new ( 0 , Hash ::default ( ) ) ;
2019-02-24 08:59:49 -08:00
poh_recorder . tick ( ) ;
assert_eq! ( poh_recorder . tick_cache . len ( ) , 1 ) ;
poh_recorder . reset ( 0 , Hash ::default ( ) ) ;
assert_eq! ( poh_recorder . tick_cache . len ( ) , 0 ) ;
}
#[ test ]
fn test_poh_recorder_clear ( ) {
let ( genesis_block , _mint_keypair ) = GenesisBlock ::new ( 2 ) ;
let bank = Arc ::new ( Bank ::new ( & genesis_block ) ) ;
2019-03-02 10:25:16 -08:00
let prev_hash = bank . last_blockhash ( ) ;
2019-03-03 16:44:06 -08:00
let ( mut poh_recorder , _entry_receiver ) = PohRecorder ::new ( 0 , prev_hash ) ;
2019-02-24 08:59:49 -08:00
let working_bank = WorkingBank {
bank ,
min_tick_height : 2 ,
max_tick_height : 3 ,
} ;
poh_recorder . set_working_bank ( working_bank ) ;
assert! ( poh_recorder . working_bank . is_some ( ) ) ;
poh_recorder . clear_bank ( ) ;
assert! ( poh_recorder . working_bank . is_none ( ) ) ;
}
#[ test ]
fn test_poh_recorder_tick_sent_after_min ( ) {
2019-02-05 08:03:52 -08:00
let ( genesis_block , _mint_keypair ) = GenesisBlock ::new ( 2 ) ;
2019-01-24 12:04:04 -08:00
let bank = Arc ::new ( Bank ::new ( & genesis_block ) ) ;
2019-03-02 10:25:16 -08:00
let prev_hash = bank . last_blockhash ( ) ;
2019-03-03 16:44:06 -08:00
let ( mut poh_recorder , entry_receiver ) = PohRecorder ::new ( 0 , prev_hash ) ;
2019-02-19 16:17:36 -08:00
let working_bank = WorkingBank {
2019-03-03 16:44:06 -08:00
bank : bank . clone ( ) ,
2019-02-24 08:59:49 -08:00
min_tick_height : 2 ,
max_tick_height : 3 ,
2019-02-19 16:17:36 -08:00
} ;
2019-02-24 08:59:49 -08:00
poh_recorder . set_working_bank ( working_bank ) ;
poh_recorder . tick ( ) ;
poh_recorder . tick ( ) ;
//tick height equal to min_tick_height
//no tick has been sent
assert_eq! ( poh_recorder . tick_cache . last ( ) . unwrap ( ) . 1 , 2 ) ;
assert! ( entry_receiver . try_recv ( ) . is_err ( ) ) ;
2018-09-26 05:52:13 -07:00
2019-02-24 08:59:49 -08:00
// all ticks are sent after height > min
poh_recorder . tick ( ) ;
assert_eq! ( poh_recorder . poh . tick_height , 3 ) ;
assert_eq! ( poh_recorder . tick_cache . len ( ) , 0 ) ;
2019-03-03 16:44:06 -08:00
let ( bank_ , e ) = entry_receiver . recv ( ) . expect ( " recv 1 " ) ;
2019-02-24 08:59:49 -08:00
assert_eq! ( e . len ( ) , 3 ) ;
2019-03-03 16:44:06 -08:00
assert_eq! ( bank_ . slot ( ) , bank . slot ( ) ) ;
2019-02-24 08:59:49 -08:00
assert! ( poh_recorder . working_bank . is_none ( ) ) ;
}
2018-12-10 20:03:04 -08:00
2019-02-24 08:59:49 -08:00
#[ test ]
fn test_poh_recorder_tick_sent_upto_and_including_max ( ) {
let ( genesis_block , _mint_keypair ) = GenesisBlock ::new ( 2 ) ;
let bank = Arc ::new ( Bank ::new ( & genesis_block ) ) ;
2019-03-02 10:25:16 -08:00
let prev_hash = bank . last_blockhash ( ) ;
2019-03-03 16:44:06 -08:00
let ( mut poh_recorder , entry_receiver ) = PohRecorder ::new ( 0 , prev_hash ) ;
2018-09-26 05:52:13 -07:00
2019-02-24 08:59:49 -08:00
poh_recorder . tick ( ) ;
poh_recorder . tick ( ) ;
poh_recorder . tick ( ) ;
poh_recorder . tick ( ) ;
assert_eq! ( poh_recorder . tick_cache . last ( ) . unwrap ( ) . 1 , 4 ) ;
assert_eq! ( poh_recorder . poh . tick_height , 4 ) ;
2018-09-26 05:52:13 -07:00
2019-02-24 08:59:49 -08:00
let working_bank = WorkingBank {
bank ,
min_tick_height : 2 ,
max_tick_height : 3 ,
} ;
poh_recorder . set_working_bank ( working_bank ) ;
poh_recorder . tick ( ) ;
2018-12-12 18:52:11 -08:00
2019-02-24 08:59:49 -08:00
assert_eq! ( poh_recorder . poh . tick_height , 5 ) ;
assert! ( poh_recorder . working_bank . is_none ( ) ) ;
2019-03-03 16:44:06 -08:00
let ( _ , e ) = entry_receiver . recv ( ) . expect ( " recv 1 " ) ;
2019-02-24 08:59:49 -08:00
assert_eq! ( e . len ( ) , 3 ) ;
2019-02-19 16:17:36 -08:00
}
#[ test ]
2019-02-24 08:59:49 -08:00
fn test_poh_recorder_record_to_early ( ) {
2019-02-19 16:17:36 -08:00
let ( genesis_block , _mint_keypair ) = GenesisBlock ::new ( 2 ) ;
let bank = Arc ::new ( Bank ::new ( & genesis_block ) ) ;
2019-03-02 10:25:16 -08:00
let prev_hash = bank . last_blockhash ( ) ;
2019-03-03 16:44:06 -08:00
let ( mut poh_recorder , entry_receiver ) = PohRecorder ::new ( 0 , prev_hash ) ;
2019-02-19 16:17:36 -08:00
let working_bank = WorkingBank {
bank ,
2019-02-24 08:59:49 -08:00
min_tick_height : 2 ,
max_tick_height : 3 ,
2019-02-19 16:17:36 -08:00
} ;
2019-02-24 08:59:49 -08:00
poh_recorder . set_working_bank ( working_bank ) ;
poh_recorder . tick ( ) ;
let tx = test_tx ( ) ;
let h1 = hash ( b " hello world! " ) ;
assert! ( poh_recorder . record ( h1 , vec! [ tx . clone ( ) ] ) . is_err ( ) ) ;
2019-02-19 16:17:36 -08:00
assert! ( entry_receiver . try_recv ( ) . is_err ( ) ) ;
2019-02-24 08:59:49 -08:00
}
2019-02-19 16:17:36 -08:00
2019-02-24 08:59:49 -08:00
#[ test ]
fn test_poh_recorder_record_at_min_passes ( ) {
let ( genesis_block , _mint_keypair ) = GenesisBlock ::new ( 2 ) ;
let bank = Arc ::new ( Bank ::new ( & genesis_block ) ) ;
2019-03-02 10:25:16 -08:00
let prev_hash = bank . last_blockhash ( ) ;
2019-03-03 16:44:06 -08:00
let ( mut poh_recorder , entry_receiver ) = PohRecorder ::new ( 0 , prev_hash ) ;
2019-02-19 16:17:36 -08:00
2019-02-24 08:59:49 -08:00
let working_bank = WorkingBank {
bank ,
min_tick_height : 1 ,
max_tick_height : 2 ,
} ;
poh_recorder . set_working_bank ( working_bank ) ;
poh_recorder . tick ( ) ;
assert_eq! ( poh_recorder . tick_cache . len ( ) , 1 ) ;
assert_eq! ( poh_recorder . poh . tick_height , 1 ) ;
let tx = test_tx ( ) ;
let h1 = hash ( b " hello world! " ) ;
assert! ( poh_recorder . record ( h1 , vec! [ tx . clone ( ) ] ) . is_ok ( ) ) ;
assert_eq! ( poh_recorder . tick_cache . len ( ) , 0 ) ;
//tick in the cache + entry
2019-03-03 16:44:06 -08:00
let ( _b , e ) = entry_receiver . recv ( ) . expect ( " recv 1 " ) ;
2019-02-24 08:59:49 -08:00
assert_eq! ( e . len ( ) , 1 ) ;
2019-02-25 13:50:31 -08:00
assert! ( e [ 0 ] . 0. is_tick ( ) ) ;
2019-03-03 16:44:06 -08:00
let ( _b , e ) = entry_receiver . recv ( ) . expect ( " recv 2 " ) ;
2019-02-25 13:50:31 -08:00
assert! ( ! e [ 0 ] . 0. is_tick ( ) ) ;
2019-02-19 16:17:36 -08:00
}
#[ test ]
2019-02-24 08:59:49 -08:00
fn test_poh_recorder_record_at_max_fails ( ) {
2019-02-19 16:17:36 -08:00
let ( genesis_block , _mint_keypair ) = GenesisBlock ::new ( 2 ) ;
let bank = Arc ::new ( Bank ::new ( & genesis_block ) ) ;
2019-03-02 10:25:16 -08:00
let prev_hash = bank . last_blockhash ( ) ;
2019-03-03 16:44:06 -08:00
let ( mut poh_recorder , entry_receiver ) = PohRecorder ::new ( 0 , prev_hash ) ;
2019-02-19 16:17:36 -08:00
let working_bank = WorkingBank {
bank ,
min_tick_height : 1 ,
2019-02-24 08:59:49 -08:00
max_tick_height : 2 ,
2019-02-19 16:17:36 -08:00
} ;
2019-02-24 08:59:49 -08:00
poh_recorder . set_working_bank ( working_bank ) ;
poh_recorder . tick ( ) ;
poh_recorder . tick ( ) ;
assert_eq! ( poh_recorder . poh . tick_height , 2 ) ;
let tx = test_tx ( ) ;
let h1 = hash ( b " hello world! " ) ;
assert! ( poh_recorder . record ( h1 , vec! [ tx . clone ( ) ] ) . is_err ( ) ) ;
2019-02-19 16:17:36 -08:00
2019-03-03 16:44:06 -08:00
let ( _bank , e ) = entry_receiver . recv ( ) . expect ( " recv 1 " ) ;
2019-02-24 08:59:49 -08:00
assert_eq! ( e . len ( ) , 2 ) ;
2019-02-25 13:50:31 -08:00
assert! ( e [ 0 ] . 0. is_tick ( ) ) ;
assert! ( e [ 1 ] . 0. is_tick ( ) ) ;
2019-02-24 08:59:49 -08:00
}
2019-02-19 16:17:36 -08:00
2019-02-24 08:59:49 -08:00
#[ test ]
fn test_poh_cache_on_disconnect ( ) {
let ( genesis_block , _mint_keypair ) = GenesisBlock ::new ( 2 ) ;
let bank = Arc ::new ( Bank ::new ( & genesis_block ) ) ;
2019-03-02 10:25:16 -08:00
let prev_hash = bank . last_blockhash ( ) ;
2019-03-03 16:44:06 -08:00
let ( mut poh_recorder , entry_receiver ) = PohRecorder ::new ( 0 , prev_hash ) ;
2019-02-19 16:17:36 -08:00
2019-02-24 08:59:49 -08:00
let working_bank = WorkingBank {
bank ,
min_tick_height : 2 ,
max_tick_height : 3 ,
} ;
poh_recorder . set_working_bank ( working_bank ) ;
poh_recorder . tick ( ) ;
poh_recorder . tick ( ) ;
assert_eq! ( poh_recorder . poh . tick_height , 2 ) ;
drop ( entry_receiver ) ;
poh_recorder . tick ( ) ;
assert! ( poh_recorder . working_bank . is_none ( ) ) ;
assert_eq! ( poh_recorder . tick_cache . len ( ) , 3 ) ;
2018-09-26 05:52:13 -07:00
}
2019-03-04 07:08:22 -08:00
#[ test ]
fn test_reset_current ( ) {
let ( mut poh_recorder , _entry_receiver ) = PohRecorder ::new ( 0 , Hash ::default ( ) ) ;
poh_recorder . tick ( ) ;
poh_recorder . tick ( ) ;
assert_eq! ( poh_recorder . tick_cache . len ( ) , 2 ) ;
poh_recorder . reset ( poh_recorder . poh . tick_height , poh_recorder . poh . hash ) ;
assert_eq! ( poh_recorder . tick_cache . len ( ) , 2 ) ;
}
#[ test ]
fn test_reset_with_cached ( ) {
let ( mut poh_recorder , _entry_receiver ) = PohRecorder ::new ( 0 , Hash ::default ( ) ) ;
poh_recorder . tick ( ) ;
poh_recorder . tick ( ) ;
assert_eq! ( poh_recorder . tick_cache . len ( ) , 2 ) ;
poh_recorder . reset (
poh_recorder . tick_cache [ 0 ] . 1 ,
poh_recorder . tick_cache [ 0 ] . 0. hash ,
) ;
assert_eq! ( poh_recorder . tick_cache . len ( ) , 2 ) ;
poh_recorder . reset (
poh_recorder . tick_cache [ 1 ] . 1 ,
poh_recorder . tick_cache [ 1 ] . 0. hash ,
) ;
assert_eq! ( poh_recorder . tick_cache . len ( ) , 2 ) ;
}
#[ test ]
#[ should_panic ]
fn test_reset_with_cached_bad_height ( ) {
let ( mut poh_recorder , _entry_receiver ) = PohRecorder ::new ( 0 , Hash ::default ( ) ) ;
poh_recorder . tick ( ) ;
poh_recorder . tick ( ) ;
assert_eq! ( poh_recorder . tick_cache . len ( ) , 2 ) ;
//mixed up heights
poh_recorder . reset (
poh_recorder . tick_cache [ 0 ] . 1 ,
poh_recorder . tick_cache [ 1 ] . 0. hash ,
) ;
}
#[ test ]
fn test_reset_to_new_value ( ) {
let ( mut poh_recorder , _entry_receiver ) = PohRecorder ::new ( 0 , Hash ::default ( ) ) ;
poh_recorder . tick ( ) ;
poh_recorder . tick ( ) ;
poh_recorder . tick ( ) ;
assert_eq! ( poh_recorder . tick_cache . len ( ) , 3 ) ;
assert_eq! ( poh_recorder . poh . tick_height , 3 ) ;
poh_recorder . reset ( 1 , hash ( b " hello " ) ) ;
assert_eq! ( poh_recorder . tick_cache . len ( ) , 0 ) ;
poh_recorder . tick ( ) ;
assert_eq! ( poh_recorder . poh . tick_height , 2 ) ;
}
2018-09-26 05:52:13 -07:00
}