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