@@ -26,11 +26,15 @@ impl<N: Network, C: ConsensusStorage<N>> VM<N, C> {
2626 /// Returns the confirmed transactions, aborted transaction IDs,
2727 /// and finalize operations from pre-ratify and post-ratify.
2828 ///
29- /// Note: This method is used to create a new block (including the genesis block).
29+ /// # Note
30+ /// This method is used to create a new block (including the genesis block).
3031 /// - If `coinbase_reward = None`, then the `ratifications` will not be modified.
3132 /// - If `coinbase_reward = Some(coinbase_reward)`, then the method will append a
3233 /// `Ratify::BlockReward(block_reward)` and `Ratify::PuzzleReward(puzzle_reward)`
3334 /// to the front of the `ratifications` list.
35+ ///
36+ /// # Panics
37+ /// This function panics if called from an async context.
3438 #[ inline]
3539 #[ allow( clippy:: too_many_arguments) ]
3640 pub fn speculate < ' a , R : Rng + CryptoRng > (
@@ -67,8 +71,8 @@ impl<N: Network, C: ConsensusStorage<N>> VM<N, C> {
6771 time_since_last_block,
6872 coinbase_reward,
6973 candidate_ratifications,
70- candidate_solutions,
71- verified_transactions. into_iter ( ) ,
74+ candidate_solutions. clone ( ) ,
75+ verified_transactions. into_iter ( ) . cloned ( ) . collect ( ) ,
7276 ) ?;
7377
7478 // Get the aborted transaction ids.
@@ -103,6 +107,9 @@ impl<N: Network, C: ConsensusStorage<N>> VM<N, C> {
103107 /// This function also ensure that the given transactions are well-formed and unique.
104108 ///
105109 /// Returns the finalize operations from pre-ratify and post-ratify.
110+ ///
111+ /// # Panics
112+ /// This function panics if called from an async context.
106113 #[ inline]
107114 pub fn check_speculate < R : Rng + CryptoRng > (
108115 & self ,
@@ -138,8 +145,8 @@ impl<N: Network, C: ConsensusStorage<N>> VM<N, C> {
138145 time_since_last_block,
139146 None ,
140147 candidate_ratifications,
141- solutions,
142- candidate_transactions. iter ( ) ,
148+ solutions. clone ( ) ,
149+ candidate_transactions,
143150 ) ?;
144151
145152 // Ensure the ratifications after speculation match.
@@ -196,29 +203,66 @@ impl<N: Network, C: ConsensusStorage<N>> VM<N, C> {
196203 /// Returns the ratifications, confirmed transactions, aborted transactions,
197204 /// and finalize operations from pre-ratify and post-ratify.
198205 ///
199- /// Note: This method is used by `VM::speculate` and `VM::check_speculate`.
206+ /// # Note
207+ /// This method is used by `VM::speculate` and `VM::check_speculate`.
200208 /// - If `coinbase_reward = None`, then the `ratifications` will not be modified.
201209 /// - If `coinbase_reward = Some(coinbase_reward)`, then the method will append a
202210 /// `Ratify::BlockReward(block_reward)` and `Ratify::PuzzleReward(puzzle_reward)`
203211 /// to the front of the `ratifications` list.
204- fn atomic_speculate < ' a > (
212+ ///
213+ /// # Panics
214+ /// This function panics if called from an async context.
215+ fn atomic_speculate (
205216 & self ,
206217 state : FinalizeGlobalState ,
207218 time_since_last_block : i64 ,
208219 coinbase_reward : Option < u64 > ,
209220 ratifications : Vec < Ratify < N > > ,
210- solutions : & Solutions < N > ,
211- transactions : impl ExactSizeIterator < Item = & ' a Transaction < N > > ,
221+ solutions : Solutions < N > ,
222+ transactions : Vec < Transaction < N > > ,
223+ ) -> Result < (
224+ Ratifications < N > ,
225+ Vec < ConfirmedTransaction < N > > ,
226+ Vec < ( Transaction < N > , String ) > ,
227+ Vec < FinalizeOperation < N > > ,
228+ ) > {
229+ let sequential_op = SequentialOperation :: AtomicSpeculate (
230+ state,
231+ time_since_last_block,
232+ coinbase_reward,
233+ ratifications,
234+ solutions,
235+ transactions,
236+ ) ;
237+ let Some ( SequentialOperationResult :: AtomicSpeculate ( ret) ) = self . run_sequential_operation ( sequential_op) else {
238+ bail ! ( "Already shutting down" ) ;
239+ } ;
240+
241+ ret
242+ }
243+
244+ /// Internal function called when invoking [`Self::atomic_speculate`].
245+ ///
246+ /// # Note
247+ /// This function must only be called from the sequential operation thread.
248+ ///
249+ /// # Panics
250+ /// This function panics if not called from the sequential operation thread.
251+ pub ( crate ) fn atomic_speculate_inner (
252+ & self ,
253+ state : FinalizeGlobalState ,
254+ time_since_last_block : i64 ,
255+ coinbase_reward : Option < u64 > ,
256+ ratifications : Vec < Ratify < N > > ,
257+ solutions : Solutions < N > ,
258+ transactions : Vec < Transaction < N > > ,
212259 ) -> Result < (
213260 Ratifications < N > ,
214261 Vec < ConfirmedTransaction < N > > ,
215262 Vec < ( Transaction < N > , String ) > ,
216263 Vec < FinalizeOperation < N > > ,
217264 ) > {
218- // Acquire the atomic lock, which is needed to ensure this function is not called concurrently
219- // with other `atomic_finalize!` macro calls, which will cause a `bail!` to be triggered erroneously.
220- // Note: This lock must be held for the entire scope of the call to `atomic_finalize!`.
221- let _atomic_lock = self . atomic_lock . lock ( ) ;
265+ self . ensure_sequential_processing ( ) ;
222266
223267 let timer = timer ! ( "VM::atomic_speculate" ) ;
224268
@@ -319,7 +363,7 @@ impl<N: Network, C: ConsensusStorage<N>> VM<N, C> {
319363
320364 // Determine if the transaction should be aborted.
321365 if let Some ( reason) = self . should_abort_transaction(
322- transaction,
366+ & transaction,
323367 & transition_ids,
324368 & input_ids,
325369 & output_ids,
@@ -336,7 +380,7 @@ impl<N: Network, C: ConsensusStorage<N>> VM<N, C> {
336380 // Process the transaction in an isolated atomic batch.
337381 // - If the transaction succeeds, the finalize operations are stored.
338382 // - If the transaction fails, the atomic batch is aborted and no finalize operations are stored.
339- let outcome = match transaction {
383+ let outcome = match & transaction {
340384 // The finalize operation here involves appending the 'stack',
341385 // and adding the program to the finalize tree.
342386 Transaction :: Deploy ( _, _, program_owner, deployment, fee) => {
@@ -535,7 +579,7 @@ impl<N: Network, C: ConsensusStorage<N>> VM<N, C> {
535579 let post_ratifications = reward_ratifications. iter( ) . chain( post_ratifications) ;
536580
537581 // Process the post-ratifications.
538- match Self :: atomic_post_ratify:: <false >( & self . puzzle, store, state, post_ratifications, solutions) {
582+ match Self :: atomic_post_ratify:: <false >( & self . puzzle, store, state, post_ratifications, & solutions) {
539583 // Store the finalize operations from the post-ratify.
540584 Ok ( operations) => ratified_finalize_operations. extend( operations) ,
541585 // Note: This will abort the entire atomic batch.
@@ -570,10 +614,9 @@ impl<N: Network, C: ConsensusStorage<N>> VM<N, C> {
570614 solutions : & Solutions < N > ,
571615 transactions : & Transactions < N > ,
572616 ) -> Result < Vec < FinalizeOperation < N > > > {
573- // Acquire the atomic lock, which is needed to ensure this function is not called concurrently
574- // with other `atomic_finalize!` macro calls, which will cause a `bail!` to be triggered erroneously.
575- // Note: This lock must be held for the entire scope of the call to `atomic_finalize!`.
576- let _atomic_lock = self . atomic_lock . lock ( ) ;
617+ // The tests may run this method ad-hoc, outside of the context of add_next_block.
618+ #[ cfg( not( test) ) ]
619+ self . ensure_sequential_processing ( ) ;
577620
578621 let timer = timer ! ( "VM::atomic_finalize" ) ;
579622
@@ -1848,8 +1891,8 @@ finalize transfer_public:
18481891 CurrentNetwork :: BLOCK_TIME as i64 ,
18491892 None ,
18501893 vec ! [ ] ,
1851- & None . into ( ) ,
1852- [ deployment_transaction] . iter ( ) ,
1894+ None . into ( ) ,
1895+ vec ! [ deployment_transaction] ,
18531896 )
18541897 . unwrap ( ) ;
18551898 assert_eq ! ( candidate_transactions. len( ) , 1 ) ;
@@ -1937,15 +1980,15 @@ finalize transfer_public:
19371980 vm. check_transaction ( & bond_validator_transaction, None , rng) . unwrap ( ) ;
19381981
19391982 // Speculate on the transactions.
1940- let transactions = [ bond_validator_transaction. clone ( ) ] ;
1983+ let transactions = vec ! [ bond_validator_transaction. clone( ) ] ;
19411984 let ( _, confirmed_transactions, _, _) = vm
19421985 . atomic_speculate (
19431986 sample_finalize_state ( 1 ) ,
19441987 CurrentNetwork :: BLOCK_TIME as i64 ,
19451988 None ,
19461989 vec ! [ ] ,
1947- & None . into ( ) ,
1948- transactions. iter ( ) ,
1990+ None . into ( ) ,
1991+ transactions,
19491992 )
19501993 . unwrap ( ) ;
19511994
@@ -2063,15 +2106,15 @@ finalize transfer_public:
20632106 vm. check_transaction ( & bond_validator_transaction, None , rng) . unwrap ( ) ;
20642107
20652108 // Speculate on the transactions.
2066- let transactions = [ bond_validator_transaction. clone ( ) ] ;
2109+ let transactions = vec ! [ bond_validator_transaction. clone( ) ] ;
20672110 let ( _, confirmed_transactions, _, _) = vm
20682111 . atomic_speculate (
20692112 sample_finalize_state ( 1 ) ,
20702113 CurrentNetwork :: BLOCK_TIME as i64 ,
20712114 None ,
20722115 vec ! [ ] ,
2073- & None . into ( ) ,
2074- transactions. iter ( ) ,
2116+ None . into ( ) ,
2117+ transactions,
20752118 )
20762119 . unwrap ( ) ;
20772120
@@ -2083,15 +2126,15 @@ finalize transfer_public:
20832126 ) ;
20842127
20852128 // Speculate on the transactions.
2086- let transactions = [ bond_validator_transaction. clone ( ) ] ;
2129+ let transactions = vec ! [ bond_validator_transaction. clone( ) ] ;
20872130 let ( _, confirmed_transactions, aborted_transaction_ids, _) = vm
20882131 . atomic_speculate (
20892132 sample_finalize_state ( CurrentNetwork :: CONSENSUS_HEIGHT ( ConsensusVersion :: V3 ) . unwrap ( ) ) ,
20902133 CurrentNetwork :: BLOCK_TIME as i64 ,
20912134 None ,
20922135 vec ! [ ] ,
2093- & None . into ( ) ,
2094- transactions. iter ( ) ,
2136+ None . into ( ) ,
2137+ transactions,
20952138 )
20962139 . unwrap ( ) ;
20972140
@@ -2194,15 +2237,15 @@ finalize transfer_public:
21942237 // Transfer_10 -> Balance = 30 - 10 = 20
21952238 // Transfer_20 -> Balance = 20 - 20 = 0
21962239 {
2197- let transactions = [ mint_10. clone ( ) , transfer_10. clone ( ) , transfer_20. clone ( ) ] ;
2240+ let transactions = vec ! [ mint_10. clone( ) , transfer_10. clone( ) , transfer_20. clone( ) ] ;
21982241 let ( _, confirmed_transactions, aborted_transaction_ids, _) = vm
21992242 . atomic_speculate (
22002243 sample_finalize_state ( 1 ) ,
22012244 CurrentNetwork :: BLOCK_TIME as i64 ,
22022245 None ,
22032246 vec ! [ ] ,
2204- & None . into ( ) ,
2205- transactions. iter ( ) ,
2247+ None . into ( ) ,
2248+ transactions,
22062249 )
22072250 . unwrap ( ) ;
22082251
@@ -2222,15 +2265,15 @@ finalize transfer_public:
22222265 // Mint_20 -> Balance = 10 + 20 = 30
22232266 // Transfer_30 -> Balance = 30 - 30 = 0
22242267 {
2225- let transactions = [ transfer_20. clone ( ) , mint_10. clone ( ) , mint_20. clone ( ) , transfer_30. clone ( ) ] ;
2268+ let transactions = vec ! [ transfer_20. clone( ) , mint_10. clone( ) , mint_20. clone( ) , transfer_30. clone( ) ] ;
22262269 let ( _, confirmed_transactions, aborted_transaction_ids, _) = vm
22272270 . atomic_speculate (
22282271 sample_finalize_state ( 1 ) ,
22292272 CurrentNetwork :: BLOCK_TIME as i64 ,
22302273 None ,
22312274 vec ! [ ] ,
2232- & None . into ( ) ,
2233- transactions. iter ( ) ,
2275+ None . into ( ) ,
2276+ transactions,
22342277 )
22352278 . unwrap ( ) ;
22362279
@@ -2250,15 +2293,15 @@ finalize transfer_public:
22502293 // Transfer_20 -> Balance = 20 - 20 = 0
22512294 // Transfer_10 -> Balance = 0 - 10 = -10 (should be rejected)
22522295 {
2253- let transactions = [ transfer_20. clone ( ) , transfer_10. clone ( ) ] ;
2296+ let transactions = vec ! [ transfer_20. clone( ) , transfer_10. clone( ) ] ;
22542297 let ( _, confirmed_transactions, aborted_transaction_ids, _) = vm
22552298 . atomic_speculate (
22562299 sample_finalize_state ( 1 ) ,
22572300 CurrentNetwork :: BLOCK_TIME as i64 ,
22582301 None ,
22592302 vec ! [ ] ,
2260- & None . into ( ) ,
2261- transactions. iter ( ) ,
2303+ None . into ( ) ,
2304+ transactions,
22622305 )
22632306 . unwrap ( ) ;
22642307
@@ -2282,15 +2325,15 @@ finalize transfer_public:
22822325 // Transfer_20 -> Balance = 10 - 20 = -10 (should be rejected)
22832326 // Transfer_10 -> Balance = 10 - 10 = 0
22842327 {
2285- let transactions = [ mint_20. clone ( ) , transfer_30. clone ( ) , transfer_20. clone ( ) , transfer_10. clone ( ) ] ;
2328+ let transactions = vec ! [ mint_20. clone( ) , transfer_30. clone( ) , transfer_20. clone( ) , transfer_10. clone( ) ] ;
22862329 let ( _, confirmed_transactions, aborted_transaction_ids, _) = vm
22872330 . atomic_speculate (
22882331 sample_finalize_state ( 1 ) ,
22892332 CurrentNetwork :: BLOCK_TIME as i64 ,
22902333 None ,
22912334 vec ! [ ] ,
2292- & None . into ( ) ,
2293- transactions. iter ( ) ,
2335+ None . into ( ) ,
2336+ transactions,
22942337 )
22952338 . unwrap ( ) ;
22962339
0 commit comments