snarkvm_ledger_block/
lib.rs

1// Copyright 2024 Aleo Network Foundation
2// This file is part of the snarkVM library.
3
4// Licensed under the Apache License, Version 2.0 (the "License");
5// you may not use this file except in compliance with the License.
6// You may obtain a copy of the License at:
7
8// http://www.apache.org/licenses/LICENSE-2.0
9
10// Unless required by applicable law or agreed to in writing, software
11// distributed under the License is distributed on an "AS IS" BASIS,
12// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13// See the License for the specific language governing permissions and
14// limitations under the License.
15
16#![forbid(unsafe_code)]
17#![allow(clippy::too_many_arguments)]
18// #![warn(clippy::cast_possible_truncation)]
19#![cfg_attr(test, allow(clippy::single_element_loop))]
20
21pub mod header;
22pub use header::*;
23
24mod helpers;
25pub use helpers::*;
26
27pub mod ratifications;
28pub use ratifications::*;
29
30pub mod ratify;
31pub use ratify::*;
32
33pub mod solutions;
34pub use solutions::*;
35
36pub mod transaction;
37pub use transaction::*;
38
39pub mod transactions;
40pub use transactions::*;
41
42pub mod transition;
43pub use transition::*;
44
45mod bytes;
46mod genesis;
47mod serialize;
48mod string;
49mod verify;
50
51use console::{
52    account::PrivateKey,
53    network::prelude::*,
54    program::{Ciphertext, Record},
55    types::{Field, Group, U64},
56};
57use ledger_authority::Authority;
58use ledger_committee::Committee;
59use ledger_narwhal_data::Data;
60use ledger_narwhal_subdag::Subdag;
61use ledger_narwhal_transmission_id::TransmissionID;
62use ledger_puzzle::{PuzzleSolutions, Solution, SolutionID};
63
64#[derive(Clone, PartialEq, Eq)]
65pub struct Block<N: Network> {
66    /// The hash of this block.
67    block_hash: N::BlockHash,
68    /// The hash of the previous block.
69    previous_hash: N::BlockHash,
70    /// The header of this block.
71    header: Header<N>,
72    /// The authority for this block.
73    authority: Authority<N>,
74    /// The ratifications in this block.
75    ratifications: Ratifications<N>,
76    /// The solutions in the block.
77    solutions: Solutions<N>,
78    /// The aborted solution IDs in this block.
79    aborted_solution_ids: Vec<SolutionID<N>>,
80    /// The transactions in this block.
81    transactions: Transactions<N>,
82    /// The aborted transaction IDs in this block.
83    aborted_transaction_ids: Vec<N::TransactionID>,
84}
85
86impl<N: Network> Block<N> {
87    /// Initializes a new beacon block from the given previous block hash, block header,
88    /// ratifications, solutions, transactions, and aborted transaction IDs.
89    pub fn new_beacon<R: Rng + CryptoRng>(
90        private_key: &PrivateKey<N>,
91        previous_hash: N::BlockHash,
92        header: Header<N>,
93        ratifications: Ratifications<N>,
94        solutions: Solutions<N>,
95        aborted_solution_ids: Vec<SolutionID<N>>,
96        transactions: Transactions<N>,
97        aborted_transaction_ids: Vec<N::TransactionID>,
98        rng: &mut R,
99    ) -> Result<Self> {
100        // Compute the block hash.
101        let block_hash = N::hash_bhp1024(&to_bits_le![previous_hash, header.to_root()?])?;
102        // Construct the beacon authority.
103        let authority = Authority::new_beacon(private_key, block_hash, rng)?;
104        // Construct the block.
105        Self::from(
106            previous_hash,
107            header,
108            authority,
109            ratifications,
110            solutions,
111            aborted_solution_ids,
112            transactions,
113            aborted_transaction_ids,
114        )
115    }
116
117    /// Initializes a new quorum block from the given previous block hash, block header,
118    /// subdag, ratifications, solutions, transactions, and aborted transaction IDs.
119    pub fn new_quorum(
120        previous_hash: N::BlockHash,
121        header: Header<N>,
122        subdag: Subdag<N>,
123        ratifications: Ratifications<N>,
124        solutions: Solutions<N>,
125        aborted_solution_ids: Vec<SolutionID<N>>,
126        transactions: Transactions<N>,
127        aborted_transaction_ids: Vec<N::TransactionID>,
128    ) -> Result<Self> {
129        // Construct the beacon authority.
130        let authority = Authority::new_quorum(subdag);
131        // Construct the block.
132        Self::from(
133            previous_hash,
134            header,
135            authority,
136            ratifications,
137            solutions,
138            aborted_solution_ids,
139            transactions,
140            aborted_transaction_ids,
141        )
142    }
143
144    /// Initializes a new block from the given previous block hash, block header,
145    /// authority, ratifications, solutions, transactions, and aborted transaction IDs.
146    pub fn from(
147        previous_hash: N::BlockHash,
148        header: Header<N>,
149        authority: Authority<N>,
150        ratifications: Ratifications<N>,
151        solutions: Solutions<N>,
152        aborted_solution_ids: Vec<SolutionID<N>>,
153        transactions: Transactions<N>,
154        aborted_transaction_ids: Vec<N::TransactionID>,
155    ) -> Result<Self> {
156        // Ensure the number of aborted solutions IDs is within the allowed range.
157        if aborted_solution_ids.len() > Solutions::<N>::max_aborted_solutions()? {
158            bail!("Cannot initialize a block with {} aborted solutions IDs", aborted_solution_ids.len());
159        }
160
161        // Ensure the number of transactions is within the allowed range.
162        if transactions.len() > Transactions::<N>::MAX_TRANSACTIONS {
163            bail!(
164                "Cannot initialize a block with more than {} confirmed transactions",
165                Transactions::<N>::MAX_TRANSACTIONS
166            );
167        }
168
169        // Ensure the number of aborted transaction IDs is within the allowed range.
170        if aborted_transaction_ids.len() > Transactions::<N>::max_aborted_transactions()? {
171            bail!(
172                "Cannot initialize a block with more than {} aborted transaction IDs",
173                Transactions::<N>::max_aborted_transactions()?
174            );
175        }
176
177        // Compute the block hash.
178        let block_hash = N::hash_bhp1024(&to_bits_le![previous_hash, header.to_root()?])?;
179
180        // Verify the authority.
181        match &authority {
182            Authority::Beacon(signature) => {
183                // Derive the signer address.
184                let address = signature.to_address();
185                // Ensure the signature is valid.
186                ensure!(signature.verify(&address, &[block_hash]), "Invalid signature for block {}", header.height());
187            }
188            Authority::Quorum(subdag) => {
189                // Ensure the transmission IDs from the subdag correspond to the block.
190                Self::check_subdag_transmissions(
191                    subdag,
192                    &solutions,
193                    &aborted_solution_ids,
194                    &transactions,
195                    &aborted_transaction_ids,
196                )?;
197            }
198        }
199
200        // Ensure that coinbase accumulator matches the solutions.
201        if header.solutions_root() != solutions.to_solutions_root()? {
202            bail!("The solutions root in the block does not correspond to the solutions");
203        }
204
205        // Ensure that the subdag root matches the authority.
206        let subdag_root = match &authority {
207            Authority::Beacon(_) => Field::<N>::zero(),
208            Authority::Quorum(subdag) => subdag.to_subdag_root()?,
209        };
210        if header.subdag_root() != subdag_root {
211            bail!("The subdag root in the block does not correspond to the authority");
212        }
213
214        // Return the block.
215        Self::from_unchecked(
216            block_hash.into(),
217            previous_hash,
218            header,
219            authority,
220            ratifications,
221            solutions,
222            aborted_solution_ids,
223            transactions,
224            aborted_transaction_ids,
225        )
226    }
227
228    /// Initializes a new block from the given block hash, previous block hash, block header,
229    /// authority, ratifications, solutions, transactions, and aborted transaction IDs.
230    pub fn from_unchecked(
231        block_hash: N::BlockHash,
232        previous_hash: N::BlockHash,
233        header: Header<N>,
234        authority: Authority<N>,
235        ratifications: Ratifications<N>,
236        solutions: Solutions<N>,
237        aborted_solution_ids: Vec<SolutionID<N>>,
238        transactions: Transactions<N>,
239        aborted_transaction_ids: Vec<N::TransactionID>,
240    ) -> Result<Self> {
241        // Return the block.
242        Ok(Self {
243            block_hash,
244            previous_hash,
245            header,
246            authority,
247            ratifications,
248            solutions,
249            aborted_solution_ids,
250            transactions,
251            aborted_transaction_ids,
252        })
253    }
254}
255
256impl<N: Network> Block<N> {
257    /// Returns the block hash.
258    pub const fn hash(&self) -> N::BlockHash {
259        self.block_hash
260    }
261
262    /// Returns the previous block hash.
263    pub const fn previous_hash(&self) -> N::BlockHash {
264        self.previous_hash
265    }
266
267    /// Returns the authority.
268    pub const fn authority(&self) -> &Authority<N> {
269        &self.authority
270    }
271
272    /// Returns the ratifications in this block.
273    pub const fn ratifications(&self) -> &Ratifications<N> {
274        &self.ratifications
275    }
276
277    /// Returns the solutions in the block.
278    pub const fn solutions(&self) -> &Solutions<N> {
279        &self.solutions
280    }
281
282    /// Returns the aborted solution IDs in this block.
283    pub const fn aborted_solution_ids(&self) -> &Vec<SolutionID<N>> {
284        &self.aborted_solution_ids
285    }
286
287    /// Returns the transactions in this block.
288    pub const fn transactions(&self) -> &Transactions<N> {
289        &self.transactions
290    }
291
292    /// Returns the aborted transaction IDs in this block.
293    pub const fn aborted_transaction_ids(&self) -> &Vec<N::TransactionID> {
294        &self.aborted_transaction_ids
295    }
296}
297
298impl<N: Network> Block<N> {
299    /// Returns the block header.
300    pub const fn header(&self) -> &Header<N> {
301        &self.header
302    }
303
304    /// Returns the previous state root from the block header.
305    pub const fn previous_state_root(&self) -> N::StateRoot {
306        self.header.previous_state_root()
307    }
308
309    /// Returns the transactions root in the block header.
310    pub const fn transactions_root(&self) -> Field<N> {
311        self.header.transactions_root()
312    }
313
314    /// Returns the finalize root in the block header.
315    pub const fn finalize_root(&self) -> Field<N> {
316        self.header.finalize_root()
317    }
318
319    /// Returns the ratifications root in the block header.
320    pub const fn ratifications_root(&self) -> Field<N> {
321        self.header.ratifications_root()
322    }
323
324    /// Returns the solutions root in the block header.
325    pub const fn solutions_root(&self) -> Field<N> {
326        self.header.solutions_root()
327    }
328
329    /// Returns the metadata in the block header.
330    pub const fn metadata(&self) -> &Metadata<N> {
331        self.header.metadata()
332    }
333
334    /// Returns the network ID of this block.
335    pub const fn network(&self) -> u16 {
336        self.header.network()
337    }
338
339    /// Returns the height of this block.
340    pub const fn height(&self) -> u32 {
341        self.header.height()
342    }
343
344    /// Returns the round number of this block.
345    pub const fn round(&self) -> u64 {
346        self.header.round()
347    }
348
349    /// Returns the epoch number of this block.
350    pub const fn epoch_number(&self) -> u32 {
351        self.height() / N::NUM_BLOCKS_PER_EPOCH
352    }
353
354    /// Returns the cumulative weight for this block.
355    pub const fn cumulative_weight(&self) -> u128 {
356        self.header.cumulative_weight()
357    }
358
359    /// Returns the cumulative proof target for this block.
360    pub const fn cumulative_proof_target(&self) -> u128 {
361        self.header.cumulative_proof_target()
362    }
363
364    /// Returns the coinbase target for this block.
365    pub const fn coinbase_target(&self) -> u64 {
366        self.header.coinbase_target()
367    }
368
369    /// Returns the proof target for this block.
370    pub const fn proof_target(&self) -> u64 {
371        self.header.proof_target()
372    }
373
374    /// Returns the coinbase target of the last coinbase.
375    pub const fn last_coinbase_target(&self) -> u64 {
376        self.header.last_coinbase_target()
377    }
378
379    /// Returns the block timestamp of the last coinbase.
380    pub const fn last_coinbase_timestamp(&self) -> i64 {
381        self.header.last_coinbase_timestamp()
382    }
383
384    /// Returns the Unix timestamp (UTC) for this block.
385    pub const fn timestamp(&self) -> i64 {
386        self.header.timestamp()
387    }
388}
389
390impl<N: Network> Block<N> {
391    /// Returns `true` if the block contains the given transition ID.
392    pub fn contains_transition(&self, transition_id: &N::TransitionID) -> bool {
393        self.transactions.contains_transition(transition_id)
394    }
395
396    /// Returns `true` if the block contains the given serial number.
397    pub fn contains_serial_number(&self, serial_number: &Field<N>) -> bool {
398        self.transactions.contains_serial_number(serial_number)
399    }
400
401    /// Returns `true` if the block contains the given commitment.
402    pub fn contains_commitment(&self, commitment: &Field<N>) -> bool {
403        self.transactions.contains_commitment(commitment)
404    }
405}
406
407impl<N: Network> Block<N> {
408    /// Returns the solution with the given solution ID, if it exists.
409    pub fn get_solution(&self, solution_id: &SolutionID<N>) -> Option<&Solution<N>> {
410        self.solutions.as_ref().and_then(|solution| solution.get_solution(solution_id))
411    }
412
413    /// Returns the transaction with the given transaction ID, if it exists.
414    pub fn get_transaction(&self, transaction_id: &N::TransactionID) -> Option<&Transaction<N>> {
415        self.transactions.get(transaction_id).map(|t| t.deref())
416    }
417
418    /// Returns the confirmed transaction with the given transaction ID, if it exists.
419    pub fn get_confirmed_transaction(&self, transaction_id: &N::TransactionID) -> Option<&ConfirmedTransaction<N>> {
420        self.transactions.get(transaction_id)
421    }
422}
423
424impl<N: Network> Block<N> {
425    /// Returns the transaction with the given transition ID, if it exists.
426    pub fn find_transaction_for_transition_id(&self, transition_id: &N::TransitionID) -> Option<&Transaction<N>> {
427        self.transactions.find_transaction_for_transition_id(transition_id)
428    }
429
430    /// Returns the transaction with the given serial number, if it exists.
431    pub fn find_transaction_for_serial_number(&self, serial_number: &Field<N>) -> Option<&Transaction<N>> {
432        self.transactions.find_transaction_for_serial_number(serial_number)
433    }
434
435    /// Returns the transaction with the given commitment, if it exists.
436    pub fn find_transaction_for_commitment(&self, commitment: &Field<N>) -> Option<&Transaction<N>> {
437        self.transactions.find_transaction_for_commitment(commitment)
438    }
439
440    /// Returns the transition with the corresponding transition ID, if it exists.
441    pub fn find_transition(&self, transition_id: &N::TransitionID) -> Option<&Transition<N>> {
442        self.transactions.find_transition(transition_id)
443    }
444
445    /// Returns the transition for the given serial number, if it exists.
446    pub fn find_transition_for_serial_number(&self, serial_number: &Field<N>) -> Option<&Transition<N>> {
447        self.transactions.find_transition_for_serial_number(serial_number)
448    }
449
450    /// Returns the transition for the given commitment, if it exists.
451    pub fn find_transition_for_commitment(&self, commitment: &Field<N>) -> Option<&Transition<N>> {
452        self.transactions.find_transition_for_commitment(commitment)
453    }
454
455    /// Returns the record with the corresponding commitment, if it exists.
456    pub fn find_record(&self, commitment: &Field<N>) -> Option<&Record<N, Ciphertext<N>>> {
457        self.transactions.find_record(commitment)
458    }
459}
460
461impl<N: Network> Block<N> {
462    /// Returns the solution IDs in this block.
463    pub fn solution_ids(&self) -> Option<impl '_ + Iterator<Item = &SolutionID<N>>> {
464        self.solutions.as_ref().map(|solution| solution.solution_ids())
465    }
466
467    /// Returns an iterator over the transaction IDs, for all transactions in `self`.
468    pub fn transaction_ids(&self) -> impl '_ + Iterator<Item = &N::TransactionID> {
469        self.transactions.transaction_ids()
470    }
471
472    /// Returns an iterator over all transactions in `self` that are accepted deploy transactions.
473    pub fn deployments(&self) -> impl '_ + Iterator<Item = &ConfirmedTransaction<N>> {
474        self.transactions.deployments()
475    }
476
477    /// Returns an iterator over all transactions in `self` that are accepted execute transactions.
478    pub fn executions(&self) -> impl '_ + Iterator<Item = &ConfirmedTransaction<N>> {
479        self.transactions.executions()
480    }
481
482    /// Returns an iterator over all transitions.
483    pub fn transitions(&self) -> impl '_ + Iterator<Item = &Transition<N>> {
484        self.transactions.transitions()
485    }
486
487    /// Returns an iterator over the transition IDs, for all transitions.
488    pub fn transition_ids(&self) -> impl '_ + Iterator<Item = &N::TransitionID> {
489        self.transactions.transition_ids()
490    }
491
492    /// Returns an iterator over the transition public keys, for all transactions.
493    pub fn transition_public_keys(&self) -> impl '_ + Iterator<Item = &Group<N>> {
494        self.transactions.transition_public_keys()
495    }
496
497    /// Returns an iterator over the transition commitments, for all transactions.
498    pub fn transition_commitments(&self) -> impl '_ + Iterator<Item = &Field<N>> {
499        self.transactions.transition_commitments()
500    }
501
502    /// Returns an iterator over the tags, for all transition inputs that are records.
503    pub fn tags(&self) -> impl '_ + Iterator<Item = &Field<N>> {
504        self.transactions.tags()
505    }
506
507    /// Returns an iterator over the input IDs, for all transition inputs that are records.
508    pub fn input_ids(&self) -> impl '_ + Iterator<Item = &Field<N>> {
509        self.transactions.input_ids()
510    }
511
512    /// Returns an iterator over the serial numbers, for all transition inputs that are records.
513    pub fn serial_numbers(&self) -> impl '_ + Iterator<Item = &Field<N>> {
514        self.transactions.serial_numbers()
515    }
516
517    /// Returns an iterator over the output IDs, for all transition inputs that are records.
518    pub fn output_ids(&self) -> impl '_ + Iterator<Item = &Field<N>> {
519        self.transactions.output_ids()
520    }
521
522    /// Returns an iterator over the commitments, for all transition outputs that are records.
523    pub fn commitments(&self) -> impl '_ + Iterator<Item = &Field<N>> {
524        self.transactions.commitments()
525    }
526
527    /// Returns an iterator over the records, for all transition outputs that are records.
528    pub fn records(&self) -> impl '_ + Iterator<Item = (&Field<N>, &Record<N, Ciphertext<N>>)> {
529        self.transactions.records()
530    }
531
532    /// Returns an iterator over the nonces, for all transition outputs that are records.
533    pub fn nonces(&self) -> impl '_ + Iterator<Item = &Group<N>> {
534        self.transactions.nonces()
535    }
536
537    /// Returns an iterator over the transaction fee amounts, for all transactions.
538    pub fn transaction_fee_amounts(&self) -> impl '_ + Iterator<Item = Result<U64<N>>> {
539        self.transactions.transaction_fee_amounts()
540    }
541}
542
543impl<N: Network> Block<N> {
544    /// Returns a consuming iterator over the transaction IDs, for all transactions in `self`.
545    pub fn into_transaction_ids(self) -> impl Iterator<Item = N::TransactionID> {
546        self.transactions.into_transaction_ids()
547    }
548
549    /// Returns a consuming iterator over all transactions in `self` that are accepted deploy transactions.
550    pub fn into_deployments(self) -> impl Iterator<Item = ConfirmedTransaction<N>> {
551        self.transactions.into_deployments()
552    }
553
554    /// Returns a consuming iterator over all transactions in `self` that are accepted execute transactions.
555    pub fn into_executions(self) -> impl Iterator<Item = ConfirmedTransaction<N>> {
556        self.transactions.into_executions()
557    }
558
559    /// Returns a consuming iterator over all transitions.
560    pub fn into_transitions(self) -> impl Iterator<Item = Transition<N>> {
561        self.transactions.into_transitions()
562    }
563
564    /// Returns a consuming iterator over the transition IDs, for all transitions.
565    pub fn into_transition_ids(self) -> impl Iterator<Item = N::TransitionID> {
566        self.transactions.into_transition_ids()
567    }
568
569    /// Returns a consuming iterator over the transition public keys, for all transactions.
570    pub fn into_transition_public_keys(self) -> impl Iterator<Item = Group<N>> {
571        self.transactions.into_transition_public_keys()
572    }
573
574    /// Returns a consuming iterator over the tags, for all transition inputs that are records.
575    pub fn into_tags(self) -> impl Iterator<Item = Field<N>> {
576        self.transactions.into_tags()
577    }
578
579    /// Returns a consuming iterator over the serial numbers, for all transition inputs that are records.
580    pub fn into_serial_numbers(self) -> impl Iterator<Item = Field<N>> {
581        self.transactions.into_serial_numbers()
582    }
583
584    /// Returns a consuming iterator over the commitments, for all transition outputs that are records.
585    pub fn into_commitments(self) -> impl Iterator<Item = Field<N>> {
586        self.transactions.into_commitments()
587    }
588
589    /// Returns a consuming iterator over the records, for all transition outputs that are records.
590    pub fn into_records(self) -> impl Iterator<Item = (Field<N>, Record<N, Ciphertext<N>>)> {
591        self.transactions.into_records()
592    }
593
594    /// Returns a consuming iterator over the nonces, for all transition outputs that are records.
595    pub fn into_nonces(self) -> impl Iterator<Item = Group<N>> {
596        self.transactions.into_nonces()
597    }
598}
599
600#[cfg(test)]
601pub mod test_helpers {
602    use super::*;
603    use algorithms::snark::varuna::VarunaVersion;
604    use console::account::{Address, PrivateKey};
605    use ledger_query::Query;
606    use ledger_store::{BlockStore, helpers::memory::BlockMemory};
607    use synthesizer_process::Process;
608
609    use once_cell::sync::OnceCell;
610
611    type CurrentNetwork = console::network::MainnetV0;
612    type CurrentAleo = circuit::network::AleoV0;
613
614    /// Samples a random genesis block.
615    pub(crate) fn sample_genesis_block(rng: &mut TestRng) -> Block<CurrentNetwork> {
616        // Sample the genesis block and components.
617        let (block, _, _) = sample_genesis_block_and_components(rng);
618        // Return the block.
619        block
620    }
621
622    /// Samples a random genesis block and the transaction from the genesis block.
623    pub(crate) fn sample_genesis_block_and_transaction(
624        rng: &mut TestRng,
625    ) -> (Block<CurrentNetwork>, Transaction<CurrentNetwork>) {
626        // Sample the genesis block and components.
627        let (block, transaction, _) = sample_genesis_block_and_components(rng);
628        // Return the block and transaction.
629        (block, transaction)
630    }
631
632    /// Samples a random genesis block, the transaction from the genesis block, and the genesis private key.
633    pub(crate) fn sample_genesis_block_and_components(
634        rng: &mut TestRng,
635    ) -> (Block<CurrentNetwork>, Transaction<CurrentNetwork>, PrivateKey<CurrentNetwork>) {
636        static INSTANCE: OnceCell<(Block<CurrentNetwork>, Transaction<CurrentNetwork>, PrivateKey<CurrentNetwork>)> =
637            OnceCell::new();
638        INSTANCE.get_or_init(|| sample_genesis_block_and_components_raw(rng)).clone()
639    }
640
641    /// Samples a random genesis block, the transaction from the genesis block, and the genesis private key.
642    fn sample_genesis_block_and_components_raw(
643        rng: &mut TestRng,
644    ) -> (Block<CurrentNetwork>, Transaction<CurrentNetwork>, PrivateKey<CurrentNetwork>) {
645        // Sample the genesis private key.
646        let private_key = PrivateKey::new(rng).unwrap();
647        let address = Address::<CurrentNetwork>::try_from(private_key).unwrap();
648
649        // Prepare the locator.
650        let locator = ("credits.aleo", "transfer_public_to_private");
651        // Prepare the amount for each call to the function.
652        let amount = 100_000_000u64;
653        // Prepare the function inputs.
654        let inputs = [address.to_string(), format!("{amount}_u64")];
655
656        // Initialize the process.
657        let process = Process::load().unwrap();
658        // Authorize the function.
659        let authorization =
660            process.authorize::<CurrentAleo, _>(&private_key, locator.0, locator.1, inputs.iter(), rng).unwrap();
661        // Execute the function.
662        let (_, mut trace) = process.execute::<CurrentAleo, _>(authorization, rng).unwrap();
663
664        // Initialize a new block store.
665        let block_store = BlockStore::<CurrentNetwork, BlockMemory<_>>::open(None).unwrap();
666
667        // Prepare the assignments.
668        trace.prepare(Query::from(block_store)).unwrap();
669        // Compute the proof and construct the execution.
670        let execution = trace.prove_execution::<CurrentAleo, _>(locator.0, VarunaVersion::V1, rng).unwrap();
671        // Convert the execution.
672        // Note: This is a testing-only hack to adhere to Rust's dependency cycle rules.
673        let execution = Execution::from_str(&execution.to_string()).unwrap();
674
675        // Construct the transaction.
676        let transaction = Transaction::from_execution(execution, None).unwrap();
677        // Prepare the confirmed transaction.
678        let confirmed = ConfirmedTransaction::accepted_execute(0, transaction.clone(), vec![]).unwrap();
679        // Prepare the transactions.
680        let transactions = Transactions::from_iter([confirmed]);
681
682        // Construct the ratifications.
683        let ratifications = Ratifications::try_from(vec![]).unwrap();
684
685        // Prepare the block header.
686        let header = Header::genesis(&ratifications, &transactions, vec![]).unwrap();
687        // Prepare the previous block hash.
688        let previous_hash = <CurrentNetwork as Network>::BlockHash::default();
689
690        // Construct the block.
691        let block = Block::new_beacon(
692            &private_key,
693            previous_hash,
694            header,
695            ratifications,
696            None.into(),
697            vec![],
698            transactions,
699            vec![],
700            rng,
701        )
702        .unwrap();
703        assert!(block.header().is_genesis(), "Failed to initialize a genesis block");
704        // Return the block, transaction, and private key.
705        (block, transaction, private_key)
706    }
707
708    pub(crate) fn sample_metadata() -> Metadata<CurrentNetwork> {
709        let network = CurrentNetwork::ID;
710        let round = u64::MAX;
711        let height = u32::MAX;
712        let cumulative_weight = u128::MAX - 1;
713        let cumulative_proof_target = u128::MAX - 1;
714        let coinbase_target = u64::MAX;
715        let proof_target = u64::MAX - 1;
716        let last_coinbase_target = u64::MAX;
717        let timestamp = i64::MAX - 1;
718        let last_coinbase_timestamp = timestamp - 1;
719        Metadata::new(
720            network,
721            round,
722            height,
723            cumulative_weight,
724            cumulative_proof_target,
725            coinbase_target,
726            proof_target,
727            last_coinbase_target,
728            last_coinbase_timestamp,
729            timestamp,
730        )
731        .unwrap()
732    }
733}
734
735#[cfg(test)]
736mod tests {
737    use super::*;
738
739    use console::network::MainnetV0;
740    use indexmap::IndexMap;
741    type CurrentNetwork = MainnetV0;
742
743    #[test]
744    fn test_find_transaction_for_transition_id() {
745        let rng = &mut TestRng::default();
746
747        let (block, transaction) = crate::test_helpers::sample_genesis_block_and_transaction(rng);
748        let transactions = block.transactions();
749
750        // Retrieve the transitions.
751        let transitions = transaction.transitions().collect::<Vec<_>>();
752        assert!(!transitions.is_empty());
753
754        // Ensure the transaction is found.
755        for transition in transitions {
756            assert_eq!(block.find_transaction_for_transition_id(transition.id()), Some(&transaction));
757            assert_eq!(transactions.find_transaction_for_transition_id(transition.id()), Some(&transaction));
758        }
759
760        // Ensure the transaction is not found.
761        for _ in 0..10 {
762            let transition_id = &rng.gen();
763            assert_eq!(block.find_transaction_for_transition_id(transition_id), None);
764            assert_eq!(transactions.find_transaction_for_transition_id(transition_id), None);
765        }
766    }
767
768    #[test]
769    fn test_find_transaction_for_commitment() {
770        let rng = &mut TestRng::default();
771
772        let (block, transaction) = crate::test_helpers::sample_genesis_block_and_transaction(rng);
773        let transactions = block.transactions();
774
775        // Retrieve the commitments.
776        let commitments = transaction.commitments().collect::<Vec<_>>();
777        assert!(!commitments.is_empty());
778
779        // Ensure the commitments are found.
780        for commitment in commitments {
781            assert_eq!(block.find_transaction_for_commitment(commitment), Some(&transaction));
782            assert_eq!(transactions.find_transaction_for_commitment(commitment), Some(&transaction));
783        }
784
785        // Ensure the commitments are not found.
786        for _ in 0..10 {
787            let commitment = &rng.gen();
788            assert_eq!(block.find_transaction_for_commitment(commitment), None);
789            assert_eq!(transactions.find_transaction_for_commitment(commitment), None);
790        }
791    }
792
793    #[test]
794    fn test_find_transition() {
795        let rng = &mut TestRng::default();
796
797        let (block, transaction) = crate::test_helpers::sample_genesis_block_and_transaction(rng);
798        let transactions = block.transactions();
799
800        // Retrieve the transitions.
801        let transitions = transaction.transitions().collect::<Vec<_>>();
802        assert!(!transitions.is_empty());
803
804        // Ensure the transitions are found.
805        for transition in transitions {
806            assert_eq!(block.find_transition(transition.id()), Some(transition));
807            assert_eq!(transactions.find_transition(transition.id()), Some(transition));
808            assert_eq!(transaction.find_transition(transition.id()), Some(transition));
809        }
810
811        // Ensure the transitions are not found.
812        for _ in 0..10 {
813            let transition_id = &rng.gen();
814            assert_eq!(block.find_transition(transition_id), None);
815            assert_eq!(transactions.find_transition(transition_id), None);
816            assert_eq!(transaction.find_transition(transition_id), None);
817        }
818    }
819
820    #[test]
821    fn test_find_transition_for_commitment() {
822        let rng = &mut TestRng::default();
823
824        let (block, transaction) = crate::test_helpers::sample_genesis_block_and_transaction(rng);
825        let transactions = block.transactions();
826
827        // Retrieve the transitions.
828        let transitions = transaction.transitions().collect::<Vec<_>>();
829        assert!(!transitions.is_empty());
830
831        for transition in transitions {
832            // Retrieve the commitments.
833            let commitments = transition.commitments().collect::<Vec<_>>();
834            assert!(!commitments.is_empty());
835
836            // Ensure the commitments are found.
837            for commitment in commitments {
838                assert_eq!(block.find_transition_for_commitment(commitment), Some(transition));
839                assert_eq!(transactions.find_transition_for_commitment(commitment), Some(transition));
840                assert_eq!(transaction.find_transition_for_commitment(commitment), Some(transition));
841            }
842        }
843
844        // Ensure the commitments are not found.
845        for _ in 0..10 {
846            let commitment = &rng.gen();
847            assert_eq!(block.find_transition_for_commitment(commitment), None);
848            assert_eq!(transactions.find_transition_for_commitment(commitment), None);
849            assert_eq!(transaction.find_transition_for_commitment(commitment), None);
850        }
851    }
852
853    #[test]
854    fn test_find_record() {
855        let rng = &mut TestRng::default();
856
857        let (block, transaction) = crate::test_helpers::sample_genesis_block_and_transaction(rng);
858        let transactions = block.transactions();
859
860        // Retrieve the records.
861        let records = transaction.records().collect::<IndexMap<_, _>>();
862        assert!(!records.is_empty());
863
864        // Ensure the records are found.
865        for (commitment, record) in records {
866            assert_eq!(block.find_record(commitment), Some(record));
867            assert_eq!(transactions.find_record(commitment), Some(record));
868            assert_eq!(transaction.find_record(commitment), Some(record));
869        }
870
871        // Ensure the records are not found.
872        for _ in 0..10 {
873            let commitment = &rng.gen();
874            assert_eq!(block.find_record(commitment), None);
875            assert_eq!(transactions.find_record(commitment), None);
876            assert_eq!(transaction.find_record(commitment), None);
877        }
878    }
879
880    #[test]
881    fn test_serde_metadata() {
882        let metadata = crate::test_helpers::sample_metadata();
883        let json_metadata = serde_json::to_string(&metadata).unwrap();
884        let deserialized_metadata: Metadata<CurrentNetwork> = serde_json::from_str(&json_metadata).unwrap();
885        assert_eq!(metadata, deserialized_metadata);
886    }
887}