diff --git a/.github/workflows/light-system-programs-tests.yml b/.github/workflows/light-system-programs-tests.yml index 5cb979b492..8a9d9909e4 100644 --- a/.github/workflows/light-system-programs-tests.yml +++ b/.github/workflows/light-system-programs-tests.yml @@ -64,7 +64,7 @@ jobs: - program: light-compressed-token sub-tests: '["cargo-test-sbf -p compressed-token-test"]' - program: system-cpi-test - sub-tests: '["cargo-test-sbf -p system-cpi-test", "cargo test -p light-system-program-pinocchio --all-features"]' + sub-tests: '["cargo-test-sbf -p system-cpi-test", "cargo test -p light-system-program-pinocchio"]' - program: system-cpi-test-v2-event sub-tests: '["cargo-test-sbf -p system-cpi-v2-test -- event::parse"]' - program: system-cpi-test-v2-functional diff --git a/program-tests/compressed-token-test/tests/test.rs b/program-tests/compressed-token-test/tests/test.rs index c8e165d856..ecf7d8cd2e 100644 --- a/program-tests/compressed-token-test/tests/test.rs +++ b/program-tests/compressed-token-test/tests/test.rs @@ -2,7 +2,6 @@ use std::{assert_eq, str::FromStr}; -use account_compression::errors::AccountCompressionErrorCode; use anchor_lang::{ prelude::AccountMeta, system_program, AccountDeserialize, AnchorDeserialize, AnchorSerialize, InstructionData, ToAccountMetas, @@ -1244,7 +1243,7 @@ async fn test_mint_to_failing() { assert_rpc_error( result, 0, - AccountCompressionErrorCode::StateMerkleTreeAccountDiscriminatorMismatch.into(), + SystemProgramError::StateMerkleTreeAccountDiscriminatorMismatch.into(), ) .unwrap(); } @@ -2303,7 +2302,7 @@ async fn test_approve_failing() { assert_rpc_error( result, 0, - AccountCompressionErrorCode::StateMerkleTreeAccountDiscriminatorMismatch.into(), + SystemProgramError::StateMerkleTreeAccountDiscriminatorMismatch.into(), ) .unwrap(); } @@ -2349,7 +2348,7 @@ async fn test_approve_failing() { assert_rpc_error( result, 0, - AccountCompressionErrorCode::StateMerkleTreeAccountDiscriminatorMismatch.into(), + SystemProgramError::StateMerkleTreeAccountDiscriminatorMismatch.into(), ) .unwrap(); } @@ -2782,7 +2781,7 @@ async fn test_revoke_failing() { assert_rpc_error( result, 0, - AccountCompressionErrorCode::StateMerkleTreeAccountDiscriminatorMismatch.into(), + SystemProgramError::StateMerkleTreeAccountDiscriminatorMismatch.into(), ) .unwrap(); } @@ -3404,7 +3403,7 @@ async fn failing_tests_burn() { assert_rpc_error( res, 0, - anchor_lang::error::ErrorCode::AccountDiscriminatorMismatch.into(), + SystemProgramError::StateMerkleTreeAccountDiscriminatorMismatch.into(), ) .unwrap(); } @@ -5251,7 +5250,7 @@ async fn test_invalid_inputs() { assert_custom_error_or_program_error( res, - anchor_lang::error::ErrorCode::AccountDiscriminatorMismatch.into(), + SystemProgramError::StateMerkleTreeAccountDiscriminatorMismatch.into(), ) .unwrap(); } diff --git a/programs/compressed-token/src/burn.rs b/programs/compressed-token/src/burn.rs index 95a42ade34..830c688dae 100644 --- a/programs/compressed-token/src/burn.rs +++ b/programs/compressed-token/src/burn.rs @@ -171,7 +171,6 @@ pub fn create_input_and_output_accounts_burn( lamports, &hashed_mint, &[inputs.change_account_merkle_tree_index], - remaining_accounts, )?; output_compressed_accounts } else { @@ -181,7 +180,6 @@ pub fn create_input_and_output_accounts_burn( &mut compressed_input_accounts, input_token_data.as_slice(), &hashed_mint, - remaining_accounts, )?; Ok((compressed_input_accounts, output_compressed_accounts)) } diff --git a/programs/compressed-token/src/delegation.rs b/programs/compressed-token/src/delegation.rs index 99eea8eec4..d900d8082d 100644 --- a/programs/compressed-token/src/delegation.rs +++ b/programs/compressed-token/src/delegation.rs @@ -158,13 +158,11 @@ pub fn create_input_and_output_accounts_approve( lamports, &hashed_mint, &merkle_tree_indices, - remaining_accounts, )?; add_data_hash_to_input_compressed_accounts::( &mut compressed_input_accounts, input_token_data.as_slice(), &hashed_mint, - remaining_accounts, )?; Ok((compressed_input_accounts, output_compressed_accounts)) } @@ -250,13 +248,11 @@ pub fn create_input_and_output_accounts_revoke( lamports, &hashed_mint, &[inputs.output_account_merkle_tree_index], - remaining_accounts, )?; add_data_hash_to_input_compressed_accounts::( &mut compressed_input_accounts, input_token_data.as_slice(), &hashed_mint, - remaining_accounts, )?; Ok((compressed_input_accounts, output_compressed_accounts)) } diff --git a/programs/compressed-token/src/freeze.rs b/programs/compressed-token/src/freeze.rs index 68163fd6e9..27ad24d400 100644 --- a/programs/compressed-token/src/freeze.rs +++ b/programs/compressed-token/src/freeze.rs @@ -1,4 +1,3 @@ -use account_compression::StateMerkleTreeAccount; use anchor_lang::prelude::*; use light_compressed_account::{ compressed_account::{CompressedAccount, CompressedAccountData}, @@ -14,7 +13,7 @@ use crate::{ process_transfer::{ add_data_hash_to_input_compressed_accounts, cpi_execute_compressed_transaction_transfer, get_input_compressed_accounts_with_merkle_context_and_check_signer, - InputTokenDataWithContext, BATCHED_DISCRIMINATOR, + InputTokenDataWithContext, }, token_data::{AccountState, TokenData}, FreezeInstruction, @@ -116,7 +115,6 @@ pub fn create_input_and_output_accounts_freeze_or_thaw< &mut compressed_input_accounts, input_token_data.as_slice(), &hashed_mint, - remaining_accounts, )?; Ok((compressed_input_accounts, output_compressed_accounts)) } @@ -165,18 +163,7 @@ fn create_token_output_accounts( }; token_data.serialize(&mut token_data_bytes)?; - let discriminator_bytes = &remaining_accounts[token_data_with_context - .merkle_context - .merkle_tree_pubkey_index - as usize] - .try_borrow_data()?[0..8]; - use anchor_lang::Discriminator; - let data_hash = match discriminator_bytes { - StateMerkleTreeAccount::DISCRIMINATOR => token_data.hash_legacy(), - BATCHED_DISCRIMINATOR => token_data.hash(), - _ => panic!(), - } - .map_err(ProgramError::from)?; + let data_hash = token_data.hash().map_err(ProgramError::from)?; let data: CompressedAccountData = CompressedAccountData { discriminator: TOKEN_COMPRESSED_ACCOUNT_DISCRIMINATOR, @@ -519,7 +506,7 @@ pub mod test_freeze { let change_data_struct = CompressedAccountData { discriminator: TOKEN_COMPRESSED_ACCOUNT_DISCRIMINATOR, data: serialized_expected_token_data.clone(), - data_hash: token_data.hash_legacy().unwrap(), + data_hash: token_data.hash().unwrap(), }; expected_compressed_output_accounts.push(OutputCompressedAccountWithPackedContext { compressed_account: CompressedAccount { @@ -578,7 +565,7 @@ pub mod test_freeze { }; let mut data = Vec::new(); token_data.serialize(&mut data).unwrap(); - let data_hash = token_data.hash_legacy().unwrap(); + let data_hash = token_data.hash().unwrap(); InAccount { lamports: 0, address: None, diff --git a/programs/compressed-token/src/process_mint.rs b/programs/compressed-token/src/process_mint.rs index 719eeda736..470c88c968 100644 --- a/programs/compressed-token/src/process_mint.rs +++ b/programs/compressed-token/src/process_mint.rs @@ -122,7 +122,6 @@ pub fn process_mint_to_or_compress<'info, const IS_MINT_TO: bool>( // We ensure that the Merkle tree account is the first // remaining account in the cpi to the system program. &vec![0; amounts.len()], - &[ctx.accounts.merkle_tree.to_account_info()], )?; bench_sbf_end!("tm_output_compressed_accounts"); @@ -564,7 +563,7 @@ mod test { let data = CompressedAccountData { discriminator: TOKEN_COMPRESSED_ACCOUNT_DISCRIMINATOR, data: token_data_bytes, - data_hash: token_data.hash_legacy().unwrap(), + data_hash: token_data.hash().unwrap(), }; let lamports = 0; @@ -629,7 +628,7 @@ mod test { let data = CompressedAccountData { discriminator: TOKEN_COMPRESSED_ACCOUNT_DISCRIMINATOR, data: token_data_bytes, - data_hash: token_data.hash_legacy().unwrap(), + data_hash: token_data.hash().unwrap(), }; let lamports = rng.gen_range(0..1_000_000_000_000); diff --git a/programs/compressed-token/src/process_transfer.rs b/programs/compressed-token/src/process_transfer.rs index 7f3d67b7bc..ea1503463e 100644 --- a/programs/compressed-token/src/process_transfer.rs +++ b/programs/compressed-token/src/process_transfer.rs @@ -1,7 +1,5 @@ -use account_compression::{utils::constants::CPI_AUTHORITY_PDA_SEED, StateMerkleTreeAccount}; -use anchor_lang::{ - prelude::*, solana_program::program_error::ProgramError, AnchorDeserialize, Discriminator, -}; +use account_compression::utils::constants::CPI_AUTHORITY_PDA_SEED; +use anchor_lang::{prelude::*, solana_program::program_error::ProgramError, AnchorDeserialize}; use light_compressed_account::{ compressed_account::{CompressedAccount, CompressedAccountData, PackedMerkleContext}, hash_to_bn254_field_size_be, @@ -128,7 +126,6 @@ pub fn process_transfer<'a, 'b, 'c, 'info: 'b + 'c>( .iter() .map(|data| data.merkle_tree_index) .collect::>(), - ctx.remaining_accounts, )?; bench_sbf_end!("t_create_output_compressed_accounts"); @@ -138,7 +135,6 @@ pub fn process_transfer<'a, 'b, 'c, 'info: 'b + 'c>( &mut compressed_input_accounts, input_token_data.as_slice(), &hashed_mint, - ctx.remaining_accounts, )?; } bench_sbf_end!("t_add_token_data_to_input_compressed_accounts"); @@ -177,8 +173,6 @@ pub fn process_transfer<'a, 'b, 'c, 'info: 'b + 'c>( ctx.remaining_accounts, ) } -pub const BATCHED_DISCRIMINATOR: &[u8] = b"BatchMta"; -pub const OUTPUT_QUEUE_DISCRIMINATOR: &[u8] = b"queueacc"; /// Creates output compressed accounts. /// Steps: @@ -197,7 +191,6 @@ pub fn create_output_compressed_accounts( lamports: Option>>, hashed_mint: &[u8; 32], merkle_tree_indices: &[u8], - remaining_accounts: &[AccountInfo<'_>], ) -> Result { let mut sum_lamports = 0; let hashed_delegate_store = if let Some(delegate) = delegate { @@ -242,29 +235,7 @@ pub fn create_output_compressed_accounts( let hashed_owner = hash_to_bn254_field_size_be(owner.to_pubkey_bytes().as_slice()); let mut amount_bytes = [0u8; 32]; - let discriminator_bytes = - &remaining_accounts[merkle_tree_indices[i] as usize].try_borrow_data()?[0..8]; - match discriminator_bytes { - StateMerkleTreeAccount::DISCRIMINATOR => { - amount_bytes[24..].copy_from_slice(amount.to_bytes_le().as_slice()); - Ok(()) - } - BATCHED_DISCRIMINATOR => { - amount_bytes[24..].copy_from_slice(amount.to_bytes_be().as_slice()); - Ok(()) - } - OUTPUT_QUEUE_DISCRIMINATOR => { - amount_bytes[24..].copy_from_slice(amount.to_bytes_be().as_slice()); - Ok(()) - } - _ => { - msg!( - "{} is no Merkle tree or output queue account. ", - remaining_accounts[merkle_tree_indices[i] as usize].key() - ); - err!(anchor_lang::error::ErrorCode::AccountDiscriminatorMismatch) - } - }?; + amount_bytes[24..].copy_from_slice(amount.to_bytes_le().as_slice()); let data_hash = TokenData::hash_with_hashed_values( hashed_mint, @@ -306,7 +277,6 @@ pub fn add_data_hash_to_input_compressed_accounts( input_compressed_accounts_with_merkle_context: &mut [InAccount], input_token_data: &[TokenData], hashed_mint: &[u8; 32], - remaining_accounts: &[AccountInfo<'_>], ) -> Result<()> { for (i, compressed_account_with_context) in input_compressed_accounts_with_merkle_context .iter_mut() @@ -315,38 +285,7 @@ pub fn add_data_hash_to_input_compressed_accounts( let hashed_owner = hash_to_bn254_field_size_be(&input_token_data[i].owner.to_bytes()); let mut amount_bytes = [0u8; 32]; - let discriminator_bytes = &remaining_accounts[compressed_account_with_context - .merkle_context - .merkle_tree_pubkey_index - as usize] - .try_borrow_data()?[0..8]; - match discriminator_bytes { - StateMerkleTreeAccount::DISCRIMINATOR => { - amount_bytes[24..] - .copy_from_slice(input_token_data[i].amount.to_le_bytes().as_slice()); - Ok(()) - } - BATCHED_DISCRIMINATOR => { - amount_bytes[24..] - .copy_from_slice(input_token_data[i].amount.to_be_bytes().as_slice()); - Ok(()) - } - OUTPUT_QUEUE_DISCRIMINATOR => { - amount_bytes[24..] - .copy_from_slice(input_token_data[i].amount.to_be_bytes().as_slice()); - Ok(()) - } - _ => { - msg!( - "{} is no Merkle tree or output queue account. ", - remaining_accounts[compressed_account_with_context - .merkle_context - .merkle_tree_pubkey_index as usize] - .key() - ); - err!(anchor_lang::error::ErrorCode::AccountDiscriminatorMismatch) - } - }?; + amount_bytes[24..].copy_from_slice(input_token_data[i].amount.to_le_bytes().as_slice()); let delegate_store; let hashed_delegate = if let Some(delegate) = input_token_data[i].delegate { delegate_store = hash_to_bn254_field_size_be(&delegate.to_bytes()); diff --git a/programs/compressed-token/src/token_data.rs b/programs/compressed-token/src/token_data.rs index b1cbdfe78e..15ad37b846 100644 --- a/programs/compressed-token/src/token_data.rs +++ b/programs/compressed-token/src/token_data.rs @@ -102,28 +102,13 @@ impl TokenData { } impl TokenData { - /// Hashes token data of token accounts. - /// - /// Note, hashing changed for token account data in batched Merkle trees. - /// For hashing of token account data stored in concurrent Merkle trees use hash_legacy(). - pub fn hash(&self) -> std::result::Result<[u8; 32], HasherError> { - self._hash::() - } - /// Hashes token data of token accounts stored in concurrent Merkle trees. - pub fn hash_legacy(&self) -> std::result::Result<[u8; 32], HasherError> { - self._hash::() - } - - fn _hash(&self) -> std::result::Result<[u8; 32], HasherError> { + pub fn hash(&self) -> std::result::Result<[u8; 32], HasherError> { let hashed_mint = hash_to_bn254_field_size_be(self.mint.to_bytes().as_slice()); let hashed_owner = hash_to_bn254_field_size_be(self.owner.to_bytes().as_slice()); let mut amount_bytes = [0u8; 32]; - if BATCHED { - amount_bytes[24..].copy_from_slice(self.amount.to_be_bytes().as_slice()); - } else { - amount_bytes[24..].copy_from_slice(self.amount.to_le_bytes().as_slice()); - } + amount_bytes[24..].copy_from_slice(self.amount.to_le_bytes().as_slice()); + let hashed_delegate; let hashed_delegate_option = if let Some(delegate) = self.delegate { hashed_delegate = hash_to_bn254_field_size_be(delegate.to_bytes().as_slice()); @@ -167,7 +152,7 @@ pub mod test { state: AccountState::Initialized, tlv: None, }; - let hashed_token_data = token_data.hash_legacy().unwrap(); + let hashed_token_data = token_data.hash().unwrap(); let hashed_mint = hash_to_bn254_field_size_be(token_data.mint.to_bytes().as_slice()); let hashed_owner = hash_to_bn254_field_size_be(token_data.owner.to_bytes().as_slice()); let hashed_delegate = @@ -192,7 +177,7 @@ pub mod test { state: AccountState::Initialized, tlv: None, }; - let hashed_token_data = token_data.hash_legacy().unwrap(); + let hashed_token_data = token_data.hash().unwrap(); let hashed_mint = hash_to_bn254_field_size_be(token_data.mint.to_bytes().as_slice()); let hashed_owner = hash_to_bn254_field_size_be(token_data.owner.to_bytes().as_slice()); let mut amount_bytes = [0u8; 32]; @@ -207,7 +192,8 @@ pub mod test { fn legacy_hash(&self) -> std::result::Result<[u8; 32], HasherError> { let hashed_mint = hash_to_bn254_field_size_be(self.mint.to_bytes().as_slice()); let hashed_owner = hash_to_bn254_field_size_be(self.owner.to_bytes().as_slice()); - let amount_bytes = self.amount.to_le_bytes(); + let mut amount_bytes = [0u8; 32]; + amount_bytes[24..].copy_from_slice(self.amount.to_le_bytes().as_slice()); let hashed_delegate; let hashed_delegate_option = if let Some(delegate) = self.delegate { hashed_delegate = hash_to_bn254_field_size_be(delegate.to_bytes().as_slice()); @@ -244,7 +230,7 @@ pub mod test { state: AccountState::Initialized, tlv: None, }; - let hashed_token_data = token_data.hash_legacy().unwrap(); + let hashed_token_data = token_data.hash().unwrap(); let hashed_mint = hash_to_bn254_field_size_be(token_data.mint.to_bytes().as_slice()); let hashed_owner = hash_to_bn254_field_size_be(token_data.owner.to_bytes().as_slice()); let hashed_delegate = @@ -270,7 +256,7 @@ pub mod test { state: AccountState::Initialized, tlv: None, }; - let hashed_token_data = token_data.hash_legacy().unwrap(); + let hashed_token_data = token_data.hash().unwrap(); let hashed_mint = hash_to_bn254_field_size_be(token_data.mint.to_bytes().as_slice()); let hashed_owner = hash_to_bn254_field_size_be(token_data.owner.to_bytes().as_slice()); let mut amount_bytes = [0u8; 32]; @@ -355,7 +341,7 @@ pub mod test { &Some(&hashed_delegate), ) .unwrap(); - let other_hash = token_data.hash_legacy().unwrap(); + let other_hash = token_data.hash().unwrap(); assert_eq!(hash, other_hash); } @@ -427,11 +413,11 @@ pub mod test { // different account state let mut token_data = token_data; token_data.state = AccountState::Frozen; - let hash9 = token_data.hash_legacy().unwrap(); + let hash9 = token_data.hash().unwrap(); assert_to_previous_hashes(hash9, &mut vec_previous_hashes); // different account state with delegate token_data.delegate = Some(delegate); - let hash10 = token_data.hash_legacy().unwrap(); + let hash10 = token_data.hash().unwrap(); assert_to_previous_hashes(hash10, &mut vec_previous_hashes); } diff --git a/programs/system/Cargo.toml b/programs/system/Cargo.toml index a214c0fbd1..493f7a5d64 100644 --- a/programs/system/Cargo.toml +++ b/programs/system/Cargo.toml @@ -18,6 +18,7 @@ default = ["debug", "readonly"] test-sbf = [] debug = [] readonly = [] +deactivate-cpi-context = [] [dependencies] light-concurrent-merkle-tree = { workspace = true, features = ["pinocchio"] } diff --git a/programs/system/src/errors.rs b/programs/system/src/errors.rs index 4b30fcb0d5..4963d5121e 100644 --- a/programs/system/src/errors.rs +++ b/programs/system/src/errors.rs @@ -116,6 +116,8 @@ pub enum SystemProgramError { BorrowingDataFailed, #[error("DuplicateAccountInInputsAndReadOnly")] DuplicateAccountInInputsAndReadOnly, + #[error("CpiContextDeactivated")] + CpiContextDeactivated, #[error("Batched Merkle tree error {0}")] BatchedMerkleTreeError(#[from] BatchedMerkleTreeError), #[error("Concurrent Merkle tree error {0}")] @@ -187,6 +189,7 @@ impl From for u32 { SystemProgramError::TooManyOutputAccounts => 6051, SystemProgramError::BorrowingDataFailed => 6052, SystemProgramError::DuplicateAccountInInputsAndReadOnly => 6053, + SystemProgramError::CpiContextDeactivated => 6054, SystemProgramError::BatchedMerkleTreeError(e) => e.into(), SystemProgramError::IndexedMerkleTreeError(e) => e.into(), SystemProgramError::ConcurrentMerkleTreeError(e) => e.into(), diff --git a/programs/system/src/invoke_cpi/process_cpi_context.rs b/programs/system/src/invoke_cpi/process_cpi_context.rs index a5cd3f03e0..ac55b00a6b 100644 --- a/programs/system/src/invoke_cpi/process_cpi_context.rs +++ b/programs/system/src/invoke_cpi/process_cpi_context.rs @@ -45,6 +45,11 @@ pub fn process_cpi_context<'a, 'info, T: InstructionData<'a>>( msg!("cpi context account is some but cpi context is none"); return Err(SystemProgramError::CpiContextMissing.into()); } + #[cfg(feature = "deactivate-cpi-context")] + if cpi_context.is_some() { + msg!("cpi context is deactivated."); + return Err(SystemProgramError::CpiContextDeactivated.into()); + } if let Some(cpi_context) = cpi_context { let cpi_context_account_info = match cpi_context_account_info {