lib.rs
1 // Copyright (c) 2019-2025 Alpha-Delta Network Inc. 2 // This file is part of the deltavm 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 deltavm_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 deltavm_ledger_authority::Authority; 54 use deltavm_ledger_committee::Committee; 55 use deltavm_ledger_narwhal_data::Data; 56 use deltavm_ledger_narwhal_subdag::Subdag; 57 use deltavm_ledger_narwhal_transmission_id::TransmissionID; 58 use deltavm_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 deltavm_algorithms::snark::varuna::VarunaVersion; 620 use deltavm_console::account::{Address, PrivateKey}; 621 use deltavm_ledger_query::Query; 622 use deltavm_ledger_store::{BlockStore, helpers::memory::BlockMemory}; 623 use deltavm_synthesizer_process::Process; 624 use deltavm_utilities::PrettyUnwrap; 625 626 use alphastd::StorageMode; 627 use std::sync::OnceLock; 628 629 type CurrentNetwork = console::network::MainnetV0; 630 type CurrentAlpha = deltavm_circuit::network::AlphaV0; 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.delta", "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::<CurrentAlpha, _>(&private_key, locator.0, locator.1, inputs.iter(), rng).unwrap(); 679 // Execute the function. 680 let (_, mut trace) = process.execute::<CurrentAlpha, _>(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::<CurrentAlpha, _>(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 }