snarkvm_synthesizer_debug/vm/
mod.rs

1// Copyright (C) 2019-2023 Aleo Systems Inc.
2// This file is part of the snarkVM library.
3
4// Licensed under the Apache License, Version 2.0 (the "License");
5// you may not use this file except in compliance with the License.
6// You may obtain a copy of the License at:
7// http://www.apache.org/licenses/LICENSE-2.0
8
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15mod helpers;
16pub use helpers::*;
17
18mod authorize;
19mod deploy;
20mod execute;
21mod finalize;
22mod verify;
23
24use crate::{cast_mut_ref, cast_ref, process};
25use console::{
26    account::{Address, PrivateKey},
27    network::prelude::*,
28    program::{Identifier, Literal, Locator, Plaintext, ProgramID, ProgramOwner, Record, Value},
29    types::{Field, U64},
30};
31use ledger_block::{
32    Block,
33    ConfirmedTransaction,
34    Deployment,
35    Execution,
36    Fee,
37    Header,
38    Ratifications,
39    Ratify,
40    Rejected,
41    Transaction,
42    Transactions,
43};
44use ledger_coinbase::CoinbaseSolution;
45use ledger_committee::Committee;
46use ledger_query::Query;
47use ledger_store::{
48    atomic_finalize,
49    BlockStore,
50    ConsensusStorage,
51    ConsensusStore,
52    FinalizeMode,
53    FinalizeStore,
54    TransactionStorage,
55    TransactionStore,
56    TransitionStore,
57};
58use synthesizer_process::{Authorization, Process, Trace};
59use synthesizer_program::{FinalizeGlobalState, FinalizeOperation, FinalizeStoreTrait, Program};
60
61use aleo_std::prelude::{finish, lap, timer};
62use indexmap::{IndexMap, IndexSet};
63use parking_lot::{Mutex, RwLock};
64use std::sync::Arc;
65
66#[cfg(not(feature = "serial"))]
67use rayon::prelude::*;
68
69#[derive(Clone)]
70pub struct VM<N: Network, C: ConsensusStorage<N>> {
71    /// The process.
72    process: Arc<RwLock<Process<N>>>,
73    /// The VM store.
74    store: ConsensusStore<N, C>,
75    /// The lock to guarantee atomicity over calls to speculate and finalize.
76    atomic_lock: Arc<Mutex<()>>,
77    /// The lock for ensuring there is no concurrency when advancing blocks.
78    block_lock: Arc<Mutex<()>>,
79}
80
81impl<N: Network, C: ConsensusStorage<N>> VM<N, C> {
82    /// Initializes the VM from storage.
83    #[inline]
84    pub fn from(store: ConsensusStore<N, C>) -> Result<Self> {
85        // Initialize a new process.
86        let mut process = Process::load()?;
87
88        // Initialize the store for 'credits.aleo'.
89        let credits = Program::<N>::credits()?;
90        for mapping in credits.mappings().values() {
91            // Ensure that all mappings are initialized.
92            if !store.finalize_store().contains_mapping_confirmed(credits.id(), mapping.name())? {
93                // Initialize the mappings for 'credits.aleo'.
94                store.finalize_store().initialize_mapping(*credits.id(), *mapping.name())?;
95            }
96        }
97
98        // A helper function to retrieve all the deployments.
99        fn load_deployment_and_imports<N: Network, T: TransactionStorage<N>>(
100            process: &Process<N>,
101            transaction_store: &TransactionStore<N, T>,
102            transaction_id: N::TransactionID,
103        ) -> Result<Vec<(ProgramID<N>, Deployment<N>)>> {
104            // Retrieve the deployment from the transaction id.
105            let deployment = match transaction_store.get_deployment(&transaction_id)? {
106                Some(deployment) => deployment,
107                None => bail!("Deployment transaction '{transaction_id}' is not found in storage."),
108            };
109
110            // Fetch the program from the deployment.
111            let program = deployment.program();
112            let program_id = program.id();
113
114            // Return early if the program is already loaded.
115            if process.contains_program(program_id) {
116                return Ok(vec![]);
117            }
118
119            // Prepare a vector for the deployments.
120            let mut deployments = vec![];
121
122            // Iterate through the program imports.
123            for import_program_id in program.imports().keys() {
124                // Add the imports to the process if does not exist yet.
125                if !process.contains_program(import_program_id) {
126                    // Fetch the deployment transaction id.
127                    let Some(transaction_id) =
128                        transaction_store.deployment_store().find_transaction_id_from_program_id(import_program_id)?
129                    else {
130                        bail!("Transaction id for '{program_id}' is not found in storage.");
131                    };
132
133                    // Add the deployment and its imports found recursively.
134                    deployments.extend_from_slice(&load_deployment_and_imports(
135                        process,
136                        transaction_store,
137                        transaction_id,
138                    )?);
139                }
140            }
141
142            // Once all the imports have been included, add the parent deployment.
143            deployments.push((*program_id, deployment));
144
145            Ok(deployments)
146        }
147
148        // Retrieve the transaction store.
149        let transaction_store = store.transaction_store();
150        // Retrieve the list of deployment transaction IDs.
151        let deployment_ids = transaction_store.deployment_transaction_ids().collect::<Vec<_>>();
152        // Load the deployments from the store.
153        for (i, chunk) in deployment_ids.chunks(256).enumerate() {
154            debug!(
155                "Loading deployments {}-{} (of {})...",
156                i * 256,
157                ((i + 1) * 256).min(deployment_ids.len()),
158                deployment_ids.len()
159            );
160            let deployments = cfg_iter!(chunk)
161                .map(|transaction_id| {
162                    // Load the deployment and its imports.
163                    load_deployment_and_imports(&process, transaction_store, **transaction_id)
164                })
165                .collect::<Result<Vec<_>>>()?;
166
167            for (program_id, deployment) in deployments.iter().flatten() {
168                // Load the deployment if it does not exist in the process yet.
169                if !process.contains_program(program_id) {
170                    process.load_deployment(deployment)?;
171                }
172            }
173        }
174
175        // Return the new VM.
176        Ok(Self {
177            process: Arc::new(RwLock::new(process)),
178            store,
179            atomic_lock: Arc::new(Mutex::new(())),
180            block_lock: Arc::new(Mutex::new(())),
181        })
182    }
183
184    /// Returns `true` if a program with the given program ID exists.
185    #[inline]
186    pub fn contains_program(&self, program_id: &ProgramID<N>) -> bool {
187        self.process.read().contains_program(program_id)
188    }
189
190    /// Returns the process.
191    #[inline]
192    pub fn process(&self) -> Arc<RwLock<Process<N>>> {
193        self.process.clone()
194    }
195}
196
197impl<N: Network, C: ConsensusStorage<N>> VM<N, C> {
198    /// Returns the finalize store.
199    #[inline]
200    pub fn finalize_store(&self) -> &FinalizeStore<N, C::FinalizeStorage> {
201        self.store.finalize_store()
202    }
203
204    /// Returns the block store.
205    #[inline]
206    pub fn block_store(&self) -> &BlockStore<N, C::BlockStorage> {
207        self.store.block_store()
208    }
209
210    /// Returns the transaction store.
211    #[inline]
212    pub fn transaction_store(&self) -> &TransactionStore<N, C::TransactionStorage> {
213        self.store.transaction_store()
214    }
215
216    /// Returns the transition store.
217    #[inline]
218    pub fn transition_store(&self) -> &TransitionStore<N, C::TransitionStorage> {
219        self.store.transition_store()
220    }
221}
222
223impl<N: Network, C: ConsensusStorage<N>> VM<N, C> {
224    /// Returns a new genesis block for a beacon chain.
225    pub fn genesis_beacon<R: Rng + CryptoRng>(&self, private_key: &PrivateKey<N>, rng: &mut R) -> Result<Block<N>> {
226        let private_keys = [*private_key, PrivateKey::new(rng)?, PrivateKey::new(rng)?, PrivateKey::new(rng)?];
227
228        // Construct the committee members.
229        let members = indexmap::indexmap! {
230            Address::try_from(private_keys[0])? => (ledger_committee::MIN_VALIDATOR_STAKE, true),
231            Address::try_from(private_keys[1])? => (ledger_committee::MIN_VALIDATOR_STAKE, true),
232            Address::try_from(private_keys[2])? => (ledger_committee::MIN_VALIDATOR_STAKE, true),
233            Address::try_from(private_keys[3])? => (ledger_committee::MIN_VALIDATOR_STAKE, true),
234        };
235        // Construct the committee.
236        let committee = Committee::<N>::new_genesis(members)?;
237
238        // Compute the remaining supply.
239        let remaining_supply = N::STARTING_SUPPLY - (ledger_committee::MIN_VALIDATOR_STAKE * 4);
240        // Construct the public balances.
241        let public_balances = indexmap::indexmap! {
242            Address::try_from(private_keys[0])? => remaining_supply / 4,
243            Address::try_from(private_keys[1])? => remaining_supply / 4,
244            Address::try_from(private_keys[2])? => remaining_supply / 4,
245            Address::try_from(private_keys[3])? => remaining_supply / 4,
246        };
247        // Return the genesis block.
248        self.genesis_quorum(private_key, committee, public_balances, rng)
249    }
250
251    /// Returns a new genesis block for a quorum chain.
252    pub fn genesis_quorum<R: Rng + CryptoRng>(
253        &self,
254        private_key: &PrivateKey<N>,
255        committee: Committee<N>,
256        public_balances: IndexMap<Address<N>, u64>,
257        rng: &mut R,
258    ) -> Result<Block<N>> {
259        // Retrieve the total stake.
260        let total_stake = committee.total_stake();
261        // Compute the account supply.
262        let account_supply = public_balances.values().fold(0u64, |acc, x| acc.saturating_add(*x));
263        // Compute the total supply.
264        let total_supply = total_stake.checked_add(account_supply).ok_or_else(|| anyhow!("Invalid total supply"))?;
265        // Ensure the total supply matches.
266        ensure!(total_supply == N::STARTING_SUPPLY, "Invalid total supply");
267
268        // Prepare the caller.
269        let caller = Address::try_from(private_key)?;
270        // Prepare the locator.
271        let locator = ("credits.aleo", "transfer_public_to_private");
272        // Prepare the amount for each call to the function.
273        let amount = ledger_committee::MIN_VALIDATOR_STAKE;
274        // Prepare the function inputs.
275        let inputs = [caller.to_string(), format!("{amount}_u64")];
276
277        // Prepare the ratifications.
278        let ratifications = vec![Ratify::Genesis(committee, public_balances)];
279        // Prepare the solutions.
280        let solutions = None; // The genesis block does not require solutions.
281        // Prepare the transactions.
282        let transactions = (0..Block::<N>::NUM_GENESIS_TRANSACTIONS)
283            .map(|_| self.execute(private_key, locator, inputs.iter(), None, 0, None, rng))
284            .collect::<Result<Vec<_>, _>>()?;
285
286        // Construct the finalize state.
287        let state = FinalizeGlobalState::new_genesis::<N>()?;
288        // Speculate on the ratifications, solutions, and transactions.
289        let (ratifications, transactions, aborted_transaction_ids, ratified_finalize_operations) =
290            self.speculate(state, None, ratifications, solutions.as_ref(), transactions.iter())?;
291        ensure!(
292            aborted_transaction_ids.is_empty(),
293            "Failed to initialize a genesis block - found aborted transaction IDs"
294        );
295
296        // Prepare the block header.
297        let header = Header::genesis(&ratifications, &transactions, ratified_finalize_operations)?;
298        // Prepare the previous block hash.
299        let previous_hash = N::BlockHash::default();
300
301        // Construct the block.
302        let block = Block::new_beacon(
303            private_key,
304            previous_hash,
305            header,
306            ratifications,
307            solutions,
308            transactions,
309            aborted_transaction_ids,
310            rng,
311        )?;
312        // Ensure the block is valid genesis block.
313        match block.is_genesis() {
314            true => Ok(block),
315            false => bail!("Failed to initialize a genesis block"),
316        }
317    }
318
319    /// Adds the given block into the VM.
320    #[inline]
321    pub fn add_next_block(&self, block: &Block<N>) -> Result<()> {
322        // Acquire the block lock, which is needed to ensure this function is not called concurrently.
323        // Note: This lock must be held for the entire scope of this function.
324        let _block_lock = self.block_lock.lock();
325
326        // Construct the finalize state.
327        let state = FinalizeGlobalState::new::<N>(
328            block.round(),
329            block.height(),
330            block.cumulative_weight(),
331            block.cumulative_proof_target(),
332            block.previous_hash(),
333        )?;
334
335        // Attention: The following order is crucial because if 'finalize' fails, we can rollback the block.
336        // If one first calls 'finalize', then calls 'insert(block)' and it fails, there is no way to rollback 'finalize'.
337
338        // First, insert the block.
339        self.block_store().insert(block)?;
340        // Next, finalize the transactions.
341        match self.finalize(state, block.ratifications(), block.solutions(), block.transactions()) {
342            Ok(_ratified_finalize_operations) => Ok(()),
343            Err(finalize_error) => {
344                // Rollback the block.
345                self.block_store().remove_last_n(1).map_err(|removal_error| {
346                    // Log the finalize error.
347                    error!("Failed to finalize block {} - {finalize_error}", block.height());
348                    // Return the removal error.
349                    removal_error
350                })?;
351                // Return the finalize error.
352                Err(finalize_error)
353            }
354        }
355    }
356}
357
358#[cfg(test)]
359pub(crate) mod test_helpers {
360    use super::*;
361    use console::{
362        account::{Address, ViewKey},
363        network::Testnet3,
364        program::Value,
365        types::Field,
366    };
367    use ledger_block::{Block, Header, Metadata, Transition};
368    use ledger_store::helpers::memory::ConsensusMemory;
369    use synthesizer_program::Program;
370
371    use indexmap::IndexMap;
372    use once_cell::sync::OnceCell;
373    use std::borrow::Borrow;
374
375    pub(crate) type CurrentNetwork = Testnet3;
376
377    /// Samples a new finalize state.
378    pub(crate) fn sample_finalize_state(block_height: u32) -> FinalizeGlobalState {
379        FinalizeGlobalState::from(block_height as u64, block_height, [0u8; 32])
380    }
381
382    pub(crate) fn sample_vm() -> VM<CurrentNetwork, ConsensusMemory<CurrentNetwork>> {
383        // Initialize a new VM.
384        VM::from(ConsensusStore::open(None).unwrap()).unwrap()
385    }
386
387    pub(crate) fn sample_genesis_private_key(rng: &mut TestRng) -> PrivateKey<CurrentNetwork> {
388        static INSTANCE: OnceCell<PrivateKey<CurrentNetwork>> = OnceCell::new();
389        *INSTANCE.get_or_init(|| {
390            // Initialize a new caller.
391            PrivateKey::<CurrentNetwork>::new(rng).unwrap()
392        })
393    }
394
395    pub(crate) fn sample_genesis_block(rng: &mut TestRng) -> Block<CurrentNetwork> {
396        static INSTANCE: OnceCell<Block<CurrentNetwork>> = OnceCell::new();
397        INSTANCE
398            .get_or_init(|| {
399                // Initialize the VM.
400                let vm = crate::vm::test_helpers::sample_vm();
401                // Initialize a new caller.
402                let caller_private_key = crate::vm::test_helpers::sample_genesis_private_key(rng);
403                // Return the block.
404                vm.genesis_beacon(&caller_private_key, rng).unwrap()
405            })
406            .clone()
407    }
408
409    pub(crate) fn sample_vm_with_genesis_block(
410        rng: &mut TestRng,
411    ) -> VM<CurrentNetwork, ConsensusMemory<CurrentNetwork>> {
412        // Initialize the VM.
413        let vm = crate::vm::test_helpers::sample_vm();
414        // Initialize the genesis block.
415        let genesis = crate::vm::test_helpers::sample_genesis_block(rng);
416        // Update the VM.
417        vm.add_next_block(&genesis).unwrap();
418        // Return the VM.
419        vm
420    }
421
422    pub(crate) fn sample_program() -> Program<CurrentNetwork> {
423        static INSTANCE: OnceCell<Program<CurrentNetwork>> = OnceCell::new();
424        INSTANCE
425            .get_or_init(|| {
426                // Initialize a new program.
427                Program::<CurrentNetwork>::from_str(
428                    r"
429program testing.aleo;
430
431struct message:
432    amount as u128;
433
434mapping account:
435    key as address.public;
436    value as u64.public;
437
438record token:
439    owner as address.private;
440    amount as u64.private;
441
442function initialize:
443    input r0 as address.private;
444    input r1 as u64.private;
445    cast r0 r1 into r2 as token.record;
446    output r2 as token.record;
447
448function compute:
449    input r0 as message.private;
450    input r1 as message.public;
451    input r2 as message.private;
452    input r3 as token.record;
453    add r0.amount r1.amount into r4;
454    cast r3.owner r3.amount into r5 as token.record;
455    output r4 as u128.public;
456    output r5 as token.record;",
457                )
458                .unwrap()
459            })
460            .clone()
461    }
462
463    pub(crate) fn sample_deployment_transaction(rng: &mut TestRng) -> Transaction<CurrentNetwork> {
464        static INSTANCE: OnceCell<Transaction<CurrentNetwork>> = OnceCell::new();
465        INSTANCE
466            .get_or_init(|| {
467                // Initialize the program.
468                let program = sample_program();
469
470                // Initialize a new caller.
471                let caller_private_key = crate::vm::test_helpers::sample_genesis_private_key(rng);
472                let caller_view_key = ViewKey::try_from(&caller_private_key).unwrap();
473
474                // Initialize the genesis block.
475                let genesis = crate::vm::test_helpers::sample_genesis_block(rng);
476
477                // Fetch the unspent records.
478                let records =
479                    genesis.transitions().cloned().flat_map(Transition::into_records).collect::<IndexMap<_, _>>();
480                trace!("Unspent Records:\n{:#?}", records);
481
482                // Prepare the fee.
483                let credits = Some(records.values().next().unwrap().decrypt(&caller_view_key).unwrap());
484
485                // Initialize the VM.
486                let vm = sample_vm();
487                // Update the VM.
488                vm.add_next_block(&genesis).unwrap();
489
490                // Deploy.
491                let transaction = vm.deploy(&caller_private_key, &program, credits, 10, None, rng).unwrap();
492                // Verify.
493                vm.check_transaction(&transaction, None, rng).unwrap();
494                // Return the transaction.
495                transaction
496            })
497            .clone()
498    }
499
500    pub(crate) fn sample_execution_transaction_without_fee(rng: &mut TestRng) -> Transaction<CurrentNetwork> {
501        static INSTANCE: OnceCell<Transaction<CurrentNetwork>> = OnceCell::new();
502        INSTANCE
503            .get_or_init(|| {
504                // Initialize a new caller.
505                let caller_private_key = crate::vm::test_helpers::sample_genesis_private_key(rng);
506                let caller_view_key = ViewKey::try_from(&caller_private_key).unwrap();
507
508                // Initialize the genesis block.
509                let genesis = crate::vm::test_helpers::sample_genesis_block(rng);
510
511                // Fetch the unspent records.
512                let records =
513                    genesis.transitions().cloned().flat_map(Transition::into_records).collect::<IndexMap<_, _>>();
514                trace!("Unspent Records:\n{:#?}", records);
515
516                // Select a record to spend.
517                let record = records.values().next().unwrap().decrypt(&caller_view_key).unwrap();
518
519                // Initialize the VM.
520                let vm = sample_vm();
521                // Update the VM.
522                vm.add_next_block(&genesis).unwrap();
523
524                // Prepare the inputs.
525                let inputs =
526                    [Value::<CurrentNetwork>::Record(record), Value::<CurrentNetwork>::from_str("1u64").unwrap()]
527                        .into_iter();
528
529                // Authorize.
530                let authorization = vm.authorize(&caller_private_key, "credits.aleo", "split", inputs, rng).unwrap();
531                assert_eq!(authorization.len(), 1);
532
533                // Construct the execute transaction.
534                let transaction = vm.execute_authorization(authorization, None, None, rng).unwrap();
535                // Verify.
536                vm.check_transaction(&transaction, None, rng).unwrap();
537                // Return the transaction.
538                transaction
539            })
540            .clone()
541    }
542
543    pub(crate) fn sample_execution_transaction_with_private_fee(rng: &mut TestRng) -> Transaction<CurrentNetwork> {
544        static INSTANCE: OnceCell<Transaction<CurrentNetwork>> = OnceCell::new();
545        INSTANCE
546            .get_or_init(|| {
547                // Initialize a new caller.
548                let caller_private_key = crate::vm::test_helpers::sample_genesis_private_key(rng);
549                let caller_view_key = ViewKey::try_from(&caller_private_key).unwrap();
550                let address = Address::try_from(&caller_private_key).unwrap();
551
552                // Initialize the genesis block.
553                let genesis = crate::vm::test_helpers::sample_genesis_block(rng);
554
555                // Fetch the unspent records.
556                let records =
557                    genesis.transitions().cloned().flat_map(Transition::into_records).collect::<IndexMap<_, _>>();
558                trace!("Unspent Records:\n{:#?}", records);
559
560                // Select a record to spend.
561                let record = Some(records.values().next().unwrap().decrypt(&caller_view_key).unwrap());
562
563                // Initialize the VM.
564                let vm = sample_vm();
565                // Update the VM.
566                vm.add_next_block(&genesis).unwrap();
567
568                // Prepare the inputs.
569                let inputs = [
570                    Value::<CurrentNetwork>::from_str(&address.to_string()).unwrap(),
571                    Value::<CurrentNetwork>::from_str("1u64").unwrap(),
572                ]
573                .into_iter();
574
575                // Execute.
576                let transaction = vm
577                    .execute(&caller_private_key, ("credits.aleo", "transfer_public"), inputs, record, 0, None, rng)
578                    .unwrap();
579                // Verify.
580                vm.check_transaction(&transaction, None, rng).unwrap();
581                // Return the transaction.
582                transaction
583            })
584            .clone()
585    }
586
587    pub(crate) fn sample_execution_transaction_with_public_fee(rng: &mut TestRng) -> Transaction<CurrentNetwork> {
588        static INSTANCE: OnceCell<Transaction<CurrentNetwork>> = OnceCell::new();
589        INSTANCE
590            .get_or_init(|| {
591                // Initialize a new caller.
592                let caller_private_key = crate::vm::test_helpers::sample_genesis_private_key(rng);
593                let address = Address::try_from(&caller_private_key).unwrap();
594
595                // Initialize the genesis block.
596                let genesis = crate::vm::test_helpers::sample_genesis_block(rng);
597
598                // Initialize the VM.
599                let vm = sample_vm();
600                // Update the VM.
601                vm.add_next_block(&genesis).unwrap();
602
603                // Prepare the inputs.
604                let inputs = [
605                    Value::<CurrentNetwork>::from_str(&address.to_string()).unwrap(),
606                    Value::<CurrentNetwork>::from_str("1u64").unwrap(),
607                ]
608                .into_iter();
609
610                // Execute.
611                let transaction_without_fee = vm
612                    .execute(&caller_private_key, ("credits.aleo", "transfer_public"), inputs, None, 0, None, rng)
613                    .unwrap();
614                let execution = transaction_without_fee.execution().unwrap().clone();
615
616                // Authorize the fee.
617                let authorization = vm
618                    .authorize_fee_public(
619                        &caller_private_key,
620                        10_000_000,
621                        100,
622                        execution.to_execution_id().unwrap(),
623                        rng,
624                    )
625                    .unwrap();
626                // Compute the fee.
627                let fee = vm.execute_fee_authorization(authorization, None, rng).unwrap();
628
629                // Construct the transaction.
630                let transaction = Transaction::from_execution(execution, Some(fee)).unwrap();
631                // Verify.
632                vm.check_transaction(&transaction, None, rng).unwrap();
633                // Return the transaction.
634                transaction
635            })
636            .clone()
637    }
638
639    pub fn sample_next_block<R: Rng + CryptoRng>(
640        vm: &VM<Testnet3, ConsensusMemory<Testnet3>>,
641        private_key: &PrivateKey<Testnet3>,
642        transactions: &[Transaction<Testnet3>],
643        rng: &mut R,
644    ) -> Result<Block<Testnet3>> {
645        // Get the most recent block.
646        let block_hash =
647            vm.block_store().get_block_hash(*vm.block_store().heights().max().unwrap().borrow()).unwrap().unwrap();
648        let previous_block = vm.block_store().get_block(&block_hash).unwrap().unwrap();
649
650        // Construct the new block header.
651        let (ratifications, transactions, aborted_transaction_ids, ratified_finalize_operations) =
652            vm.speculate(sample_finalize_state(1), None, vec![], None, transactions.iter())?;
653        assert!(aborted_transaction_ids.is_empty());
654
655        // Construct the metadata associated with the block.
656        let metadata = Metadata::new(
657            Testnet3::ID,
658            previous_block.round() + 1,
659            previous_block.height() + 1,
660            0,
661            0,
662            Testnet3::GENESIS_COINBASE_TARGET,
663            Testnet3::GENESIS_PROOF_TARGET,
664            previous_block.last_coinbase_target(),
665            previous_block.last_coinbase_timestamp(),
666            Testnet3::GENESIS_TIMESTAMP + 1,
667        )?;
668
669        let header = Header::from(
670            vm.block_store().current_state_root(),
671            transactions.to_transactions_root().unwrap(),
672            transactions.to_finalize_root(ratified_finalize_operations).unwrap(),
673            ratifications.to_ratifications_root().unwrap(),
674            Field::zero(),
675            Field::zero(),
676            metadata,
677        )?;
678
679        // Construct the new block.
680        Block::new_beacon(
681            private_key,
682            previous_block.hash(),
683            header,
684            ratifications,
685            None,
686            transactions,
687            aborted_transaction_ids,
688            rng,
689        )
690    }
691
692    #[test]
693    fn test_multiple_deployments_and_multiple_executions() {
694        let rng = &mut TestRng::default();
695
696        // Initialize a new caller.
697        let caller_private_key = crate::vm::test_helpers::sample_genesis_private_key(rng);
698        let caller_view_key = ViewKey::try_from(&caller_private_key).unwrap();
699
700        // Initialize the genesis block.
701        let genesis = crate::vm::test_helpers::sample_genesis_block(rng);
702
703        // Fetch the unspent records.
704        let records = genesis.transitions().cloned().flat_map(Transition::into_records).collect::<IndexMap<_, _>>();
705        trace!("Unspent Records:\n{:#?}", records);
706
707        // Select a record to spend.
708        let record = records.values().next().unwrap().decrypt(&caller_view_key).unwrap();
709
710        // Initialize the VM.
711        let vm = sample_vm();
712        // Update the VM.
713        vm.add_next_block(&genesis).unwrap();
714
715        // Split once.
716        let transaction = vm
717            .execute(
718                &caller_private_key,
719                ("credits.aleo", "split"),
720                [Value::Record(record), Value::from_str("1000000000u64").unwrap()].iter(), // 1000 credits
721                None,
722                0,
723                None,
724                rng,
725            )
726            .unwrap();
727        let records = transaction.records().collect_vec();
728        let first_record = records[0].1.clone().decrypt(&caller_view_key).unwrap();
729        let second_record = records[1].1.clone().decrypt(&caller_view_key).unwrap();
730        let block = sample_next_block(&vm, &caller_private_key, &[transaction], rng).unwrap();
731        vm.add_next_block(&block).unwrap();
732
733        // Split again.
734        let mut transactions = Vec::new();
735        let transaction = vm
736            .execute(
737                &caller_private_key,
738                ("credits.aleo", "split"),
739                [Value::Record(first_record), Value::from_str("100000000u64").unwrap()].iter(), // 100 credits
740                None,
741                0,
742                None,
743                rng,
744            )
745            .unwrap();
746        let records = transaction.records().collect_vec();
747        let first_record = records[0].1.clone().decrypt(&caller_view_key).unwrap();
748        let third_record = records[1].1.clone().decrypt(&caller_view_key).unwrap();
749        transactions.push(transaction);
750        // Split again.
751        let transaction = vm
752            .execute(
753                &caller_private_key,
754                ("credits.aleo", "split"),
755                [Value::Record(second_record), Value::from_str("100000000u64").unwrap()].iter(), // 100 credits
756                None,
757                0,
758                None,
759                rng,
760            )
761            .unwrap();
762        let records = transaction.records().collect_vec();
763        let second_record = records[0].1.clone().decrypt(&caller_view_key).unwrap();
764        let fourth_record = records[1].1.clone().decrypt(&caller_view_key).unwrap();
765        transactions.push(transaction);
766        // Add the split transactions to a block and update the VM.
767        let fee_block = sample_next_block(&vm, &caller_private_key, &transactions, rng).unwrap();
768        vm.add_next_block(&fee_block).unwrap();
769
770        // Deploy the programs.
771        let first_program = r"
772program test_program_1.aleo;
773mapping map_0:
774    key as field.public;
775    value as field.public;
776function init:
777    async init into r0;
778    output r0 as test_program_1.aleo/init.future;
779finalize init:
780    set 0field into map_0[0field];
781function getter:
782    async getter into r0;
783    output r0 as test_program_1.aleo/getter.future;
784finalize getter:
785    get map_0[0field] into r0;
786        ";
787        let second_program = r"
788program test_program_2.aleo;
789mapping map_0:
790    key as field.public;
791    value as field.public;
792function init:
793    async init into r0;
794    output r0 as test_program_2.aleo/init.future;
795finalize init:
796    set 0field into map_0[0field];
797function getter:
798    async getter into r0;
799    output r0 as test_program_2.aleo/getter.future;
800finalize getter:
801    get map_0[0field] into r0;
802        ";
803        let first_deployment = vm
804            .deploy(&caller_private_key, &Program::from_str(first_program).unwrap(), Some(first_record), 1, None, rng)
805            .unwrap();
806        let second_deployment = vm
807            .deploy(&caller_private_key, &Program::from_str(second_program).unwrap(), Some(second_record), 1, None, rng)
808            .unwrap();
809        let deployment_block =
810            sample_next_block(&vm, &caller_private_key, &[first_deployment, second_deployment], rng).unwrap();
811        vm.add_next_block(&deployment_block).unwrap();
812
813        // Execute the programs.
814        let first_execution = vm
815            .execute(
816                &caller_private_key,
817                ("test_program_1.aleo", "init"),
818                Vec::<Value<Testnet3>>::new().iter(),
819                Some(third_record),
820                1,
821                None,
822                rng,
823            )
824            .unwrap();
825        let second_execution = vm
826            .execute(
827                &caller_private_key,
828                ("test_program_2.aleo", "init"),
829                Vec::<Value<Testnet3>>::new().iter(),
830                Some(fourth_record),
831                1,
832                None,
833                rng,
834            )
835            .unwrap();
836        let execution_block =
837            sample_next_block(&vm, &caller_private_key, &[first_execution, second_execution], rng).unwrap();
838        vm.add_next_block(&execution_block).unwrap();
839    }
840
841    #[test]
842    fn test_load_deployments_with_imports() {
843        // NOTE: This seed was chosen for the CI's RNG to ensure that the test passes.
844        let rng = &mut TestRng::fixed(123456789);
845
846        // Initialize a new caller.
847        let caller_private_key = PrivateKey::<CurrentNetwork>::new(rng).unwrap();
848        let caller_view_key = ViewKey::try_from(&caller_private_key).unwrap();
849
850        // Initialize the VM.
851        let vm = crate::vm::test_helpers::sample_vm();
852        // Initialize the genesis block.
853        let genesis = vm.genesis_beacon(&caller_private_key, rng).unwrap();
854        // Update the VM.
855        vm.add_next_block(&genesis).unwrap();
856
857        // Fetch the unspent records.
858        let records = genesis.transitions().cloned().flat_map(Transition::into_records).collect::<Vec<(_, _)>>();
859        trace!("Unspent Records:\n{:#?}", records);
860        let record_0 = records[0].1.decrypt(&caller_view_key).unwrap();
861        let record_1 = records[1].1.decrypt(&caller_view_key).unwrap();
862        let record_2 = records[2].1.decrypt(&caller_view_key).unwrap();
863        let record_3 = records[3].1.decrypt(&caller_view_key).unwrap();
864
865        // Create the deployment for the first program.
866        let program_1 = r"
867program first_program.aleo;
868
869function c:
870    input r0 as u8.private;
871    input r1 as u8.private;
872    add r0 r1 into r2;
873    output r2 as u8.private;
874        ";
875        let deployment_1 = vm
876            .deploy(&caller_private_key, &Program::from_str(program_1).unwrap(), Some(record_0), 0, None, rng)
877            .unwrap();
878
879        // Deploy the first program.
880        let deployment_block = sample_next_block(&vm, &caller_private_key, &[deployment_1.clone()], rng).unwrap();
881        vm.add_next_block(&deployment_block).unwrap();
882
883        // Create the deployment for the second program.
884        let program_2 = r"
885import first_program.aleo;
886
887program second_program.aleo;
888
889function b:
890    input r0 as u8.private;
891    input r1 as u8.private;
892    call first_program.aleo/c r0 r1 into r2;
893    output r2 as u8.private;
894        ";
895        let deployment_2 = vm
896            .deploy(&caller_private_key, &Program::from_str(program_2).unwrap(), Some(record_1), 0, None, rng)
897            .unwrap();
898
899        // Deploy the second program.
900        let deployment_block = sample_next_block(&vm, &caller_private_key, &[deployment_2.clone()], rng).unwrap();
901        vm.add_next_block(&deployment_block).unwrap();
902
903        // Create the deployment for the third program.
904        let program_3 = r"
905import second_program.aleo;
906
907program third_program.aleo;
908
909function a:
910    input r0 as u8.private;
911    input r1 as u8.private;
912    call second_program.aleo/b r0 r1 into r2;
913    output r2 as u8.private;
914        ";
915        let deployment_3 = vm
916            .deploy(&caller_private_key, &Program::from_str(program_3).unwrap(), Some(record_2), 0, None, rng)
917            .unwrap();
918
919        // Create the deployment for the fourth program.
920        let program_4 = r"
921import second_program.aleo;
922import first_program.aleo;
923
924program fourth_program.aleo;
925
926function a:
927    input r0 as u8.private;
928    input r1 as u8.private;
929    call second_program.aleo/b r0 r1 into r2;
930    output r2 as u8.private;
931        ";
932        let deployment_4 = vm
933            .deploy(&caller_private_key, &Program::from_str(program_4).unwrap(), Some(record_3), 0, None, rng)
934            .unwrap();
935
936        // Deploy the third and fourth program together.
937        let deployment_block =
938            sample_next_block(&vm, &caller_private_key, &[deployment_3.clone(), deployment_4.clone()], rng).unwrap();
939        vm.add_next_block(&deployment_block).unwrap();
940
941        // Check that the iterator ordering is not the same as the deployment ordering.
942        let deployment_transaction_ids =
943            vm.transaction_store().deployment_transaction_ids().map(|id| *id).collect::<Vec<_>>();
944        // This `assert_ne` check is here to ensure that we are properly loading imports even though any order will work for `VM::from`.
945        // Note: `deployment_transaction_ids` is sorted lexicographically by transaction id, so the order may change if we update internal methods.
946        assert_ne!(deployment_transaction_ids, vec![
947            deployment_1.id(),
948            deployment_2.id(),
949            deployment_3.id(),
950            deployment_4.id()
951        ]);
952
953        // Enforce that the VM can load properly with the imports.
954        assert!(VM::from(vm.store.clone()).is_ok());
955    }
956
957    #[test]
958    fn test_multiple_external_calls() {
959        let rng = &mut TestRng::default();
960
961        // Initialize a new caller.
962        let caller_private_key = crate::vm::test_helpers::sample_genesis_private_key(rng);
963        let caller_view_key = ViewKey::try_from(&caller_private_key).unwrap();
964        let address = Address::try_from(&caller_private_key).unwrap();
965
966        // Initialize the genesis block.
967        let genesis = crate::vm::test_helpers::sample_genesis_block(rng);
968
969        // Fetch the unspent records.
970        let records =
971            genesis.transitions().cloned().flat_map(Transition::into_records).take(3).collect::<IndexMap<_, _>>();
972        trace!("Unspent Records:\n{:#?}", records);
973        let record_0 = records.values().next().unwrap().decrypt(&caller_view_key).unwrap();
974        let record_1 = records.values().nth(1).unwrap().decrypt(&caller_view_key).unwrap();
975        let record_2 = records.values().nth(2).unwrap().decrypt(&caller_view_key).unwrap();
976
977        // Initialize the VM.
978        let vm = sample_vm();
979        // Update the VM.
980        vm.add_next_block(&genesis).unwrap();
981
982        // Deploy the program.
983        let program = Program::from_str(
984            r"
985import credits.aleo;
986
987program test_multiple_external_calls.aleo;
988
989function multitransfer:
990    input r0 as credits.aleo/credits.record;
991    input r1 as address.private;
992    input r2 as u64.private;
993    call credits.aleo/transfer_private r0 r1 r2 into r3 r4;
994    call credits.aleo/transfer_private r4 r1 r2 into r5 r6;
995    output r4 as credits.aleo/credits.record;
996    output r5 as credits.aleo/credits.record;
997    output r6 as credits.aleo/credits.record;
998    ",
999        )
1000        .unwrap();
1001        let deployment = vm.deploy(&caller_private_key, &program, Some(record_0), 1, None, rng).unwrap();
1002        vm.add_next_block(&sample_next_block(&vm, &caller_private_key, &[deployment], rng).unwrap()).unwrap();
1003
1004        // Execute the programs.
1005        let inputs = [
1006            Value::<Testnet3>::Record(record_1),
1007            Value::<Testnet3>::from_str(&address.to_string()).unwrap(),
1008            Value::<Testnet3>::from_str("10u64").unwrap(),
1009        ];
1010        let execution = vm
1011            .execute(
1012                &caller_private_key,
1013                ("test_multiple_external_calls.aleo", "multitransfer"),
1014                inputs.into_iter(),
1015                Some(record_2),
1016                1,
1017                None,
1018                rng,
1019            )
1020            .unwrap();
1021        vm.add_next_block(&sample_next_block(&vm, &caller_private_key, &[execution], rng).unwrap()).unwrap();
1022    }
1023
1024    #[test]
1025    fn test_nested_deployment_with_assert() {
1026        let rng = &mut TestRng::default();
1027
1028        // Initialize a private key.
1029        let private_key = sample_genesis_private_key(rng);
1030
1031        // Initialize the genesis block.
1032        let genesis = sample_genesis_block(rng);
1033
1034        // Initialize the VM.
1035        let vm = sample_vm();
1036        // Update the VM.
1037        vm.add_next_block(&genesis).unwrap();
1038
1039        // Deploy the base program.
1040        let program = Program::from_str(
1041            r"
1042program child_program.aleo;
1043
1044function check:
1045    input r0 as field.private;
1046    assert.eq r0 123456789123456789123456789123456789123456789123456789field;
1047        ",
1048        )
1049        .unwrap();
1050
1051        let deployment = vm.deploy(&private_key, &program, None, 0, None, rng).unwrap();
1052        assert!(vm.check_transaction(&deployment, None, rng).is_ok());
1053        vm.add_next_block(&sample_next_block(&vm, &private_key, &[deployment], rng).unwrap()).unwrap();
1054
1055        // Check that program is deployed.
1056        assert!(vm.contains_program(&ProgramID::from_str("child_program.aleo").unwrap()));
1057
1058        // Deploy the program that calls the program from the previous layer.
1059        let program = Program::from_str(
1060            r"
1061import child_program.aleo;
1062
1063program parent_program.aleo;
1064
1065function check:
1066    input r0 as field.private;
1067    call child_program.aleo/check r0;
1068        ",
1069        )
1070        .unwrap();
1071
1072        let deployment = vm.deploy(&private_key, &program, None, 0, None, rng).unwrap();
1073        assert!(vm.check_transaction(&deployment, None, rng).is_ok());
1074        vm.add_next_block(&sample_next_block(&vm, &private_key, &[deployment], rng).unwrap()).unwrap();
1075
1076        // Check that program is deployed.
1077        assert!(vm.contains_program(&ProgramID::from_str("parent_program.aleo").unwrap()));
1078    }
1079
1080    #[test]
1081    #[ignore]
1082    fn test_deployment_memory_overload() {
1083        const NUM_DEPLOYMENTS: usize = 32;
1084
1085        let rng = &mut TestRng::default();
1086
1087        // Initialize a private key.
1088        let private_key = sample_genesis_private_key(rng);
1089
1090        // Initialize a view key.
1091        let view_key = ViewKey::try_from(&private_key).unwrap();
1092
1093        // Initialize the genesis block.
1094        let genesis = sample_genesis_block(rng);
1095
1096        // Initialize the VM.
1097        let vm = sample_vm();
1098        // Update the VM.
1099        vm.add_next_block(&genesis).unwrap();
1100
1101        // Deploy the base program.
1102        let program = Program::from_str(
1103            r"
1104program program_layer_0.aleo;
1105
1106mapping m:
1107    key as u8.public;
1108    value as u32.public;
1109
1110function do:
1111    input r0 as u32.public;
1112    async do r0 into r1;
1113    output r1 as program_layer_0.aleo/do.future;
1114
1115finalize do:
1116    input r0 as u32.public;
1117    set r0 into m[0u8];",
1118        )
1119        .unwrap();
1120
1121        let deployment = vm.deploy(&private_key, &program, None, 0, None, rng).unwrap();
1122        vm.add_next_block(&sample_next_block(&vm, &private_key, &[deployment], rng).unwrap()).unwrap();
1123
1124        // For each layer, deploy a program that calls the program from the previous layer.
1125        for i in 1..NUM_DEPLOYMENTS {
1126            let mut program_string = String::new();
1127            // Add the import statements.
1128            for j in 0..i {
1129                program_string.push_str(&format!("import program_layer_{}.aleo;\n", j));
1130            }
1131            // Add the program body.
1132            program_string.push_str(&format!(
1133                "program program_layer_{i}.aleo;
1134
1135mapping m:
1136    key as u8.public;
1137    value as u32.public;
1138
1139function do:
1140    input r0 as u32.public;
1141    call program_layer_{prev}.aleo/do r0 into r1;
1142    async do r0 r1 into r2;
1143    output r2 as program_layer_{i}.aleo/do.future;
1144
1145finalize do:
1146    input r0 as u32.public;
1147    input r1 as program_layer_{prev}.aleo/do.future;
1148    await r1;
1149    set r0 into m[0u8];",
1150                prev = i - 1
1151            ));
1152            // Construct the program.
1153            let program = Program::from_str(&program_string).unwrap();
1154
1155            // Deploy the program.
1156            let deployment = vm.deploy(&private_key, &program, None, 0, None, rng).unwrap();
1157
1158            vm.add_next_block(&sample_next_block(&vm, &private_key, &[deployment], rng).unwrap()).unwrap();
1159        }
1160
1161        // Fetch the unspent records.
1162        let records = genesis.transitions().cloned().flat_map(Transition::into_records).collect::<IndexMap<_, _>>();
1163        trace!("Unspent Records:\n{:#?}", records);
1164
1165        // Select a record to spend.
1166        let record = Some(records.values().next().unwrap().decrypt(&view_key).unwrap());
1167
1168        // Prepare the inputs.
1169        let inputs = [Value::<CurrentNetwork>::from_str("1u32").unwrap()].into_iter();
1170
1171        // Execute.
1172        let transaction =
1173            vm.execute(&private_key, ("program_layer_30.aleo", "do"), inputs, record, 0, None, rng).unwrap();
1174
1175        // Verify.
1176        vm.check_transaction(&transaction, None, rng).unwrap();
1177    }
1178}