1313// See the License for the specific language governing permissions and
1414// limitations under the License.
1515
16- use crate :: { LedgerService , fmt_id, spawn_blocking} ;
16+ use crate :: { BeginLedgerUpdateError , LedgerService , LedgerUpdateService , fmt_id, spawn_blocking} ;
1717
1818use snarkos_utilities:: Stoppable ;
1919
2020use snarkvm:: {
2121 ledger:: {
2222 Block ,
23+ CheckBlockError ,
2324 Ledger ,
2425 PendingBlock ,
2526 Transaction ,
@@ -48,9 +49,13 @@ use snarkvm::{
4849use anyhow:: ensure;
4950use indexmap:: IndexMap ;
5051#[ cfg( feature = "locktick" ) ]
51- use locktick:: parking_lot:: RwLock ;
52+ use locktick:: {
53+ LockGuard ,
54+ parking_lot:: { Mutex , RwLock } ,
55+ } ;
56+ use parking_lot:: MutexGuard ;
5257#[ cfg( not( feature = "locktick" ) ) ]
53- use parking_lot:: RwLock ;
58+ use parking_lot:: { Mutex , RwLock } ;
5459#[ cfg( not( feature = "serial" ) ) ]
5560use rayon:: prelude:: * ;
5661
@@ -62,12 +67,73 @@ pub struct CoreLedgerService<N: Network, C: ConsensusStorage<N>> {
6267 ledger : Ledger < N , C > ,
6368 latest_leader : Arc < RwLock < Option < ( u64 , Address < N > ) > > > ,
6469 stoppable : Arc < dyn Stoppable > ,
70+ update_lock : Arc < Mutex < ( ) > > ,
71+ }
72+
73+ /// A transactional update to the ledger.
74+ #[ cfg( feature = "ledger-write" ) ]
75+ pub struct LedgerUpdate < ' a , N : Network , C : ConsensusStorage < N > > {
76+ ledger : Ledger < N , C > ,
77+ #[ cfg( feature = "locktick" ) ]
78+ _lock : LockGuard < MutexGuard < ' a , ( ) > > ,
79+ #[ cfg( not( feature = "locktick" ) ) ]
80+ _lock : MutexGuard < ' a , ( ) > ,
81+ }
82+
83+ #[ cfg( feature = "ledger-write" ) ]
84+ impl < ' a , N : Network , C : ConsensusStorage < N > > LedgerUpdateService < N > for LedgerUpdate < ' a , N , C > {
85+ fn check_block_subdag (
86+ & self ,
87+ block : Block < N > ,
88+ prefix : & [ PendingBlock < N > ] ,
89+ ) -> Result < PendingBlock < N > , CheckBlockError < N > > {
90+ self . ledger . check_block_subdag ( block, prefix)
91+ }
92+
93+ fn check_block_content ( & self , block : PendingBlock < N > ) -> Result < Block < N > , CheckBlockError < N > > {
94+ self . ledger . check_block_content ( block, & mut rand:: thread_rng ( ) )
95+ }
96+
97+ /// Checks the given block is valid next block.
98+ fn check_next_block ( & self , block : & Block < N > ) -> Result < ( ) > {
99+ self . ledger . check_next_block ( block, & mut rand:: thread_rng ( ) )
100+ }
101+
102+ /// Returns a candidate for the next block in the ledger, using a committed subdag and its transmissions.
103+ fn prepare_advance_to_next_quorum_block (
104+ & self ,
105+ subdag : Subdag < N > ,
106+ transmissions : IndexMap < TransmissionID < N > , Transmission < N > > ,
107+ ) -> Result < Block < N > > {
108+ self . ledger . prepare_advance_to_next_quorum_block ( subdag, transmissions, & mut rand:: thread_rng ( ) )
109+ }
110+
111+ /// Adds the given block as the next block in the ledger.
112+ fn advance_to_next_block ( & self , block : & Block < N > ) -> Result < ( ) > {
113+ // Advance to the next block.
114+ self . ledger . advance_to_next_block ( block) ?;
115+ // Update BFT metrics.
116+ #[ cfg( feature = "metrics" ) ]
117+ {
118+ let num_sol = block. solutions ( ) . len ( ) ;
119+ let num_tx = block. transactions ( ) . len ( ) ;
120+
121+ metrics:: gauge ( metrics:: bft:: HEIGHT , block. height ( ) as f64 ) ;
122+ metrics:: gauge ( metrics:: bft:: LAST_COMMITTED_ROUND , block. round ( ) as f64 ) ;
123+ metrics:: increment_gauge ( metrics:: blocks:: SOLUTIONS , num_sol as f64 ) ;
124+ metrics:: increment_gauge ( metrics:: blocks:: TRANSACTIONS , num_tx as f64 ) ;
125+ metrics:: update_block_metrics ( block) ;
126+ }
127+
128+ tracing:: info!( "\n \n Advanced to block {} at round {} - {}\n " , block. height( ) , block. round( ) , block. hash( ) ) ;
129+ Ok ( ( ) )
130+ }
65131}
66132
67133impl < N : Network , C : ConsensusStorage < N > > CoreLedgerService < N , C > {
68134 /// Initializes a new core ledger service.
69135 pub fn new ( ledger : Ledger < N , C > , stoppable : Arc < dyn Stoppable > ) -> Self {
70- Self { ledger, latest_leader : Default :: default ( ) , stoppable }
136+ Self { ledger, latest_leader : Default :: default ( ) , stoppable, update_lock : Default :: default ( ) }
71137 }
72138}
73139
@@ -338,53 +404,26 @@ impl<N: Network, C: ConsensusStorage<N>> LedgerService<N> for CoreLedgerService<
338404 spawn_blocking ! ( ledger. check_transaction_basic( & transaction, None , & mut rand:: thread_rng( ) ) )
339405 }
340406
341- fn check_block_subdag ( & self , block : Block < N > , prefix : & [ PendingBlock < N > ] ) -> Result < PendingBlock < N > > {
342- self . ledger . check_block_subdag ( block, prefix)
343- }
344-
345- fn check_block_content ( & self , block : PendingBlock < N > ) -> Result < Block < N > > {
346- self . ledger . check_block_content ( block, & mut rand:: thread_rng ( ) )
347- }
348-
349- /// Checks the given block is valid next block.
350- fn check_next_block ( & self , block : & Block < N > ) -> Result < ( ) > {
351- self . ledger . check_next_block ( block, & mut rand:: thread_rng ( ) )
352- }
353-
354- /// Returns a candidate for the next block in the ledger, using a committed subdag and its transmissions.
355- #[ cfg( feature = "ledger-write" ) ]
356- fn prepare_advance_to_next_quorum_block (
407+ fn check_block_subdag (
357408 & self ,
358- subdag : Subdag < N > ,
359- transmissions : IndexMap < TransmissionID < N > , Transmission < N > > ,
360- ) -> Result < Block < N > > {
361- self . ledger . prepare_advance_to_next_quorum_block ( subdag , transmissions , & mut rand :: thread_rng ( ) )
409+ block : Block < N > ,
410+ prefix : & [ PendingBlock < N > ] ,
411+ ) -> Result < PendingBlock < N > , CheckBlockError < N > > {
412+ self . ledger . check_block_subdag ( block , prefix )
362413 }
363414
364- /// Adds the given block as the next block in the ledger.
365- #[ cfg( feature = "ledger-write" ) ]
366- fn advance_to_next_block ( & self , block : & Block < N > ) -> Result < ( ) > {
367- // If the Ctrl-C handler registered the signal, then skip advancing to the next block.
415+ /// Begins a ledger update.i
416+ ///
417+ /// # Returns
418+ /// - `Ok(Some(LedgerUpdate<N, C>))` if the ledger update was successfully started.
419+ /// - `Ok(None)` if the node is stopped.
420+ /// - `Err(anyhow::Error)` if we failed to acquire the update lock.
421+ fn begin_ledger_update < ' a > ( & ' a self ) -> Result < Box < dyn LedgerUpdateService < N > + ' a > , BeginLedgerUpdateError > {
368422 if self . stoppable . is_stopped ( ) {
369- bail ! ( "Skipping advancing to block {} - The node is shutting down" , block. height( ) ) ;
370- }
371- // Advance to the next block.
372- self . ledger . advance_to_next_block ( block) ?;
373- // Update BFT metrics.
374- #[ cfg( feature = "metrics" ) ]
375- {
376- let num_sol = block. solutions ( ) . len ( ) ;
377- let num_tx = block. transactions ( ) . len ( ) ;
378-
379- metrics:: gauge ( metrics:: bft:: HEIGHT , block. height ( ) as f64 ) ;
380- metrics:: gauge ( metrics:: bft:: LAST_COMMITTED_ROUND , block. round ( ) as f64 ) ;
381- metrics:: increment_gauge ( metrics:: blocks:: SOLUTIONS , num_sol as f64 ) ;
382- metrics:: increment_gauge ( metrics:: blocks:: TRANSACTIONS , num_tx as f64 ) ;
383- metrics:: update_block_metrics ( block) ;
423+ return Err ( BeginLedgerUpdateError :: ShuttingDown ) ;
384424 }
385425
386- tracing:: info!( "\n \n Advanced to block {} at round {} - {}\n " , block. height( ) , block. round( ) , block. hash( ) ) ;
387- Ok ( ( ) )
426+ Ok ( Box :: new ( LedgerUpdate { ledger : self . ledger . clone ( ) , _lock : self . update_lock . lock ( ) } ) )
388427 }
389428
390429 /// Returns the spend for a transaction in microcredits.
0 commit comments