/ ledger / block / src / lib.rs
lib.rs
  1  // Copyright (c) 2025 ADnet Contributors
  2  // This file is part of the AlphaVM 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  
 21  extern crate alphavm_console as console;
 22  
 23  pub mod header;
 24  pub use header::*;
 25  
 26  mod helpers;
 27  pub use helpers::*;
 28  
 29  pub mod ratifications;
 30  pub use ratifications::*;
 31  
 32  pub mod ratify;
 33  pub use ratify::*;
 34  
 35  pub mod solutions;
 36  pub use solutions::*;
 37  
 38  pub mod transaction;
 39  pub use transaction::*;
 40  
 41  pub mod transactions;
 42  pub use transactions::*;
 43  
 44  pub mod transition;
 45  pub use transition::*;
 46  
 47  mod bytes;
 48  mod genesis;
 49  mod serialize;
 50  mod string;
 51  mod verify;
 52  
 53  use alphavm_ledger_authority::Authority;
 54  use alphavm_ledger_committee::Committee;
 55  use alphavm_ledger_narwhal_data::Data;
 56  use alphavm_ledger_narwhal_subdag::Subdag;
 57  use alphavm_ledger_narwhal_transmission_id::TransmissionID;
 58  use alphavm_ledger_puzzle::{PuzzleSolutions, Solution, SolutionID};
 59  use console::{
 60      account::PrivateKey,
 61      network::prelude::*,
 62      program::{Ciphertext, Record},
 63      types::{Field, Group, U64},
 64  };
 65  
 66  #[derive(Clone, PartialEq, Eq)]
 67  pub 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  
 88  impl<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  
271  impl<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  
313  impl<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  
405  impl<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  
422  impl<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  
439  impl<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  
476  impl<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  
558  impl<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)]
616  pub mod test_helpers {
617      use super::*;
618  
619      use alphavm_algorithms::snark::varuna::VarunaVersion;
620      use alphavm_console::account::{Address, PrivateKey};
621      use alphavm_ledger_query::Query;
622      use alphavm_ledger_store::{BlockStore, helpers::memory::BlockMemory};
623      use alphavm_synthesizer_process::Process;
624      use alphavm_utilities::PrettyUnwrap;
625  
626      use alpha_std::StorageMode;
627      use std::sync::OnceLock;
628  
629      type CurrentNetwork = console::network::MainnetV0;
630      type CurrentAleo = alphavm_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.alpha", "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)]
755  mod 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  }