Skip to main content

snarkvm_ledger_block/
lib.rs

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