mod.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 mod helpers; 17 pub use helpers::*; 18 19 mod authorize; 20 mod deploy; 21 mod execute; 22 mod finalize; 23 mod verify; 24 25 #[cfg(test)] 26 mod tests; 27 28 use crate::{Restrictions, cast_mut_ref, cast_ref, convert, process}; 29 use alphavm_algorithms::snark::varuna::VarunaVersion; 30 use alphavm_ledger_block::{ 31 Block, 32 ConfirmedTransaction, 33 Deployment, 34 Execution, 35 Fee, 36 Header, 37 Output, 38 Ratifications, 39 Ratify, 40 Rejected, 41 Solutions, 42 Transaction, 43 Transactions, 44 }; 45 use alphavm_ledger_committee::Committee; 46 use alphavm_ledger_narwhal_data::Data; 47 use alphavm_ledger_puzzle::Puzzle; 48 use alphavm_ledger_query::{Query, QueryTrait}; 49 use alphavm_ledger_store::{ 50 BlockStore, 51 ConsensusStorage, 52 ConsensusStore, 53 FinalizeMode, 54 FinalizeStore, 55 TransactionStore, 56 TransitionStore, 57 atomic_finalize, 58 }; 59 use alphavm_synthesizer_process::{ 60 Authorization, 61 InclusionVersion, 62 Process, 63 Trace, 64 deployment_cost, 65 execute_compute_cost_in_microcredits, 66 execution_cost, 67 }; 68 use alphavm_synthesizer_program::{ 69 FinalizeGlobalState, 70 FinalizeOperation, 71 FinalizeStoreTrait, 72 Program, 73 StackTrait as _, 74 }; 75 use alphavm_synthesizer_snark::VerifyingKey; 76 use alphavm_utilities::try_vm_runtime; 77 use console::{ 78 account::{Address, PrivateKey}, 79 network::prelude::*, 80 program::{Argument, Identifier, Literal, Locator, Plaintext, ProgramID, ProgramOwner, Record, Response, Value}, 81 types::{Field, Group, U16, U64}, 82 }; 83 84 use alpha_std::prelude::{finish, lap, timer}; 85 use anyhow::Context; 86 use indexmap::{IndexMap, IndexSet}; 87 use itertools::Either; 88 #[cfg(feature = "locktick")] 89 use locktick::parking_lot::{Mutex, RwLock}; 90 use lru::LruCache; 91 #[cfg(not(feature = "locktick"))] 92 use parking_lot::{Mutex, RwLock}; 93 use rand::{SeedableRng, rngs::StdRng}; 94 use std::{ 95 collections::HashSet, 96 num::NonZeroUsize, 97 sync::{Arc, mpsc}, 98 thread, 99 }; 100 101 #[cfg(not(feature = "serial"))] 102 use rayon::prelude::*; 103 104 // The key for the partially-verified transactions cache. 105 // The key is a tuple of the transaction ID and a list of program checksums for the transitions in the transaction. 106 // Note: If a program is upgraded and its contents are changed, then the program checksums will change, invalidating the previously cached result. 107 type TransactionCacheKey<N> = (<N as Network>::TransactionID, Vec<U16<N>>); 108 109 #[derive(Clone)] 110 pub struct VM<N: Network, C: ConsensusStorage<N>> { 111 /// The process. 112 process: Arc<RwLock<Process<N>>>, 113 /// The puzzle. 114 puzzle: Puzzle<N>, 115 /// The VM store. 116 store: ConsensusStore<N, C>, 117 /// A cache containing the list of recent partially-verified transactions. 118 partially_verified_transactions: Arc<RwLock<LruCache<TransactionCacheKey<N>, N::TransmissionChecksum>>>, 119 /// The restrictions list. 120 restrictions: Restrictions<N>, 121 /// A sender to the channel for operations that must be performed sequentially. 122 sequential_ops_tx: Arc<RwLock<Option<mpsc::Sender<SequentialOperationRequest<N>>>>>, 123 /// The handle to the thread which processes operations sequentially. 124 sequential_ops_thread: Arc<Mutex<Option<thread::JoinHandle<()>>>>, 125 } 126 127 impl<N: Network, C: ConsensusStorage<N>> VM<N, C> { 128 /// Initializes the VM from storage. 129 #[inline] 130 pub fn from(store: ConsensusStore<N, C>) -> Result<Self> { 131 // Initialize the store for 'credits.alpha'. 132 let credits = Program::<N>::credits()?; 133 for mapping in credits.mappings().values() { 134 // Ensure that all mappings are initialized. 135 if !store.finalize_store().contains_mapping_confirmed(credits.id(), mapping.name())? { 136 // Initialize the mappings for 'credits.alpha'. 137 store.finalize_store().initialize_mapping(*credits.id(), *mapping.name())?; 138 } 139 } 140 141 // Retrieve the transaction store. 142 let transaction_store = store.transaction_store(); 143 // Retrieve the block store. 144 let block_store = store.block_store(); 145 146 #[cfg(not(any(test, feature = "test")))] 147 let mut process = { 148 // Determine the latest block height. 149 let latest_block_height = block_store.current_block_height(); 150 // Determine the consensus version. 151 let consensus_version = N::CONSENSUS_VERSION(latest_block_height)?; // TODO (raychu86): Record Commitment - Select the proper consensus version. 152 // Initialize a new process based on the consensus version. 153 if (ConsensusVersion::V1..=ConsensusVersion::V7).contains(&consensus_version) { 154 Process::load_v0()? 155 } else { 156 Process::load()? 157 } 158 }; 159 #[cfg(any(test, feature = "test"))] 160 // Initialize a new process. 161 let mut process = Process::load()?; 162 163 // Retrieve the list of deployment transaction IDs and their associated block heights. 164 let deployment_ids = transaction_store.deployment_transaction_ids().collect::<Vec<_>>(); 165 let mut deployment_ids = cfg_into_iter!(deployment_ids) 166 .map(|transaction_id| { 167 // Retrieve the block hash for the deployment transaction ID. 168 let Some(hash) = block_store.find_block_hash(&transaction_id)? else { 169 bail!("Deployment transaction '{transaction_id}' is not found in storage.") 170 }; 171 // Retrieve the height. 172 let Some(height) = block_store.get_block_height(&hash)? else { 173 bail!("Block height for deployment transaction '{transaction_id}' is not found in storage.") 174 }; 175 // Get the corresponding block's transactions. 176 let Some(transactions) = block_store.get_block_transactions(&hash)? else { 177 bail!("Transactions for deployment transaction '{hash}' is not found in storage.") 178 }; 179 // Find the index of the deployment transaction ID in the block's transactions. 180 let Some(index) = transactions.index_of(transaction_id.deref()) else { 181 bail!("Transaction for deployment transaction '{transaction_id}' is not found in storage.") 182 }; 183 Ok((transaction_id, (height, index))) 184 }) 185 .collect::<Result<Vec<_>>>()?; 186 // Sort the deployment transaction IDs by their block heights. 187 deployment_ids.sort_unstable_by(|(_, a), (_, b)| a.cmp(b)); 188 189 // Load the deployments in order of their block heights. 190 const PARALLELIZATION_FACTOR: usize = 256; 191 for (i, chunk) in deployment_ids.chunks(PARALLELIZATION_FACTOR).enumerate() { 192 debug!( 193 "Loading deployments {}-{} (of {})...", 194 i * PARALLELIZATION_FACTOR, 195 ((i + 1) * PARALLELIZATION_FACTOR).min(deployment_ids.len()), 196 deployment_ids.len() 197 ); 198 // Load the deployments. 199 let deployments = cfg_iter!(chunk) 200 .map(|(transaction_id, _)| { 201 // Retrieve the deployment from the transaction ID. 202 match transaction_store.get_deployment(transaction_id)? { 203 Some(deployment) => Ok(deployment), 204 None => bail!("Deployment transaction '{transaction_id}' is not found in storage."), 205 } 206 }) 207 .collect::<Result<Vec<_>>>()?; 208 // Add the deployments to the process. 209 // Note: This iterator must be serial, to ensure deployments are loaded in the order of their dependencies. 210 // NOTE: Program deployment is disabled. Only credits.alpha is supported. 211 // Skip loading any non-credits deployments (they shouldn't exist in a properly configured chain). 212 deployments.iter().try_for_each(|deployment| { 213 let program_id = deployment.program_id(); 214 if program_id.to_string() != "credits.alpha" { 215 warn!("Skipping non-credits deployment: {program_id} (deployment is disabled on ALPHA chain)"); 216 return Ok(()); 217 } 218 process.load_deployment(deployment) 219 })?; 220 } 221 222 // Construct the VM object. 223 let vm = Self { 224 process: Arc::new(RwLock::new(process)), 225 puzzle: Self::new_puzzle()?, 226 store, 227 partially_verified_transactions: Arc::new(RwLock::new(LruCache::new( 228 NonZeroUsize::new(Transactions::<N>::MAX_TRANSACTIONS).unwrap(), 229 ))), 230 restrictions: Restrictions::load()?, 231 sequential_ops_tx: Default::default(), 232 sequential_ops_thread: Default::default(), 233 }; 234 235 // Spawn a thread for sequential operations. 236 let (sequential_ops_tx, sequential_ops_rx) = mpsc::channel(); 237 let sequential_ops_thread = vm.start_sequential_queue(sequential_ops_rx); 238 239 // Populate the fields related to the sequential operations. 240 *vm.sequential_ops_tx.write() = Some(sequential_ops_tx); 241 *vm.sequential_ops_thread.lock() = Some(sequential_ops_thread); 242 243 // Return the new VM. 244 Ok(vm) 245 } 246 247 /// Returns `true` if a program with the given program ID exists. 248 #[inline] 249 pub fn contains_program(&self, program_id: &ProgramID<N>) -> bool { 250 self.process.read().contains_program(program_id) 251 } 252 253 /// Returns the process. 254 #[inline] 255 pub fn process(&self) -> Arc<RwLock<Process<N>>> { 256 self.process.clone() 257 } 258 259 /// Returns the puzzle. 260 #[inline] 261 pub const fn puzzle(&self) -> &Puzzle<N> { 262 &self.puzzle 263 } 264 265 /// Returns the partially-verified transactions. 266 #[inline] 267 pub fn partially_verified_transactions( 268 &self, 269 ) -> Arc<RwLock<LruCache<TransactionCacheKey<N>, N::TransmissionChecksum>>> { 270 self.partially_verified_transactions.clone() 271 } 272 273 /// Returns the restrictions. 274 #[inline] 275 pub const fn restrictions(&self) -> &Restrictions<N> { 276 &self.restrictions 277 } 278 } 279 280 impl<N: Network, C: ConsensusStorage<N>> VM<N, C> { 281 /// Returns the finalize store. 282 #[inline] 283 pub fn finalize_store(&self) -> &FinalizeStore<N, C::FinalizeStorage> { 284 self.store.finalize_store() 285 } 286 287 /// Returns the block store. 288 #[inline] 289 pub fn block_store(&self) -> &BlockStore<N, C::BlockStorage> { 290 self.store.block_store() 291 } 292 293 /// Returns the transaction store. 294 #[inline] 295 pub fn transaction_store(&self) -> &TransactionStore<N, C::TransactionStorage> { 296 self.store.transaction_store() 297 } 298 299 /// Returns the transition store. 300 #[inline] 301 pub fn transition_store(&self) -> &TransitionStore<N, C::TransitionStorage> { 302 self.store.transition_store() 303 } 304 } 305 306 impl<N: Network, C: ConsensusStorage<N>> VM<N, C> { 307 /// Returns a new instance of the puzzle. 308 pub fn new_puzzle() -> Result<Puzzle<N>> { 309 // Initialize a new instance of the puzzle. 310 macro_rules! logic { 311 ($network:path, $aleo:path) => {{ 312 let puzzle = Puzzle::new::<alphavm_ledger_puzzle_epoch::SynthesisPuzzle<$network, $aleo>>(); 313 Ok(cast_ref!(puzzle as Puzzle<N>).clone()) 314 }}; 315 } 316 // Initialize the puzzle. 317 convert!(logic) 318 } 319 } 320 321 impl<N: Network, C: ConsensusStorage<N>> VM<N, C> { 322 /// Returns a new genesis block for a beacon chain with the default size (four validators). 323 pub fn genesis_beacon<R: Rng + CryptoRng>(&self, private_key: &PrivateKey<N>, rng: &mut R) -> Result<Block<N>> { 324 self.genesis_beacon_with_size(private_key, 4, rng) 325 } 326 327 /// Returns a new genesis block for a beacon chain. 328 pub fn genesis_beacon_with_size<R: Rng + CryptoRng>( 329 &self, 330 private_key: &PrivateKey<N>, 331 num_validators: usize, 332 rng: &mut R, 333 ) -> Result<Block<N>> { 334 ensure!(num_validators >= 4, "Need at least four validators"); 335 336 let mut private_keys = vec![*private_key]; 337 for _ in 1..num_validators { 338 private_keys.push(PrivateKey::new(rng)?); 339 } 340 341 // Construct the committee members. 342 let mut members = IndexMap::with_capacity(num_validators); 343 for key in &private_keys { 344 let addr = Address::try_from(key)?; 345 members.insert(addr, (alphavm_ledger_committee::MIN_VALIDATOR_STAKE, true, 0u8)); 346 } 347 348 // Construct the committee. 349 let committee = Committee::<N>::new_genesis(members)?; 350 351 // Compute the remaining supply. 352 let remaining_supply = N::STARTING_SUPPLY 353 .checked_sub(alphavm_ledger_committee::MIN_VALIDATOR_STAKE * (num_validators as u64)) 354 .with_context(|| "Not enough starting supply for this many validators")?; 355 356 // Construct the public balances. 357 let mut public_balances = IndexMap::with_capacity(4); 358 for key in &private_keys { 359 let addr = Address::try_from(key)?; 360 public_balances.insert(addr, remaining_supply / num_validators as u64); 361 } 362 363 // Construct the bonded balances. 364 let bonded_balances = committee 365 .members() 366 .iter() 367 .map(|(address, (amount, _, _))| (*address, (*address, *address, *amount))) 368 .collect(); 369 370 // Return the genesis block. 371 self.genesis_quorum(private_key, committee, public_balances, bonded_balances, rng) 372 } 373 374 /// Returns a new genesis block for a quorum chain. 375 /// 376 /// # Panics 377 /// This function panics if called from an async context. 378 pub fn genesis_quorum<R: Rng + CryptoRng>( 379 &self, 380 private_key: &PrivateKey<N>, 381 committee: Committee<N>, 382 public_balances: IndexMap<Address<N>, u64>, 383 bonded_balances: IndexMap<Address<N>, (Address<N>, Address<N>, u64)>, 384 rng: &mut R, 385 ) -> Result<Block<N>> { 386 // Retrieve the total bonded balance. 387 let total_bonded_amount = bonded_balances 388 .values() 389 .try_fold(0u64, |acc, (_, _, x)| acc.checked_add(*x).ok_or(anyhow!("Invalid bonded amount")))?; 390 // Compute the account supply. 391 let account_supply = public_balances 392 .values() 393 .try_fold(0u64, |acc, x| acc.checked_add(*x).ok_or(anyhow!("Invalid account supply")))?; 394 // Compute the total supply. 395 let total_supply = 396 total_bonded_amount.checked_add(account_supply).ok_or_else(|| anyhow!("Invalid total supply"))?; 397 // Ensure the total supply matches. 398 ensure!( 399 total_supply == N::STARTING_SUPPLY, 400 "Invalid total supply. Found {total_supply}, expected {}", 401 N::STARTING_SUPPLY 402 ); 403 404 // Prepare the caller. 405 let caller = Address::try_from(private_key)?; 406 // Prepare the locator. 407 let locator = ("credits.alpha", "transfer_public_to_private"); 408 // Prepare the amount for each call to the function. 409 let amount = public_balances 410 .get(&caller) 411 .ok_or_else(|| anyhow!("Missing public balance for {caller}"))? 412 .saturating_div(Block::<N>::NUM_GENESIS_TRANSACTIONS.saturating_mul(2) as u64); 413 // Prepare the function inputs. 414 let inputs = [caller.to_string(), format!("{amount}_u64")]; 415 416 // Prepare the ratifications. 417 let ratifications = 418 vec![Ratify::Genesis(Box::new(committee), Box::new(public_balances), Box::new(bonded_balances))]; 419 // Prepare the solutions. 420 let solutions = Solutions::<N>::from(None); // The genesis block does not require solutions. 421 // Prepare the aborted solution IDs. 422 let aborted_solution_ids = vec![]; 423 // Prepare the transactions. 424 let transactions = (0..Block::<N>::NUM_GENESIS_TRANSACTIONS) 425 .map(|_| self.execute(private_key, locator, inputs.iter(), None, 0, None, rng)) 426 .collect::<Result<Vec<_>, _>>()?; 427 428 // Construct the finalize state. 429 let state = FinalizeGlobalState::new_genesis::<N>()?; 430 // Speculate on the ratifications, solutions, and transactions. 431 let (ratifications, transactions, aborted_transaction_ids, ratified_finalize_operations) = 432 self.speculate(state, 0, None, ratifications, &solutions, transactions.iter(), rng)?; 433 ensure!( 434 aborted_transaction_ids.is_empty(), 435 "Failed to initialize a genesis block - found aborted transaction IDs" 436 ); 437 438 // Prepare the block header. 439 let header = Header::genesis(&ratifications, &transactions, ratified_finalize_operations)?; 440 // Prepare the previous block hash. 441 let previous_hash = N::BlockHash::default(); 442 443 // Construct the block. 444 let block = Block::new_beacon( 445 private_key, 446 previous_hash, 447 header, 448 ratifications, 449 solutions, 450 aborted_solution_ids, 451 transactions, 452 aborted_transaction_ids, 453 rng, 454 )?; 455 // Ensure the block is valid genesis block. 456 match block.is_genesis()? { 457 true => Ok(block), 458 false => bail!("Failed to initialize a genesis block"), 459 } 460 } 461 462 /// Adds the given block into the VM. 463 /// 464 /// # Panics 465 /// This function panics if called from an async context. 466 #[inline] 467 pub fn add_next_block(&self, block: &Block<N>) -> Result<()> { 468 let sequential_op = SequentialOperation::AddNextBlock(block.clone()); 469 let Some(SequentialOperationResult::AddNextBlock(ret)) = self.run_sequential_operation(sequential_op) else { 470 bail!("Already shutting down"); 471 }; 472 473 ret 474 } 475 476 /// Adds the given block into the VM. 477 /// 478 /// # Note 479 /// This must only be called from the sequential operation thread. 480 /// 481 /// # Panics 482 /// This function panics if not called from the sequential operation thread. 483 #[inline] 484 pub(crate) fn add_next_block_inner(&self, block: Block<N>) -> Result<()> { 485 self.ensure_sequential_processing(); 486 487 // Determine if the block timestamp should be included. 488 let block_timestamp = (block.height() >= N::CONSENSUS_HEIGHT(ConsensusVersion::V12).unwrap_or_default()) 489 .then_some(block.timestamp()); 490 // Construct the finalize state. 491 let state = FinalizeGlobalState::new::<N>( 492 block.round(), 493 block.height(), 494 block_timestamp, 495 block.cumulative_weight(), 496 block.cumulative_proof_target(), 497 block.previous_hash(), 498 )?; 499 500 // Pause the atomic writes, so that both the insertion and finalization belong to a single batch. 501 #[cfg(feature = "rocks")] 502 self.block_store().pause_atomic_writes()?; 503 504 // First, insert the block. 505 if let Err(insert_error) = self.block_store().insert(&block) { 506 if cfg!(feature = "rocks") { 507 // Clear all pending atomic operations so that unpausing the atomic writes 508 // doesn't execute any of the queued storage operations. 509 self.block_store().abort_atomic(); 510 // Disable the atomic batch override. 511 // Note: This call is guaranteed to succeed (without error), because `DISCARD_BATCH == true`. 512 self.block_store().unpause_atomic_writes::<true>()?; 513 } 514 515 return Err(insert_error); 516 }; 517 518 // Next, finalize the transactions. 519 match self.finalize(state, block.ratifications(), block.solutions(), block.transactions()) { 520 Ok(_ratified_finalize_operations) => { 521 // If the block advances to `ConsensusVersion::V8`, updated the VKs used for the credits program. 522 if N::CONSENSUS_HEIGHT(ConsensusVersion::V8).unwrap_or_default() == block.height() { 523 self.update_credits_verifying_keys()?; 524 } 525 // Unpause the atomic writes, executing the ones queued from block insertion and finalization. 526 #[cfg(feature = "rocks")] 527 self.block_store().unpause_atomic_writes::<false>()?; 528 // If the block advances to a new consensus version, clear the partial verification cache. 529 if N::CONSENSUS_VERSION_HEIGHTS().iter().rev().any(|(_, height)| { 530 if block.height() < *height { 531 // If the block height is less than the consensus version height, break early. 532 return false; 533 } 534 height == &block.height() 535 }) { 536 self.partially_verified_transactions().write().clear(); 537 } 538 Ok(()) 539 } 540 Err(finalize_error) => { 541 if cfg!(feature = "rocks") { 542 // Clear all pending atomic operations so that unpausing the atomic writes 543 // doesn't execute any of the queued storage operations. 544 self.block_store().abort_atomic(); 545 self.finalize_store().abort_atomic(); 546 // Disable the atomic batch override. 547 // Note: This call is guaranteed to succeed (without error), because `DISCARD_BATCH == true`. 548 self.block_store().unpause_atomic_writes::<true>()?; 549 // Rollback the Merkle tree. 550 self.block_store().remove_last_n_from_tree_only(1).inspect_err(|_| { 551 // Log the finalize error. 552 error!("Failed to finalize block {} - {finalize_error}", block.height()); 553 })?; 554 } else { 555 // Rollback the block. 556 self.block_store().remove_last_n(1).inspect_err(|_| { 557 // Log the finalize error. 558 error!("Failed to finalize block {} - {finalize_error}", block.height()); 559 })?; 560 } 561 // Return the finalize error. 562 Err(finalize_error) 563 } 564 } 565 } 566 } 567 568 impl<N: Network, C: ConsensusStorage<N>> VM<N, C> { 569 /// Update the `credits.alpha` program in the VM with the latest verifying keys. 570 fn update_credits_verifying_keys(&self) -> Result<()> { 571 // Initialize the store for 'credits.alpha'. 572 let credits = Program::<N>::credits()?; 573 574 // Acquire the process lock. 575 let process = self.process.write(); 576 577 // Synthesize the 'credits.alpha' verifying keys. 578 for function_name in credits.functions().keys() { 579 // Remove the proving key. 580 process.remove_proving_key(credits.id(), function_name)?; 581 // Load the verifying key. 582 let verifying_key = N::get_credits_verifying_key(function_name.to_string())?; 583 // Retrieve the number of public and private variables. 584 // Note: This number does *NOT* include the number of constants. This is safe because 585 // this program is never deployed, as it is a first-class citizen of the protocol. 586 let num_variables = verifying_key.circuit_info.num_public_and_private_variables as u64; 587 // Insert the verifying key. 588 process.insert_verifying_key( 589 credits.id(), 590 function_name, 591 VerifyingKey::new(verifying_key.clone(), num_variables), 592 )?; 593 } 594 595 Ok(()) 596 } 597 } 598 599 impl<N: Network, C: ConsensusStorage<N>> Drop for VM<N, C> { 600 fn drop(&mut self) { 601 // Check if this the final external reference to `VM`. 602 if Arc::strong_count(&self.sequential_ops_tx) == 1 { 603 // If the background thread exists, shut it down. 604 if let Some(thread) = self.sequential_ops_thread.lock().take() { 605 // First, close the channel. 606 self.sequential_ops_tx.write().take(); 607 // Wait for the thread to terminate. 608 trace!("Waiting for sequential ops thread to terminate"); 609 thread.join().expect("Sequential ops thread had an error"); 610 } else { 611 debug!("No sequential ops background thread existed durign shutdown"); 612 } 613 } 614 } 615 } 616 617 #[cfg(test)] 618 pub(crate) mod test_helpers { 619 use super::*; 620 use alphavm_ledger_block::{Block, Header, Input, Metadata, Transition}; 621 use alphavm_ledger_test_helpers::{large_transaction_program, small_transaction_program}; 622 use alphavm_synthesizer_program::Program; 623 use circuit::AleoV0; 624 use console::{ 625 account::{Address, ViewKey}, 626 network::MainnetV0, 627 program::{Entry, Value}, 628 types::Field, 629 }; 630 631 use alpha_std::StorageMode; 632 use alphavm_synthesizer_snark::{Proof, VerifyingKey}; 633 use indexmap::IndexMap; 634 use serde_json::json; 635 use std::sync::OnceLock; 636 637 pub(crate) type CurrentNetwork = MainnetV0; 638 pub(crate) type CurrentAleo = AleoV0; 639 640 #[cfg(not(feature = "rocks"))] 641 pub(crate) type LedgerType = alphavm_ledger_store::helpers::memory::ConsensusMemory<CurrentNetwork>; 642 #[cfg(feature = "rocks")] 643 pub(crate) type LedgerType = alphavm_ledger_store::helpers::rocksdb::ConsensusDB<CurrentNetwork>; 644 645 /// Samples a new finalize state. 646 pub(crate) fn sample_finalize_state(block_height: u32) -> FinalizeGlobalState { 647 FinalizeGlobalState::from(block_height as u64, block_height, None, [0u8; 32]) 648 } 649 650 pub(crate) fn sample_vm() -> VM<CurrentNetwork, LedgerType> { 651 // Initialize a new VM. 652 VM::from(ConsensusStore::open(StorageMode::new_test(None)).unwrap()).unwrap() 653 } 654 655 #[cfg(feature = "test")] 656 pub(crate) fn sample_vm_at_height(height: u32, rng: &mut TestRng) -> VM<CurrentNetwork, LedgerType> { 657 // Initialize the VM with a genesis block. 658 let mut vm = sample_vm_with_genesis_block(rng); 659 // Get the genesis private key. 660 let genesis_private_key = sample_genesis_private_key(rng); 661 // Advance the VM to the given height. 662 advance_vm_to_height(&mut vm, genesis_private_key, height, rng); 663 // Return the VM. 664 vm 665 } 666 667 #[cfg(feature = "test")] 668 pub(crate) fn advance_vm_to_height( 669 vm: &mut VM<CurrentNetwork, LedgerType>, 670 genesis_private_key: PrivateKey<CurrentNetwork>, 671 height: u32, 672 rng: &mut TestRng, 673 ) { 674 // Advance the VM to the given height. 675 for _ in vm.block_store().current_block_height()..height { 676 let block = sample_next_block(vm, &genesis_private_key, &[], rng).unwrap(); 677 vm.add_next_block(&block).unwrap(); 678 } 679 } 680 681 pub(crate) fn sample_genesis_private_key(rng: &mut TestRng) -> PrivateKey<CurrentNetwork> { 682 static INSTANCE: OnceLock<PrivateKey<CurrentNetwork>> = OnceLock::new(); 683 *INSTANCE.get_or_init(|| { 684 // Initialize a new caller. 685 PrivateKey::<CurrentNetwork>::new(rng).unwrap() 686 }) 687 } 688 689 pub(crate) fn sample_genesis_block(rng: &mut TestRng) -> Block<CurrentNetwork> { 690 static INSTANCE: OnceLock<Block<CurrentNetwork>> = OnceLock::new(); 691 INSTANCE 692 .get_or_init(|| { 693 // Initialize the VM. 694 let vm = crate::vm::test_helpers::sample_vm(); 695 // Initialize a new caller. 696 let caller_private_key = crate::vm::test_helpers::sample_genesis_private_key(rng); 697 // Return the block. 698 vm.genesis_beacon(&caller_private_key, rng).unwrap() 699 }) 700 .clone() 701 } 702 703 pub(crate) fn sample_vm_with_genesis_block(rng: &mut TestRng) -> VM<CurrentNetwork, LedgerType> { 704 // Initialize the VM. 705 let vm = crate::vm::test_helpers::sample_vm(); 706 // Initialize the genesis block. 707 let genesis = crate::vm::test_helpers::sample_genesis_block(rng); 708 // Update the VM. 709 vm.add_next_block(&genesis).unwrap(); 710 // Return the VM. 711 vm 712 } 713 714 pub(crate) fn sample_program() -> Program<CurrentNetwork> { 715 static INSTANCE: OnceLock<Program<CurrentNetwork>> = OnceLock::new(); 716 INSTANCE 717 .get_or_init(|| { 718 // Initialize a new program. 719 Program::<CurrentNetwork>::from_str( 720 r" 721 program testing.alpha; 722 723 struct message: 724 amount as u128; 725 726 mapping account: 727 key as address.public; 728 value as u64.public; 729 730 record token: 731 owner as address.private; 732 amount as u64.private; 733 734 function initialize: 735 input r0 as address.private; 736 input r1 as u64.private; 737 cast r0 r1 into r2 as token.record; 738 output r2 as token.record; 739 740 function compute: 741 input r0 as message.private; 742 input r1 as message.public; 743 input r2 as message.private; 744 input r3 as token.record; 745 add r0.amount r1.amount into r4; 746 cast r3.owner r3.amount into r5 as token.record; 747 output r4 as u128.public; 748 output r5 as token.record;", 749 ) 750 .unwrap() 751 }) 752 .clone() 753 } 754 755 pub(crate) fn sample_deployment_transaction(rng: &mut TestRng) -> Transaction<CurrentNetwork> { 756 static INSTANCE: OnceLock<Transaction<CurrentNetwork>> = OnceLock::new(); 757 INSTANCE 758 .get_or_init(|| { 759 // Initialize the program. 760 let program = sample_program(); 761 762 // Initialize a new caller. 763 let caller_private_key = crate::vm::test_helpers::sample_genesis_private_key(rng); 764 let caller_view_key = ViewKey::try_from(&caller_private_key).unwrap(); 765 766 // Initialize the genesis block. 767 let genesis = crate::vm::test_helpers::sample_genesis_block(rng); 768 769 // Fetch the unspent records. 770 let records = 771 genesis.transitions().cloned().flat_map(Transition::into_records).collect::<IndexMap<_, _>>(); 772 trace!("Unspent Records:\n{:#?}", records); 773 774 // Prepare the fee. 775 let credits = Some(records.values().next().unwrap().decrypt(&caller_view_key).unwrap()); 776 777 // Initialize the VM. 778 let vm = sample_vm(); 779 // Update the VM. 780 vm.add_next_block(&genesis).unwrap(); 781 782 // Deploy. 783 let transaction = vm.deploy(&caller_private_key, &program, credits, 10, None, rng).unwrap(); 784 // Verify. 785 vm.check_transaction(&transaction, None, rng).unwrap(); 786 // Return the transaction. 787 transaction 788 }) 789 .clone() 790 } 791 792 pub(crate) fn sample_execution_transaction_without_fee(rng: &mut TestRng) -> Transaction<CurrentNetwork> { 793 static INSTANCE: OnceLock<Transaction<CurrentNetwork>> = OnceLock::new(); 794 INSTANCE 795 .get_or_init(|| { 796 // Initialize a new caller. 797 let caller_private_key = crate::vm::test_helpers::sample_genesis_private_key(rng); 798 let caller_view_key = ViewKey::try_from(&caller_private_key).unwrap(); 799 800 // Initialize the genesis block. 801 let genesis = crate::vm::test_helpers::sample_genesis_block(rng); 802 803 // Fetch the unspent records. 804 let records = 805 genesis.transitions().cloned().flat_map(Transition::into_records).collect::<IndexMap<_, _>>(); 806 trace!("Unspent Records:\n{:#?}", records); 807 808 // Select a record to spend. 809 let record = records.values().next().unwrap().decrypt(&caller_view_key).unwrap(); 810 811 // Initialize the VM. 812 let vm = sample_vm(); 813 // Update the VM. 814 vm.add_next_block(&genesis).unwrap(); 815 816 // Prepare the inputs. 817 let inputs = 818 [Value::<CurrentNetwork>::Record(record), Value::<CurrentNetwork>::from_str("1u64").unwrap()] 819 .into_iter(); 820 821 // Authorize. 822 let authorization = vm.authorize(&caller_private_key, "credits.alpha", "split", inputs, rng).unwrap(); 823 assert_eq!(authorization.len(), 1); 824 825 // Construct the execute transaction. 826 let transaction = vm.execute_authorization(authorization, None, None, rng).unwrap(); 827 // Verify. 828 vm.check_transaction(&transaction, None, rng).unwrap(); 829 // Return the transaction. 830 transaction 831 }) 832 .clone() 833 } 834 835 pub(crate) fn sample_execution_transaction_with_private_fee(rng: &mut TestRng) -> Transaction<CurrentNetwork> { 836 static INSTANCE: OnceLock<Transaction<CurrentNetwork>> = OnceLock::new(); 837 INSTANCE 838 .get_or_init(|| { 839 // Initialize a new caller. 840 let caller_private_key = crate::vm::test_helpers::sample_genesis_private_key(rng); 841 let caller_view_key = ViewKey::try_from(&caller_private_key).unwrap(); 842 let address = Address::try_from(&caller_private_key).unwrap(); 843 844 // Initialize the genesis block. 845 let genesis = crate::vm::test_helpers::sample_genesis_block(rng); 846 847 // Fetch the unspent records. 848 let records = 849 genesis.transitions().cloned().flat_map(Transition::into_records).collect::<IndexMap<_, _>>(); 850 trace!("Unspent Records:\n{:#?}", records); 851 852 // Select a record to spend. 853 let record = Some(records.values().next().unwrap().decrypt(&caller_view_key).unwrap()); 854 855 // Initialize the VM. 856 let vm = sample_vm(); 857 // Update the VM. 858 vm.add_next_block(&genesis).unwrap(); 859 860 // Prepare the inputs. 861 let inputs = [ 862 Value::<CurrentNetwork>::from_str(&address.to_string()).unwrap(), 863 Value::<CurrentNetwork>::from_str("1u64").unwrap(), 864 ] 865 .into_iter(); 866 867 // Execute. 868 let transaction = vm 869 .execute(&caller_private_key, ("credits.alpha", "transfer_public"), inputs, record, 0, None, rng) 870 .unwrap(); 871 // Verify. 872 vm.check_transaction(&transaction, None, rng).unwrap(); 873 // Return the transaction. 874 transaction 875 }) 876 .clone() 877 } 878 879 pub(crate) fn sample_execution_transaction_with_public_fee(rng: &mut TestRng) -> Transaction<CurrentNetwork> { 880 static INSTANCE: OnceLock<Transaction<CurrentNetwork>> = OnceLock::new(); 881 INSTANCE 882 .get_or_init(|| { 883 // Initialize a new caller. 884 let caller_private_key = crate::vm::test_helpers::sample_genesis_private_key(rng); 885 let address = Address::try_from(&caller_private_key).unwrap(); 886 887 // Initialize the genesis block. 888 let genesis = crate::vm::test_helpers::sample_genesis_block(rng); 889 890 // Initialize the VM. 891 let vm = sample_vm(); 892 // Update the VM. 893 vm.add_next_block(&genesis).unwrap(); 894 895 // Prepare the inputs. 896 let inputs = [ 897 Value::<CurrentNetwork>::from_str(&address.to_string()).unwrap(), 898 Value::<CurrentNetwork>::from_str("1u64").unwrap(), 899 ] 900 .into_iter(); 901 902 // Execute. 903 let transaction_without_fee = vm 904 .execute(&caller_private_key, ("credits.alpha", "transfer_public"), inputs, None, 0, None, rng) 905 .unwrap(); 906 let execution = transaction_without_fee.execution().unwrap().clone(); 907 908 // Authorize the fee. 909 let authorization = vm 910 .authorize_fee_public( 911 &caller_private_key, 912 10_000_000, 913 100, 914 execution.to_execution_id().unwrap(), 915 rng, 916 ) 917 .unwrap(); 918 // Compute the fee. 919 let fee = vm.execute_fee_authorization(authorization, None, rng).unwrap(); 920 921 // Construct the transaction. 922 let transaction = Transaction::from_execution(execution, Some(fee)).unwrap(); 923 // Verify. 924 vm.check_transaction(&transaction, None, rng).unwrap(); 925 // Return the transaction. 926 transaction 927 }) 928 .clone() 929 } 930 931 pub fn sample_next_block<R: Rng + CryptoRng>( 932 vm: &VM<MainnetV0, LedgerType>, 933 private_key: &PrivateKey<MainnetV0>, 934 transactions: &[Transaction<MainnetV0>], 935 rng: &mut R, 936 ) -> Result<Block<MainnetV0>> { 937 // Get the most recent block. 938 let block_hash = vm.block_store().get_block_hash(vm.block_store().max_height().unwrap()).unwrap().unwrap(); 939 let previous_block = vm.block_store().get_block(&block_hash).unwrap().unwrap(); 940 941 // Create the finalize state for the next block height. 942 let next_block_height = previous_block.height() + 1; 943 let time_since_last_block = MainnetV0::BLOCK_TIME as i64; 944 let next_block_timestamp = previous_block.timestamp().saturating_add(time_since_last_block); 945 let next_timestamp = (next_block_height 946 >= MainnetV0::CONSENSUS_HEIGHT(ConsensusVersion::V12).unwrap_or_default()) 947 .then_some(next_block_timestamp); 948 let finalize_state = 949 FinalizeGlobalState::from(next_block_height as u64, next_block_height, next_timestamp, [0u8; 32]); 950 951 // Speculate on the ratifications, solutions, and transactions. 952 let (ratifications, transactions, aborted_transaction_ids, ratified_finalize_operations) = 953 vm.speculate(finalize_state, time_since_last_block, None, vec![], &None.into(), transactions.iter(), rng)?; 954 955 // Construct the metadata associated with the block. 956 let metadata = Metadata::new( 957 MainnetV0::ID, 958 previous_block.round() + 1, 959 previous_block.height() + 1, 960 0, 961 0, 962 MainnetV0::GENESIS_COINBASE_TARGET, 963 MainnetV0::GENESIS_PROOF_TARGET, 964 previous_block.last_coinbase_target(), 965 previous_block.last_coinbase_timestamp(), 966 previous_block.timestamp().saturating_add(time_since_last_block), 967 )?; 968 969 // Construct the new block header. 970 let header = Header::from( 971 vm.block_store().current_state_root(), 972 transactions.to_transactions_root().unwrap(), 973 transactions.to_finalize_root(ratified_finalize_operations).unwrap(), 974 ratifications.to_ratifications_root().unwrap(), 975 Field::zero(), 976 Field::zero(), 977 metadata, 978 )?; 979 980 // Construct the new block. 981 Block::new_beacon( 982 private_key, 983 previous_block.hash(), 984 header, 985 ratifications, 986 None.into(), 987 vec![], 988 transactions, 989 aborted_transaction_ids, 990 rng, 991 ) 992 } 993 994 #[test] 995 fn test_multiple_deployments_and_multiple_executions() { 996 let rng = &mut TestRng::default(); 997 998 // Initialize a new caller. 999 let caller_private_key = crate::vm::test_helpers::sample_genesis_private_key(rng); 1000 let caller_view_key = ViewKey::try_from(&caller_private_key).unwrap(); 1001 1002 // Initialize the genesis block. 1003 let genesis = crate::vm::test_helpers::sample_genesis_block(rng); 1004 1005 // Fetch the unspent records. 1006 let records = genesis.transitions().cloned().flat_map(Transition::into_records).collect::<IndexMap<_, _>>(); 1007 trace!("Unspent Records:\n{:#?}", records); 1008 1009 // Select a record to spend. 1010 let record = records.values().next().unwrap().decrypt(&caller_view_key).unwrap(); 1011 1012 // Initialize the VM. 1013 let vm = sample_vm(); 1014 // Update the VM. 1015 vm.add_next_block(&genesis).unwrap(); 1016 1017 // Split once. 1018 let transaction = vm 1019 .execute( 1020 &caller_private_key, 1021 ("credits.alpha", "split"), 1022 [Value::Record(record), Value::from_str("1000000000u64").unwrap()].iter(), // 1000 credits 1023 None, 1024 0, 1025 None, 1026 rng, 1027 ) 1028 .unwrap(); 1029 let records = transaction.records().collect_vec(); 1030 let first_record = records[0].1.clone().decrypt(&caller_view_key).unwrap(); 1031 let second_record = records[1].1.clone().decrypt(&caller_view_key).unwrap(); 1032 let block = sample_next_block(&vm, &caller_private_key, &[transaction], rng).unwrap(); 1033 vm.add_next_block(&block).unwrap(); 1034 1035 // Split again. 1036 let mut transactions = Vec::new(); 1037 let transaction = vm 1038 .execute( 1039 &caller_private_key, 1040 ("credits.alpha", "split"), 1041 [Value::Record(first_record), Value::from_str("100000000u64").unwrap()].iter(), // 100 credits 1042 None, 1043 0, 1044 None, 1045 rng, 1046 ) 1047 .unwrap(); 1048 let records = transaction.records().collect_vec(); 1049 let first_record = records[0].1.clone().decrypt(&caller_view_key).unwrap(); 1050 let third_record = records[1].1.clone().decrypt(&caller_view_key).unwrap(); 1051 transactions.push(transaction); 1052 // Split again. 1053 let transaction = vm 1054 .execute( 1055 &caller_private_key, 1056 ("credits.alpha", "split"), 1057 [Value::Record(second_record), Value::from_str("100000000u64").unwrap()].iter(), // 100 credits 1058 None, 1059 0, 1060 None, 1061 rng, 1062 ) 1063 .unwrap(); 1064 let records = transaction.records().collect_vec(); 1065 let second_record = records[0].1.clone().decrypt(&caller_view_key).unwrap(); 1066 let fourth_record = records[1].1.clone().decrypt(&caller_view_key).unwrap(); 1067 transactions.push(transaction); 1068 // Add the split transactions to a block and update the VM. 1069 let fee_block = sample_next_block(&vm, &caller_private_key, &transactions, rng).unwrap(); 1070 vm.add_next_block(&fee_block).unwrap(); 1071 1072 // Deploy the programs. 1073 let first_program = r" 1074 program test_program_1.alpha; 1075 mapping map_0: 1076 key as field.public; 1077 value as field.public; 1078 function init: 1079 async init into r0; 1080 output r0 as test_program_1.alpha/init.future; 1081 finalize init: 1082 set 0field into map_0[0field]; 1083 function getter: 1084 async getter into r0; 1085 output r0 as test_program_1.alpha/getter.future; 1086 finalize getter: 1087 get map_0[0field] into r0; 1088 "; 1089 let second_program = r" 1090 program test_program_2.alpha; 1091 mapping map_0: 1092 key as field.public; 1093 value as field.public; 1094 function init: 1095 async init into r0; 1096 output r0 as test_program_2.alpha/init.future; 1097 finalize init: 1098 set 0field into map_0[0field]; 1099 function getter: 1100 async getter into r0; 1101 output r0 as test_program_2.alpha/getter.future; 1102 finalize getter: 1103 get map_0[0field] into r0; 1104 "; 1105 let first_deployment = vm 1106 .deploy(&caller_private_key, &Program::from_str(first_program).unwrap(), Some(first_record), 1, None, rng) 1107 .unwrap(); 1108 let second_deployment = vm 1109 .deploy(&caller_private_key, &Program::from_str(second_program).unwrap(), Some(second_record), 1, None, rng) 1110 .unwrap(); 1111 let deployment_block = 1112 sample_next_block(&vm, &caller_private_key, &[first_deployment, second_deployment], rng).unwrap(); 1113 vm.add_next_block(&deployment_block).unwrap(); 1114 1115 // Execute the programs. 1116 let first_execution = vm 1117 .execute( 1118 &caller_private_key, 1119 ("test_program_1.alpha", "init"), 1120 Vec::<Value<MainnetV0>>::new().iter(), 1121 Some(third_record), 1122 1, 1123 None, 1124 rng, 1125 ) 1126 .unwrap(); 1127 let second_execution = vm 1128 .execute( 1129 &caller_private_key, 1130 ("test_program_2.alpha", "init"), 1131 Vec::<Value<MainnetV0>>::new().iter(), 1132 Some(fourth_record), 1133 1, 1134 None, 1135 rng, 1136 ) 1137 .unwrap(); 1138 let execution_block = 1139 sample_next_block(&vm, &caller_private_key, &[first_execution, second_execution], rng).unwrap(); 1140 vm.add_next_block(&execution_block).unwrap(); 1141 } 1142 1143 #[test] 1144 fn test_load_deployments_with_imports() { 1145 // NOTE: This seed was chosen for the CI's RNG to ensure that the test passes. 1146 let rng = &mut TestRng::fixed(123456789); 1147 1148 // Initialize a new caller. 1149 let caller_private_key = PrivateKey::<CurrentNetwork>::new(rng).unwrap(); 1150 let caller_view_key = ViewKey::try_from(&caller_private_key).unwrap(); 1151 1152 // Initialize the VM. 1153 let vm = crate::vm::test_helpers::sample_vm(); 1154 // Initialize the genesis block. 1155 let genesis = vm.genesis_beacon(&caller_private_key, rng).unwrap(); 1156 // Update the VM. 1157 vm.add_next_block(&genesis).unwrap(); 1158 1159 // Fetch the unspent records. 1160 let records = genesis.transitions().cloned().flat_map(Transition::into_records).collect::<Vec<(_, _)>>(); 1161 trace!("Unspent Records:\n{:#?}", records); 1162 let record_0 = records[0].1.decrypt(&caller_view_key).unwrap(); 1163 let record_1 = records[1].1.decrypt(&caller_view_key).unwrap(); 1164 let record_2 = records[2].1.decrypt(&caller_view_key).unwrap(); 1165 let record_3 = records[3].1.decrypt(&caller_view_key).unwrap(); 1166 1167 // Create the deployment for the first program. 1168 let program_1 = r" 1169 program first_program.alpha; 1170 1171 function c: 1172 input r0 as u8.private; 1173 input r1 as u8.private; 1174 add r0 r1 into r2; 1175 output r2 as u8.private; 1176 "; 1177 let deployment_1 = vm 1178 .deploy(&caller_private_key, &Program::from_str(program_1).unwrap(), Some(record_0), 0, None, rng) 1179 .unwrap(); 1180 1181 // Deploy the first program. 1182 let deployment_block = sample_next_block(&vm, &caller_private_key, &[deployment_1.clone()], rng).unwrap(); 1183 vm.add_next_block(&deployment_block).unwrap(); 1184 1185 // Create the deployment for the second program. 1186 let program_2 = r" 1187 import first_program.alpha; 1188 1189 program second_program.alpha; 1190 1191 function b: 1192 input r0 as u8.private; 1193 input r1 as u8.private; 1194 call first_program.alpha/c r0 r1 into r2; 1195 output r2 as u8.private; 1196 "; 1197 let deployment_2 = vm 1198 .deploy(&caller_private_key, &Program::from_str(program_2).unwrap(), Some(record_1), 0, None, rng) 1199 .unwrap(); 1200 1201 // Deploy the second program. 1202 let deployment_block = sample_next_block(&vm, &caller_private_key, &[deployment_2.clone()], rng).unwrap(); 1203 vm.add_next_block(&deployment_block).unwrap(); 1204 1205 // Create the deployment for the third program. 1206 let program_3 = r" 1207 import second_program.alpha; 1208 1209 program third_program.alpha; 1210 1211 function a: 1212 input r0 as u8.private; 1213 input r1 as u8.private; 1214 call second_program.alpha/b r0 r1 into r2; 1215 output r2 as u8.private; 1216 "; 1217 let deployment_3 = vm 1218 .deploy(&caller_private_key, &Program::from_str(program_3).unwrap(), Some(record_2), 0, None, rng) 1219 .unwrap(); 1220 1221 // Create the deployment for the fourth program. 1222 let program_4 = r" 1223 import second_program.alpha; 1224 import first_program.alpha; 1225 1226 program fourth_program.alpha; 1227 1228 function a: 1229 input r0 as u8.private; 1230 input r1 as u8.private; 1231 call second_program.alpha/b r0 r1 into r2; 1232 output r2 as u8.private; 1233 "; 1234 let deployment_4 = vm 1235 .deploy(&caller_private_key, &Program::from_str(program_4).unwrap(), Some(record_3), 0, None, rng) 1236 .unwrap(); 1237 1238 // Deploy the third and fourth program together. 1239 let deployment_block = 1240 sample_next_block(&vm, &caller_private_key, &[deployment_3.clone(), deployment_4.clone()], rng).unwrap(); 1241 vm.add_next_block(&deployment_block).unwrap(); 1242 1243 // Sanity check the ordering of the deployment transaction IDs from storage. 1244 { 1245 let deployment_transaction_ids = 1246 vm.transaction_store().deployment_transaction_ids().map(|id| *id).collect::<Vec<_>>(); 1247 // This assert check is here to ensure that we are properly loading imports even though any order will work for `VM::from`. 1248 // Note: `deployment_transaction_ids` is sorted lexicographically by transaction ID, so the order may change if we update internal methods. 1249 assert_eq!( 1250 deployment_transaction_ids, 1251 vec![deployment_1.id(), deployment_2.id(), deployment_4.id(), deployment_3.id()], 1252 "Update me if serialization has changed" 1253 ); 1254 } 1255 1256 // Enforce that the VM can load properly with the imports. 1257 assert!(VM::from(vm.store.clone()).is_ok()); 1258 } 1259 1260 #[test] 1261 fn test_multiple_external_calls() { 1262 let rng = &mut TestRng::default(); 1263 1264 // Initialize a new caller. 1265 let caller_private_key = crate::vm::test_helpers::sample_genesis_private_key(rng); 1266 let caller_view_key = ViewKey::try_from(&caller_private_key).unwrap(); 1267 let address = Address::try_from(&caller_private_key).unwrap(); 1268 1269 // Initialize the genesis block. 1270 let genesis = crate::vm::test_helpers::sample_genesis_block(rng); 1271 1272 // Fetch the unspent records. 1273 let records = 1274 genesis.transitions().cloned().flat_map(Transition::into_records).take(3).collect::<IndexMap<_, _>>(); 1275 trace!("Unspent Records:\n{:#?}", records); 1276 let record_0 = records.values().next().unwrap().decrypt(&caller_view_key).unwrap(); 1277 let record_1 = records.values().nth(1).unwrap().decrypt(&caller_view_key).unwrap(); 1278 let record_2 = records.values().nth(2).unwrap().decrypt(&caller_view_key).unwrap(); 1279 1280 // Initialize the VM. 1281 let vm = sample_vm(); 1282 // Update the VM. 1283 vm.add_next_block(&genesis).unwrap(); 1284 1285 // Deploy the program. 1286 let program = Program::from_str( 1287 r" 1288 import credits.alpha; 1289 1290 program test_multiple_external_calls.alpha; 1291 1292 function multitransfer: 1293 input r0 as credits.alpha/credits.record; 1294 input r1 as address.private; 1295 input r2 as u64.private; 1296 call credits.alpha/transfer_private r0 r1 r2 into r3 r4; 1297 call credits.alpha/transfer_private r4 r1 r2 into r5 r6; 1298 output r4 as credits.alpha/credits.record; 1299 output r5 as credits.alpha/credits.record; 1300 output r6 as credits.alpha/credits.record; 1301 ", 1302 ) 1303 .unwrap(); 1304 let deployment = vm.deploy(&caller_private_key, &program, Some(record_0), 1, None, rng).unwrap(); 1305 vm.add_next_block(&sample_next_block(&vm, &caller_private_key, &[deployment], rng).unwrap()).unwrap(); 1306 1307 // Execute the programs. 1308 let inputs = [ 1309 Value::<MainnetV0>::Record(record_1), 1310 Value::<MainnetV0>::from_str(&address.to_string()).unwrap(), 1311 Value::<MainnetV0>::from_str("10u64").unwrap(), 1312 ]; 1313 let execution = vm 1314 .execute( 1315 &caller_private_key, 1316 ("test_multiple_external_calls.alpha", "multitransfer"), 1317 inputs.into_iter(), 1318 Some(record_2), 1319 1, 1320 None, 1321 rng, 1322 ) 1323 .unwrap(); 1324 vm.add_next_block(&sample_next_block(&vm, &caller_private_key, &[execution], rng).unwrap()).unwrap(); 1325 } 1326 1327 #[test] 1328 fn test_nested_deployment_with_assert() { 1329 let rng = &mut TestRng::default(); 1330 1331 // Initialize a private key. 1332 let private_key = sample_genesis_private_key(rng); 1333 1334 // Initialize the genesis block. 1335 let genesis = sample_genesis_block(rng); 1336 1337 // Initialize the VM. 1338 let vm = sample_vm(); 1339 // Update the VM. 1340 vm.add_next_block(&genesis).unwrap(); 1341 1342 // Deploy the base program. 1343 let program = Program::from_str( 1344 r" 1345 program child_program.alpha; 1346 1347 function check: 1348 input r0 as field.private; 1349 assert.eq r0 123456789123456789123456789123456789123456789123456789field; 1350 ", 1351 ) 1352 .unwrap(); 1353 1354 let deployment = vm.deploy(&private_key, &program, None, 0, None, rng).unwrap(); 1355 assert!(vm.check_transaction(&deployment, None, rng).is_ok()); 1356 vm.add_next_block(&sample_next_block(&vm, &private_key, &[deployment], rng).unwrap()).unwrap(); 1357 1358 // Check that program is deployed. 1359 assert!(vm.contains_program(&ProgramID::from_str("child_program.alpha").unwrap())); 1360 1361 // Deploy the program that calls the program from the previous layer. 1362 let program = Program::from_str( 1363 r" 1364 import child_program.alpha; 1365 1366 program parent_program.alpha; 1367 1368 function check: 1369 input r0 as field.private; 1370 call child_program.alpha/check r0; 1371 ", 1372 ) 1373 .unwrap(); 1374 1375 let deployment = vm.deploy(&private_key, &program, None, 0, None, rng).unwrap(); 1376 assert!(vm.check_transaction(&deployment, None, rng).is_ok()); 1377 vm.add_next_block(&sample_next_block(&vm, &private_key, &[deployment], rng).unwrap()).unwrap(); 1378 1379 // Check that program is deployed. 1380 assert!(vm.contains_program(&ProgramID::from_str("parent_program.alpha").unwrap())); 1381 } 1382 1383 #[test] 1384 fn test_deployment_with_external_records() { 1385 let rng = &mut TestRng::default(); 1386 1387 // Initialize a private key. 1388 let private_key = sample_genesis_private_key(rng); 1389 1390 // Initialize the genesis block. 1391 let genesis = sample_genesis_block(rng); 1392 1393 // Initialize the VM. 1394 let vm = sample_vm(); 1395 // Update the VM. 1396 vm.add_next_block(&genesis).unwrap(); 1397 1398 // Deploy the program. 1399 let program = Program::from_str( 1400 r" 1401 import credits.alpha; 1402 program test_program.alpha; 1403 1404 function transfer: 1405 input r0 as credits.alpha/credits.record; 1406 input r1 as u64.private; 1407 input r2 as u64.private; 1408 input r3 as [address; 10u32].private; 1409 call credits.alpha/transfer_private r0 r3[0u32] r1 into r4 r5; 1410 call credits.alpha/transfer_private r5 r3[0u32] r2 into r6 r7; 1411 ", 1412 ) 1413 .unwrap(); 1414 1415 let deployment = vm.deploy(&private_key, &program, None, 0, None, rng).unwrap(); 1416 assert!(vm.check_transaction(&deployment, None, rng).is_ok()); 1417 vm.add_next_block(&sample_next_block(&vm, &private_key, &[deployment], rng).unwrap()).unwrap(); 1418 1419 // Check that program is deployed. 1420 assert!(vm.contains_program(&ProgramID::from_str("test_program.alpha").unwrap())); 1421 } 1422 1423 #[test] 1424 fn test_internal_fee_calls_are_invalid() { 1425 let rng = &mut TestRng::default(); 1426 1427 // Initialize a private key. 1428 let private_key = sample_genesis_private_key(rng); 1429 let view_key = ViewKey::try_from(&private_key).unwrap(); 1430 1431 // Initialize the genesis block. 1432 let genesis = sample_genesis_block(rng); 1433 1434 // Initialize the VM. 1435 let vm = sample_vm(); 1436 // Update the VM. 1437 vm.add_next_block(&genesis).unwrap(); 1438 1439 // Fetch the unspent records. 1440 let records = 1441 genesis.transitions().cloned().flat_map(Transition::into_records).take(3).collect::<IndexMap<_, _>>(); 1442 trace!("Unspent Records:\n{:#?}", records); 1443 let record_0 = records.values().next().unwrap().decrypt(&view_key).unwrap(); 1444 1445 // Deploy the program. 1446 let program = Program::from_str( 1447 r" 1448 import credits.alpha; 1449 program test_program.alpha; 1450 1451 function call_fee_public: 1452 input r0 as u64.private; 1453 input r1 as u64.private; 1454 input r2 as field.private; 1455 call credits.alpha/fee_public r0 r1 r2 into r3; 1456 async call_fee_public r3 into r4; 1457 output r4 as test_program.alpha/call_fee_public.future; 1458 1459 finalize call_fee_public: 1460 input r0 as credits.alpha/fee_public.future; 1461 await r0; 1462 1463 function call_fee_private: 1464 input r0 as credits.alpha/credits.record; 1465 input r1 as u64.private; 1466 input r2 as u64.private; 1467 input r3 as field.private; 1468 call credits.alpha/fee_private r0 r1 r2 r3 into r4; 1469 output r4 as credits.alpha/credits.record; 1470 ", 1471 ) 1472 .unwrap(); 1473 1474 let deployment = vm.deploy(&private_key, &program, None, 0, None, rng).unwrap(); 1475 assert!(vm.check_transaction(&deployment, None, rng).is_ok()); 1476 vm.add_next_block(&sample_next_block(&vm, &private_key, &[deployment], rng).unwrap()).unwrap(); 1477 1478 // Execute the programs. 1479 let internal_base_fee_amount: u64 = rng.gen_range(1..1000); 1480 let internal_priority_fee_amount: u64 = rng.gen_range(1..1000); 1481 1482 // Ensure that the transaction that calls `fee_public` internally cannot be generated. 1483 let inputs = [ 1484 Value::<MainnetV0>::from_str(&format!("{internal_base_fee_amount}u64")).unwrap(), 1485 Value::<MainnetV0>::from_str(&format!("{internal_priority_fee_amount}u64")).unwrap(), 1486 Value::<MainnetV0>::from_str("1field").unwrap(), 1487 ]; 1488 assert!( 1489 vm.execute(&private_key, ("test_program.alpha", "call_fee_public"), inputs.into_iter(), None, 0, None, rng) 1490 .is_err() 1491 ); 1492 1493 // Ensure that the transaction that calls `fee_private` internally cannot be generated. 1494 let inputs = [ 1495 Value::<MainnetV0>::Record(record_0), 1496 Value::<MainnetV0>::from_str(&format!("{internal_base_fee_amount}u64")).unwrap(), 1497 Value::<MainnetV0>::from_str(&format!("{internal_priority_fee_amount}u64")).unwrap(), 1498 Value::<MainnetV0>::from_str("1field").unwrap(), 1499 ]; 1500 assert!( 1501 vm.execute( 1502 &private_key, 1503 ("test_program.alpha", "call_fee_private"), 1504 inputs.into_iter(), 1505 None, 1506 0, 1507 None, 1508 rng 1509 ) 1510 .is_err() 1511 ); 1512 } 1513 1514 #[test] 1515 #[ignore = "memory-intensive"] 1516 fn test_deployment_synthesis_overload() { 1517 let rng = &mut TestRng::default(); 1518 1519 // Initialize a private key. 1520 let private_key = sample_genesis_private_key(rng); 1521 1522 // Initialize the genesis block. 1523 let genesis = sample_genesis_block(rng); 1524 1525 // Initialize the VM. 1526 let vm = sample_vm(); 1527 // Update the VM. 1528 vm.add_next_block(&genesis).unwrap(); 1529 1530 // Deploy the base program. 1531 let program = Program::from_str( 1532 r" 1533 program synthesis_overload.alpha; 1534 1535 function do: 1536 input r0 as [[u128; 32u32]; 2u32].private; 1537 hash.sha3_256 r0 into r1 as field; 1538 hash.sha3_256 r0 into r2 as field; 1539 output r2 as field.public;", 1540 ) 1541 .unwrap(); 1542 1543 // Create the deployment transaction. 1544 let deployment = vm.deploy(&private_key, &program, None, 0, None, rng).unwrap(); 1545 1546 // Verify the deployment transaction. It should fail because there are too many constraints. 1547 assert!(vm.check_transaction(&deployment, None, rng).is_err()); 1548 } 1549 1550 #[test] 1551 fn test_deployment_num_constant_overload() { 1552 let rng = &mut TestRng::default(); 1553 1554 // Initialize a private key. 1555 let private_key = sample_genesis_private_key(rng); 1556 1557 // Initialize the genesis block. 1558 let genesis = sample_genesis_block(rng); 1559 1560 // Initialize the VM. 1561 let vm = sample_vm(); 1562 // Update the VM. 1563 vm.add_next_block(&genesis).unwrap(); 1564 1565 // Deploy the base program. 1566 let program = Program::from_str( 1567 r" 1568 program synthesis_num_constants.alpha; 1569 function do: 1570 cast 0u32 0u32 0u32 0u32 0u32 0u32 0u32 0u32 0u32 0u32 0u32 0u32 0u32 0u32 0u32 0u32 0u32 0u32 0u32 0u32 0u32 0u32 0u32 0u32 0u32 0u32 0u32 0u32 0u32 0u32 0u32 0u32 into r0 as [u32; 32u32]; 1571 cast r0 r0 r0 r0 r0 r0 r0 r0 r0 r0 r0 r0 r0 r0 r0 r0 r0 r0 r0 r0 r0 r0 r0 r0 r0 r0 r0 r0 r0 r0 r0 r0 into r1 as [[u32; 32u32]; 32u32]; 1572 cast r1 r1 r1 r1 r1 into r2 as [[[u32; 32u32]; 32u32]; 5u32]; 1573 cast r1 r1 r1 r1 r1 into r3 as [[[u32; 32u32]; 32u32]; 5u32]; 1574 hash.bhp1024 r2 into r4 as u32; 1575 hash.bhp1024 r3 into r5 as u32; 1576 output r4 as u32.private; 1577 function do2: 1578 cast 0u32 0u32 0u32 0u32 0u32 0u32 0u32 0u32 0u32 0u32 0u32 0u32 0u32 0u32 0u32 0u32 0u32 0u32 0u32 0u32 0u32 0u32 0u32 0u32 0u32 0u32 0u32 0u32 0u32 0u32 0u32 0u32 into r0 as [u32; 32u32]; 1579 cast r0 r0 r0 r0 r0 r0 r0 r0 r0 r0 r0 r0 r0 r0 r0 r0 r0 r0 r0 r0 r0 r0 r0 r0 r0 r0 r0 r0 r0 r0 r0 r0 into r1 as [[u32; 32u32]; 32u32]; 1580 cast r1 r1 r1 r1 r1 into r2 as [[[u32; 32u32]; 32u32]; 5u32]; 1581 hash.bhp1024 r2 into r3 as u32; 1582 output r3 as u32.private;", 1583 ) 1584 .unwrap(); 1585 1586 // Create the deployment transaction. 1587 let deployment = vm.deploy(&private_key, &program, None, 0, None, rng).unwrap(); 1588 1589 // Verify the deployment transaction. It should fail because there are too many constants. 1590 let check_tx_res = vm.check_transaction(&deployment, None, rng); 1591 assert!(check_tx_res.is_err()); 1592 } 1593 1594 #[test] 1595 fn test_deployment_synthesis_overreport() { 1596 let rng = &mut TestRng::default(); 1597 1598 // Initialize a private key. 1599 let private_key = sample_genesis_private_key(rng); 1600 1601 // Initialize the genesis block. 1602 let genesis = sample_genesis_block(rng); 1603 1604 // Initialize the VM. 1605 let vm = sample_vm(); 1606 // Update the VM. 1607 vm.add_next_block(&genesis).unwrap(); 1608 1609 // Deploy the base program. 1610 let program = Program::from_str( 1611 r" 1612 program synthesis_overreport.alpha; 1613 1614 function do: 1615 input r0 as u32.private; 1616 add r0 r0 into r1; 1617 output r1 as u32.public;", 1618 ) 1619 .unwrap(); 1620 1621 // Create the deployment transaction. 1622 let transaction = vm.deploy(&private_key, &program, None, 0, None, rng).unwrap(); 1623 1624 // Destructure the deployment transaction. 1625 let Transaction::Deploy(_, _, program_owner, deployment, fee) = transaction else { 1626 panic!("Expected a deployment transaction"); 1627 }; 1628 1629 // Increase the number of constraints in the verifying keys. 1630 let mut vks_with_overreport = Vec::with_capacity(deployment.verifying_keys().len()); 1631 for (id, (vk, cert)) in deployment.verifying_keys() { 1632 let mut vk_deref = vk.deref().clone(); 1633 vk_deref.circuit_info.num_constraints += 1; 1634 let vk = VerifyingKey::new(Arc::new(vk_deref), vk.num_variables()); 1635 vks_with_overreport.push((*id, (vk, cert.clone()))); 1636 } 1637 1638 // Each additional constraint costs 25 microcredits, so we need to increase the fee by 25 microcredits. 1639 let required_fee = *fee.base_amount().unwrap() + 25; 1640 // Authorize a new fee. 1641 let fee_authorization = vm 1642 .authorize_fee_public(&private_key, required_fee, 0, deployment.as_ref().to_deployment_id().unwrap(), rng) 1643 .unwrap(); 1644 // Compute the fee. 1645 let fee = vm.execute_fee_authorization(fee_authorization, None, rng).unwrap(); 1646 1647 // Create a new deployment transaction with the overreported verifying keys. 1648 let adjusted_deployment = Deployment::new( 1649 deployment.edition(), 1650 deployment.program().clone(), 1651 vks_with_overreport, 1652 deployment.program_checksum(), 1653 deployment.program_owner(), 1654 ) 1655 .unwrap(); 1656 let adjusted_transaction = Transaction::from_deployment(program_owner, adjusted_deployment, fee).unwrap(); 1657 1658 // Verify the deployment transaction. It should error when certificate checking for constraint count mismatch. 1659 let res = vm.check_transaction(&adjusted_transaction, None, rng); 1660 assert!(res.is_err()); 1661 } 1662 1663 #[test] 1664 fn test_deployment_synthesis_underreport() { 1665 let rng = &mut TestRng::default(); 1666 1667 // Initialize a private key. 1668 let private_key = sample_genesis_private_key(rng); 1669 let address = Address::try_from(&private_key).unwrap(); 1670 1671 // Initialize the genesis block. 1672 let genesis = sample_genesis_block(rng); 1673 1674 // Initialize the VM. 1675 let vm = sample_vm(); 1676 // Update the VM. 1677 vm.add_next_block(&genesis).unwrap(); 1678 1679 // Deploy the base program. 1680 let program = Program::from_str( 1681 r" 1682 program synthesis_underreport.alpha; 1683 1684 function do: 1685 input r0 as u32.private; 1686 add r0 r0 into r1; 1687 output r1 as u32.public;", 1688 ) 1689 .unwrap(); 1690 1691 // Create the deployment transaction. 1692 let transaction = vm.deploy(&private_key, &program, None, 0, None, rng).unwrap(); 1693 1694 // Destructure the deployment transaction. 1695 let Transaction::Deploy(txid, _, program_owner, deployment, fee) = transaction else { 1696 panic!("Expected a deployment transaction"); 1697 }; 1698 1699 // Decrease the number of constraints in the verifying keys. 1700 let mut vks_with_underreport = Vec::with_capacity(deployment.verifying_keys().len()); 1701 for (id, (vk, cert)) in deployment.verifying_keys() { 1702 let mut vk_deref = vk.deref().clone(); 1703 vk_deref.circuit_info.num_constraints -= 2; 1704 let vk = VerifyingKey::new(Arc::new(vk_deref), vk.num_variables()); 1705 vks_with_underreport.push((*id, (vk, cert.clone()))); 1706 } 1707 1708 // Create a new deployment transaction with the underreported verifying keys. 1709 let adjusted_deployment = Deployment::new( 1710 deployment.edition(), 1711 deployment.program().clone(), 1712 vks_with_underreport, 1713 deployment.program_checksum(), 1714 deployment.program_owner(), 1715 ) 1716 .unwrap(); 1717 let deployment_id = adjusted_deployment.to_deployment_id().unwrap(); 1718 let adjusted_transaction = 1719 Transaction::Deploy(txid, deployment_id, program_owner, Box::new(adjusted_deployment), fee); 1720 1721 // Verify the deployment transaction. It should error when enforcing the first constraint over the vk limit. 1722 let result = vm.check_transaction(&adjusted_transaction, None, rng); 1723 assert!(result.is_err()); 1724 1725 // Create a standard transaction 1726 // Prepare the inputs. 1727 let inputs = [ 1728 Value::<CurrentNetwork>::from_str(&address.to_string()).unwrap(), 1729 Value::<CurrentNetwork>::from_str("1u64").unwrap(), 1730 ] 1731 .into_iter(); 1732 1733 // Execute. 1734 let transaction = 1735 vm.execute(&private_key, ("credits.alpha", "transfer_public"), inputs, None, 0, None, rng).unwrap(); 1736 1737 // Check that the deployment transaction will be aborted if injected into a block. 1738 let block = sample_next_block(&vm, &private_key, &[transaction, adjusted_transaction.clone()], rng).unwrap(); 1739 1740 // Check that the block aborts the deployment transaction. 1741 assert_eq!(block.aborted_transaction_ids(), &vec![adjusted_transaction.id()]); 1742 1743 // Update the VM. 1744 vm.add_next_block(&block).unwrap(); 1745 } 1746 1747 #[test] 1748 fn test_deployment_variable_underreport() { 1749 let rng = &mut TestRng::default(); 1750 1751 // Initialize a private key. 1752 let private_key = sample_genesis_private_key(rng); 1753 let address = Address::try_from(&private_key).unwrap(); 1754 1755 // Initialize the genesis block. 1756 let genesis = sample_genesis_block(rng); 1757 1758 // Initialize the VM. 1759 let vm = sample_vm(); 1760 // Update the VM. 1761 vm.add_next_block(&genesis).unwrap(); 1762 1763 // Deploy the base program. 1764 let program = Program::from_str( 1765 r" 1766 program synthesis_underreport.alpha; 1767 function do: 1768 input r0 as u32.private; 1769 add r0 r0 into r1; 1770 output r1 as u32.public;", 1771 ) 1772 .unwrap(); 1773 1774 // Create the deployment transaction. 1775 let transaction = vm.deploy(&private_key, &program, None, 0, None, rng).unwrap(); 1776 1777 // Destructure the deployment transaction. 1778 let Transaction::Deploy(txid, _, program_owner, deployment, fee) = transaction else { 1779 panic!("Expected a deployment transaction"); 1780 }; 1781 1782 // Decrease the number of reported variables in the verifying keys. 1783 let mut vks_with_underreport = Vec::with_capacity(deployment.verifying_keys().len()); 1784 for (id, (vk, cert)) in deployment.verifying_keys() { 1785 let vk = VerifyingKey::new(Arc::new(vk.deref().clone()), vk.num_variables() - 2); 1786 vks_with_underreport.push((*id, (vk.clone(), cert.clone()))); 1787 } 1788 1789 // Create a new deployment transaction with the underreported verifying keys. 1790 let adjusted_deployment = Deployment::new( 1791 deployment.edition(), 1792 deployment.program().clone(), 1793 vks_with_underreport, 1794 deployment.program_checksum(), 1795 deployment.program_owner(), 1796 ) 1797 .unwrap(); 1798 let deployment_id = adjusted_deployment.to_deployment_id().unwrap(); 1799 let adjusted_transaction = 1800 Transaction::Deploy(txid, deployment_id, program_owner, Box::new(adjusted_deployment), fee); 1801 1802 // Verify the deployment transaction. It should error when synthesizing the first variable over the vk limit. 1803 let result = vm.check_transaction(&adjusted_transaction, None, rng); 1804 assert!(result.is_err()); 1805 1806 // Create a standard transaction 1807 // Prepare the inputs. 1808 let inputs = [ 1809 Value::<CurrentNetwork>::from_str(&address.to_string()).unwrap(), 1810 Value::<CurrentNetwork>::from_str("1u64").unwrap(), 1811 ] 1812 .into_iter(); 1813 1814 // Execute. 1815 let transaction = 1816 vm.execute(&private_key, ("credits.alpha", "transfer_public"), inputs, None, 0, None, rng).unwrap(); 1817 1818 // Check that the deployment transaction will be aborted if injected into a block. 1819 let block = sample_next_block(&vm, &private_key, &[transaction, adjusted_transaction.clone()], rng).unwrap(); 1820 1821 // Check that the block aborts the deployment transaction. 1822 assert_eq!(block.aborted_transaction_ids(), &vec![adjusted_transaction.id()]); 1823 1824 // Update the VM. 1825 vm.add_next_block(&block).unwrap(); 1826 } 1827 1828 #[test] 1829 #[ignore] 1830 fn test_deployment_memory_overload() { 1831 const NUM_DEPLOYMENTS: usize = 32; 1832 1833 let rng = &mut TestRng::default(); 1834 1835 // Initialize a private key. 1836 let private_key = sample_genesis_private_key(rng); 1837 1838 // Initialize a view key. 1839 let view_key = ViewKey::try_from(&private_key).unwrap(); 1840 1841 // Initialize the genesis block. 1842 let genesis = sample_genesis_block(rng); 1843 1844 // Initialize the VM. 1845 let vm = sample_vm(); 1846 // Update the VM. 1847 vm.add_next_block(&genesis).unwrap(); 1848 1849 // Deploy the base program. 1850 let program = Program::from_str( 1851 r" 1852 program program_layer_0.alpha; 1853 1854 mapping m: 1855 key as u8.public; 1856 value as u32.public; 1857 1858 function do: 1859 input r0 as u32.public; 1860 async do r0 into r1; 1861 output r1 as program_layer_0.alpha/do.future; 1862 1863 finalize do: 1864 input r0 as u32.public; 1865 set r0 into m[0u8];", 1866 ) 1867 .unwrap(); 1868 1869 let deployment = vm.deploy(&private_key, &program, None, 0, None, rng).unwrap(); 1870 vm.add_next_block(&sample_next_block(&vm, &private_key, &[deployment], rng).unwrap()).unwrap(); 1871 1872 // For each layer, deploy a program that calls the program from the previous layer. 1873 for i in 1..NUM_DEPLOYMENTS { 1874 let mut program_string = String::new(); 1875 // Add the import statements. 1876 for j in 0..i { 1877 program_string.push_str(&format!("import program_layer_{j}.alpha;\n")); 1878 } 1879 // Add the program body. 1880 program_string.push_str(&format!( 1881 "program program_layer_{i}.alpha; 1882 1883 mapping m: 1884 key as u8.public; 1885 value as u32.public; 1886 1887 function do: 1888 input r0 as u32.public; 1889 call program_layer_{prev}.alpha/do r0 into r1; 1890 async do r0 r1 into r2; 1891 output r2 as program_layer_{i}.alpha/do.future; 1892 1893 finalize do: 1894 input r0 as u32.public; 1895 input r1 as program_layer_{prev}.alpha/do.future; 1896 await r1; 1897 set r0 into m[0u8];", 1898 prev = i - 1 1899 )); 1900 // Construct the program. 1901 let program = Program::from_str(&program_string).unwrap(); 1902 1903 // Deploy the program. 1904 let deployment = vm.deploy(&private_key, &program, None, 0, None, rng).unwrap(); 1905 1906 vm.add_next_block(&sample_next_block(&vm, &private_key, &[deployment], rng).unwrap()).unwrap(); 1907 } 1908 1909 // Fetch the unspent records. 1910 let records = genesis.transitions().cloned().flat_map(Transition::into_records).collect::<IndexMap<_, _>>(); 1911 trace!("Unspent Records:\n{:#?}", records); 1912 1913 // Select a record to spend. 1914 let record = Some(records.values().next().unwrap().decrypt(&view_key).unwrap()); 1915 1916 // Prepare the inputs. 1917 let inputs = [Value::<CurrentNetwork>::from_str("1u32").unwrap()].into_iter(); 1918 1919 // Execute. 1920 let transaction = 1921 vm.execute(&private_key, ("program_layer_30.alpha", "do"), inputs, record, 0, None, rng).unwrap(); 1922 1923 // Verify. 1924 vm.check_transaction(&transaction, None, rng).unwrap(); 1925 } 1926 1927 #[test] 1928 fn test_transfer_public_from_user() { 1929 let rng = &mut TestRng::default(); 1930 1931 // Initialize a new caller. 1932 let caller_private_key = crate::vm::test_helpers::sample_genesis_private_key(rng); 1933 let caller_address = Address::try_from(&caller_private_key).unwrap(); 1934 1935 // Initialize a recipient. 1936 let recipient_private_key = PrivateKey::new(rng).unwrap(); 1937 let recipient_address = Address::try_from(&recipient_private_key).unwrap(); 1938 1939 // Initialize the genesis block. 1940 let genesis = crate::vm::test_helpers::sample_genesis_block(rng); 1941 1942 // Initialize the VM. 1943 let vm = crate::vm::test_helpers::sample_vm(); 1944 1945 // Update the VM. 1946 vm.add_next_block(&genesis).unwrap(); 1947 1948 // Check the balance of the caller. 1949 let credits_program_id = ProgramID::from_str("credits.alpha").unwrap(); 1950 let account_mapping_name = Identifier::from_str("account").unwrap(); 1951 let balance = match vm 1952 .finalize_store() 1953 .get_value_confirmed( 1954 credits_program_id, 1955 account_mapping_name, 1956 &Plaintext::from(Literal::Address(caller_address)), 1957 ) 1958 .unwrap() 1959 { 1960 Some(Value::Plaintext(Plaintext::Literal(Literal::U64(balance), _))) => *balance, 1961 _ => panic!("Expected a valid balance"), 1962 }; 1963 assert_eq!(balance, 182_499_999_894_112, "Update me if the initial balance changes."); 1964 1965 // Transfer credits from the caller to the recipient. 1966 let transaction = vm 1967 .execute( 1968 &caller_private_key, 1969 ("credits.alpha", "transfer_public"), 1970 [Value::from_str(&format!("{recipient_address}")).unwrap(), Value::from_str("1u64").unwrap()].iter(), 1971 None, 1972 0, 1973 None, 1974 rng, 1975 ) 1976 .unwrap(); 1977 1978 // Verify the transaction. 1979 vm.check_transaction(&transaction, None, rng).unwrap(); 1980 1981 // Add the transaction to a block and update the VM. 1982 let block = sample_next_block(&vm, &caller_private_key, &[transaction], rng).unwrap(); 1983 1984 // Update the VM. 1985 vm.add_next_block(&block).unwrap(); 1986 1987 // Check the balance of the caller. 1988 let balance = match vm 1989 .finalize_store() 1990 .get_value_confirmed( 1991 credits_program_id, 1992 account_mapping_name, 1993 &Plaintext::from(Literal::Address(caller_address)), 1994 ) 1995 .unwrap() 1996 { 1997 Some(Value::Plaintext(Plaintext::Literal(Literal::U64(balance), _))) => *balance, 1998 _ => panic!("Expected a valid balance"), 1999 }; 2000 assert_eq!(balance, 182_499_999_843_051, "Update me if the initial balance changes."); 2001 2002 // Check the balance of the recipient. 2003 let balance = match vm 2004 .finalize_store() 2005 .get_value_confirmed( 2006 credits_program_id, 2007 account_mapping_name, 2008 &Plaintext::from(Literal::Address(recipient_address)), 2009 ) 2010 .unwrap() 2011 { 2012 Some(Value::Plaintext(Plaintext::Literal(Literal::U64(balance), _))) => *balance, 2013 _ => panic!("Expected a valid balance"), 2014 }; 2015 assert_eq!(balance, 1, "Update me if the test amount changes."); 2016 } 2017 2018 #[test] 2019 fn test_transfer_public_as_signer_from_user() { 2020 let rng = &mut TestRng::default(); 2021 2022 // Initialize a new caller. 2023 let caller_private_key = crate::vm::test_helpers::sample_genesis_private_key(rng); 2024 let caller_address = Address::try_from(&caller_private_key).unwrap(); 2025 2026 // Initialize a recipient. 2027 let recipient_private_key = PrivateKey::new(rng).unwrap(); 2028 let recipient_address = Address::try_from(&recipient_private_key).unwrap(); 2029 2030 // Initialize the genesis block. 2031 let genesis = crate::vm::test_helpers::sample_genesis_block(rng); 2032 2033 // Initialize the VM. 2034 let vm = crate::vm::test_helpers::sample_vm(); 2035 2036 // Update the VM. 2037 vm.add_next_block(&genesis).unwrap(); 2038 2039 // Check the balance of the caller. 2040 let credits_program_id = ProgramID::from_str("credits.alpha").unwrap(); 2041 let account_mapping_name = Identifier::from_str("account").unwrap(); 2042 let balance = match vm 2043 .finalize_store() 2044 .get_value_confirmed( 2045 credits_program_id, 2046 account_mapping_name, 2047 &Plaintext::from(Literal::Address(caller_address)), 2048 ) 2049 .unwrap() 2050 { 2051 Some(Value::Plaintext(Plaintext::Literal(Literal::U64(balance), _))) => *balance, 2052 _ => panic!("Expected a valid balance"), 2053 }; 2054 assert_eq!(balance, 182_499_999_894_112, "Update me if the initial balance changes."); 2055 2056 // Transfer credits from the caller to the recipient. 2057 let transaction = vm 2058 .execute( 2059 &caller_private_key, 2060 ("credits.alpha", "transfer_public_as_signer"), 2061 [Value::from_str(&format!("{recipient_address}")).unwrap(), Value::from_str("1u64").unwrap()].iter(), 2062 None, 2063 0, 2064 None, 2065 rng, 2066 ) 2067 .unwrap(); 2068 2069 // Verify the transaction. 2070 vm.check_transaction(&transaction, None, rng).unwrap(); 2071 2072 // Add the transaction to a block and update the VM. 2073 let block = sample_next_block(&vm, &caller_private_key, &[transaction], rng).unwrap(); 2074 2075 // Update the VM. 2076 vm.add_next_block(&block).unwrap(); 2077 2078 // Check the balance of the caller. 2079 let balance = match vm 2080 .finalize_store() 2081 .get_value_confirmed( 2082 credits_program_id, 2083 account_mapping_name, 2084 &Plaintext::from(Literal::Address(caller_address)), 2085 ) 2086 .unwrap() 2087 { 2088 Some(Value::Plaintext(Plaintext::Literal(Literal::U64(balance), _))) => *balance, 2089 _ => panic!("Expected a valid balance"), 2090 }; 2091 assert_eq!(balance, 182_499_999_843_031, "Update me if the initial balance changes."); 2092 2093 // Check the balance of the recipient. 2094 let balance = match vm 2095 .finalize_store() 2096 .get_value_confirmed( 2097 credits_program_id, 2098 account_mapping_name, 2099 &Plaintext::from(Literal::Address(recipient_address)), 2100 ) 2101 .unwrap() 2102 { 2103 Some(Value::Plaintext(Plaintext::Literal(Literal::U64(balance), _))) => *balance, 2104 _ => panic!("Expected a valid balance"), 2105 }; 2106 assert_eq!(balance, 1, "Update me if the test amount changes."); 2107 } 2108 2109 #[test] 2110 fn transfer_public_from_program() { 2111 let rng = &mut TestRng::default(); 2112 2113 // Initialize a new caller. 2114 let caller_private_key = crate::vm::test_helpers::sample_genesis_private_key(rng); 2115 let caller_address = Address::try_from(&caller_private_key).unwrap(); 2116 2117 // Initialize a recipient. 2118 let recipient_private_key = PrivateKey::new(rng).unwrap(); 2119 let recipient_address = Address::try_from(&recipient_private_key).unwrap(); 2120 2121 // Initialize the genesis block. 2122 let genesis = crate::vm::test_helpers::sample_genesis_block(rng); 2123 2124 // Initialize the VM. 2125 let vm = crate::vm::test_helpers::sample_vm(); 2126 2127 // Update the VM. 2128 vm.add_next_block(&genesis).unwrap(); 2129 2130 // Check the balance of the caller. 2131 let credits_program_id = ProgramID::from_str("credits.alpha").unwrap(); 2132 let account_mapping_name = Identifier::from_str("account").unwrap(); 2133 let balance = match vm 2134 .finalize_store() 2135 .get_value_confirmed( 2136 credits_program_id, 2137 account_mapping_name, 2138 &Plaintext::from(Literal::Address(caller_address)), 2139 ) 2140 .unwrap() 2141 { 2142 Some(Value::Plaintext(Plaintext::Literal(Literal::U64(balance), _))) => *balance, 2143 _ => panic!("Expected a valid balance"), 2144 }; 2145 assert_eq!(balance, 182_499_999_894_112, "Update me if the initial balance changes."); 2146 2147 // Initialize a wrapper program, importing `credits.alpha` and calling `transfer_public`. 2148 let program = Program::from_str( 2149 r" 2150 import credits.alpha; 2151 program credits_wrapper.alpha; 2152 2153 function transfer_public: 2154 input r0 as address.public; 2155 input r1 as u64.public; 2156 call credits.alpha/transfer_public r0 r1 into r2; 2157 async transfer_public r2 into r3; 2158 output r3 as credits_wrapper.alpha/transfer_public.future; 2159 2160 finalize transfer_public: 2161 input r0 as credits.alpha/transfer_public.future; 2162 await r0; 2163 ", 2164 ) 2165 .unwrap(); 2166 2167 // Get the address of the wrapper program. 2168 let wrapper_program_id = ProgramID::from_str("credits_wrapper.alpha").unwrap(); 2169 let wrapper_program_address = wrapper_program_id.to_address().unwrap(); 2170 2171 // Deploy the wrapper program. 2172 let deployment = vm.deploy(&caller_private_key, &program, None, 0, None, rng).unwrap(); 2173 2174 // Add the deployment to a block and update the VM. 2175 let block = sample_next_block(&vm, &caller_private_key, &[deployment], rng).unwrap(); 2176 2177 // Update the VM. 2178 vm.add_next_block(&block).unwrap(); 2179 2180 // Transfer credits from the caller to the `credits_wrapper` program. 2181 let transaction = vm 2182 .execute( 2183 &caller_private_key, 2184 ("credits.alpha", "transfer_public"), 2185 [Value::from_str(&format!("{wrapper_program_address}")).unwrap(), Value::from_str("1u64").unwrap()] 2186 .iter(), 2187 None, 2188 0, 2189 None, 2190 rng, 2191 ) 2192 .unwrap(); 2193 2194 // Verify the transaction. 2195 vm.check_transaction(&transaction, None, rng).unwrap(); 2196 2197 // Add the transaction to a block and update the VM. 2198 let block = sample_next_block(&vm, &caller_private_key, &[transaction], rng).unwrap(); 2199 2200 // Update the VM. 2201 vm.add_next_block(&block).unwrap(); 2202 2203 // Check the balance of the caller. 2204 let balance = match vm 2205 .finalize_store() 2206 .get_value_confirmed( 2207 credits_program_id, 2208 account_mapping_name, 2209 &Plaintext::from(Literal::Address(caller_address)), 2210 ) 2211 .unwrap() 2212 { 2213 Some(Value::Plaintext(Plaintext::Literal(Literal::U64(balance), _))) => *balance, 2214 _ => panic!("Expected a valid balance"), 2215 }; 2216 assert_eq!(balance, 182_499_996_914_676, "Update me if the initial balance changes."); 2217 2218 // Check the balance of the `credits_wrapper` program. 2219 let balance = match vm 2220 .finalize_store() 2221 .get_value_confirmed( 2222 credits_program_id, 2223 account_mapping_name, 2224 &Plaintext::from(Literal::Address(wrapper_program_address)), 2225 ) 2226 .unwrap() 2227 { 2228 Some(Value::Plaintext(Plaintext::Literal(Literal::U64(balance), _))) => *balance, 2229 _ => panic!("Expected a valid balance"), 2230 }; 2231 assert_eq!(balance, 1, "Update me if the test amount changes."); 2232 2233 // Transfer credits from the `credits_wrapper` program to the recipient. 2234 let transaction = vm 2235 .execute( 2236 &caller_private_key, 2237 ("credits_wrapper.alpha", "transfer_public"), 2238 [Value::from_str(&format!("{recipient_address}")).unwrap(), Value::from_str("1u64").unwrap()].iter(), 2239 None, 2240 0, 2241 None, 2242 rng, 2243 ) 2244 .unwrap(); 2245 2246 // Verify the transaction. 2247 vm.check_transaction(&transaction, None, rng).unwrap(); 2248 2249 // Add the transaction to a block and update the VM. 2250 let block = sample_next_block(&vm, &caller_private_key, &[transaction], rng).unwrap(); 2251 2252 // Update the VM. 2253 vm.add_next_block(&block).unwrap(); 2254 2255 // Check the balance of the caller. 2256 let balance = match vm 2257 .finalize_store() 2258 .get_value_confirmed( 2259 credits_program_id, 2260 account_mapping_name, 2261 &Plaintext::from(Literal::Address(caller_address)), 2262 ) 2263 .unwrap() 2264 { 2265 Some(Value::Plaintext(Plaintext::Literal(Literal::U64(balance), _))) => *balance, 2266 _ => panic!("Expected a valid balance"), 2267 }; 2268 assert_eq!(balance, 182_499_996_862_151, "Update me if the initial balance changes."); 2269 2270 // Check the balance of the `credits_wrapper` program. 2271 let balance = match vm 2272 .finalize_store() 2273 .get_value_confirmed( 2274 credits_program_id, 2275 account_mapping_name, 2276 &Plaintext::from(Literal::Address(wrapper_program_address)), 2277 ) 2278 .unwrap() 2279 { 2280 Some(Value::Plaintext(Plaintext::Literal(Literal::U64(balance), _))) => *balance, 2281 _ => panic!("Expected a valid balance"), 2282 }; 2283 assert_eq!(balance, 0); 2284 2285 // Check the balance of the recipient. 2286 let balance = match vm 2287 .finalize_store() 2288 .get_value_confirmed( 2289 credits_program_id, 2290 account_mapping_name, 2291 &Plaintext::from(Literal::Address(recipient_address)), 2292 ) 2293 .unwrap() 2294 { 2295 Some(Value::Plaintext(Plaintext::Literal(Literal::U64(balance), _))) => *balance, 2296 _ => panic!("Expected a valid balance"), 2297 }; 2298 assert_eq!(balance, 1, "Update me if the test amount changes."); 2299 } 2300 2301 #[test] 2302 fn transfer_public_as_signer_from_program() { 2303 let rng = &mut TestRng::default(); 2304 2305 // Initialize a new caller. 2306 let caller_private_key = crate::vm::test_helpers::sample_genesis_private_key(rng); 2307 let caller_address = Address::try_from(&caller_private_key).unwrap(); 2308 2309 // Initialize a recipient. 2310 let recipient_private_key = PrivateKey::new(rng).unwrap(); 2311 let recipient_address = Address::try_from(&recipient_private_key).unwrap(); 2312 2313 // Initialize the genesis block. 2314 let genesis = crate::vm::test_helpers::sample_genesis_block(rng); 2315 2316 // Initialize the VM. 2317 let vm = crate::vm::test_helpers::sample_vm(); 2318 2319 // Update the VM. 2320 vm.add_next_block(&genesis).unwrap(); 2321 2322 // Check the balance of the caller. 2323 let credits_program_id = ProgramID::from_str("credits.alpha").unwrap(); 2324 let account_mapping_name = Identifier::from_str("account").unwrap(); 2325 let balance = match vm 2326 .finalize_store() 2327 .get_value_confirmed( 2328 credits_program_id, 2329 account_mapping_name, 2330 &Plaintext::from(Literal::Address(caller_address)), 2331 ) 2332 .unwrap() 2333 { 2334 Some(Value::Plaintext(Plaintext::Literal(Literal::U64(balance), _))) => *balance, 2335 _ => panic!("Expected a valid balance"), 2336 }; 2337 assert_eq!(balance, 182_499_999_894_112, "Update me if the initial balance changes."); 2338 2339 // Initialize a wrapper program, importing `credits.alpha` and calling `transfer_public`. 2340 let program = Program::from_str( 2341 r" 2342 import credits.alpha; 2343 program credits_wrapper.alpha; 2344 2345 function transfer_public_as_signer: 2346 input r0 as address.public; 2347 input r1 as u64.public; 2348 call credits.alpha/transfer_public_as_signer r0 r1 into r2; 2349 async transfer_public_as_signer r2 into r3; 2350 output r3 as credits_wrapper.alpha/transfer_public_as_signer.future; 2351 2352 finalize transfer_public_as_signer: 2353 input r0 as credits.alpha/transfer_public_as_signer.future; 2354 await r0; 2355 ", 2356 ) 2357 .unwrap(); 2358 2359 // Get the address of the wrapper program. 2360 let wrapper_program_id = ProgramID::from_str("credits_wrapper.alpha").unwrap(); 2361 let wrapper_program_address = wrapper_program_id.to_address().unwrap(); 2362 2363 // Deploy the wrapper program. 2364 let deployment = vm.deploy(&caller_private_key, &program, None, 0, None, rng).unwrap(); 2365 2366 // Add the deployment to a block and update the VM. 2367 let block = sample_next_block(&vm, &caller_private_key, &[deployment], rng).unwrap(); 2368 2369 // Update the VM. 2370 vm.add_next_block(&block).unwrap(); 2371 2372 // Transfer credits from the signer using `credits_wrapper` program. 2373 let transaction = vm 2374 .execute( 2375 &caller_private_key, 2376 ("credits_wrapper.alpha", "transfer_public_as_signer"), 2377 [Value::from_str(&format!("{recipient_address}")).unwrap(), Value::from_str("1u64").unwrap()].iter(), 2378 None, 2379 0, 2380 None, 2381 rng, 2382 ) 2383 .unwrap(); 2384 2385 // Verify the transaction. 2386 vm.check_transaction(&transaction, None, rng).unwrap(); 2387 2388 // Add the transaction to a block and update the VM. 2389 let block = sample_next_block(&vm, &caller_private_key, &[transaction], rng).unwrap(); 2390 2391 // Update the VM. 2392 vm.add_next_block(&block).unwrap(); 2393 2394 // Check the balance of the caller. 2395 let balance = match vm 2396 .finalize_store() 2397 .get_value_confirmed( 2398 credits_program_id, 2399 account_mapping_name, 2400 &Plaintext::from(Literal::Address(caller_address)), 2401 ) 2402 .unwrap() 2403 { 2404 Some(Value::Plaintext(Plaintext::Literal(Literal::U64(balance), _))) => *balance, 2405 _ => panic!("Expected a valid balance"), 2406 }; 2407 assert_eq!(balance, 182_499_996_821_661, "Update me if the initial balance changes."); 2408 2409 // Check the `credits_wrapper` program does not have any balance. 2410 let balance = vm 2411 .finalize_store() 2412 .get_value_confirmed( 2413 credits_program_id, 2414 account_mapping_name, 2415 &Plaintext::from(Literal::Address(wrapper_program_address)), 2416 ) 2417 .unwrap(); 2418 assert!(balance.is_none()); 2419 2420 // Check the balance of the recipient. 2421 let balance = match vm 2422 .finalize_store() 2423 .get_value_confirmed( 2424 credits_program_id, 2425 account_mapping_name, 2426 &Plaintext::from(Literal::Address(recipient_address)), 2427 ) 2428 .unwrap() 2429 { 2430 Some(Value::Plaintext(Plaintext::Literal(Literal::U64(balance), _))) => *balance, 2431 _ => panic!("Expected a valid balance"), 2432 }; 2433 assert_eq!(balance, 1, "Update me if the test amount changes."); 2434 } 2435 2436 #[test] 2437 fn test_transfer_public_to_private_from_program() { 2438 let rng = &mut TestRng::default(); 2439 2440 // Initialize a new caller. 2441 let caller_private_key = crate::vm::test_helpers::sample_genesis_private_key(rng); 2442 let caller_address = Address::try_from(&caller_private_key).unwrap(); 2443 2444 // Initialize a recipient. 2445 let recipient_private_key = PrivateKey::new(rng).unwrap(); 2446 let recipient_address = Address::try_from(&recipient_private_key).unwrap(); 2447 2448 // Initialize the genesis block. 2449 let genesis = crate::vm::test_helpers::sample_genesis_block(rng); 2450 2451 // Initialize the VM. 2452 let vm = crate::vm::test_helpers::sample_vm(); 2453 2454 // Update the VM. 2455 vm.add_next_block(&genesis).unwrap(); 2456 2457 // Check the balance of the caller. 2458 let credits_program_id = ProgramID::from_str("credits.alpha").unwrap(); 2459 let account_mapping_name = Identifier::from_str("account").unwrap(); 2460 let balance = match vm 2461 .finalize_store() 2462 .get_value_confirmed( 2463 credits_program_id, 2464 account_mapping_name, 2465 &Plaintext::from(Literal::Address(caller_address)), 2466 ) 2467 .unwrap() 2468 { 2469 Some(Value::Plaintext(Plaintext::Literal(Literal::U64(balance), _))) => *balance, 2470 _ => panic!("Expected a valid balance"), 2471 }; 2472 assert_eq!(balance, 182_499_999_894_112, "Update me if the initial balance changes."); 2473 2474 // Check that the recipient does not have a public balance. 2475 let balance = vm 2476 .finalize_store() 2477 .get_value_confirmed( 2478 credits_program_id, 2479 account_mapping_name, 2480 &Plaintext::from(Literal::Address(recipient_address)), 2481 ) 2482 .unwrap(); 2483 assert!(balance.is_none()); 2484 2485 // Initialize a wrapper program, importing `credits.alpha` and calling `transfer_public_as_signer` then `transfer_public_to_private`. 2486 let program = Program::from_str( 2487 r" 2488 import credits.alpha; 2489 2490 program credits_wrapper.alpha; 2491 2492 function transfer_public_to_private: 2493 input r0 as address.private; 2494 input r1 as u64.public; 2495 call credits.alpha/transfer_public_as_signer credits_wrapper.alpha r1 into r2; 2496 call credits.alpha/transfer_public_to_private r0 r1 into r3 r4; 2497 async transfer_public_to_private r2 r4 into r5; 2498 output r3 as credits.alpha/credits.record; 2499 output r5 as credits_wrapper.alpha/transfer_public_to_private.future; 2500 2501 finalize transfer_public_to_private: 2502 input r0 as credits.alpha/transfer_public_as_signer.future; 2503 input r1 as credits.alpha/transfer_public_to_private.future; 2504 contains credits.alpha/account[credits_wrapper.alpha] into r2; 2505 assert.eq r2 false; 2506 await r0; 2507 get credits.alpha/account[credits_wrapper.alpha] into r3; 2508 assert.eq r3 r0[2u32]; 2509 await r1; 2510 ", 2511 ) 2512 .unwrap(); 2513 2514 // Get the address of the wrapper program. 2515 let wrapper_program_id = ProgramID::from_str("credits_wrapper.alpha").unwrap(); 2516 2517 // Deploy the wrapper program. 2518 let deployment = vm.deploy(&caller_private_key, &program, None, 0, None, rng).unwrap(); 2519 2520 // Add the deployment to a block and update the VM. 2521 let block = sample_next_block(&vm, &caller_private_key, &[deployment], rng).unwrap(); 2522 2523 // Update the VM. 2524 vm.add_next_block(&block).unwrap(); 2525 2526 // Call the wrapper program to transfer credits from the caller to the recipient. 2527 let transaction = vm 2528 .execute( 2529 &caller_private_key, 2530 ("credits_wrapper.alpha", "transfer_public_to_private"), 2531 [Value::from_str(&format!("{recipient_address}")).unwrap(), Value::from_str("1u64").unwrap()].iter(), 2532 None, 2533 0, 2534 None, 2535 rng, 2536 ) 2537 .unwrap(); 2538 2539 // Verify the transaction. 2540 vm.check_transaction(&transaction, None, rng).unwrap(); 2541 2542 // Add the transaction to a block and update the VM. 2543 let block = sample_next_block(&vm, &caller_private_key, &[transaction.clone()], rng).unwrap(); 2544 2545 // Update the VM. 2546 vm.add_next_block(&block).unwrap(); 2547 2548 // Check the balance of the caller. 2549 let balance = match vm 2550 .finalize_store() 2551 .get_value_confirmed( 2552 credits_program_id, 2553 account_mapping_name, 2554 &Plaintext::from(Literal::Address(caller_address)), 2555 ) 2556 .unwrap() 2557 { 2558 Some(Value::Plaintext(Plaintext::Literal(Literal::U64(balance), _))) => *balance, 2559 _ => panic!("Expected a valid balance"), 2560 }; 2561 2562 assert_eq!(balance, 182_499_995_667_116, "Update me if the initial balance changes."); 2563 2564 // Check that the `credits_wrapper` program has a balance of 0. 2565 let balance = match vm 2566 .finalize_store() 2567 .get_value_confirmed( 2568 credits_program_id, 2569 account_mapping_name, 2570 &Plaintext::from(Literal::Address(wrapper_program_id.to_address().unwrap())), 2571 ) 2572 .unwrap() 2573 { 2574 Some(Value::Plaintext(Plaintext::Literal(Literal::U64(balance), _))) => *balance, 2575 _ => panic!("Expected a valid balance"), 2576 }; 2577 assert_eq!(balance, 0); 2578 2579 // Check that the recipient does not have a public balance. 2580 let balance = vm 2581 .finalize_store() 2582 .get_value_confirmed( 2583 credits_program_id, 2584 account_mapping_name, 2585 &Plaintext::from(Literal::Address(recipient_address)), 2586 ) 2587 .unwrap(); 2588 assert!(balance.is_none()); 2589 2590 // Get the output record from the transaction and check that it is well-formed. 2591 let records = transaction.records().collect_vec(); 2592 assert_eq!(records.len(), 1); 2593 let (commitment, record) = records[0]; 2594 let record = record.decrypt(&ViewKey::try_from(&recipient_private_key).unwrap()).unwrap(); 2595 assert_eq!(**record.owner(), recipient_address); 2596 let data = record.data(); 2597 assert_eq!(data.len(), 1); 2598 match data.get(&Identifier::from_str("microcredits").unwrap()) { 2599 Some(Entry::<CurrentNetwork, _>::Private(Plaintext::Literal(Literal::U64(value), _))) => { 2600 assert_eq!(**value, 1) 2601 } 2602 _ => panic!("Incorrect record."), 2603 } 2604 2605 // Check that the record exists in the VM. 2606 assert!(vm.transition_store().get_record(commitment).unwrap().is_some()); 2607 2608 // Check that the serial number of the record does not exist in the VM. 2609 assert!( 2610 !vm.transition_store() 2611 .contains_serial_number( 2612 &Record::<CurrentNetwork, Plaintext<CurrentNetwork>>::serial_number( 2613 recipient_private_key, 2614 *commitment 2615 ) 2616 .unwrap() 2617 ) 2618 .unwrap() 2619 ); 2620 } 2621 2622 #[test] 2623 fn test_modify_transaction_output() { 2624 let rng = &mut TestRng::default(); 2625 2626 // Initialize a new caller. 2627 let caller_private_key = crate::vm::test_helpers::sample_genesis_private_key(rng); 2628 2629 // Initialize the genesis block. 2630 let genesis = crate::vm::test_helpers::sample_genesis_block(rng); 2631 2632 // Initialize the VM. 2633 let vm = crate::vm::test_helpers::sample_vm(); 2634 2635 // Update the VM. 2636 vm.add_next_block(&genesis).unwrap(); 2637 2638 // Initialize a new private key. 2639 let private_key = PrivateKey::<CurrentNetwork>::new(rng).unwrap(); 2640 2641 // Call `transfer_public_to_private`. 2642 let inputs = [ 2643 Value::from_str(&format!("{}", Address::try_from(&private_key).unwrap())).unwrap(), 2644 Value::from_str("1u64").unwrap(), 2645 ]; 2646 let transaction = vm 2647 .execute( 2648 &caller_private_key, 2649 ("credits.alpha", "transfer_public_to_private"), 2650 inputs.iter(), 2651 None, 2652 0u64, 2653 None, 2654 rng, 2655 ) 2656 .unwrap(); 2657 2658 // Check that the transaction is valid. 2659 vm.check_transaction(&transaction, None, rng).unwrap(); 2660 2661 // Check that the transaction is as expected. 2662 let transaction_string = transaction.to_string(); 2663 // Parse the transaction string as a JSON map. 2664 let transaction: serde_json::Map<String, serde_json::Value> = 2665 serde_json::from_str(&transaction_string).unwrap(); 2666 // Get the execution. 2667 let execution = transaction.get("execution").unwrap(); 2668 // Get the `transfer_public_to_private` transition. 2669 let transition = execution.get("transitions").unwrap().as_array().unwrap().first().unwrap(); 2670 // Check that the transition is as expected. 2671 assert_eq!(transition.get("program").unwrap(), "credits.alpha"); 2672 assert_eq!(transition.get("function").unwrap(), "transfer_public_to_private"); 2673 // Get the transition outputs. 2674 let outputs = transition.get("outputs").unwrap().as_array().unwrap(); 2675 // For any output that is a future, modify it to an external record. 2676 let new_outputs = outputs 2677 .iter() 2678 .map(|output| { 2679 if output.get("type").unwrap() == "future" { 2680 let id = output.get("id").unwrap().as_str().unwrap(); 2681 json!({ 2682 "type": "external_record", 2683 "id": id 2684 }) 2685 } else { 2686 output.clone() 2687 } 2688 }) 2689 .collect::<Vec<_>>(); 2690 2691 // Compute the new transition ID. 2692 let inputs = transition 2693 .get("inputs") 2694 .unwrap() 2695 .as_array() 2696 .unwrap() 2697 .iter() 2698 .map(|value| { 2699 let string = serde_json::to_string(value).unwrap(); 2700 Input::from_str(&string).unwrap() 2701 }) 2702 .collect::<Vec<_>>(); 2703 let outputs = new_outputs 2704 .iter() 2705 .map(|value| { 2706 let string = serde_json::to_string(value).unwrap(); 2707 Output::from_str(&string).unwrap() 2708 }) 2709 .collect(); 2710 let tpk = Group::from_str(transition.get("tpk").unwrap().as_str().unwrap()).unwrap(); 2711 let tcm = Field::from_str(transition.get("tcm").unwrap().as_str().unwrap()).unwrap(); 2712 let scm = Field::from_str(transition.get("scm").unwrap().as_str().unwrap()).unwrap(); 2713 let transition = Transition::<CurrentNetwork>::new( 2714 ProgramID::from_str("credits.alpha").unwrap(), 2715 Identifier::from_str("transfer_public_to_private").unwrap(), 2716 inputs, 2717 outputs, 2718 tpk, 2719 tcm, 2720 scm, 2721 ) 2722 .unwrap(); 2723 2724 // Construct the new transaction. 2725 let mut new_transitions = vec![transition]; 2726 new_transitions.extend(execution.get("transitions").unwrap().as_array().unwrap().iter().skip(1).map(|value| { 2727 let string = serde_json::to_string(value).unwrap(); 2728 Transition::from_str(&string).unwrap() 2729 })); 2730 let global_state_root = <CurrentNetwork as Network>::StateRoot::from_str( 2731 execution.get("global_state_root").unwrap().as_str().unwrap(), 2732 ) 2733 .unwrap(); 2734 let proof = Proof::<CurrentNetwork>::from_str(execution.get("proof").unwrap().as_str().unwrap()).unwrap(); 2735 let new_execution = Execution::from(new_transitions.into_iter(), global_state_root, Some(proof)).unwrap(); 2736 let authorization = vm 2737 .authorize_fee_public(&caller_private_key, 10_000_000, 0, new_execution.to_execution_id().unwrap(), rng) 2738 .unwrap(); 2739 let fee = vm.execute_fee_authorization(authorization, None, rng).unwrap(); 2740 let new_transaction = Transaction::from_execution(new_execution, Some(fee)).unwrap(); 2741 2742 // Verify the new transaction. 2743 assert!(vm.check_transaction(&new_transaction, None, rng).is_err()); 2744 } 2745 2746 #[test] 2747 fn test_modify_fee() { 2748 let rng = &mut TestRng::default(); 2749 2750 // Initialize a new caller. 2751 let caller_private_key = crate::vm::test_helpers::sample_genesis_private_key(rng); 2752 2753 // Initialize the genesis block. 2754 let genesis = crate::vm::test_helpers::sample_genesis_block(rng); 2755 2756 // Initialize the VM. 2757 let vm = crate::vm::test_helpers::sample_vm(); 2758 2759 // Update the VM. 2760 vm.add_next_block(&genesis).unwrap(); 2761 2762 // Initialize a new private key. 2763 let private_key = PrivateKey::<CurrentNetwork>::new(rng).unwrap(); 2764 2765 // Call `transfer_public_to_private`. 2766 let inputs = [ 2767 Value::from_str(&format!("{}", Address::try_from(&private_key).unwrap())).unwrap(), 2768 Value::from_str("1u64").unwrap(), 2769 ]; 2770 let transaction = vm 2771 .execute( 2772 &caller_private_key, 2773 ("credits.alpha", "transfer_public_to_private"), 2774 inputs.iter(), 2775 None, 2776 0u64, 2777 None, 2778 rng, 2779 ) 2780 .unwrap(); 2781 2782 // Check that the transaction is valid. 2783 vm.check_transaction(&transaction, None, rng).unwrap(); 2784 2785 // Check that the transaction is as expected. 2786 let transaction_string = transaction.to_string(); 2787 // Parse the transaction string as a JSON map. 2788 let transaction: serde_json::Map<String, serde_json::Value> = 2789 serde_json::from_str(&transaction_string).unwrap(); 2790 // Get the execution. 2791 let execution: Execution<CurrentNetwork> = 2792 serde_json::from_value(transaction.get("execution").unwrap().clone()).unwrap(); 2793 2794 // Get the fee. 2795 let fee = transaction.get("fee").unwrap().as_object().unwrap(); 2796 // Get the transition 2797 let transition = fee.get("transition").unwrap().as_object().unwrap(); 2798 // Check that the transition is as expected. 2799 assert_eq!(transition.get("program").unwrap(), "credits.alpha"); 2800 assert_eq!(transition.get("function").unwrap(), "fee_public"); 2801 // Get the transition outputs. 2802 let outputs = transition.get("outputs").unwrap().as_array().unwrap(); 2803 // For any output that is a future, modify it to an external record. 2804 let new_outputs = outputs 2805 .iter() 2806 .map(|output| { 2807 if output.get("type").unwrap() == "future" { 2808 let id = output.get("id").unwrap().as_str().unwrap(); 2809 json!({ 2810 "type": "external_record", 2811 "id": id 2812 }) 2813 } else { 2814 output.clone() 2815 } 2816 }) 2817 .collect::<Vec<_>>(); 2818 2819 // Compute the new transition ID. 2820 let inputs = transition 2821 .get("inputs") 2822 .unwrap() 2823 .as_array() 2824 .unwrap() 2825 .iter() 2826 .map(|value| { 2827 let string = serde_json::to_string(value).unwrap(); 2828 Input::from_str(&string).unwrap() 2829 }) 2830 .collect::<Vec<_>>(); 2831 let outputs = new_outputs 2832 .iter() 2833 .map(|value| { 2834 let string = serde_json::to_string(value).unwrap(); 2835 Output::from_str(&string).unwrap() 2836 }) 2837 .collect(); 2838 let tpk = Group::from_str(transition.get("tpk").unwrap().as_str().unwrap()).unwrap(); 2839 let tcm = Field::from_str(transition.get("tcm").unwrap().as_str().unwrap()).unwrap(); 2840 let scm = Field::from_str(transition.get("scm").unwrap().as_str().unwrap()).unwrap(); 2841 // Construct the new transition. 2842 let transition = Transition::<CurrentNetwork>::new( 2843 ProgramID::from_str("credits.alpha").unwrap(), 2844 Identifier::from_str("fee_public").unwrap(), 2845 inputs, 2846 outputs, 2847 tpk, 2848 tcm, 2849 scm, 2850 ) 2851 .unwrap(); 2852 // Get the state root. 2853 let global_state_root = 2854 <CurrentNetwork as Network>::StateRoot::from_str(fee.get("global_state_root").unwrap().as_str().unwrap()) 2855 .unwrap(); 2856 // Get the proof. 2857 let proof = Proof::<CurrentNetwork>::from_str(fee.get("proof").unwrap().as_str().unwrap()).unwrap(); 2858 // Construct the new fee. 2859 let fee = Fee::from(transition, global_state_root, Some(proof)).unwrap(); 2860 2861 // Construct the new transaction. 2862 let new_transaction = Transaction::from_execution(execution, Some(fee)).unwrap(); 2863 2864 // Verify the new transaction. 2865 assert!(vm.check_transaction(&new_transaction, None, rng).is_err()); 2866 } 2867 2868 #[test] 2869 fn test_modify_input_and_output() { 2870 let rng = &mut TestRng::default(); 2871 2872 // Initialize a new caller. 2873 let caller_private_key = crate::vm::test_helpers::sample_genesis_private_key(rng); 2874 2875 // Initialize the genesis block. 2876 let genesis = crate::vm::test_helpers::sample_genesis_block(rng); 2877 2878 // Initialize the VM. 2879 let vm = crate::vm::test_helpers::sample_vm(); 2880 2881 // Update the VM. 2882 vm.add_next_block(&genesis).unwrap(); 2883 2884 // Deploy the test program. 2885 let program = Program::from_str( 2886 r" 2887 program basic_math.alpha; 2888 2889 function add_thrice: 2890 input r0 as u64.public; 2891 input r1 as u64.private; 2892 add r0 r1 into r2; 2893 add r2 r1 into r3; 2894 add r3 r1 into r4; 2895 output r2 as u64.constant; 2896 output r3 as u64.public; 2897 output r4 as u64.private; 2898 ", 2899 ) 2900 .unwrap(); 2901 let deployment = vm.deploy(&caller_private_key, &program, None, 0, None, rng).unwrap(); 2902 let block = sample_next_block(&vm, &caller_private_key, &[deployment], rng).unwrap(); 2903 vm.add_next_block(&block).unwrap(); 2904 2905 // Call the test program. 2906 let transaction = vm 2907 .execute( 2908 &caller_private_key, 2909 ("basic_math.alpha", "add_thrice"), 2910 [Value::from_str("1u64").unwrap(), Value::from_str("2u64").unwrap()].iter(), 2911 None, 2912 0u64, 2913 None, 2914 rng, 2915 ) 2916 .unwrap(); 2917 2918 // Check that the transaction is valid. 2919 vm.check_transaction(&transaction, None, rng).unwrap(); 2920 2921 // Get the transaction string. 2922 let transaction_string = transaction.to_string(); 2923 // Parse the transaction string as a JSON map. 2924 let transaction: serde_json::Map<String, serde_json::Value> = 2925 serde_json::from_str(&transaction_string).unwrap(); 2926 // Get the execution. 2927 let execution = transaction.get("execution").unwrap(); 2928 // Get the `add_twice` transition. 2929 let transition = execution.get("transitions").unwrap().as_array().unwrap().first().unwrap(); 2930 // Get the transition inputs. 2931 let inputs = transition.get("inputs").unwrap().as_array().unwrap(); 2932 // For any input, modify it to an external record. 2933 let new_inputs = inputs 2934 .iter() 2935 .map(|input| { 2936 let id = input.get("id").unwrap().as_str().unwrap(); 2937 json!({ 2938 "type": "external_record", 2939 "id": id 2940 }) 2941 }) 2942 .collect::<Vec<_>>(); 2943 // Get the transition outputs. 2944 let outputs = transition.get("outputs").unwrap().as_array().unwrap(); 2945 // For any output, modify it to an external record. 2946 let new_outputs = outputs 2947 .iter() 2948 .map(|output| { 2949 let id = output.get("id").unwrap().as_str().unwrap(); 2950 json!({ 2951 "type": "external_record", 2952 "id": id 2953 }) 2954 }) 2955 .collect::<Vec<_>>(); 2956 2957 // Compute the new transition ID. 2958 let inputs = new_inputs 2959 .iter() 2960 .map(|value| { 2961 let string = serde_json::to_string(value).unwrap(); 2962 Input::from_str(&string).unwrap() 2963 }) 2964 .collect::<Vec<_>>(); 2965 let outputs = new_outputs 2966 .iter() 2967 .map(|value| { 2968 let string = serde_json::to_string(value).unwrap(); 2969 Output::from_str(&string).unwrap() 2970 }) 2971 .collect(); 2972 let tpk = Group::from_str(transition.get("tpk").unwrap().as_str().unwrap()).unwrap(); 2973 let tcm = Field::from_str(transition.get("tcm").unwrap().as_str().unwrap()).unwrap(); 2974 let scm = Field::from_str(transition.get("scm").unwrap().as_str().unwrap()).unwrap(); 2975 2976 // Construct the new transition. 2977 let transition = Transition::<CurrentNetwork>::new( 2978 ProgramID::from_str("basic_math.alpha").unwrap(), 2979 Identifier::from_str("add_thrice").unwrap(), 2980 inputs, 2981 outputs, 2982 tpk, 2983 tcm, 2984 scm, 2985 ) 2986 .unwrap(); 2987 2988 // Construct the new transaction. 2989 let mut new_transitions = vec![transition]; 2990 new_transitions.extend(execution.get("transitions").unwrap().as_array().unwrap().iter().skip(1).map(|value| { 2991 let string = serde_json::to_string(value).unwrap(); 2992 Transition::from_str(&string).unwrap() 2993 })); 2994 let global_state_root = <CurrentNetwork as Network>::StateRoot::from_str( 2995 execution.get("global_state_root").unwrap().as_str().unwrap(), 2996 ) 2997 .unwrap(); 2998 let proof = Proof::<CurrentNetwork>::from_str(execution.get("proof").unwrap().as_str().unwrap()).unwrap(); 2999 let new_execution = Execution::from(new_transitions.into_iter(), global_state_root, Some(proof)).unwrap(); 3000 let authorization = vm 3001 .authorize_fee_public(&caller_private_key, 10_000_000, 0, new_execution.to_execution_id().unwrap(), rng) 3002 .unwrap(); 3003 let fee = vm.execute_fee_authorization(authorization, None, rng).unwrap(); 3004 let new_transaction = Transaction::from_execution(new_execution, Some(fee)).unwrap(); 3005 3006 // Verify the new transaction. 3007 assert!(vm.check_transaction(&new_transaction, None, rng).is_err()); 3008 } 3009 3010 #[test] 3011 fn test_large_transaction_is_aborted() { 3012 let rng = &mut TestRng::default(); 3013 3014 // Initialize a new caller. 3015 let caller_private_key = crate::vm::test_helpers::sample_genesis_private_key(rng); 3016 3017 // Initialize the genesis block. 3018 let genesis = crate::vm::test_helpers::sample_genesis_block(rng); 3019 3020 // Initialize the VM. 3021 let vm = crate::vm::test_helpers::sample_vm(); 3022 3023 // Update the VM. 3024 vm.add_next_block(&genesis).unwrap(); 3025 3026 // Deploy a program that produces small transactions. 3027 let program = small_transaction_program(); 3028 3029 // Deploy the program. 3030 let deployment = vm.deploy(&caller_private_key, &program, None, 0, None, rng).unwrap(); 3031 3032 // Add the deployment to a block and update the VM. 3033 let block = sample_next_block(&vm, &caller_private_key, &[deployment], rng).unwrap(); 3034 3035 // Update the VM. 3036 vm.add_next_block(&block).unwrap(); 3037 3038 // Deploy a program that produces large transactions. 3039 let program = large_transaction_program(); 3040 3041 // Deploy the program. 3042 let deployment = vm.deploy(&caller_private_key, &program, None, 0, None, rng).unwrap(); 3043 3044 // Add the deployment to a block and update the VM. 3045 let block = sample_next_block(&vm, &caller_private_key, &[deployment], rng).unwrap(); 3046 3047 // Update the VM. 3048 vm.add_next_block(&block).unwrap(); 3049 3050 // Call the program to produce the small transaction. 3051 let transaction = vm 3052 .execute( 3053 &caller_private_key, 3054 ("testing_small.alpha", "small_transaction"), 3055 Vec::<Value<CurrentNetwork>>::new().iter(), 3056 None, 3057 0, 3058 None, 3059 rng, 3060 ) 3061 .unwrap(); 3062 3063 // Verify the transaction. 3064 vm.check_transaction(&transaction, None, rng).unwrap(); 3065 3066 // Add the transaction to a block and update the VM. 3067 let block = sample_next_block(&vm, &caller_private_key, &[transaction], rng).unwrap(); 3068 3069 // Check that the transaction was accepted. 3070 assert_eq!(block.transactions().num_accepted(), 1); 3071 3072 // Update the VM. 3073 vm.add_next_block(&block).unwrap(); 3074 3075 // Call the program to produce a large transaction. 3076 let transaction = vm 3077 .execute( 3078 &caller_private_key, 3079 ("testing_large.alpha", "large_transaction"), 3080 Vec::<Value<CurrentNetwork>>::new().iter(), 3081 None, 3082 0, 3083 None, 3084 rng, 3085 ) 3086 .unwrap(); 3087 3088 // Verify that the transaction is invalid. 3089 assert!(vm.check_transaction(&transaction, None, rng).is_err()); 3090 3091 // Add the transaction to a block and update the VM. 3092 let block = sample_next_block(&vm, &caller_private_key, &[transaction], rng).unwrap(); 3093 3094 // Check that the transaction was aborted. 3095 assert_eq!(block.aborted_transaction_ids().len(), 1); 3096 3097 // Update the VM. 3098 vm.add_next_block(&block).unwrap(); 3099 } 3100 3101 #[test] 3102 fn test_vm_puzzle() { 3103 // Attention: This test is used to ensure that the VM has performed downcasting correctly for 3104 // the puzzle, and that the underlying traits in the puzzle are working correctly. Please 3105 // *do not delete* this test as it is a critical safety check for the integrity of the 3106 // instantiation of the puzzle in the VM. 3107 3108 let rng = &mut TestRng::default(); 3109 3110 // Initialize the VM. 3111 let vm = sample_vm(); 3112 3113 // Ensure this call succeeds. 3114 vm.puzzle.prove(rng.r#gen(), rng.r#gen(), rng.r#gen(), None).unwrap(); 3115 } 3116 3117 #[test] 3118 fn test_multi_transition_authorization_deserialization() { 3119 let rng = &mut TestRng::default(); 3120 3121 // Initialize a private key. 3122 let private_key = sample_genesis_private_key(rng); 3123 3124 // Initialize the genesis block. 3125 let genesis = sample_genesis_block(rng); 3126 3127 // Initialize the VM. 3128 let vm = sample_vm(); 3129 // Update the VM. 3130 vm.add_next_block(&genesis).unwrap(); 3131 3132 // Deploy the base program. 3133 let child_program_1 = Program::from_str( 3134 r" 3135 program child_program_1.alpha; 3136 3137 function check: 3138 input r0 as field.private; 3139 assert.eq r0 123456789123456789123456789123456789123456789123456789field; 3140 ", 3141 ) 3142 .unwrap(); 3143 3144 let child_program_2 = Program::from_str( 3145 r" 3146 program child_program_2.alpha; 3147 3148 function check: 3149 input r0 as field.private; 3150 assert.eq r0 123456789123456789123456789123456789123456789123456789field; 3151 ", 3152 ) 3153 .unwrap(); 3154 3155 // Deploy the child programs and add them to a block 3156 let deployment_1 = vm.deploy(&private_key, &child_program_1, None, 0, None, rng).unwrap(); 3157 assert!(vm.check_transaction(&deployment_1, None, rng).is_ok()); 3158 vm.add_next_block(&sample_next_block(&vm, &private_key, &[deployment_1], rng).unwrap()).unwrap(); 3159 3160 let deployment_2 = vm.deploy(&private_key, &child_program_2, None, 0, None, rng).unwrap(); 3161 assert!(vm.check_transaction(&deployment_2, None, rng).is_ok()); 3162 vm.add_next_block(&sample_next_block(&vm, &private_key, &[deployment_2], rng).unwrap()).unwrap(); 3163 3164 // Check that child programs are deployed 3165 assert!(vm.contains_program(&ProgramID::from_str("child_program_1.alpha").unwrap())); 3166 assert!(vm.contains_program(&ProgramID::from_str("child_program_2.alpha").unwrap())); 3167 3168 // Deploy the program that calls the program from the previous layer. 3169 let parent_program = Program::from_str( 3170 r" 3171 import child_program_1.alpha; 3172 import child_program_2.alpha; 3173 3174 program parent_program.alpha; 3175 3176 function check: 3177 input r0 as field.private; 3178 call child_program_1.alpha/check r0; 3179 call child_program_2.alpha/check r0; 3180 ", 3181 ) 3182 .unwrap(); 3183 3184 let deployment = vm.deploy(&private_key, &parent_program, None, 0, None, rng).unwrap(); 3185 assert!(vm.check_transaction(&deployment, None, rng).is_ok()); 3186 vm.add_next_block(&sample_next_block(&vm, &private_key, &[deployment], rng).unwrap()).unwrap(); 3187 3188 // Check that program is deployed. 3189 assert!(vm.contains_program(&ProgramID::from_str("parent_program.alpha").unwrap())); 3190 3191 // Deploy the program that calls the program from the previous layer. 3192 let grandparent_program = Program::from_str( 3193 r" 3194 import parent_program.alpha; 3195 3196 program grandparent_program.alpha; 3197 3198 function check: 3199 input r0 as field.private; 3200 call parent_program.alpha/check r0; 3201 call parent_program.alpha/check r0; 3202 call parent_program.alpha/check r0; 3203 ", 3204 ) 3205 .unwrap(); 3206 3207 let deployment = vm.deploy(&private_key, &grandparent_program, None, 0, None, rng).unwrap(); 3208 assert!(vm.check_transaction(&deployment, None, rng).is_ok()); 3209 vm.add_next_block(&sample_next_block(&vm, &private_key, &[deployment], rng).unwrap()).unwrap(); 3210 3211 // Check that program is deployed. 3212 assert!(vm.contains_program(&ProgramID::from_str("grandparent_program.alpha").unwrap())); 3213 3214 // Initialize the process. 3215 let mut process = Process::<CurrentNetwork>::load().unwrap(); 3216 3217 // Load the child and parent program 3218 process.add_program(&child_program_1).unwrap(); 3219 process.add_program(&child_program_2).unwrap(); 3220 process.add_program(&parent_program).unwrap(); 3221 process.add_program(&grandparent_program).unwrap(); 3222 3223 // Specify the function name on the parent program 3224 let function_name = Identifier::<CurrentNetwork>::from_str("check").unwrap(); 3225 3226 // Generate a random Field for input 3227 let input = 3228 Value::<CurrentNetwork>::from_str("123456789123456789123456789123456789123456789123456789field").unwrap(); 3229 3230 // Generate the authorization that will contain multiple transitions 3231 let authorization = process 3232 .authorize::<CurrentAleo, _>( 3233 &private_key, 3234 grandparent_program.id(), 3235 &function_name, 3236 vec![input].iter(), 3237 rng, 3238 ) 3239 .unwrap(); 3240 3241 // Assert the Authorization has more than 1 transitions 3242 assert!(authorization.transitions().len() > 1); 3243 3244 // Serialize the Authorization into a String 3245 let authorization_serialized = authorization.to_string(); 3246 3247 // Attempt to deserialize the Authorization from String 3248 let deserialization_result = Authorization::<CurrentNetwork>::from_str(&authorization_serialized); 3249 3250 // Assert that the deserialization result is Ok 3251 assert!(deserialization_result.is_ok()); 3252 } 3253 3254 #[cfg(feature = "rocks")] 3255 #[test] 3256 fn test_atomic_unpause_on_error() { 3257 let rng = &mut TestRng::default(); 3258 3259 // Initialize a genesis private key.. 3260 let genesis_private_key = sample_genesis_private_key(rng); 3261 3262 // Initialize the genesis block. 3263 let genesis = sample_genesis_block(rng); 3264 3265 // Initialize a VM and sample 2 blocks using it. 3266 let vm = sample_vm(); 3267 vm.add_next_block(&genesis).unwrap(); 3268 let block1 = sample_next_block(&vm, &genesis_private_key, &[], rng).unwrap(); 3269 vm.add_next_block(&block1).unwrap(); 3270 let block2 = sample_next_block(&vm, &genesis_private_key, &[], rng).unwrap(); 3271 3272 // Create a new, rocks-based VM shadowing the 1st one. 3273 let vm = sample_vm(); 3274 vm.add_next_block(&genesis).unwrap(); 3275 // This time, however, try to insert the 2nd block first, which fails due to height. 3276 assert!(vm.add_next_block(&block2).is_err()); 3277 3278 // It should still be possible to insert the 1st block afterwards. 3279 vm.add_next_block(&block1).unwrap(); 3280 } 3281 3282 #[test] 3283 fn test_dependent_deployments_in_same_block() { 3284 let rng = &mut TestRng::default(); 3285 3286 // Initialize a new caller. 3287 let caller_private_key = crate::vm::test_helpers::sample_genesis_private_key(rng); 3288 3289 // Initialize the genesis block. 3290 let genesis = crate::vm::test_helpers::sample_genesis_block(rng); 3291 3292 // Initialize the VM. 3293 let vm = crate::vm::test_helpers::sample_vm(); 3294 vm.add_next_block(&genesis).unwrap(); 3295 3296 // Fund two accounts to pay for the deployment. 3297 // This has to be done because only one deployment can be made per fee-paying address per block. 3298 let private_key_1 = PrivateKey::new(rng).unwrap(); 3299 let private_key_2 = PrivateKey::new(rng).unwrap(); 3300 let address_1 = Address::try_from(&private_key_1).unwrap(); 3301 let address_2 = Address::try_from(&private_key_2).unwrap(); 3302 3303 let tx_1 = vm 3304 .execute( 3305 &caller_private_key, 3306 ("credits.alpha", "transfer_public"), 3307 [Value::from_str(&format!("{address_1}")).unwrap(), Value::from_str("100000000u64").unwrap()].iter(), 3308 None, 3309 0, 3310 None, 3311 rng, 3312 ) 3313 .unwrap(); 3314 let tx_2 = vm 3315 .execute( 3316 &caller_private_key, 3317 ("credits.alpha", "transfer_public"), 3318 [Value::from_str(&format!("{address_2}")).unwrap(), Value::from_str("100000000u64").unwrap()].iter(), 3319 None, 3320 0, 3321 None, 3322 rng, 3323 ) 3324 .unwrap(); 3325 3326 let block = sample_next_block(&vm, &caller_private_key, &[tx_1, tx_2], rng).unwrap(); 3327 assert_eq!(block.transactions().num_accepted(), 2); 3328 assert_eq!(block.transactions().num_rejected(), 0); 3329 assert_eq!(block.aborted_transaction_ids().len(), 0); 3330 vm.add_next_block(&block).unwrap(); 3331 3332 // Deploy two programs that depend on each other. 3333 let program_1 = Program::from_str( 3334 r" 3335 program child_program.alpha; 3336 3337 function adder: 3338 input r0 as u64.public; 3339 input r1 as u64.public; 3340 add r0 r1 into r2; 3341 output r2 as u64.public; 3342 ", 3343 ) 3344 .unwrap(); 3345 3346 let program_2 = Program::from_str( 3347 r" 3348 import child_program.alpha; 3349 3350 program parent_program.alpha; 3351 3352 function adder: 3353 input r0 as u64.public; 3354 input r1 as u64.public; 3355 call child_program.alpha/adder r0 r1 into r2; 3356 output r2 as u64.public; 3357 ", 3358 ) 3359 .unwrap(); 3360 3361 // Initialize an "off-chain" VM to generate the deployments. 3362 let off_chain_vm = sample_vm(); 3363 off_chain_vm.add_next_block(&genesis).unwrap(); 3364 off_chain_vm.add_next_block(&block).unwrap(); 3365 // Deploy the first program. 3366 let deployment_1 = off_chain_vm.deploy(&private_key_1, &program_1, None, 0, None, rng).unwrap(); 3367 // Check that the account has enough to pay for the deployment. 3368 assert_eq!(*deployment_1.fee_amount().unwrap(), 2483025); 3369 // Add the first program to the off-chain VM. 3370 off_chain_vm.process().write().add_program(&program_1).unwrap(); 3371 // Deploy the second program. 3372 let deployment_2 = off_chain_vm.deploy(&private_key_2, &program_2, None, 0, None, rng).unwrap(); 3373 // Check that the account has enough to pay for the deployment. 3374 assert_eq!(*deployment_2.fee_amount().unwrap(), 2659575); 3375 // Drop the off-chain VM. 3376 drop(off_chain_vm); 3377 3378 let block = sample_next_block(&vm, &caller_private_key, &[deployment_1, deployment_2], rng).unwrap(); 3379 assert_eq!(block.transactions().num_accepted(), 1); 3380 assert_eq!(block.transactions().num_rejected(), 0); 3381 assert_eq!(block.aborted_transaction_ids().len(), 1); 3382 vm.add_next_block(&block).unwrap(); 3383 3384 // Check that only `child_program.alpha` is in the VM. 3385 assert!(vm.process().read().contains_program(&ProgramID::from_str("child_program.alpha").unwrap())); 3386 } 3387 3388 #[cfg(feature = "test")] 3389 #[test] 3390 fn test_versioned_keyword_restrictions() { 3391 let rng = &mut TestRng::default(); 3392 3393 // Initialize a new caller. 3394 let caller_private_key = crate::vm::test_helpers::sample_genesis_private_key(rng); 3395 3396 // Initialize the VM at a specific height. 3397 // We subtract by 7 to deploy the 7 invalid programs. 3398 let vm = sample_vm_at_height(CurrentNetwork::CONSENSUS_HEIGHT(ConsensusVersion::V6).unwrap() - 7, rng); 3399 3400 // Define the invalid program bodies. 3401 let invalid_program_bodies = [ 3402 "function constructor:", 3403 "function dummy:\nclosure constructor: input r0 as u8; assert.eq r0 0u8;", 3404 "function dummy:\nmapping constructor: key as boolean.public; value as boolean.public;", 3405 "function dummy:\nrecord constructor: owner as address.private;", 3406 "function dummy:\nrecord foo: owner as address.public; constructor as address.public;", 3407 "function dummy:\nstruct constructor: foo as address;", 3408 "function dummy:\nstruct foo: constructor as address;", 3409 ]; 3410 3411 println!("Current height: {}", vm.block_store().current_block_height()); 3412 3413 // Deploy a test program for each of the invalid program bodies. 3414 // They should all be accepted by the VM, because the restriction is not yet in place. 3415 for (i, body) in invalid_program_bodies.iter().enumerate() { 3416 println!("Deploying 'valid' test program {i}: {body}"); 3417 let program = Program::from_str(&format!("program test_valid_{i}.alpha;\n{body}")).unwrap(); 3418 let deployment = vm.deploy(&caller_private_key, &program, None, 0, None, rng).unwrap(); 3419 let block = sample_next_block(&vm, &caller_private_key, &[deployment], rng).unwrap(); 3420 assert_eq!(block.transactions().num_accepted(), 1); 3421 assert_eq!(block.transactions().num_rejected(), 0); 3422 assert_eq!(block.aborted_transaction_ids().len(), 0); 3423 vm.add_next_block(&block).unwrap(); 3424 } 3425 3426 println!("Current height: {}", vm.block_store().current_block_height()); 3427 3428 // Deploy a test program for each of the invalid program bodies. 3429 // Verify that `check_transaction` fails for each of them. 3430 for (i, body) in invalid_program_bodies.iter().enumerate() { 3431 println!("Deploying 'invalid' test program {i}: {body}"); 3432 let program = Program::from_str(&format!("program test_invalid_{i}.alpha;\n{body}")).unwrap(); 3433 let deployment = vm.deploy(&caller_private_key, &program, None, 0, None, rng).unwrap(); 3434 if let Err(e) = vm.check_transaction(&deployment, None, rng) { 3435 println!("Error: {e}"); 3436 } else { 3437 panic!("Expected an error, but the deployment was accepted.") 3438 } 3439 } 3440 3441 // Attempt to deploy a program with the name `constructor`. 3442 // Verify that `check_transaction` fails. 3443 let program = Program::from_str(r"program constructor.alpha; function dummy:").unwrap(); 3444 let deployment = vm.deploy(&caller_private_key, &program, None, 0, None, rng).unwrap(); 3445 if let Err(e) = vm.check_transaction(&deployment, None, rng) { 3446 println!("Error: {e}"); 3447 } else { 3448 panic!("Expected an error, but the deployment was accepted.") 3449 } 3450 } 3451 3452 #[cfg(feature = "test")] 3453 #[test] 3454 fn test_deploy_and_execute_in_same_block_fails() { 3455 let rng = &mut TestRng::default(); 3456 3457 // Initialize a new caller. 3458 let caller_private_key = crate::vm::test_helpers::sample_genesis_private_key(rng); 3459 3460 // Initialize the genesis block. 3461 let genesis = crate::vm::test_helpers::sample_genesis_block(rng); 3462 3463 // Initialize the VM. 3464 let vm = crate::vm::test_helpers::sample_vm(); 3465 vm.add_next_block(&genesis).unwrap(); 3466 3467 // Deploy and execute a program in the same block. 3468 let program = Program::from_str( 3469 r" 3470 program adder_program.alpha; 3471 function adder: 3472 input r0 as u64.public; 3473 input r1 as u64.public; 3474 add r0 r1 into r2; 3475 output r2 as u64.public; 3476 ", 3477 ) 3478 .unwrap(); 3479 3480 // Initialize an "off-chain" VM to generate the deployment and execution. 3481 let off_chain_vm = sample_vm(); 3482 off_chain_vm.add_next_block(&genesis).unwrap(); 3483 // Deploy the program. 3484 let deployment = off_chain_vm.deploy(&caller_private_key, &program, None, 0, None, rng).unwrap(); 3485 // Check that the account has enough to pay for the deployment. 3486 assert_eq!(*deployment.fee_amount().unwrap(), 2483025); 3487 // Add the program to the off-chain VM. 3488 off_chain_vm.process().write().add_program(&program).unwrap(); 3489 // Execute the program. 3490 let transaction = off_chain_vm 3491 .execute( 3492 &caller_private_key, 3493 ("adder_program.alpha", "adder"), 3494 [Value::from_str("1u64").unwrap(), Value::from_str("2u64").unwrap()].iter(), 3495 None, 3496 0, 3497 None, 3498 rng, 3499 ) 3500 .unwrap(); 3501 // Verify the transaction. 3502 off_chain_vm.check_transaction(&transaction, None, rng).unwrap(); 3503 // Check that the account has enough to pay for the execution. 3504 assert_eq!(*transaction.fee_amount().unwrap(), 1283); 3505 // Drop the off-chain VM. 3506 drop(off_chain_vm); 3507 3508 let block = sample_next_block(&vm, &caller_private_key, &[deployment, transaction], rng).unwrap(); 3509 assert_eq!(block.transactions().num_accepted(), 1); 3510 assert_eq!(block.transactions().num_rejected(), 0); 3511 assert_eq!(block.aborted_transaction_ids().len(), 1); 3512 vm.add_next_block(&block).unwrap(); 3513 3514 // Check that the program was deployed. 3515 assert!(vm.process().read().contains_program(&ProgramID::from_str("adder_program.alpha").unwrap())); 3516 } 3517 3518 #[cfg(feature = "test")] 3519 #[test] 3520 fn test_deploy_string() { 3521 let rng = &mut TestRng::default(); 3522 3523 // Initialize a new caller. 3524 let caller_private_key = crate::vm::test_helpers::sample_genesis_private_key(rng); 3525 3526 // Initialize the VM at consensus version 11. 3527 let vm = crate::vm::test_helpers::sample_vm_at_height( 3528 CurrentNetwork::CONSENSUS_HEIGHT(ConsensusVersion::V11).unwrap(), 3529 rng, 3530 ); 3531 3532 // Deploy and execute a program in the same block. 3533 let program = |i: u32| { 3534 Program::from_str(&format!( 3535 r#" 3536 program strings_{i}.alpha; 3537 3538 mapping foo: 3539 key as string.public; 3540 value as string.public; 3541 3542 mapping test: 3543 key as string.public; 3544 value as [boolean; 1u32].public; 3545 3546 function dummy: 3547 input r0 as string.public; 3548 input r1 as string.private; 3549 input r2 as string.private; 3550 assert.eq "hello_friend" "hello_friend"; 3551 assert.neq r1 r2; 3552 async dummy r0 r1 r2 into r3; 3553 hash.bhp256 "hello" into r4 as address; 3554 output r3 as strings_{i}.alpha/dummy.future; 3555 3556 finalize dummy: 3557 input r0 as string.public; 3558 input r1 as string.public; 3559 input r2 as string.public; 3560 assert.eq "hello_friend" "hello_friend"; 3561 assert.neq r1 r2; 3562 get.or_use foo[r1] r0 into r3; 3563 set r2 into foo[r1]; 3564 set "test" into foo[r2]; 3565 set r2 into foo[r2]; 3566 get foo[r1] into r4; 3567 assert.neq r3 r4; 3568 assert.eq r2 r4; 3569 assert.neq r0 r4; 3570 get.or_use foo[r1] "hello" into r5; 3571 3572 function dummy_with_array: 3573 input r0 as [string; 3u32].public; 3574 input r1 as [string; 4u32].private; 3575 async dummy_with_array r0 r1 "test" into r2; 3576 output r2 as strings_{i}.alpha/dummy_with_array.future; 3577 3578 finalize dummy_with_array: 3579 input r0 as [string; 3u32].public; 3580 input r1 as [string; 4u32].public; 3581 input r2 as string.public; 3582 set r2 into foo[r2]; 3583 3584 constructor: 3585 assert.eq true true; 3586 "# 3587 )) 3588 .unwrap() 3589 }; 3590 3591 // Deploy the program. 3592 let _deployment = vm.deploy(&caller_private_key, &program(0), None, 0, None, rng).unwrap(); 3593 // Check the deployment. 3594 // NOTE: this will only consistently pass if string sampling is updated. 3595 // vm.check_transaction(&deployment, None, rng).unwrap(); 3596 3597 // let block = sample_next_block(&vm, &caller_private_key, &[deployment], rng).unwrap(); 3598 // assert_eq!(block.transactions().num_accepted(), 1); 3599 // assert_eq!(block.transactions().num_rejected(), 0); 3600 // assert_eq!(block.aborted_transaction_ids().len(), 0); 3601 // vm.add_next_block(&block).unwrap(); 3602 3603 // // Check that the program was deployed. 3604 // assert!(vm.process().read().contains_program(&ProgramID::from_str("strings_0.alpha").unwrap())); 3605 3606 // let hello_literal = Literal::String(StringType::new("hello")); 3607 // let hello_friend_literal = Literal::String(StringType::new("hello_friend")); 3608 // let hello_friends_literal = Literal::String(StringType::new("hello_friends")); 3609 3610 // // Execution test 1 3611 // let hello_friend_1 = Value::from(hello_friend_literal.clone()); 3612 // let hello_friend_2 = Value::from(hello_friend_literal.clone()); 3613 // let hello_friends = Value::from(hello_friends_literal.clone()); 3614 3615 // // Execute the program. 3616 // let transaction = vm 3617 // .execute( 3618 // &caller_private_key, 3619 // ("strings_0.alpha", "dummy"), 3620 // [hello_friend_1, hello_friend_2, hello_friends].iter(), 3621 // None, 3622 // 0, 3623 // None, 3624 // rng, 3625 // ) 3626 // .unwrap(); 3627 // // Verify the transaction. 3628 // vm.check_transaction(&transaction, None, rng).unwrap(); 3629 3630 // let block = sample_next_block(&vm, &caller_private_key, &[transaction], rng).unwrap(); 3631 // assert_eq!(block.transactions().num_accepted(), 1); 3632 // assert_eq!(block.transactions().num_rejected(), 0); 3633 // assert_eq!(block.aborted_transaction_ids().len(), 0); 3634 // vm.add_next_block(&block).unwrap(); 3635 3636 // // Execution test 2: change the public type 3637 // let hello = Value::from(hello_literal.clone()); 3638 // let hello_friend = Value::from(hello_friend_literal.clone()); 3639 // let hello_friends = Value::from(hello_friends_literal.clone()); 3640 3641 // // Execute the program. 3642 // let transaction = vm.execute( 3643 // &caller_private_key, 3644 // ("strings_0.alpha", "dummy"), 3645 // [hello, hello_friend, hello_friends].iter(), 3646 // None, 3647 // 0, 3648 // None, 3649 // rng, 3650 // ); 3651 // assert!(transaction.is_err()); 3652 3653 // // Execution test 3: change the private type 3654 // let hello_friend_1 = Value::from(hello_friend_literal.clone()); 3655 // let hello_friend_2 = Value::from(hello_friend_literal.clone()); 3656 // let hello = Value::from(hello_literal.clone()); 3657 3658 // // Execute the program. 3659 // let transaction = vm.execute( 3660 // &caller_private_key, 3661 // ("strings_0.alpha", "dummy"), 3662 // [hello_friend_1, hello_friend_2, hello].iter(), 3663 // None, 3664 // 0, 3665 // None, 3666 // rng, 3667 // ); 3668 // assert!(transaction.is_err()); 3669 3670 // // Deploy another program. 3671 // let deployment = vm.deploy(&caller_private_key, &program(1), None, 0, None, rng).unwrap(); 3672 // // Check the deployment. 3673 // assert!(vm.check_transaction(&deployment, None, rng).is_err()); 3674 3675 // let block = sample_next_block(&vm, &caller_private_key, &[deployment], rng).unwrap(); 3676 // assert_eq!(block.transactions().num_accepted(), 0); 3677 // assert_eq!(block.transactions().num_rejected(), 0); 3678 // assert_eq!(block.aborted_transaction_ids().len(), 1); 3679 // vm.add_next_block(&block).unwrap(); 3680 3681 // // Check that the program was notdeployed. 3682 // assert!(!vm.process().read().contains_program(&ProgramID::from_str("strings_1.alpha").unwrap())); 3683 } 3684 }