From 1635858cc56773ee170d1879b961ebdb8d2bc319 Mon Sep 17 00:00:00 2001 From: Pranav Gaddamadugu <23022326+d0cd@users.noreply.github.com> Date: Thu, 17 Apr 2025 07:53:49 -0700 Subject: [PATCH 1/7] Implement check --- synthesizer/src/vm/verify.rs | 46 ++++++++++++++++++++++++++++++++++++ 1 file changed, 46 insertions(+) diff --git a/synthesizer/src/vm/verify.rs b/synthesizer/src/vm/verify.rs index 062fece936..6e158026b3 100644 --- a/synthesizer/src/vm/verify.rs +++ b/synthesizer/src/vm/verify.rs @@ -293,6 +293,52 @@ impl> VM { if self.block_store().contains_rejected_deployment_or_execution_id(execution_id)? { bail!("Transaction '{id}' contains a previously rejected execution") } + + // Ensure that the state root of the execution is greater than or equal to the height at which its component programs were deployed or upgraded. + // Note: This is only enforced for programs deployed at or after `ConsensusVersion::V5`, when upgradability was introduced, + // to prevent executions on old versions of the program. + + // Track the maximum block height. + let mut max_block_height = 0; + // For each transition in the execution, get the block height at which the program was deployed or upgraded and update the maximum block height. + for transition in execution.transitions() { + // Get the program ID. + let program_id = transition.program_id(); + // Get the transaction ID of the transaction that last deployed or upgraded the program. + let Some(transaction_id) = self + .block_store() + .transaction_store() + .find_latest_transaction_id_from_program_id(program_id)? + else { + bail!("Program '{program_id}' does not have a corresponding transaction ID in the store"); + }; + // Get the block hash associated with the transaction ID. + let Some(block_hash) = self.block_store().find_block_hash(&transaction_id)? else { + bail!("Transaction '{transaction_id}' does not have a corresponding block hash in the store"); + }; + // Get the block height associated with the block hash. + let Some(block_height) = self.block_store().get_block_height(&block_hash)? else { + bail!("Block hash '{block_hash}' does not have a corresponding block height in the store"); + }; + // Update the maximum block height. + max_block_height = max_block_height.max(block_height); + } + // If the maximum block height is greater than or equal to `ConsensusVersion::V5`, then check that the execution state root is later than the maximum block height. + if max_block_height >= N::CONSENSUS_HEIGHT(ConsensusVersion::V5)? { + // Get the block height of the execution. + let Some(block_height) = + self.block_store().find_block_height_from_state_root(execution.global_state_root())? + else { + bail!( + "The state root of execution '{id}' does not have a corresponding block height in the store" + ); + }; + // Ensure the block height is greater than or equal to the maximum block height. + ensure!( + block_height >= max_block_height, + "Execution '{id}' state root is earlier than the last deployment or upgrade for one of the programs in the execution" + ); + } // Verify the execution. match try_vm_runtime!(|| self.check_execution_internal(execution, is_partially_verified)) { Ok(result) => result?, From 0570b296626eb1da83822fafbfdf0b8f6dbfed11 Mon Sep 17 00:00:00 2001 From: Pranav Gaddamadugu <23022326+d0cd@users.noreply.github.com> Date: Thu, 17 Apr 2025 08:03:24 -0700 Subject: [PATCH 2/7] Add better error reporting --- synthesizer/src/vm/verify.rs | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/synthesizer/src/vm/verify.rs b/synthesizer/src/vm/verify.rs index 6e158026b3..c44f074495 100644 --- a/synthesizer/src/vm/verify.rs +++ b/synthesizer/src/vm/verify.rs @@ -298,8 +298,9 @@ impl> VM { // Note: This is only enforced for programs deployed at or after `ConsensusVersion::V5`, when upgradability was introduced, // to prevent executions on old versions of the program. - // Track the maximum block height. + // Track the maximum block height and the associated program ID. let mut max_block_height = 0; + let mut latest_program = None; // For each transition in the execution, get the block height at which the program was deployed or upgraded and update the maximum block height. for transition in execution.transitions() { // Get the program ID. @@ -321,7 +322,10 @@ impl> VM { bail!("Block hash '{block_hash}' does not have a corresponding block height in the store"); }; // Update the maximum block height. - max_block_height = max_block_height.max(block_height); + if max_block_height < block_height { + max_block_height = block_height; + latest_program = Some(program_id); + } } // If the maximum block height is greater than or equal to `ConsensusVersion::V5`, then check that the execution state root is later than the maximum block height. if max_block_height >= N::CONSENSUS_HEIGHT(ConsensusVersion::V5)? { @@ -336,7 +340,10 @@ impl> VM { // Ensure the block height is greater than or equal to the maximum block height. ensure!( block_height >= max_block_height, - "Execution '{id}' state root is earlier than the last deployment or upgrade for one of the programs in the execution" + "Execution '{id}' state root is earlier than the last deployment or upgrade for program '{}'", + // Note: This unwrap is safe because if `max_block_height` is greater than `N::CONSENSUS_HEIGHT(ConsensusVersion::V5)`, + // then `latest_program` must have been set in the loop above. + latest_program.unwrap() ); } // Verify the execution. From 7f9fc31b96f2b4acc12903b87a4b5d76c3dca61a Mon Sep 17 00:00:00 2001 From: Pranav Gaddamadugu <23022326+d0cd@users.noreply.github.com> Date: Mon, 21 Apr 2025 10:53:38 -0700 Subject: [PATCH 3/7] Move check to should_abort_transaction --- synthesizer/src/vm/finalize.rs | 77 +++++++++++++++++++++++++++++++--- synthesizer/src/vm/verify.rs | 52 ----------------------- 2 files changed, 72 insertions(+), 57 deletions(-) diff --git a/synthesizer/src/vm/finalize.rs b/synthesizer/src/vm/finalize.rs index d57a0b4221..9fef844bf6 100644 --- a/synthesizer/src/vm/finalize.rs +++ b/synthesizer/src/vm/finalize.rs @@ -788,6 +788,9 @@ impl> VM { /// - The transaction is producing a duplicate transition public key /// - The transaction is another deployment in the block from the same public fee payer. /// - The transaction is an execution for a program following its deployment or redeployment in this block. + /// - The transaction is an execution with a state root whose corresponding block precedes the latest block + /// at which any of the execution's programs were deployed or upgraded. This check is enforced only after + /// `ConsensusVersion::V5` when program upgrades were introduced. /// /// - Note: If a transaction is a deployment for a program following its deployment or redeployment in this block, /// it is not aborted. Instead, it will be rejected and its fee will be consumed. @@ -847,16 +850,80 @@ impl> VM { } } - // If the transaction is an execution, ensure that its corresponding program(s) - // have not been deployed or redeployed prior to this transaction in this block. - // Note: This logic is compatible with deployments prior to `ConsensusVersion::V5`. - if let Transaction::Execute(_, _, execution, _) = transaction { - // If one of the component programs have been deployed or upgraded in this block, abort the transaction. + if let Transaction::Execute(_, id, execution, _) = transaction { + // If the transaction is an execution, ensure that its corresponding program(s) + // have not been deployed or redeployed prior to this transaction in this block. + // Note: This logic is compatible with deployments prior to `ConsensusVersion::V5`. for program_id in execution.transitions().map(|t| t.program_id()) { if deployments.contains(program_id) { return Some(format!("Program {program_id} has been deployed or upgraded in this block")); } } + + // If the current height is at `ConsensusVersion::V5` or higher, then enforce that the execution's + // state root is from a block whose height is greater than the latest block height at which any of + // the execution's programs were deployed or upgraded. + let current_height = self.block_store().current_block_height(); + let Ok(current_version) = N::CONSENSUS_VERSION(current_height) else { + return Some(format!("Failed to get consensus version for the current height: '{current_height}'")); + }; + if current_version >= ConsensusVersion::V5 { + // Track the maximum block height and the associated program ID. + let mut max_block_height = 0; + let mut latest_program = None; + // For each transition in the execution, get the block height at which the program was deployed or upgraded and update the maximum block height. + for transition in execution.transitions() { + // Get the program ID. + let program_id = transition.program_id(); + // If the program is `credits.aleo`, set the appropriate state and continue. + if program_id.to_string() == "credits.aleo" { + // Note: This unwrap is safe as `credits.aleo` is known to be a valid program ID. + latest_program = Some(ProgramID::from_str("credits.aleo").unwrap()) + } + // Get the transaction ID of the transaction that last deployed or upgraded the program. + let Ok(Some(transaction_id)) = + self.block_store().transaction_store().find_latest_transaction_id_from_program_id(program_id) + else { + return Some(format!( + "Program '{program_id}' does not have a corresponding transaction ID in the store" + )); + }; + // Get the block hash associated with the transaction ID. + let Ok(Some(block_hash)) = self.block_store().find_block_hash(&transaction_id) else { + return Some(format!( + "Transaction '{transaction_id}' does not have a corresponding block hash in the store" + )); + }; + // Get the block height associated with the block hash. + let Ok(Some(block_height)) = self.block_store().get_block_height(&block_hash) else { + return Some(format!( + "Block hash '{block_hash}' does not have a corresponding block height in the store" + )); + }; + // Update the maximum block height. + if max_block_height < block_height { + max_block_height = block_height; + latest_program = Some(*program_id); + } + } + // Get the block height of the execution. + let Ok(Some(block_height)) = + self.block_store().find_block_height_from_state_root(execution.global_state_root()) + else { + return Some(format!( + "The state root of execution '{id}' does not have a corresponding block height in the store" + )); + }; + // Ensure the block height is greater than or equal to the maximum block height. + if block_height >= max_block_height { + // Note: This unwrap is safe because if `max_block_height` is greater than `N::CONSENSUS_HEIGHT(ConsensusVersion::V5)`, + // then `latest_program` must have been set in the loop above. + return Some(format!( + "Execution '{id}' state root is earlier than the last deployment or upgrade for program '{}'", + latest_program.unwrap() + )); + } + } } // Return `None` because the transaction is well-formed. diff --git a/synthesizer/src/vm/verify.rs b/synthesizer/src/vm/verify.rs index c44f074495..de9ef40377 100644 --- a/synthesizer/src/vm/verify.rs +++ b/synthesizer/src/vm/verify.rs @@ -294,58 +294,6 @@ impl> VM { bail!("Transaction '{id}' contains a previously rejected execution") } - // Ensure that the state root of the execution is greater than or equal to the height at which its component programs were deployed or upgraded. - // Note: This is only enforced for programs deployed at or after `ConsensusVersion::V5`, when upgradability was introduced, - // to prevent executions on old versions of the program. - - // Track the maximum block height and the associated program ID. - let mut max_block_height = 0; - let mut latest_program = None; - // For each transition in the execution, get the block height at which the program was deployed or upgraded and update the maximum block height. - for transition in execution.transitions() { - // Get the program ID. - let program_id = transition.program_id(); - // Get the transaction ID of the transaction that last deployed or upgraded the program. - let Some(transaction_id) = self - .block_store() - .transaction_store() - .find_latest_transaction_id_from_program_id(program_id)? - else { - bail!("Program '{program_id}' does not have a corresponding transaction ID in the store"); - }; - // Get the block hash associated with the transaction ID. - let Some(block_hash) = self.block_store().find_block_hash(&transaction_id)? else { - bail!("Transaction '{transaction_id}' does not have a corresponding block hash in the store"); - }; - // Get the block height associated with the block hash. - let Some(block_height) = self.block_store().get_block_height(&block_hash)? else { - bail!("Block hash '{block_hash}' does not have a corresponding block height in the store"); - }; - // Update the maximum block height. - if max_block_height < block_height { - max_block_height = block_height; - latest_program = Some(program_id); - } - } - // If the maximum block height is greater than or equal to `ConsensusVersion::V5`, then check that the execution state root is later than the maximum block height. - if max_block_height >= N::CONSENSUS_HEIGHT(ConsensusVersion::V5)? { - // Get the block height of the execution. - let Some(block_height) = - self.block_store().find_block_height_from_state_root(execution.global_state_root())? - else { - bail!( - "The state root of execution '{id}' does not have a corresponding block height in the store" - ); - }; - // Ensure the block height is greater than or equal to the maximum block height. - ensure!( - block_height >= max_block_height, - "Execution '{id}' state root is earlier than the last deployment or upgrade for program '{}'", - // Note: This unwrap is safe because if `max_block_height` is greater than `N::CONSENSUS_HEIGHT(ConsensusVersion::V5)`, - // then `latest_program` must have been set in the loop above. - latest_program.unwrap() - ); - } // Verify the execution. match try_vm_runtime!(|| self.check_execution_internal(execution, is_partially_verified)) { Ok(result) => result?, From cbfbe18851771418d48f180c222389bb99fde25b Mon Sep 17 00:00:00 2001 From: Pranav Gaddamadugu <23022326+d0cd@users.noreply.github.com> Date: Mon, 21 Apr 2025 11:37:33 -0700 Subject: [PATCH 4/7] Add tests --- ledger/store/src/block/mod.rs | 2 +- synthesizer/src/vm/finalize.rs | 20 ++- synthesizer/src/vm/tests/test_vm_upgrade.rs | 159 ++++++++++++++++++-- 3 files changed, 162 insertions(+), 19 deletions(-) diff --git a/ledger/store/src/block/mod.rs b/ledger/store/src/block/mod.rs index 8688d82ebd..f0e9b81847 100644 --- a/ledger/store/src/block/mod.rs +++ b/ledger/store/src/block/mod.rs @@ -1189,7 +1189,7 @@ impl> BlockStore { /// Returns the current block height. pub fn current_block_height(&self) -> u32 { - u32::try_from(self.tree.read().number_of_leaves()).unwrap() - 1 + u32::try_from(self.tree.read().number_of_leaves()).unwrap().saturating_sub(1) } /// Returns the state root that contains the given `block height`. diff --git a/synthesizer/src/vm/finalize.rs b/synthesizer/src/vm/finalize.rs index 9fef844bf6..3961a8de27 100644 --- a/synthesizer/src/vm/finalize.rs +++ b/synthesizer/src/vm/finalize.rs @@ -77,6 +77,8 @@ impl> VM { let unordered_aborted_transaction_ids: IndexMap = verification_aborted_transaction_ids.chain(speculation_aborted_transaction_ids).collect(); + println!("Unordered aborted transaction IDs: {unordered_aborted_transaction_ids:?}"); + // Filter and order the aborted transaction ids according to candidate_transactions let aborted_transaction_ids: Vec<_> = candidate_transaction_ids .into_iter() @@ -788,9 +790,9 @@ impl> VM { /// - The transaction is producing a duplicate transition public key /// - The transaction is another deployment in the block from the same public fee payer. /// - The transaction is an execution for a program following its deployment or redeployment in this block. - /// - The transaction is an execution with a state root whose corresponding block precedes the latest block - /// at which any of the execution's programs were deployed or upgraded. This check is enforced only after - /// `ConsensusVersion::V5` when program upgrades were introduced. + /// - The transaction is an execution with a state root whose corresponding block height is greater than or + /// equal to the latest block at which any of the execution's programs were deployed or upgraded. This + /// check is enforced only after `ConsensusVersion::V5` when program upgrades were introduced. /// /// - Note: If a transaction is a deployment for a program following its deployment or redeployment in this block, /// it is not aborted. Instead, it will be rejected and its fee will be consumed. @@ -878,7 +880,8 @@ impl> VM { // If the program is `credits.aleo`, set the appropriate state and continue. if program_id.to_string() == "credits.aleo" { // Note: This unwrap is safe as `credits.aleo` is known to be a valid program ID. - latest_program = Some(ProgramID::from_str("credits.aleo").unwrap()) + latest_program = Some(ProgramID::from_str("credits.aleo").unwrap()); + continue; } // Get the transaction ID of the transaction that last deployed or upgraded the program. let Ok(Some(transaction_id)) = @@ -914,10 +917,11 @@ impl> VM { "The state root of execution '{id}' does not have a corresponding block height in the store" )); }; - // Ensure the block height is greater than or equal to the maximum block height. - if block_height >= max_block_height { - // Note: This unwrap is safe because if `max_block_height` is greater than `N::CONSENSUS_HEIGHT(ConsensusVersion::V5)`, - // then `latest_program` must have been set in the loop above. + // If the block height of the execution is less than the maximum block height, abort the transaction. + if block_height < max_block_height { + // Note: This unwrap is safe because `latest_program` must have been set in the loop above. + // - Either the program was `credits.aleo`, in which case `latest_program` was explicitly set. + // - Or the program was deployed after the genesis block and `latest_program` was set to the program ID. return Some(format!( "Execution '{id}' state root is earlier than the last deployment or upgrade for program '{}'", latest_program.unwrap() diff --git a/synthesizer/src/vm/tests/test_vm_upgrade.rs b/synthesizer/src/vm/tests/test_vm_upgrade.rs index e37b12676b..c459707dea 100644 --- a/synthesizer/src/vm/tests/test_vm_upgrade.rs +++ b/synthesizer/src/vm/tests/test_vm_upgrade.rs @@ -500,7 +500,7 @@ constructor: None, rng ) - .is_err() + .is_err() ); // Get the first record and execute the convert function. @@ -554,7 +554,7 @@ constructor: None, rng ) - .is_err() + .is_err() ); Ok(()) @@ -1234,7 +1234,7 @@ constructor: None, rng, ) - .is_err() + .is_err() ); Ok(()) @@ -2032,7 +2032,7 @@ fn test_simple_admin_upgrade() { Value::from_str(&format!("{}", separate_caller_address)).unwrap(), Value::from_str("10_000_000_000_000u64").unwrap(), ] - .into_iter(), + .into_iter(), None, 0, None, @@ -2054,7 +2054,7 @@ constructor: assert.eq program_owner {caller_address}; " )) - .unwrap(); + .unwrap(); let program_v1 = Program::from_str(&format!( r" @@ -2065,7 +2065,7 @@ constructor: assert.eq program_owner {caller_address}; " )) - .unwrap(); + .unwrap(); // Attempt to deploy the first version of the program with the wrong admin. let transaction = vm.deploy(&separate_caller_private_key, &program_v0, None, 0, None, rng).unwrap(); @@ -2122,7 +2122,7 @@ constructor: assert.eq true true; ", ) - .unwrap(); + .unwrap(); let program_v1 = Program::from_str( r" @@ -2134,7 +2134,7 @@ constructor: assert.eq true true; ", ) - .unwrap(); + .unwrap(); // Deploy the first version of the program. let transaction = vm.deploy(&caller_private_key, &program_v0, None, 0, None, rng).unwrap(); @@ -2200,7 +2200,7 @@ fn test_program_deployed_before_v5_do_not_have_owner() { program test_program_0.aleo; function foo:", ) - .unwrap(); + .unwrap(); let program_after_v5 = Program::from_str( r" @@ -2210,7 +2210,7 @@ constructor: assert.eq true true; ", ) - .unwrap(); + .unwrap(); // Deploy the first program. let transaction = vm.deploy(&caller_private_key, &program_before_v5, None, 0, None, rng).unwrap(); @@ -2247,3 +2247,142 @@ constructor: assert!(stack.program_owner().is_some()); assert_eq!(stack.program_owner().unwrap(), caller_address); } + +#[test] +fn test_old_execution_is_aborted_after_upgrade() { + let rng = &mut TestRng::default(); + + // Initialize a new caller. + let caller_private_key = sample_genesis_private_key(rng); + + // Initialize the VM. + let vm = sample_vm_at_height(CurrentNetwork::CONSENSUS_HEIGHT(ConsensusVersion::V5).unwrap(), rng); + + // Define the programs. + let program_v0 = Program::from_str( + r" +program test_program.aleo; +constructor: + assert.eq true true; +function dummy:", + ) + .unwrap(); + + let program_v1 = Program::from_str( + r" +program test_program.aleo; +constructor: + assert.eq true true; +function dummy: +function dummy2:", + ) + .unwrap(); + + // Deploy the first version of the program. + let transaction = vm.deploy(&caller_private_key, &program_v0, None, 0, None, rng).unwrap(); + let block = sample_next_block(&vm, &caller_private_key, &[transaction], rng).unwrap(); + assert_eq!(block.transactions().num_accepted(), 1); + assert_eq!(block.transactions().num_rejected(), 0); + assert_eq!(block.aborted_transaction_ids().len(), 0); + vm.add_next_block(&block).unwrap(); + + // Pre-generate 3 executions of the dummy function. + let executions = (0..3) + .map(|_| { + vm.execute( + &caller_private_key, + ("test_program.aleo", "dummy"), + Vec::>::new().into_iter(), + None, + 0, + None, + rng, + ) + .unwrap() + }) + .collect::>(); + + // Add 2 transactions individually to blocks. + // They are expected to pass because the program has not been upgraded. + for execution in &executions[0..2] { + let block = sample_next_block(&vm, &caller_private_key, &[execution.clone()], rng).unwrap(); + assert_eq!(block.transactions().num_accepted(), 1); + assert_eq!(block.transactions().num_rejected(), 0); + assert_eq!(block.aborted_transaction_ids().len(), 0); + vm.add_next_block(&block).unwrap(); + } + + // Upgrade the program. + let transaction = vm.deploy(&caller_private_key, &program_v1, None, 0, None, rng).unwrap(); + let block = sample_next_block(&vm, &caller_private_key, &[transaction], rng).unwrap(); + assert_eq!(block.transactions().num_accepted(), 1); + assert_eq!(block.transactions().num_rejected(), 0); + assert_eq!(block.aborted_transaction_ids().len(), 0); + vm.add_next_block(&block).unwrap(); + + // Add the third transaction to a block. + // It is expected to be aborted because the program has been upgraded. + let block = sample_next_block(&vm, &caller_private_key, &[executions[2].clone()], rng).unwrap(); + assert_eq!(block.transactions().num_accepted(), 0); + assert_eq!(block.transactions().num_rejected(), 0); + assert_eq!(block.aborted_transaction_ids().len(), 1); + vm.add_next_block(&block).unwrap(); +} + +#[test] +fn test_credits_execution_with_genesis_state_root() { + let rng = &mut TestRng::default(); + + // Initialize a new caller. + let caller_private_key = sample_genesis_private_key(rng); + let caller_address = Address::try_from(&caller_private_key).unwrap(); + + // Initialize the VM at height 0. + let vm = sample_vm_at_height(0, rng); + + // Generate two executions of `transfer_public`. + let transfer_1 = vm + .execute( + &caller_private_key, + ("credits.aleo", "transfer_public"), + vec![Value::from_str(&format!("{caller_address}")).unwrap(), Value::from_str("2u64").unwrap()].into_iter(), + None, + 0, + None, + rng, + ) + .unwrap(); + assert!(vm.check_transaction(&transfer_1, None, rng).is_ok()); + + let transfer_2 = vm + .execute( + &caller_private_key, + ("credits.aleo", "transfer_public"), + vec![Value::from_str(&format!("{caller_address}")).unwrap(), Value::from_str("4u64").unwrap()].into_iter(), + None, + 0, + None, + rng, + ) + .unwrap(); + assert!(vm.check_transaction(&transfer_2, None, rng).is_ok()); + + // Add the first transaction to a block. + let block = sample_next_block(&vm, &caller_private_key, &[transfer_1], rng).unwrap(); + assert_eq!(block.transactions().num_accepted(), 1); + assert_eq!(block.transactions().num_rejected(), 0); + assert_eq!(block.aborted_transaction_ids().len(), 0); + vm.add_next_block(&block).unwrap(); + + // Skip to consensus height V5. + while vm.block_store().current_block_height() <= CurrentNetwork::CONSENSUS_HEIGHT(ConsensusVersion::V5).unwrap() { + let block = sample_next_block(&vm, &caller_private_key, &[], rng).unwrap(); + vm.add_next_block(&block).unwrap(); + } + + // Add the second transaction to a block. + let block = sample_next_block(&vm, &caller_private_key, &[transfer_2], rng).unwrap(); + assert_eq!(block.transactions().num_accepted(), 1); + assert_eq!(block.transactions().num_rejected(), 0); + assert_eq!(block.aborted_transaction_ids().len(), 0); +} \ No newline at end of file From 2a685c2f7fa98d5872498284291f502732e33d6c Mon Sep 17 00:00:00 2001 From: Pranav Gaddamadugu <23022326+d0cd@users.noreply.github.com> Date: Wed, 21 May 2025 12:00:44 -0400 Subject: [PATCH 5/7] Cleanup --- synthesizer/src/vm/finalize.rs | 2 -- synthesizer/src/vm/tests/test_vm_upgrade.rs | 28 ++++++++++----------- synthesizer/src/vm/verify.rs | 1 - 3 files changed, 14 insertions(+), 17 deletions(-) diff --git a/synthesizer/src/vm/finalize.rs b/synthesizer/src/vm/finalize.rs index 3961a8de27..dd1c31fca4 100644 --- a/synthesizer/src/vm/finalize.rs +++ b/synthesizer/src/vm/finalize.rs @@ -77,8 +77,6 @@ impl> VM { let unordered_aborted_transaction_ids: IndexMap = verification_aborted_transaction_ids.chain(speculation_aborted_transaction_ids).collect(); - println!("Unordered aborted transaction IDs: {unordered_aborted_transaction_ids:?}"); - // Filter and order the aborted transaction ids according to candidate_transactions let aborted_transaction_ids: Vec<_> = candidate_transaction_ids .into_iter() diff --git a/synthesizer/src/vm/tests/test_vm_upgrade.rs b/synthesizer/src/vm/tests/test_vm_upgrade.rs index c459707dea..bcad9d2b0c 100644 --- a/synthesizer/src/vm/tests/test_vm_upgrade.rs +++ b/synthesizer/src/vm/tests/test_vm_upgrade.rs @@ -500,7 +500,7 @@ constructor: None, rng ) - .is_err() + .is_err() ); // Get the first record and execute the convert function. @@ -554,7 +554,7 @@ constructor: None, rng ) - .is_err() + .is_err() ); Ok(()) @@ -1234,7 +1234,7 @@ constructor: None, rng, ) - .is_err() + .is_err() ); Ok(()) @@ -2032,7 +2032,7 @@ fn test_simple_admin_upgrade() { Value::from_str(&format!("{}", separate_caller_address)).unwrap(), Value::from_str("10_000_000_000_000u64").unwrap(), ] - .into_iter(), + .into_iter(), None, 0, None, @@ -2054,7 +2054,7 @@ constructor: assert.eq program_owner {caller_address}; " )) - .unwrap(); + .unwrap(); let program_v1 = Program::from_str(&format!( r" @@ -2065,7 +2065,7 @@ constructor: assert.eq program_owner {caller_address}; " )) - .unwrap(); + .unwrap(); // Attempt to deploy the first version of the program with the wrong admin. let transaction = vm.deploy(&separate_caller_private_key, &program_v0, None, 0, None, rng).unwrap(); @@ -2122,7 +2122,7 @@ constructor: assert.eq true true; ", ) - .unwrap(); + .unwrap(); let program_v1 = Program::from_str( r" @@ -2134,7 +2134,7 @@ constructor: assert.eq true true; ", ) - .unwrap(); + .unwrap(); // Deploy the first version of the program. let transaction = vm.deploy(&caller_private_key, &program_v0, None, 0, None, rng).unwrap(); @@ -2200,7 +2200,7 @@ fn test_program_deployed_before_v5_do_not_have_owner() { program test_program_0.aleo; function foo:", ) - .unwrap(); + .unwrap(); let program_after_v5 = Program::from_str( r" @@ -2210,7 +2210,7 @@ constructor: assert.eq true true; ", ) - .unwrap(); + .unwrap(); // Deploy the first program. let transaction = vm.deploy(&caller_private_key, &program_before_v5, None, 0, None, rng).unwrap(); @@ -2266,7 +2266,7 @@ constructor: assert.eq true true; function dummy:", ) - .unwrap(); + .unwrap(); let program_v1 = Program::from_str( r" @@ -2276,7 +2276,7 @@ constructor: function dummy: function dummy2:", ) - .unwrap(); + .unwrap(); // Deploy the first version of the program. let transaction = vm.deploy(&caller_private_key, &program_v0, None, 0, None, rng).unwrap(); @@ -2298,7 +2298,7 @@ function dummy2:", None, rng, ) - .unwrap() + .unwrap() }) .collect::>(); @@ -2385,4 +2385,4 @@ fn test_credits_execution_with_genesis_state_root() { assert_eq!(block.transactions().num_accepted(), 1); assert_eq!(block.transactions().num_rejected(), 0); assert_eq!(block.aborted_transaction_ids().len(), 0); -} \ No newline at end of file +} diff --git a/synthesizer/src/vm/verify.rs b/synthesizer/src/vm/verify.rs index de9ef40377..062fece936 100644 --- a/synthesizer/src/vm/verify.rs +++ b/synthesizer/src/vm/verify.rs @@ -293,7 +293,6 @@ impl> VM { if self.block_store().contains_rejected_deployment_or_execution_id(execution_id)? { bail!("Transaction '{id}' contains a previously rejected execution") } - // Verify the execution. match try_vm_runtime!(|| self.check_execution_internal(execution, is_partially_verified)) { Ok(result) => result?, From aa2a0e5bb4679088a04705e815982c0da725797b Mon Sep 17 00:00:00 2001 From: Pranav Gaddamadugu <23022326+d0cd@users.noreply.github.com> Date: Mon, 26 May 2025 20:33:54 -0700 Subject: [PATCH 6/7] Feedback --- synthesizer/src/vm/finalize.rs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/synthesizer/src/vm/finalize.rs b/synthesizer/src/vm/finalize.rs index 1f526337d2..d806fd4540 100644 --- a/synthesizer/src/vm/finalize.rs +++ b/synthesizer/src/vm/finalize.rs @@ -877,8 +877,7 @@ impl> VM { let program_id = transition.program_id(); // If the program is `credits.aleo`, set the appropriate state and continue. if program_id.to_string() == "credits.aleo" { - // Note: This unwrap is safe as `credits.aleo` is known to be a valid program ID. - latest_program = Some(ProgramID::from_str("credits.aleo").unwrap()); + latest_program = Some(*program_id); continue; } // Get the transaction ID of the transaction that last deployed or upgraded the program. From 962d5fd0f2055ca3fa1f73234c2eee381307a105 Mon Sep 17 00:00:00 2001 From: Pranav Gaddamadugu <23022326+d0cd@users.noreply.github.com> Date: Tue, 27 May 2025 06:16:56 -0700 Subject: [PATCH 7/7] Fix test --- synthesizer/src/vm/tests/test_vm_upgrade.rs | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/synthesizer/src/vm/tests/test_vm_upgrade.rs b/synthesizer/src/vm/tests/test_vm_upgrade.rs index 3c63f2cb2d..b00f9a2d1a 100644 --- a/synthesizer/src/vm/tests/test_vm_upgrade.rs +++ b/synthesizer/src/vm/tests/test_vm_upgrade.rs @@ -20,6 +20,8 @@ use crate::vm::test_helpers::*; use console::{account::ViewKey, program::Value}; use synthesizer_program::{Program, StackProgram}; +use crate::vm::test_helpers::sample_vm_at_height; +use console::network::ConsensusVersion; use std::panic::AssertUnwindSafe; // This test checks that: @@ -2329,16 +2331,18 @@ function dummy2:", vm.add_next_block(&block).unwrap(); } +// This test verifies that `credits.aleo` transactions can be executed and added to blocks after the upgrade to V8. #[test] -fn test_credits_execution_with_genesis_state_root() { +fn test_credits_executions() { let rng = &mut TestRng::default(); // Initialize a new caller. let caller_private_key = sample_genesis_private_key(rng); let caller_address = Address::try_from(&caller_private_key).unwrap(); - // Initialize the VM at height 0. - let vm = sample_vm_at_height(0, rng); + // Initialize the VM. + let vm: crate::VM = + sample_vm_at_height(CurrentNetwork::CONSENSUS_HEIGHT(ConsensusVersion::V8).unwrap() - 1, rng); // Generate two executions of `transfer_public`. let transfer_1 = vm