From 88144deb6ae515c8fa79937a96afc41ae9e5acce Mon Sep 17 00:00:00 2001 From: ananas-block Date: Fri, 15 Aug 2025 17:40:35 +0200 Subject: [PATCH 1/4] refactor: move sdk-test, sdk-pinocchio-test, client-test from program-tests/ -> sdk-tests --- Cargo.toml | 8 +- sdk-tests/client-test/Cargo.toml | 67 ++ .../client-test}/Xargo.toml | 0 sdk-tests/client-test/src/lib.rs | 1 + sdk-tests/client-test/tests/light_client.rs | 825 ++++++++++++++++++ .../client-test/tests/light_program_test.rs | 713 +++++++++++++++ sdk-tests/client-test/tests/sdk_compat.rs | 112 +++ sdk-tests/sdk-anchor-test/.gitignore | 7 + sdk-tests/sdk-anchor-test/.prettierignore | 8 + sdk-tests/sdk-anchor-test/Anchor.toml | 18 + sdk-tests/sdk-anchor-test/README.md | 1 + sdk-tests/sdk-anchor-test/package.json | 20 + .../programs/sdk-anchor-test/Cargo.toml | 38 + .../programs/sdk-anchor-test/Xargo.toml | 2 + .../programs/sdk-anchor-test/src/lib.rs | 196 +++++ .../programs/sdk-anchor-test/tests/test.rs | 196 +++++ sdk-tests/sdk-anchor-test/tsconfig.json | 10 + .../sdk-pinocchio-test/Cargo.toml | 0 sdk-tests/sdk-pinocchio-test/Xargo.toml | 2 + .../sdk-pinocchio-test/src/create_pda.rs | 0 .../sdk-pinocchio-test/src/lib.rs | 0 .../sdk-pinocchio-test/src/update_pda.rs | 0 .../sdk-pinocchio-test/tests/test.rs | 0 sdk-tests/sdk-test/Cargo.toml | 40 + sdk-tests/sdk-test/Xargo.toml | 2 + sdk-tests/sdk-test/src/create_pda.rs | 87 ++ sdk-tests/sdk-test/src/lib.rs | 49 ++ sdk-tests/sdk-test/src/update_pda.rs | 65 ++ sdk-tests/sdk-test/tests/test.rs | 177 ++++ 29 files changed, 2640 insertions(+), 4 deletions(-) create mode 100644 sdk-tests/client-test/Cargo.toml rename {program-tests/sdk-pinocchio-test => sdk-tests/client-test}/Xargo.toml (100%) create mode 100644 sdk-tests/client-test/src/lib.rs create mode 100644 sdk-tests/client-test/tests/light_client.rs create mode 100644 sdk-tests/client-test/tests/light_program_test.rs create mode 100644 sdk-tests/client-test/tests/sdk_compat.rs create mode 100644 sdk-tests/sdk-anchor-test/.gitignore create mode 100644 sdk-tests/sdk-anchor-test/.prettierignore create mode 100644 sdk-tests/sdk-anchor-test/Anchor.toml create mode 100644 sdk-tests/sdk-anchor-test/README.md create mode 100644 sdk-tests/sdk-anchor-test/package.json create mode 100644 sdk-tests/sdk-anchor-test/programs/sdk-anchor-test/Cargo.toml create mode 100644 sdk-tests/sdk-anchor-test/programs/sdk-anchor-test/Xargo.toml create mode 100644 sdk-tests/sdk-anchor-test/programs/sdk-anchor-test/src/lib.rs create mode 100644 sdk-tests/sdk-anchor-test/programs/sdk-anchor-test/tests/test.rs create mode 100644 sdk-tests/sdk-anchor-test/tsconfig.json rename {program-tests => sdk-tests}/sdk-pinocchio-test/Cargo.toml (100%) create mode 100644 sdk-tests/sdk-pinocchio-test/Xargo.toml rename {program-tests => sdk-tests}/sdk-pinocchio-test/src/create_pda.rs (100%) rename {program-tests => sdk-tests}/sdk-pinocchio-test/src/lib.rs (100%) rename {program-tests => sdk-tests}/sdk-pinocchio-test/src/update_pda.rs (100%) rename {program-tests => sdk-tests}/sdk-pinocchio-test/tests/test.rs (100%) create mode 100644 sdk-tests/sdk-test/Cargo.toml create mode 100644 sdk-tests/sdk-test/Xargo.toml create mode 100644 sdk-tests/sdk-test/src/create_pda.rs create mode 100644 sdk-tests/sdk-test/src/lib.rs create mode 100644 sdk-tests/sdk-test/src/update_pda.rs create mode 100644 sdk-tests/sdk-test/tests/test.rs diff --git a/Cargo.toml b/Cargo.toml index ae4693fe8a..881233cd9c 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -34,13 +34,13 @@ members = [ "program-tests/system-cpi-test", "program-tests/system-cpi-v2-test", "program-tests/system-test", - "program-tests/sdk-anchor-test/programs/sdk-anchor-test", - "program-tests/sdk-test", - "program-tests/sdk-pinocchio-test", + "sdk-tests/sdk-anchor-test/programs/sdk-anchor-test", + "sdk-tests/sdk-test", + "sdk-tests/sdk-pinocchio-test", "program-tests/create-address-test-program", "program-tests/utils", "program-tests/merkle-tree", - "program-tests/client-test", + "sdk-tests/client-test", "forester-utils", "forester", "sparse-merkle-tree", diff --git a/sdk-tests/client-test/Cargo.toml b/sdk-tests/client-test/Cargo.toml new file mode 100644 index 0000000000..8436feda1b --- /dev/null +++ b/sdk-tests/client-test/Cargo.toml @@ -0,0 +1,67 @@ +[package] +name = "client-test" +version = "0.1.0" +description = "Tests for light-client and light-program-test." +repository = "https://github.com/Lightprotocol/light-protocol" +license = "Apache-2.0" +edition = "2021" + +[lib] +crate-type = ["cdylib", "lib"] +name = "client_test" + +[features] +test-sbf = [] + +[dev-dependencies] +light-client = { workspace = true, features = ["devenv"] } +light-program-test = { workspace = true, features = ["devenv"] } +light-prover-client = { workspace = true, features = ["devenv"] } +light-test-utils = { workspace = true } +light-sdk = { workspace = true } +light-sdk-pinocchio = { workspace = true } +light-sdk-types = { workspace = true } +light-zero-copy = { workspace = true } +light-hasher = { workspace = true } +light-compressed-account = { workspace = true } +light-compressed-token = { workspace = true } +light-indexed-array = { workspace = true } +light-merkle-tree-reference = { workspace = true } + +tokio = { workspace = true } +rand = { workspace = true } +num-bigint = { workspace = true } + +solana-sdk = { workspace = true } +spl-token = { workspace = true } +solana-rpc-client = { workspace = true } +solana-rpc-client-api = { workspace = true } +solana-transaction-status-client-types = { workspace = true } +solana-account-decoder-client-types = { workspace = true } +solana-pubkey = { workspace = true } +solana-instruction = { workspace = true } +solana-program-error = { workspace = true } +solana-transaction = { workspace = true } +solana-transaction-error = { workspace = true } +solana-hash = { workspace = true } +solana-clock = { workspace = true } +solana-signature = { workspace = true } +solana-commitment-config = { workspace = true } +solana-account = { workspace = true } +solana-signer = { workspace = true } +solana-epoch-info = { workspace = true } +solana-keypair = { workspace = true } +solana-compute-budget-interface = { workspace = true } +solana-address-lookup-table-interface = { version = "2.2.1", features = [ + "bytemuck", + "bincode", +] } +solana-system-interface = { workspace = true } + + +[lints.rust.unexpected_cfgs] +level = "allow" +check-cfg = [ + 'cfg(target_os, values("solana"))', + 'cfg(feature, values("frozen-abi", "no-entrypoint"))', +] diff --git a/program-tests/sdk-pinocchio-test/Xargo.toml b/sdk-tests/client-test/Xargo.toml similarity index 100% rename from program-tests/sdk-pinocchio-test/Xargo.toml rename to sdk-tests/client-test/Xargo.toml diff --git a/sdk-tests/client-test/src/lib.rs b/sdk-tests/client-test/src/lib.rs new file mode 100644 index 0000000000..10051c7680 --- /dev/null +++ b/sdk-tests/client-test/src/lib.rs @@ -0,0 +1 @@ +// Placeholder diff --git a/sdk-tests/client-test/tests/light_client.rs b/sdk-tests/client-test/tests/light_client.rs new file mode 100644 index 0000000000..c63a4915e1 --- /dev/null +++ b/sdk-tests/client-test/tests/light_client.rs @@ -0,0 +1,825 @@ +use light_client::{ + indexer::{ + AccountProofInputs, AddressProofInputs, AddressWithTree, + GetCompressedTokenAccountsByOwnerOrDelegateOptions, Hash, Indexer, IndexerRpcConfig, + MerkleProof, PaginatedOptions, RetryConfig, RootIndex, TreeInfo, ValidityProofWithContext, + }, + local_test_validator::{spawn_validator, LightValidatorConfig}, + rpc::{LightClient, LightClientConfig}, +}; +use light_compressed_account::{hash_to_bn254_field_size_be, TreeType}; +use light_compressed_token::mint_sdk::{ + create_create_token_pool_instruction, create_mint_to_instruction, +}; +use light_hasher::Poseidon; +use light_merkle_tree_reference::{indexed::IndexedMerkleTree, MerkleTree}; +use light_program_test::accounts::test_accounts::TestAccounts; +use light_prover_client::prover::ProverConfig; +use light_sdk::{ + address::{v1::derive_address, NewAddressParams}, + token::{AccountState, TokenData}, +}; +use light_test_utils::{system_program::create_invoke_instruction, Rpc, RpcError}; +use solana_compute_budget_interface::ComputeBudgetInstruction; +use solana_keypair::Keypair; +use solana_pubkey::Pubkey; +use solana_signature::Signature; +use solana_signer::Signer; +use solana_system_interface::instruction::create_account; +use solana_transaction::Transaction; + +// Constants +const LAMPORTS_PER_SOL: u64 = 1_000_000_000; + +/// Endpoints tested: +/// 1. get_compressed_accounts_by_owner +/// 2. get_multiple_compressed_accounts +/// 3. get_validity_proof +/// 4. get_compressed_account +/// 5. get_compressed_account_by_hash +/// 6. get_compressed_balance +/// 7. get_compressed_balance_by_owner +/// 8. get_compression_signatures_for_account +/// 9. get_compression_signatures_for_address +/// 10. get_compression_signatures_for_owner +/// 11. get_multiple_compressed_account_proofs +/// 12. get_multiple_new_address_proofs +/// 13. get_compressed_token_accounts_by_owner +/// 14. get_compressed_token_account_balance +/// 15. get_compressed_token_balances_by_owner_v2 +/// 16. get_compressed_mint_token_holders +/// 17. get_compression_signatures_for_token_owner +#[tokio::test(flavor = "multi_thread", worker_threads = 1)] +async fn test_all_endpoints() { + let config = LightValidatorConfig { + enable_indexer: true, + prover_config: Some(ProverConfig::default()), + wait_time: 75, + sbf_programs: vec![], + limit_ledger_size: None, + }; + + spawn_validator(config).await; + + let test_accounts = TestAccounts::get_local_test_validator_accounts(); + let mut rpc: LightClient = LightClient::new(LightClientConfig::local()).await.unwrap(); + + let payer_pubkey = rpc.get_payer().pubkey(); + rpc.airdrop_lamports(&payer_pubkey, 10 * LAMPORTS_PER_SOL) + .await + .unwrap(); + let mt = test_accounts.v1_state_trees[0].merkle_tree; + let _address_mt = test_accounts.v1_address_trees[0].merkle_tree; + + let lamports = LAMPORTS_PER_SOL / 2; + let lamports_1 = LAMPORTS_PER_SOL / 2 + 1; + let owner = rpc.get_payer().pubkey(); + + // create compressed account with address + let (address, signature) = create_address(&mut rpc, lamports, owner, mt).await.unwrap(); + let (address_1, signature_1) = create_address(&mut rpc, lamports_1, owner, mt) + .await + .unwrap(); + + // 1. get_compressed_accounts_by_owner + let initial_accounts = { + let accounts = rpc + .get_compressed_accounts_by_owner( + &payer_pubkey, + None, + Some(IndexerRpcConfig { + slot: rpc.client.get_slot().unwrap(), + retry_config: RetryConfig::default(), + }), + ) + .await + .unwrap() + .value; + assert_eq!(accounts.items.len(), 2); + assert_eq!(accounts.items[0].owner, owner); + assert_eq!(accounts.items[1].owner, owner); + + assert!(accounts + .items + .iter() + .any(|x| x.lamports == lamports && x.address == Some(address))); + + assert!(accounts + .items + .iter() + .any(|x| x.lamports == lamports_1 && x.address == Some(address_1))); + + accounts + }; + + let account_hashes: Vec = initial_accounts.items.iter().map(|a| a.hash).collect(); + let mut reference_tree = MerkleTree::::new(26, 10); + for hash in &account_hashes { + reference_tree.append(hash).unwrap(); + } + let account_addresses: Vec = initial_accounts + .items + .iter() + .map(|a| a.address.unwrap()) + .collect(); + + // Create reference address tree and add the addresses + let _reference_address_tree = IndexedMerkleTree::::new(26, 10).unwrap(); + + // Don't add the test address to the reference tree since we want non-inclusion proof + + // 2. get_multiple_compressed_accounts + let accounts = rpc + .get_multiple_compressed_accounts(None, Some(account_hashes.clone()), None) + .await + .unwrap() + .value; + + assert_eq!(accounts.items.len(), account_hashes.len()); + for item in accounts.items.iter() { + assert!(initial_accounts.items.iter().any(|x| x.hash == item.hash)); + } + // Currently fails because photon doesn't deliver cpi context accounts. + // for item in accounts.items.iter() { + // assert!(initial_accounts.items.iter().any(|x| *x == *item)); + // } + let accounts = rpc + .get_multiple_compressed_accounts(Some(account_addresses), None, None) + .await + .unwrap() + .value; + assert_eq!(accounts.items.len(), initial_accounts.items.len()); + for item in accounts.items.iter() { + assert!(initial_accounts.items.iter().any(|x| x.hash == item.hash)); + } + // Currently fails because photon doesn't deliver cpi context accounts. + // for item in accounts.items.iter() { + // assert!(initial_accounts.items.iter().any(|x| *x == *item)); + // } + // 3. get_validity_proof + { + let seed = rand::random::<[u8; 32]>(); + let new_addresses = vec![AddressWithTree { + address: hash_to_bn254_field_size_be(&seed), + tree: test_accounts.v1_address_trees[0].merkle_tree, + }]; + + let result = rpc + .get_validity_proof(account_hashes.clone(), new_addresses.clone(), None) + .await + .unwrap() + .value; + assert_eq!(result.accounts.len(), account_hashes.len()); + assert_eq!(result.addresses.len(), new_addresses.len()); + + println!("account_proof {:?}", result); + + // Build expected ValidityProofWithContext using reference tree + let expected_result = ValidityProofWithContext { + proof: result.proof, // Keep the actual proof as-is + accounts: account_hashes + .iter() + .enumerate() + .map(|(i, &hash)| AccountProofInputs { + hash, + root: reference_tree.root(), + root_index: RootIndex::new_some(2), + leaf_index: i as u64, + tree_info: TreeInfo { + cpi_context: None, + next_tree_info: None, + queue: test_accounts.v1_state_trees[0].nullifier_queue, + tree: mt, + tree_type: TreeType::StateV1, + }, + }) + .collect(), + addresses: new_addresses + .iter() + .enumerate() + .map(|(i, addr_with_tree)| { + // TODO: enable once photon bug is fixed + // let address_bigint = BigUint::from_bytes_be(&addr_with_tree.address); + // let non_inclusion_proof = reference_address_tree.get_non_inclusion_proof(&address_bigint).unwrap(); + AddressProofInputs { + address: addr_with_tree.address, + root: result.addresses[i].root, + root_index: 3, + tree_info: TreeInfo { + cpi_context: None, + next_tree_info: None, + queue: test_accounts.v1_address_trees[0].queue, + tree: addr_with_tree.tree, + tree_type: TreeType::AddressV1, + }, + } + }) + .collect(), + }; + + assert_eq!(result, expected_result); + } + // 4. get_compressed_account + let first_account = rpc + .get_compressed_account(accounts.items[0].address.unwrap(), None) + .await + .unwrap() + .value; + assert_eq!(first_account, accounts.items[0]); + + // 5. get_compressed_account_by_hash + { + let account = rpc + .get_compressed_account_by_hash(first_account.hash, None) + .await + .unwrap() + .value; + assert_eq!(account, first_account); + } + // 6. get_compressed_balance + { + let balance = rpc + .get_compressed_balance(None, Some(first_account.hash), None) + .await + .unwrap() + .value; + assert_eq!(balance, lamports); + } + // 7. get_compressed_balance_by_owner + { + let balance = rpc + .get_compressed_balance_by_owner(&payer_pubkey, None) + .await + .unwrap() + .value; + assert_eq!(balance, lamports + lamports_1); + } + // 8. get_compression_signatures_for_account + { + let signatures = rpc + .get_compression_signatures_for_account(first_account.hash, None) + .await + .unwrap() + .value; + assert_eq!(signatures.items[0].signature, signature.to_string()); + } + // 9. get_compression_signatures_for_address + { + let signatures = rpc + .get_compression_signatures_for_address(&first_account.address.unwrap(), None, None) + .await + .unwrap() + .value; + assert_eq!(signatures.items[0].signature, signature.to_string()); + } + // 10. get_compression_signatures_for_owner + { + let signatures = rpc + .get_compression_signatures_for_owner(&owner, None, None) + .await + .unwrap() + .value; + assert_eq!(signatures.items.len(), 2); + assert!(signatures + .items + .iter() + .any(|s| s.signature == signature.to_string())); + assert!(signatures + .items + .iter() + .any(|s| s.signature == signature_1.to_string())); + let options = PaginatedOptions { + limit: Some(1), + cursor: None, + }; + let signatures = rpc + .get_compression_signatures_for_owner(&owner, Some(options), None) + .await + .unwrap() + .value; + assert_eq!(signatures.items.len(), 1); + assert!(signatures.items.iter().any( + |s| s.signature == signature_1.to_string() || s.signature == signature.to_string() + )); + } + // 11. get_multiple_compressed_account_proofs + { + let proofs = rpc + .get_multiple_compressed_account_proofs(account_hashes.to_vec(), None) + .await + .unwrap() + .value; + assert!(!proofs.items.is_empty()); + assert_eq!(proofs.items[0].hash, account_hashes[0]); + + // Build expected Vec using reference tree + let expected_proofs: Vec = account_hashes + .iter() + .enumerate() + .map(|(i, &hash)| { + let expected_proof = reference_tree.get_proof_of_leaf(i, false).unwrap(); + MerkleProof { + hash, + leaf_index: i as u64, + merkle_tree: mt, + proof: expected_proof, + root_seq: 2, + root: reference_tree.root(), + } + }) + .collect(); + + assert_eq!(proofs.items, expected_proofs); + + // 12. get_multiple_new_address_proofs + let addresses = vec![address]; + let new_address_proofs = rpc + .get_multiple_new_address_proofs( + test_accounts.v1_address_trees[0].merkle_tree.to_bytes(), + addresses.clone(), + None, + ) + .await + .unwrap(); + assert!(!new_address_proofs.value.items.is_empty()); + // TODO: update once photon is ready + // Build expected Vec using reference address tree + // let expected_address_proofs: Vec = addresses + // .iter() + // .map(|&addr| { + // let address_bigint = BigUint::from_bytes_be(&addr); + // let non_inclusion_proof = reference_address_tree + // .get_non_inclusion_proof(&address_bigint) + // .unwrap(); + + // NewAddressProofWithContext { + // merkle_tree: address_mt, + // root: non_inclusion_proof.root, + // root_seq: 3, + // low_address_index: non_inclusion_proof.leaf_index as u64, + // low_address_value: non_inclusion_proof.leaf_lower_range_value, + // low_address_next_index: non_inclusion_proof.next_index as u64, + // low_address_next_value: non_inclusion_proof.leaf_higher_range_value, + // low_address_proof: non_inclusion_proof.merkle_proof, + // new_low_element: None, + // new_element: None, + // new_element_next_value: None, + // } + // }) + // .collect(); + assert_eq!(new_address_proofs.value.items.len(), 1); + } + + test_token_api(&rpc, &test_accounts).await; +} + +/// Token API endpoints tested: +/// 1. get_compressed_token_accounts_by_owner +/// 2. get_compressed_token_account_balance +/// 3. get_compressed_token_balances_by_owner_v2 +/// 4. get_compressed_mint_token_holders +/// 5. get_compression_signatures_for_token_owner +async fn test_token_api(rpc: &LightClient, test_accounts: &TestAccounts) { + let payer = rpc.get_payer().insecure_clone(); + let payer_pubkey = payer.pubkey(); + let mint_1 = Keypair::new(); + let mint_2 = Keypair::new(); + + create_two_mints(rpc, payer_pubkey, &mint_1, &mint_2); + let mint_1 = mint_1.pubkey(); + let mint_2 = mint_2.pubkey(); + let base_amount = 1_000_000; + let recipients = (0..5) + .map(|_| Pubkey::new_unique()) + .collect::>(); + let amounts = (0..5).map(|i| base_amount + i).collect::>(); + // Mint amounts to payer for both mints with and without lamports + let signatures = mint_to_token_accounts( + rpc, + test_accounts, + payer_pubkey, + mint_1, + mint_2, + base_amount, + &recipients, + &amounts, + ); + let slot = rpc.get_slot().await.unwrap(); + let config = IndexerRpcConfig { + slot, + retry_config: RetryConfig::default(), + }; + // 1. get_compressed_mint_token_holders + for mint in [mint_1, mint_2] { + let res = rpc + .get_compressed_mint_token_holders(&mint, None, Some(config.clone())) + .await + .unwrap() + .value + .items; + assert_eq!(res.len(), 5); + + let mut owners = res.iter().map(|x| x.owner).collect::>(); + owners.sort(); + owners.dedup(); + assert_eq!(owners.len(), 5); + for (amount, recipient) in amounts.iter().zip(recipients.iter()) { + // * 2 because we mint two times the same amount per token mint (with and without lamports) + assert!(res + .iter() + .any(|item| item.balance == (*amount * 2) && item.owner == *recipient)); + } + let option = PaginatedOptions { + limit: Some(1), + cursor: None, + }; + let res = rpc + .get_compressed_mint_token_holders(&mint, Some(option), None) + .await + .unwrap() + .value + .items; + assert_eq!(res.len(), 1); + } + + // 2. get_compression_signatures_for_token_owner + for recipient in &recipients { + let res = rpc + .get_compression_signatures_for_token_owner(recipient, None, None) + .await + .unwrap() + .value + .items; + assert_eq!(res.len(), 2); + assert_eq!(res[0].signature, signatures[1].to_string()); + assert_eq!(res[1].signature, signatures[0].to_string()); + let option = PaginatedOptions { + limit: Some(1), + cursor: None, + }; + let res = rpc + .get_compression_signatures_for_token_owner(recipient, Some(option), None) + .await + .unwrap() + .value + .items; + assert_eq!(res.len(), 1); + } + + // 3. get_compressed_token_accounts_by_owner + test_get_compressed_token_accounts_by_owner( + rpc, + mint_1, + mint_2, + base_amount, + &recipients, + &amounts, + ) + .await; + // 4. get_compressed_token_account_balance + { + let token_accounts = rpc + .get_compressed_token_accounts_by_owner(&recipients[0], None, None) + .await + .unwrap() + .value; + let hash = token_accounts.items[0].account.hash; + let balance = rpc + .get_compressed_token_account_balance(None, Some(hash), None) + .await + .unwrap() + .value; + assert_eq!(balance, amounts[0]); + assert_eq!(balance, token_accounts.items[0].token.amount); + } + // 5. get_compressed_token_balances_by_owner_v2 + { + // No options + test_get_compressed_token_balances_by_owner_v2( + rpc, + vec![mint_1, mint_2], + recipients.clone(), + amounts.clone(), + None, + ) + .await; + // Limit to mint1 + let options = Some(GetCompressedTokenAccountsByOwnerOrDelegateOptions { + mint: Some(mint_1), + cursor: None, + limit: None, + }); + test_get_compressed_token_balances_by_owner_v2( + rpc, + vec![mint_1], + recipients.clone(), + amounts.clone(), + options, + ) + .await; + + // Limit to mint2 + let options = Some(GetCompressedTokenAccountsByOwnerOrDelegateOptions { + mint: Some(mint_2), + cursor: None, + limit: None, + }); + test_get_compressed_token_balances_by_owner_v2( + rpc, + vec![mint_2], + recipients.clone(), + amounts.clone(), + options, + ) + .await; + } +} + +#[allow(clippy::too_many_arguments)] +fn mint_to_token_accounts( + rpc: &LightClient, + test_accounts: &TestAccounts, + payer_pubkey: Pubkey, + mint_1: Pubkey, + mint_2: Pubkey, + base_amount: u64, + recipients: &[Pubkey], + amounts: &[u64], +) -> [Signature; 2] { + let mut signatures = Vec::new(); + + for mint in [mint_1, mint_2] { + let mint_ix_with_lamports = create_mint_to_instruction( + &payer_pubkey, + &payer_pubkey, + &mint, + &test_accounts.v1_state_trees[0].merkle_tree, + amounts.to_vec(), + recipients.to_vec(), + Some(base_amount), + false, + 0, + ); + + let mint_ix_no_lamports = create_mint_to_instruction( + &payer_pubkey, + &payer_pubkey, + &mint, + &test_accounts.v1_state_trees[0].merkle_tree, + amounts.to_vec(), + recipients.to_vec(), + None, + false, + 0, + ); + + let compute_budget_ix = ComputeBudgetInstruction::set_compute_unit_limit(500_000); + + let tx = Transaction::new_signed_with_payer( + &[ + compute_budget_ix, + mint_ix_with_lamports, + mint_ix_no_lamports, + ], + Some(&payer_pubkey), + &[&rpc.get_payer()], + rpc.client.get_latest_blockhash().unwrap(), + ); + signatures.push(rpc.client.send_and_confirm_transaction(&tx).unwrap()); + } + signatures.try_into().unwrap() +} + +fn create_two_mints(rpc: &LightClient, payer_pubkey: Pubkey, mint_1: &Keypair, mint_2: &Keypair) { + let mint_rent = rpc + .client + .get_minimum_balance_for_rent_exemption(82) + .unwrap(); + let create_mint_ix = create_account( + &payer_pubkey, + &mint_1.pubkey(), + mint_rent, + 82, + &spl_token::id(), + ); + let create_mint_ix_2 = create_account( + &payer_pubkey, + &mint_2.pubkey(), + mint_rent, + 82, + &spl_token::id(), + ); + let init_mint_ix = spl_token::instruction::initialize_mint( + &spl_token::id(), + &mint_1.pubkey(), + &payer_pubkey, + None, + 9, + ) + .unwrap(); + let init_mint_ix_2 = spl_token::instruction::initialize_mint( + &spl_token::id(), + &mint_2.pubkey(), + &payer_pubkey, + None, + 2, + ) + .unwrap(); + // Create token pool for compression + let create_pool_ix = + create_create_token_pool_instruction(&payer_pubkey, &mint_1.pubkey(), false); + let create_pool_ix_2 = + create_create_token_pool_instruction(&payer_pubkey, &mint_2.pubkey(), false); + let compute_budget_ix = ComputeBudgetInstruction::set_compute_unit_limit(500_000); + let tx = Transaction::new_signed_with_payer( + &[ + compute_budget_ix, + create_mint_ix, + create_mint_ix_2, + init_mint_ix, + init_mint_ix_2, + create_pool_ix, + create_pool_ix_2, + ], + Some(&payer_pubkey), + &[rpc.get_payer(), mint_1, mint_2], + rpc.client.get_latest_blockhash().unwrap(), + ); + rpc.client.send_and_confirm_transaction(&tx).unwrap(); +} + +/// Tests: +/// 1. fetch all no options +/// 2. fetch only for mint 1, with limit 1 +async fn test_get_compressed_token_accounts_by_owner( + rpc: &LightClient, + mint_1: Pubkey, + mint_2: Pubkey, + base_amount: u64, + recipients: &[Pubkey], + amounts: &[u64], +) { + let slot = rpc.get_slot().await.unwrap(); + let indexer_config = IndexerRpcConfig { + slot, + retry_config: RetryConfig::default(), + }; + for (amount, recipient) in amounts.iter().zip(recipients.iter()) { + { + let token_accounts = &rpc + .indexer() + .unwrap() + .get_compressed_token_accounts_by_owner( + recipient, + None, + Some(indexer_config.clone()), + ) + .await + .unwrap() + .value; + // every recipient should have 4 token accounts + // 1. 2 with lamports and 2 without + // 2. 2 with mint 1 and 2 with mint 2 + let mut expected_token_data = TokenData { + mint: mint_1, + amount: *amount, + owner: *recipient, + delegate: None, + state: AccountState::Initialized, + tlv: None, + }; + assert_eq!( + token_accounts + .items + .iter() + .filter(|item| item.token == expected_token_data) + .count(), + 2 + ); + assert!(token_accounts + .items + .iter() + .any(|item| item.token == expected_token_data + && item.account.lamports == base_amount)); + expected_token_data.mint = mint_2; + assert_eq!( + token_accounts + .items + .iter() + .filter(|item| item.token == expected_token_data) + .count(), + 2 + ); + assert!(token_accounts + .items + .iter() + .any(|item| item.token == expected_token_data + && item.account.lamports == base_amount)); + } + // fetch only for mint 1, with limit 1 + { + let options = GetCompressedTokenAccountsByOwnerOrDelegateOptions { + mint: Some(mint_1), + cursor: None, + limit: Some(1), + }; + let token_accounts = &rpc + .indexer() + .unwrap() + .get_compressed_token_accounts_by_owner(recipient, Some(options.clone()), None) + .await + .unwrap() + .value; + assert_eq!(token_accounts.items.len(), 1); + assert_eq!(token_accounts.items[0].token.mint, options.mint.unwrap()); + } + } +} + +async fn create_address( + rpc: &mut LightClient, + lamports: u64, + owner: Pubkey, + merkle_tree: Pubkey, +) -> Result<([u8; 32], Signature), RpcError> { + let address_merkle_tree = rpc.get_address_tree_v1(); + let (address, address_seed) = derive_address( + &[Pubkey::new_unique().to_bytes().as_slice()], + &address_merkle_tree.tree, + &Pubkey::new_unique(), + ); + + let output_account = light_compressed_account::compressed_account::CompressedAccount { + lamports, + owner: owner.into(), + data: None, + address: Some(address), + }; + let rpc_proof_result = rpc + .get_validity_proof( + vec![], + vec![AddressWithTree { + address, + tree: address_merkle_tree.tree, + }], + None, + ) + .await + .unwrap(); + + let new_address_params = NewAddressParams { + seed: address_seed, + address_queue_pubkey: address_merkle_tree.queue.into(), + address_merkle_tree_pubkey: address_merkle_tree.tree.into(), + address_merkle_tree_root_index: rpc_proof_result.value.addresses[0].root_index, + }; + let compute_budget_ix = ComputeBudgetInstruction::set_compute_unit_limit(500_000); + let ix = create_invoke_instruction( + &rpc.get_payer().pubkey(), + &rpc.get_payer().pubkey(), + &[], + &[output_account], + &[], + &[merkle_tree], + &[], + &[new_address_params], + rpc_proof_result.value.proof.0, + Some(lamports), + true, + None, + true, + ); + + let tx_create_compressed_account = Transaction::new_signed_with_payer( + &[compute_budget_ix, ix], + Some(&rpc.get_payer().pubkey()), + &[&rpc.get_payer()], + rpc.client.get_latest_blockhash().unwrap(), + ); + let signature = rpc + .client + .send_and_confirm_transaction(&tx_create_compressed_account)?; + Ok((address, signature)) +} + +async fn test_get_compressed_token_balances_by_owner_v2( + rpc: &LightClient, + mints: Vec, + recipients: Vec, + amounts: Vec, + options: Option, +) { + for (amount, recipient) in amounts.iter().zip(recipients.iter()) { + let balances = rpc + .get_compressed_token_balances_by_owner_v2(recipient, options.clone(), None) + .await + .unwrap(); + let balances = balances.value.items; + assert_eq!(balances.len(), mints.len()); + for mint in mints.iter() { + assert!(balances + .iter() + .any(|balance| balance.mint == *mint && balance.balance == (*amount) * 2)); + } + } +} diff --git a/sdk-tests/client-test/tests/light_program_test.rs b/sdk-tests/client-test/tests/light_program_test.rs new file mode 100644 index 0000000000..087674193a --- /dev/null +++ b/sdk-tests/client-test/tests/light_program_test.rs @@ -0,0 +1,713 @@ +#![cfg(feature = "test-sbf")] +use light_client::{ + indexer::{ + AddressWithTree, GetCompressedTokenAccountsByOwnerOrDelegateOptions, Hash, Indexer, + IndexerRpcConfig, RetryConfig, + }, + rpc::Rpc, +}; +use light_compressed_account::hash_to_bn254_field_size_be; +use light_compressed_token::mint_sdk::{ + create_create_token_pool_instruction, create_mint_to_instruction, +}; +use light_program_test::{ + accounts::test_accounts::TestAccounts, program_test::LightProgramTest, ProgramTestConfig, +}; +use light_sdk::{ + address::{v1::derive_address, NewAddressParams}, + token::{AccountState, TokenData}, +}; +use light_test_utils::{system_program::create_invoke_instruction, RpcError}; +use solana_sdk::{ + compute_budget::ComputeBudgetInstruction, + pubkey::Pubkey, + signature::{Keypair, Signature, Signer}, + system_instruction::create_account, + transaction::Transaction, +}; + +// Constants +const LAMPORTS_PER_SOL: u64 = 1_000_000_000; + +/// Endpoints tested: +/// 1. get_compressed_accounts_by_owner +/// 2. get_multiple_compressed_accounts +/// 3. get_validity_proof +/// 4. get_compressed_account +/// 5. get_compressed_account_by_hash +/// 6. get_compressed_balance +/// 7. get_compressed_balance_by_owner +/// 8. get_compression_signatures_for_account +/// 9. get_compression_signatures_for_address +/// 10. get_compression_signatures_for_owner +/// 11. get_multiple_compressed_account_proofs +/// 12. get_multiple_new_address_proofs +/// 13. get_compressed_token_accounts_by_owner +/// 14. get_compressed_token_account_balance +/// 15. get_compressed_token_balances_by_owner_v2 +/// 16. get_compressed_mint_token_holders +/// 17. get_compression_signatures_for_token_owner +#[tokio::test(flavor = "multi_thread", worker_threads = 1)] +async fn test_all_endpoints() { + let config = ProgramTestConfig::default(); + let mut rpc = LightProgramTest::new(config).await.unwrap(); + let test_accounts = rpc.test_accounts().clone(); + + let payer_pubkey = rpc.get_payer().pubkey(); + let mt = test_accounts.v1_state_trees[0].merkle_tree; + + let lamports = LAMPORTS_PER_SOL / 2; + let lamports_1 = LAMPORTS_PER_SOL / 2 + 1; + let owner = rpc.get_payer().pubkey(); + + // create compressed account with address + let (address, _signature) = create_address(&mut rpc, lamports, owner, mt).await.unwrap(); + let (address_1, _signature_1) = create_address(&mut rpc, lamports_1, owner, mt) + .await + .unwrap(); + + // 1. get_compressed_accounts_by_owner + let initial_accounts = { + let accounts = rpc + .get_compressed_accounts_by_owner(&payer_pubkey, None, None) + .await + .unwrap() + .value; + assert_eq!(accounts.items.len(), 2); + assert_eq!(accounts.items[0].owner, owner); + assert_eq!(accounts.items[1].owner, owner); + + assert!(accounts + .items + .iter() + .any(|x| x.lamports == lamports && x.address == Some(address))); + + assert!(accounts + .items + .iter() + .any(|x| x.lamports == lamports_1 && x.address == Some(address_1))); + + accounts + }; + + let account_hashes: Vec = initial_accounts.items.iter().map(|a| a.hash).collect(); + let account_addresses: Vec = initial_accounts + .items + .iter() + .map(|a| a.address.unwrap()) + .collect(); + + // 2. get_multiple_compressed_accounts + let accounts = rpc + .get_multiple_compressed_accounts(None, Some(account_hashes.clone()), None) + .await + .unwrap() + .value; + + assert_eq!(accounts.items.len(), account_hashes.len()); + for item in accounts.items.iter() { + assert!(initial_accounts.items.iter().any(|x| x.hash == item.hash)); + } + // Currently fails because photon doesn't deliver cpi context accounts. + // for item in accounts.items.iter() { + // assert!(initial_accounts.items.iter().any(|x| *x == *item)); + // } + let accounts = rpc + .get_multiple_compressed_accounts(Some(account_addresses), None, None) + .await + .unwrap() + .value; + assert_eq!(accounts.items.len(), initial_accounts.items.len()); + for item in accounts.items.iter() { + assert!(initial_accounts.items.iter().any(|x| x.hash == item.hash)); + } + // Currently fails because photon doesn't deliver cpi context accounts. + // for item in accounts.items.iter() { + // assert!(initial_accounts.items.iter().any(|x| *x == *item)); + // } + // 3. get_validity_proof + { + let seed = rand::random::<[u8; 32]>(); + let new_addresses = vec![AddressWithTree { + address: hash_to_bn254_field_size_be(&seed), + tree: test_accounts.v1_address_trees[0].merkle_tree, + }]; + + let result = rpc + .get_validity_proof(account_hashes.clone(), new_addresses.clone(), None) + .await + .unwrap() + .value; + assert_eq!(result.accounts.len(), account_hashes.len()); + assert_eq!(result.addresses.len(), new_addresses.len()); + } + // 4. get_compressed_account + let first_account = rpc + .get_compressed_account(accounts.items[0].address.unwrap(), None) + .await + .unwrap() + .value; + assert_eq!(first_account, accounts.items[0]); + + // 5. get_compressed_account_by_hash + { + let account = rpc + .get_compressed_account_by_hash(first_account.hash, None) + .await + .unwrap() + .value; + assert_eq!(account, first_account); + } + // 6. get_compressed_balance + { + let balance = rpc + .get_compressed_balance(None, Some(first_account.hash), None) + .await + .unwrap() + .value; + assert_eq!(balance, first_account.lamports); + } + // // 7. get_compressed_balance_by_owner + // { + // let balance = rpc + // .get_compressed_balance_by_owner(&payer_pubkey, None) + // .await + // .unwrap() + // .value; + // assert_eq!(balance, lamports + lamports_1); + // } + // // 8. get_compression_signatures_for_account + // { + // let signatures = rpc + // .get_compression_signatures_for_account(first_account.hash, None) + // .await + // .unwrap() + // .value; + // assert_eq!(signatures.items[0].signature, signature.to_string()); + // } + // // 9. get_compression_signatures_for_address + // { + // let signatures = rpc + // .get_compression_signatures_for_address(&first_account.address.unwrap(), None, None) + // .await + // .unwrap() + // .value; + // assert_eq!(signatures.items[0].signature, signature.to_string()); + // } + // // 10. get_compression_signatures_for_owner + // { + // let signatures = rpc + // .get_compression_signatures_for_owner(&owner, None, None) + // .await + // .unwrap() + // .value; + // assert_eq!(signatures.items.len(), 2); + // assert!(signatures + // .items + // .iter() + // .any(|s| s.signature == signature.to_string())); + // assert!(signatures + // .items + // .iter() + // .any(|s| s.signature == signature_1.to_string())); + // let options = PaginatedOptions { + // limit: Some(1), + // cursor: None, + // }; + // let signatures = rpc + // .get_compression_signatures_for_owner(&owner, Some(options), None) + // .await + // .unwrap() + // .value; + // assert_eq!(signatures.items.len(), 1); + // assert!(signatures.items.iter().any( + // |s| s.signature == signature_1.to_string() || s.signature == signature.to_string() + // )); + // } + // 11. get_multiple_compressed_account_proofs + { + let proofs = rpc + .get_multiple_compressed_account_proofs(account_hashes.to_vec(), None) + .await + .unwrap() + .value; + assert!(!proofs.items.is_empty()); + assert_eq!(proofs.items[0].hash, account_hashes[0]); + + // 12. get_multiple_new_address_proofs + let addresses = vec![address]; + let new_address_proofs = rpc + .get_multiple_new_address_proofs( + test_accounts.v1_address_trees[0].merkle_tree.to_bytes(), + addresses, + None, + ) + .await + .unwrap(); + assert!(!new_address_proofs.value.items.is_empty()); + assert_eq!( + new_address_proofs.value.items[0].merkle_tree.to_bytes(), + test_accounts.v1_address_trees[0].merkle_tree.to_bytes() + ); + } + + test_token_api(&mut rpc, &test_accounts).await; +} + +/// Token API endpoints tested: +/// 1. get_compressed_token_accounts_by_owner +/// 2. get_compressed_token_account_balance +/// 3. get_compressed_token_balances_by_owner_v2 +/// 4. get_compressed_mint_token_holders +/// 5. get_compression_signatures_for_token_owner +async fn test_token_api(rpc: &mut LightProgramTest, test_accounts: &TestAccounts) { + let payer = rpc.get_payer().insecure_clone(); + let payer_pubkey = payer.pubkey(); + let mint_1 = Keypair::new(); + let mint_2 = Keypair::new(); + + create_two_mints(rpc, payer_pubkey, &mint_1, &mint_2).await; + let mint_1 = mint_1.pubkey(); + let mint_2 = mint_2.pubkey(); + let base_amount = 1_000_000; + let recipients = (0..5) + .map(|_| Pubkey::new_unique()) + .collect::>(); + let amounts = (0..5).map(|i| base_amount + i).collect::>(); + // Mint amounts to payer for both mints with and without lamports + let _signatures = mint_to_token_accounts( + rpc, + test_accounts, + payer_pubkey, + mint_1, + mint_2, + base_amount, + &recipients, + &amounts, + ) + .await; + // // 1. get_compressed_mint_token_holders + // for mint in [mint_1, mint_2] { + // let res = rpc + // .get_compressed_mint_token_holders(&mint, None, None) + // .await + // .unwrap() + // .value + // .items; + // assert_eq!(res.len(), 5); + + // let mut owners = res.iter().map(|x| x.owner).collect::>(); + // owners.sort(); + // owners.dedup(); + // assert_eq!(owners.len(), 5); + // for (amount, recipient) in amounts.iter().zip(recipients.iter()) { + // // * 2 because we mint two times the same amount per token mint (with and without lamports) + // assert!(res + // .iter() + // .any(|item| item.balance == (*amount * 2) && item.owner == *recipient)); + // } + // let option = PaginatedOptions { + // limit: Some(1), + // cursor: None, + // }; + // let res = rpc + // .get_compressed_mint_token_holders(&mint, Some(option), None) + // .await + // .unwrap() + // .value + // .items; + // assert_eq!(res.len(), 1); + // } + + // // 2. get_compression_signatures_for_token_owner + // for recipient in &recipients { + // let res = rpc + // .get_compression_signatures_for_token_owner(recipient, None, None) + // .await + // .unwrap() + // .value + // .items; + // assert_eq!(res.len(), 2); + // assert_eq!(res[0].signature, signatures[1].to_string()); + // assert_eq!(res[1].signature, signatures[0].to_string()); + // let option = PaginatedOptions { + // limit: Some(1), + // cursor: None, + // }; + // let res = rpc + // .get_compression_signatures_for_token_owner(recipient, Some(option), None) + // .await + // .unwrap() + // .value + // .items; + // assert_eq!(res.len(), 1); + // } + + // 3. get_compressed_token_accounts_by_owner + test_get_compressed_token_accounts_by_owner( + rpc, + mint_1, + mint_2, + base_amount, + &recipients, + &amounts, + ) + .await; + // 4. get_compressed_token_account_balance + { + let token_accounts = rpc + .get_compressed_token_accounts_by_owner(&recipients[0], None, None) + .await + .unwrap() + .value; + let hash = token_accounts.items[0].account.hash; + let balance = rpc + .get_compressed_token_account_balance(None, Some(hash), None) + .await + .unwrap() + .value; + assert_eq!(balance, amounts[0]); + assert_eq!(balance, token_accounts.items[0].token.amount); + } + // 5. get_compressed_token_balances_by_owner_v2 + { + // No options + test_get_compressed_token_balances_by_owner_v2( + rpc, + vec![mint_1, mint_2], + recipients.clone(), + amounts.clone(), + None, + ) + .await; + // Limit to mint1 + let options = Some(GetCompressedTokenAccountsByOwnerOrDelegateOptions { + mint: Some(mint_1), + cursor: None, + limit: None, + }); + test_get_compressed_token_balances_by_owner_v2( + rpc, + vec![mint_1], + recipients.clone(), + amounts.clone(), + options, + ) + .await; + + // Limit to mint2 + let options = Some(GetCompressedTokenAccountsByOwnerOrDelegateOptions { + mint: Some(mint_2), + cursor: None, + limit: None, + }); + test_get_compressed_token_balances_by_owner_v2( + rpc, + vec![mint_2], + recipients.clone(), + amounts.clone(), + options, + ) + .await; + } +} + +#[allow(clippy::too_many_arguments)] +async fn mint_to_token_accounts( + rpc: &mut LightProgramTest, + test_accounts: &TestAccounts, + payer_pubkey: Pubkey, + mint_1: Pubkey, + mint_2: Pubkey, + base_amount: u64, + recipients: &[Pubkey], + amounts: &[u64], +) -> [Signature; 2] { + let mut signatures = Vec::new(); + + for mint in [mint_1, mint_2] { + let mint_ix_with_lamports = create_mint_to_instruction( + &payer_pubkey, + &payer_pubkey, + &mint, + &test_accounts.v1_state_trees[0].merkle_tree, + amounts.to_vec(), + recipients.to_vec(), + Some(base_amount), + false, + 0, + ); + + let mint_ix_no_lamports = create_mint_to_instruction( + &payer_pubkey, + &payer_pubkey, + &mint, + &test_accounts.v1_state_trees[0].merkle_tree, + amounts.to_vec(), + recipients.to_vec(), + None, + false, + 0, + ); + + let compute_budget_ix = ComputeBudgetInstruction::set_compute_unit_limit(500_000); + let blockhash = rpc.get_latest_blockhash().await.unwrap().0; + let payer = rpc.get_payer().insecure_clone(); + + let tx = Transaction::new_signed_with_payer( + &[ + compute_budget_ix, + mint_ix_with_lamports, + mint_ix_no_lamports, + ], + Some(&payer_pubkey), + &[&payer], + blockhash, + ); + signatures.push(rpc.process_transaction(tx).await.unwrap()); + } + signatures.try_into().unwrap() +} + +async fn create_two_mints( + rpc: &mut LightProgramTest, + payer_pubkey: Pubkey, + mint_1: &Keypair, + mint_2: &Keypair, +) { + let mint_rent = rpc + .get_minimum_balance_for_rent_exemption(82) + .await + .unwrap(); + let create_mint_ix = create_account( + &payer_pubkey, + &mint_1.pubkey(), + mint_rent, + 82, + &spl_token::id(), + ); + let create_mint_ix_2 = create_account( + &payer_pubkey, + &mint_2.pubkey(), + mint_rent, + 82, + &spl_token::id(), + ); + let init_mint_ix = spl_token::instruction::initialize_mint( + &spl_token::id(), + &mint_1.pubkey(), + &payer_pubkey, + None, + 9, + ) + .unwrap(); + let init_mint_ix_2 = spl_token::instruction::initialize_mint( + &spl_token::id(), + &mint_2.pubkey(), + &payer_pubkey, + None, + 2, + ) + .unwrap(); + // Create token pool for compression + let create_pool_ix = + create_create_token_pool_instruction(&payer_pubkey, &mint_1.pubkey(), false); + let create_pool_ix_2 = + create_create_token_pool_instruction(&payer_pubkey, &mint_2.pubkey(), false); + let compute_budget_ix = ComputeBudgetInstruction::set_compute_unit_limit(500_000); + let blockhash = rpc.get_latest_blockhash().await.unwrap().0; + let payer = rpc.get_payer().insecure_clone(); + let tx = Transaction::new_signed_with_payer( + &[ + compute_budget_ix, + create_mint_ix, + create_mint_ix_2, + init_mint_ix, + init_mint_ix_2, + create_pool_ix, + create_pool_ix_2, + ], + Some(&payer_pubkey), + &[&payer, mint_1, mint_2], + blockhash, + ); + rpc.process_transaction(tx).await.unwrap(); +} + +/// Tests: +/// 1. fetch all no options +/// 2. fetch only for mint 1, with limit 1 +async fn test_get_compressed_token_accounts_by_owner( + rpc: &mut LightProgramTest, + mint_1: Pubkey, + mint_2: Pubkey, + base_amount: u64, + recipients: &[Pubkey], + amounts: &[u64], +) { + let slot = rpc.get_slot().await.unwrap(); + let indexer_config = IndexerRpcConfig { + slot, + retry_config: RetryConfig::default(), + }; + for (amount, recipient) in amounts.iter().zip(recipients.iter()) { + { + let token_accounts = &rpc + .indexer() + .unwrap() + .get_compressed_token_accounts_by_owner( + recipient, + None, + Some(indexer_config.clone()), + ) + .await + .unwrap() + .value; + // every recipient should have 4 token accounts + // 1. 2 with lamports and 2 without + // 2. 2 with mint 1 and 2 with mint 2 + let mut expected_token_data = TokenData { + mint: mint_1, + amount: *amount, + owner: *recipient, + delegate: None, + state: AccountState::Initialized, + tlv: None, + }; + assert_eq!( + token_accounts + .items + .iter() + .filter(|item| item.token == expected_token_data) + .count(), + 2 + ); + assert!(token_accounts + .items + .iter() + .any(|item| item.token == expected_token_data + && item.account.lamports == base_amount)); + expected_token_data.mint = mint_2; + assert_eq!( + token_accounts + .items + .iter() + .filter(|item| item.token == expected_token_data) + .count(), + 2 + ); + assert!(token_accounts + .items + .iter() + .any(|item| item.token == expected_token_data + && item.account.lamports == base_amount)); + } + // fetch only for mint 1, with limit 1 + { + let options = GetCompressedTokenAccountsByOwnerOrDelegateOptions { + mint: Some(mint_1), + cursor: None, + limit: Some(1), + }; + let token_accounts = &rpc + .indexer() + .unwrap() + .get_compressed_token_accounts_by_owner(recipient, Some(options.clone()), None) + .await + .unwrap() + .value; + assert_eq!(token_accounts.items.len(), 1); + assert_eq!(token_accounts.items[0].token.mint, options.mint.unwrap()); + } + } +} + +async fn create_address( + rpc: &mut LightProgramTest, + lamports: u64, + owner: Pubkey, + merkle_tree: Pubkey, +) -> Result<([u8; 32], Signature), RpcError> { + let address_merkle_tree = rpc.get_address_tree_v1(); + let (address, address_seed) = derive_address( + &[Pubkey::new_unique().to_bytes().as_slice()], + &address_merkle_tree.tree, + &Pubkey::new_unique(), + ); + + let output_account = light_compressed_account::compressed_account::CompressedAccount { + lamports, + owner: owner.into(), + data: None, + address: Some(address), + }; + let rpc_proof_result = rpc + .get_validity_proof( + vec![], + vec![AddressWithTree { + address, + tree: address_merkle_tree.tree, + }], + None, + ) + .await + .unwrap(); + + let new_address_params = NewAddressParams { + seed: address_seed, + address_queue_pubkey: address_merkle_tree.queue.into(), + address_merkle_tree_pubkey: address_merkle_tree.tree.into(), + address_merkle_tree_root_index: rpc_proof_result.value.addresses[0].root_index, + }; + let compute_budget_ix = ComputeBudgetInstruction::set_compute_unit_limit(500_000); + let ix = create_invoke_instruction( + &rpc.get_payer().pubkey(), + &rpc.get_payer().pubkey(), + &[], + &[output_account], + &[], + &[merkle_tree], + &[], + &[new_address_params], + rpc_proof_result.value.proof.0, + Some(lamports), + true, + None, + true, + ); + + let blockhash = rpc.get_latest_blockhash().await.unwrap().0; + let payer = rpc.get_payer().insecure_clone(); + let tx_create_compressed_account = Transaction::new_signed_with_payer( + &[compute_budget_ix, ix], + Some(&payer.pubkey()), + &[&payer], + blockhash, + ); + let signature = rpc + .process_transaction(tx_create_compressed_account) + .await?; + Ok((address, signature)) +} + +async fn test_get_compressed_token_balances_by_owner_v2( + rpc: &mut LightProgramTest, + mints: Vec, + recipients: Vec, + amounts: Vec, + options: Option, +) { + for (amount, recipient) in amounts.iter().zip(recipients.iter()) { + let balances = rpc + .get_compressed_token_balances_by_owner_v2(recipient, options.clone(), None) + .await + .unwrap(); + let balances = balances.value.items; + assert_eq!(balances.len(), mints.len()); + for mint in mints.iter() { + assert!(balances + .iter() + .any(|balance| balance.mint == *mint && balance.balance == (*amount) * 2)); + } + } +} diff --git a/sdk-tests/client-test/tests/sdk_compat.rs b/sdk-tests/client-test/tests/sdk_compat.rs new file mode 100644 index 0000000000..0c893b622c --- /dev/null +++ b/sdk-tests/client-test/tests/sdk_compat.rs @@ -0,0 +1,112 @@ +use light_hasher::HasherError; +use light_sdk::error::LightSdkError as SolanaLightSdkError; +use light_sdk_pinocchio::error::LightSdkError as PinocchioLightSdkError; +use light_zero_copy::errors::ZeroCopyError; + +fn generate_all_solana_errors() -> Vec { + vec![ + SolanaLightSdkError::ConstraintViolation, + SolanaLightSdkError::InvalidLightSystemProgram, + SolanaLightSdkError::ExpectedAccounts, + SolanaLightSdkError::ExpectedAddressTreeInfo, + SolanaLightSdkError::ExpectedAddressRootIndex, + SolanaLightSdkError::ExpectedData, + SolanaLightSdkError::ExpectedDiscriminator, + SolanaLightSdkError::ExpectedHash, + SolanaLightSdkError::ExpectedLightSystemAccount("test".to_string()), + SolanaLightSdkError::ExpectedMerkleContext, + SolanaLightSdkError::ExpectedRootIndex, + SolanaLightSdkError::TransferFromNoInput, + SolanaLightSdkError::TransferFromNoLamports, + SolanaLightSdkError::TransferFromInsufficientLamports, + SolanaLightSdkError::TransferIntegerOverflow, + SolanaLightSdkError::Borsh, + SolanaLightSdkError::FewerAccountsThanSystemAccounts, + SolanaLightSdkError::InvalidCpiSignerAccount, + SolanaLightSdkError::MissingField("test".to_string()), + SolanaLightSdkError::OutputStateTreeIndexIsNone, + SolanaLightSdkError::InitAddressIsNone, + SolanaLightSdkError::InitWithAddressIsNone, + SolanaLightSdkError::InitWithAddressOutputIsNone, + SolanaLightSdkError::MetaMutAddressIsNone, + SolanaLightSdkError::MetaMutInputIsNone, + SolanaLightSdkError::MetaMutOutputLamportsIsNone, + SolanaLightSdkError::MetaMutOutputIsNone, + SolanaLightSdkError::MetaCloseAddressIsNone, + SolanaLightSdkError::MetaCloseInputIsNone, + SolanaLightSdkError::CpiAccountsIndexOutOfBounds(1), + SolanaLightSdkError::Hasher(HasherError::IntegerOverflow), + SolanaLightSdkError::ZeroCopy(ZeroCopyError::Full), + ] +} + +fn generate_all_pinocchio_errors() -> Vec { + vec![ + PinocchioLightSdkError::ConstraintViolation, + PinocchioLightSdkError::InvalidLightSystemProgram, + PinocchioLightSdkError::ExpectedAccounts, + PinocchioLightSdkError::ExpectedAddressTreeInfo, + PinocchioLightSdkError::ExpectedAddressRootIndex, + PinocchioLightSdkError::ExpectedData, + PinocchioLightSdkError::ExpectedDiscriminator, + PinocchioLightSdkError::ExpectedHash, + PinocchioLightSdkError::ExpectedLightSystemAccount("test".to_string()), + PinocchioLightSdkError::ExpectedMerkleContext, + PinocchioLightSdkError::ExpectedRootIndex, + PinocchioLightSdkError::TransferFromNoInput, + PinocchioLightSdkError::TransferFromNoLamports, + PinocchioLightSdkError::TransferFromInsufficientLamports, + PinocchioLightSdkError::TransferIntegerOverflow, + PinocchioLightSdkError::Borsh, + PinocchioLightSdkError::FewerAccountsThanSystemAccounts, + PinocchioLightSdkError::InvalidCpiSignerAccount, + PinocchioLightSdkError::MissingField("test".to_string()), + PinocchioLightSdkError::OutputStateTreeIndexIsNone, + PinocchioLightSdkError::InitAddressIsNone, + PinocchioLightSdkError::InitWithAddressIsNone, + PinocchioLightSdkError::InitWithAddressOutputIsNone, + PinocchioLightSdkError::MetaMutAddressIsNone, + PinocchioLightSdkError::MetaMutInputIsNone, + PinocchioLightSdkError::MetaMutOutputLamportsIsNone, + PinocchioLightSdkError::MetaMutOutputIsNone, + PinocchioLightSdkError::MetaCloseAddressIsNone, + PinocchioLightSdkError::MetaCloseInputIsNone, + PinocchioLightSdkError::CpiAccountsIndexOutOfBounds(1), + PinocchioLightSdkError::Hasher(HasherError::IntegerOverflow), + PinocchioLightSdkError::ZeroCopy(ZeroCopyError::Full), + ] +} + +#[test] +fn test_error_compatibility() { + let solana_errors = generate_all_solana_errors(); + let pinocchio_errors = generate_all_pinocchio_errors(); + + // Ensure both SDKs have the same number of error variants + assert_eq!( + solana_errors.len(), + pinocchio_errors.len(), + "SDKs have different number of error variants" + ); + + // Test string representations + for (solana_error, pinocchio_error) in solana_errors.iter().zip(pinocchio_errors.iter()) { + assert_eq!( + solana_error.to_string(), + pinocchio_error.to_string(), + "String representations differ for error variants" + ); + } + + // Test error codes (consuming the values) + for (solana_error, pinocchio_error) in + solana_errors.into_iter().zip(pinocchio_errors.into_iter()) + { + let solana_code: u32 = solana_error.into(); + let pinocchio_code: u32 = pinocchio_error.into(); + assert_eq!( + solana_code, pinocchio_code, + "Error codes differ for error variants" + ); + } +} diff --git a/sdk-tests/sdk-anchor-test/.gitignore b/sdk-tests/sdk-anchor-test/.gitignore new file mode 100644 index 0000000000..2e0446b07f --- /dev/null +++ b/sdk-tests/sdk-anchor-test/.gitignore @@ -0,0 +1,7 @@ +.anchor +.DS_Store +target +**/*.rs.bk +node_modules +test-ledger +.yarn diff --git a/sdk-tests/sdk-anchor-test/.prettierignore b/sdk-tests/sdk-anchor-test/.prettierignore new file mode 100644 index 0000000000..c1a0b75f09 --- /dev/null +++ b/sdk-tests/sdk-anchor-test/.prettierignore @@ -0,0 +1,8 @@ + +.anchor +.DS_Store +target +node_modules +dist +build +test-ledger diff --git a/sdk-tests/sdk-anchor-test/Anchor.toml b/sdk-tests/sdk-anchor-test/Anchor.toml new file mode 100644 index 0000000000..a443e6fb8c --- /dev/null +++ b/sdk-tests/sdk-anchor-test/Anchor.toml @@ -0,0 +1,18 @@ +[toolchain] + +[features] +seeds = false +skip-lint = false + +[programs.localnet] +sdk_test = "2tzfijPBGbrR5PboyFUFKzfEoLTwdDSHUjANCw929wyt" + +[registry] +url = "https://api.apr.dev" + +[provider] +cluster = "Localnet" +wallet = "~/.config/solana/id.json" + +[scripts] +test = "yarn run ts-mocha -p ./tsconfig.json -t 1000000 tests/**/*.ts" diff --git a/sdk-tests/sdk-anchor-test/README.md b/sdk-tests/sdk-anchor-test/README.md new file mode 100644 index 0000000000..8c768e8b2c --- /dev/null +++ b/sdk-tests/sdk-anchor-test/README.md @@ -0,0 +1 @@ +# SDK test program diff --git a/sdk-tests/sdk-anchor-test/package.json b/sdk-tests/sdk-anchor-test/package.json new file mode 100644 index 0000000000..665fce3d8c --- /dev/null +++ b/sdk-tests/sdk-anchor-test/package.json @@ -0,0 +1,20 @@ +{ + "scripts": { + "test": "cargo test-sbf -p sdk-test" + }, + "dependencies": { + "@coral-xyz/anchor": "^0.29.0" + }, + "devDependencies": { + "@lightprotocol/zk-compression-cli": "workspace:*", + + "chai": "^5.2.0", + "mocha": "^11.7.1", + "ts-mocha": "^11.1.0", + "@types/bn.js": "^5.2.0", + "@types/chai": "^5.2.2", + "@types/mocha": "^10.0.10", + "typescript": "^5.8.3", + "prettier": "^3.6.2" + } +} diff --git a/sdk-tests/sdk-anchor-test/programs/sdk-anchor-test/Cargo.toml b/sdk-tests/sdk-anchor-test/programs/sdk-anchor-test/Cargo.toml new file mode 100644 index 0000000000..f0faca1233 --- /dev/null +++ b/sdk-tests/sdk-anchor-test/programs/sdk-anchor-test/Cargo.toml @@ -0,0 +1,38 @@ +[package] +name = "sdk-anchor-test" +version = "0.7.0" +description = "Test program for Light SDK and Light Macros" +edition = "2021" +license = "Apache-2.0" + +[lib] +crate-type = ["cdylib", "lib"] +name = "sdk_anchor_test" + +[features] +no-entrypoint = [] +no-idl = [] +no-log-ix-name = [] +cpi = ["no-entrypoint"] +default = ["idl-build"] +test-sbf = [] +bench-sbf = [] +idl-build = ["anchor-lang/idl-build", "light-sdk/idl-build"] + +[dependencies] +# Needs to be imported for LightHasher +light-hasher = { workspace = true, features = ["solana"] } +anchor-lang = { workspace = true } +light-sdk = { workspace = true, features = ["anchor", "v2"] } +light-sdk-types = { workspace = true } + +[target.'cfg(not(target_os = "solana"))'.dependencies] +solana-sdk = { workspace = true } + +[dev-dependencies] +light-client = { workspace = true, features = ["devenv"] } +light-program-test = { workspace = true, features = ["devenv"] } +light-test-utils = { workspace = true, features = ["devenv"] } +light-prover-client = { workspace = true, features = ["devenv"] } +tokio = { workspace = true } +light-compressed-account = { workspace = true, features = ["solana"] } diff --git a/sdk-tests/sdk-anchor-test/programs/sdk-anchor-test/Xargo.toml b/sdk-tests/sdk-anchor-test/programs/sdk-anchor-test/Xargo.toml new file mode 100644 index 0000000000..475fb71ed1 --- /dev/null +++ b/sdk-tests/sdk-anchor-test/programs/sdk-anchor-test/Xargo.toml @@ -0,0 +1,2 @@ +[target.bpfel-unknown-unknown.dependencies.std] +features = [] diff --git a/sdk-tests/sdk-anchor-test/programs/sdk-anchor-test/src/lib.rs b/sdk-tests/sdk-anchor-test/programs/sdk-anchor-test/src/lib.rs new file mode 100644 index 0000000000..9f5f0367d5 --- /dev/null +++ b/sdk-tests/sdk-anchor-test/programs/sdk-anchor-test/src/lib.rs @@ -0,0 +1,196 @@ +#![allow(unexpected_cfgs)] + +use anchor_lang::{prelude::*, Discriminator}; +use light_sdk::{ + account::LightAccount, + address::v1::derive_address, + cpi::{CpiAccounts, CpiInputs, CpiSigner}, + derive_light_cpi_signer, + instruction::{account_meta::CompressedAccountMeta, PackedAddressTreeInfo, ValidityProof}, + LightDiscriminator, LightHasher, +}; + +declare_id!("2tzfijPBGbrR5PboyFUFKzfEoLTwdDSHUjANCw929wyt"); + +pub const LIGHT_CPI_SIGNER: CpiSigner = + derive_light_cpi_signer!("2tzfijPBGbrR5PboyFUFKzfEoLTwdDSHUjANCw929wyt"); + +#[program] +pub mod sdk_anchor_test { + + use super::*; + + pub fn create_compressed_account<'info>( + ctx: Context<'_, '_, '_, 'info, WithNestedData<'info>>, + proof: ValidityProof, + address_tree_info: PackedAddressTreeInfo, + output_tree_index: u8, + name: String, + ) -> Result<()> { + let light_cpi_accounts = CpiAccounts::new( + ctx.accounts.signer.as_ref(), + ctx.remaining_accounts, + crate::LIGHT_CPI_SIGNER, + ); + + let (address, address_seed) = derive_address( + &[b"compressed", name.as_bytes()], + &address_tree_info + .get_tree_pubkey(&light_cpi_accounts) + .map_err(|_| ErrorCode::AccountNotEnoughKeys)?, + &crate::ID, + ); + let new_address_params = address_tree_info.into_new_address_params_packed(address_seed); + + let mut my_compressed_account = LightAccount::<'_, MyCompressedAccount>::new_init( + &crate::ID, + Some(address), + output_tree_index, + ); + + my_compressed_account.name = name; + my_compressed_account.nested = NestedData::default(); + + let cpi_inputs = CpiInputs::new_with_address( + proof, + vec![my_compressed_account + .to_account_info() + .map_err(ProgramError::from)?], + vec![new_address_params], + ); + + cpi_inputs + .invoke_light_system_program(light_cpi_accounts) + .map_err(ProgramError::from)?; + + Ok(()) + } + + pub fn update_compressed_account<'info>( + ctx: Context<'_, '_, '_, 'info, UpdateNestedData<'info>>, + proof: ValidityProof, + my_compressed_account: MyCompressedAccount, + account_meta: CompressedAccountMeta, + nested_data: NestedData, + ) -> Result<()> { + let mut my_compressed_account = LightAccount::<'_, MyCompressedAccount>::new_mut( + &crate::ID, + &account_meta, + my_compressed_account, + ) + .map_err(ProgramError::from)?; + + my_compressed_account.nested = nested_data; + + let light_cpi_accounts = CpiAccounts::new( + ctx.accounts.signer.as_ref(), + ctx.remaining_accounts, + crate::LIGHT_CPI_SIGNER, + ); + + let cpi_inputs = CpiInputs::new( + proof, + vec![my_compressed_account + .to_account_info() + .map_err(ProgramError::from)?], + ); + + cpi_inputs + .invoke_light_system_program(light_cpi_accounts) + .map_err(ProgramError::from)?; + + Ok(()) + } + + pub fn without_compressed_account<'info>( + ctx: Context<'_, '_, '_, 'info, WithoutCompressedAccount<'info>>, + name: String, + ) -> Result<()> { + ctx.accounts.my_regular_account.name = name; + Ok(()) + } +} + +#[event] +#[derive(Clone, Debug, Default, LightHasher, LightDiscriminator)] +pub struct MyCompressedAccount { + #[hash] + pub name: String, + pub nested: NestedData, +} + +// Illustrates nested hashing feature. +#[derive(LightHasher, Clone, Debug, AnchorSerialize, AnchorDeserialize)] +pub struct NestedData { + pub one: u16, + pub two: u16, + pub three: u16, + pub four: u16, + pub five: u16, + pub six: u16, + pub seven: u16, + pub eight: u16, + pub nine: u16, + pub ten: u16, + pub eleven: u16, + pub twelve: u16, +} + +impl Default for NestedData { + fn default() -> Self { + Self { + one: 1, + two: 2, + three: 3, + four: 4, + five: 5, + six: 6, + seven: 7, + eight: 8, + nine: 9, + ten: 10, + eleven: 11, + twelve: 12, + } + } +} + +#[account] +pub struct MyRegularAccount { + name: String, +} + +#[derive(Accounts)] +#[instruction(name: String)] +pub struct WithCompressedAccount<'info> { + #[account(mut)] + pub signer: Signer<'info>, +} + +#[derive(Accounts)] +pub struct WithNestedData<'info> { + #[account(mut)] + pub signer: Signer<'info>, +} + +#[derive(Accounts)] +pub struct UpdateNestedData<'info> { + #[account(mut)] + pub signer: Signer<'info>, +} + +#[derive(Accounts)] +#[instruction(name: String)] +pub struct WithoutCompressedAccount<'info> { + #[account(mut)] + pub signer: Signer<'info>, + #[account( + init, + seeds = [b"compressed".as_slice(), name.as_bytes()], + bump, + payer = signer, + space = 8 + 8, + )] + pub my_regular_account: Account<'info, MyRegularAccount>, + pub system_program: Program<'info, System>, +} diff --git a/sdk-tests/sdk-anchor-test/programs/sdk-anchor-test/tests/test.rs b/sdk-tests/sdk-anchor-test/programs/sdk-anchor-test/tests/test.rs new file mode 100644 index 0000000000..96949c26e5 --- /dev/null +++ b/sdk-tests/sdk-anchor-test/programs/sdk-anchor-test/tests/test.rs @@ -0,0 +1,196 @@ +#![cfg(feature = "test-sbf")] + +use anchor_lang::AnchorDeserialize; +use light_client::indexer::CompressedAccount; +use light_program_test::{ + indexer::TestIndexerExtensions, program_test::LightProgramTest, AddressWithTree, Indexer, + ProgramTestConfig, +}; +use light_sdk::{ + address::v1::derive_address, + instruction::{account_meta::CompressedAccountMeta, PackedAccounts, SystemAccountMetaConfig}, +}; +use light_test_utils::{Rpc, RpcError}; +use sdk_anchor_test::{MyCompressedAccount, NestedData}; +use solana_sdk::{ + instruction::{AccountMeta, Instruction}, + signature::{Keypair, Signature, Signer}, +}; + +#[tokio::test] +async fn test_sdk_test() { + let config = + ProgramTestConfig::new_v2(true, Some(vec![("sdk_anchor_test", sdk_anchor_test::ID)])); + let mut rpc = LightProgramTest::new(config).await.unwrap(); + let payer = rpc.get_payer().insecure_clone(); + + let address_tree_info = rpc.get_address_tree_v1(); + + let (address, _) = derive_address( + &[b"compressed", b"test".as_slice()], + &address_tree_info.tree, + &sdk_anchor_test::ID, + ); + + create_compressed_account("test".to_string(), &mut rpc, &payer, &address) + .await + .unwrap(); + + // Check that it was created correctly. + let compressed_account = rpc + .get_compressed_account(address, None) + .await + .unwrap() + .value; + + let record = &compressed_account.data.as_ref().unwrap().data; + let record = MyCompressedAccount::deserialize(&mut &record[..]).unwrap(); + assert_eq!(record.nested.one, 1); + + update_compressed_account( + &mut rpc, + NestedData { + one: 2, + two: 3, + three: 3, + four: 4, + five: 5, + six: 6, + seven: 7, + eight: 8, + nine: 9, + ten: 10, + eleven: 11, + twelve: 12, + }, + &payer, + compressed_account, + ) + .await + .unwrap(); + + // Check that it was updated correctly. + let compressed_accounts = + rpc.get_compressed_accounts_with_merkle_context_by_owner(&sdk_anchor_test::ID); + assert_eq!(compressed_accounts.len(), 1); + let compressed_account = &compressed_accounts[0]; + let record = &compressed_account + .compressed_account + .data + .as_ref() + .unwrap() + .data; + let record = MyCompressedAccount::deserialize(&mut &record[..]).unwrap(); + assert_eq!(record.nested.one, 2); +} + +async fn create_compressed_account( + name: String, + rpc: &mut LightProgramTest, + payer: &Keypair, + address: &[u8; 32], +) -> Result { + let config = SystemAccountMetaConfig::new(sdk_anchor_test::ID); + let mut remaining_accounts = PackedAccounts::default(); + remaining_accounts.add_system_accounts(config); + + let address_merkle_tree_info = rpc.get_address_tree_v1(); + + let rpc_result = rpc + .get_validity_proof( + vec![], + vec![AddressWithTree { + address: *address, + tree: address_merkle_tree_info.tree, + }], + None, + ) + .await? + .value; + let packed_accounts = rpc_result.pack_tree_infos(&mut remaining_accounts); + + let output_tree_index = rpc + .get_random_state_tree_info() + .unwrap() + .pack_output_tree_index(&mut remaining_accounts) + .unwrap(); + + let (remaining_accounts, _, _) = remaining_accounts.to_account_metas(); + + let instruction = Instruction { + program_id: sdk_anchor_test::ID, + accounts: [ + vec![AccountMeta::new(payer.pubkey(), true)], + remaining_accounts, + ] + .concat(), + data: { + use anchor_lang::InstructionData; + sdk_anchor_test::instruction::CreateCompressedAccount { + proof: rpc_result.proof, + address_tree_info: packed_accounts.address_trees[0], + output_tree_index, + name, + } + .data() + }, + }; + + rpc.create_and_send_transaction(&[instruction], &payer.pubkey(), &[payer]) + .await +} + +async fn update_compressed_account( + rpc: &mut LightProgramTest, + nested_data: NestedData, + payer: &Keypair, + mut compressed_account: CompressedAccount, +) -> Result { + let mut remaining_accounts = PackedAccounts::default(); + + let config = SystemAccountMetaConfig::new(sdk_anchor_test::ID); + remaining_accounts.add_system_accounts(config); + let hash = compressed_account.hash; + + let rpc_result = rpc + .get_validity_proof(vec![hash], vec![], None) + .await? + .value; + + let packed_tree_accounts = rpc_result + .pack_tree_infos(&mut remaining_accounts) + .state_trees + .unwrap(); + + let (remaining_accounts, _, _) = remaining_accounts.to_account_metas(); + + let my_compressed_account = MyCompressedAccount::deserialize( + &mut compressed_account.data.as_mut().unwrap().data.as_slice(), + ) + .unwrap(); + let instruction = Instruction { + program_id: sdk_anchor_test::ID, + accounts: [ + vec![AccountMeta::new(payer.pubkey(), true)], + remaining_accounts, + ] + .concat(), + data: { + use anchor_lang::InstructionData; + sdk_anchor_test::instruction::UpdateCompressedAccount { + proof: rpc_result.proof, + my_compressed_account, + account_meta: CompressedAccountMeta { + tree_info: packed_tree_accounts.packed_tree_infos[0], + address: compressed_account.address.unwrap(), + output_state_tree_index: packed_tree_accounts.output_tree_index, + }, + nested_data, + } + .data() + }, + }; + + rpc.create_and_send_transaction(&[instruction], &payer.pubkey(), &[payer]) + .await +} diff --git a/sdk-tests/sdk-anchor-test/tsconfig.json b/sdk-tests/sdk-anchor-test/tsconfig.json new file mode 100644 index 0000000000..cd5d2e3d06 --- /dev/null +++ b/sdk-tests/sdk-anchor-test/tsconfig.json @@ -0,0 +1,10 @@ +{ + "compilerOptions": { + "types": ["mocha", "chai"], + "typeRoots": ["./node_modules/@types"], + "lib": ["es2015"], + "module": "commonjs", + "target": "es6", + "esModuleInterop": true + } +} diff --git a/program-tests/sdk-pinocchio-test/Cargo.toml b/sdk-tests/sdk-pinocchio-test/Cargo.toml similarity index 100% rename from program-tests/sdk-pinocchio-test/Cargo.toml rename to sdk-tests/sdk-pinocchio-test/Cargo.toml diff --git a/sdk-tests/sdk-pinocchio-test/Xargo.toml b/sdk-tests/sdk-pinocchio-test/Xargo.toml new file mode 100644 index 0000000000..475fb71ed1 --- /dev/null +++ b/sdk-tests/sdk-pinocchio-test/Xargo.toml @@ -0,0 +1,2 @@ +[target.bpfel-unknown-unknown.dependencies.std] +features = [] diff --git a/program-tests/sdk-pinocchio-test/src/create_pda.rs b/sdk-tests/sdk-pinocchio-test/src/create_pda.rs similarity index 100% rename from program-tests/sdk-pinocchio-test/src/create_pda.rs rename to sdk-tests/sdk-pinocchio-test/src/create_pda.rs diff --git a/program-tests/sdk-pinocchio-test/src/lib.rs b/sdk-tests/sdk-pinocchio-test/src/lib.rs similarity index 100% rename from program-tests/sdk-pinocchio-test/src/lib.rs rename to sdk-tests/sdk-pinocchio-test/src/lib.rs diff --git a/program-tests/sdk-pinocchio-test/src/update_pda.rs b/sdk-tests/sdk-pinocchio-test/src/update_pda.rs similarity index 100% rename from program-tests/sdk-pinocchio-test/src/update_pda.rs rename to sdk-tests/sdk-pinocchio-test/src/update_pda.rs diff --git a/program-tests/sdk-pinocchio-test/tests/test.rs b/sdk-tests/sdk-pinocchio-test/tests/test.rs similarity index 100% rename from program-tests/sdk-pinocchio-test/tests/test.rs rename to sdk-tests/sdk-pinocchio-test/tests/test.rs diff --git a/sdk-tests/sdk-test/Cargo.toml b/sdk-tests/sdk-test/Cargo.toml new file mode 100644 index 0000000000..6929b36a55 --- /dev/null +++ b/sdk-tests/sdk-test/Cargo.toml @@ -0,0 +1,40 @@ +[package] +name = "sdk-test" +version = "1.0.0" +description = "Test program using generalized account compression" +repository = "https://github.com/Lightprotocol/light-protocol" +license = "Apache-2.0" +edition = "2021" + +[lib] +crate-type = ["cdylib", "lib"] +name = "sdk_test" + +[features] +no-entrypoint = [] +no-idl = [] +no-log-ix-name = [] +cpi = ["no-entrypoint"] +test-sbf = [] +default = [] + +[dependencies] +light-sdk = { workspace = true } +light-sdk-types = { workspace = true } +light-hasher = { workspace = true, features = ["solana"] } +solana-program = { workspace = true } +light-macros = { workspace = true, features = ["solana"] } +borsh = { workspace = true } +light-compressed-account = { workspace = true, features = ["solana"] } + +[dev-dependencies] +light-program-test = { workspace = true, features = ["devenv"] } +tokio = { workspace = true } +solana-sdk = { workspace = true } + +[lints.rust.unexpected_cfgs] +level = "allow" +check-cfg = [ + 'cfg(target_os, values("solana"))', + 'cfg(feature, values("frozen-abi", "no-entrypoint"))', +] diff --git a/sdk-tests/sdk-test/Xargo.toml b/sdk-tests/sdk-test/Xargo.toml new file mode 100644 index 0000000000..475fb71ed1 --- /dev/null +++ b/sdk-tests/sdk-test/Xargo.toml @@ -0,0 +1,2 @@ +[target.bpfel-unknown-unknown.dependencies.std] +features = [] diff --git a/sdk-tests/sdk-test/src/create_pda.rs b/sdk-tests/sdk-test/src/create_pda.rs new file mode 100644 index 0000000000..95a7293589 --- /dev/null +++ b/sdk-tests/sdk-test/src/create_pda.rs @@ -0,0 +1,87 @@ +use borsh::{BorshDeserialize, BorshSerialize}; +use light_sdk::{ + account::LightAccount, + cpi::{CpiAccounts, CpiAccountsConfig, CpiInputs}, + error::LightSdkError, + instruction::{PackedAddressTreeInfo, ValidityProof}, + light_hasher::hash_to_field_size::hashv_to_bn254_field_size_be_const_array, + LightDiscriminator, LightHasher, +}; +use solana_program::account_info::AccountInfo; + +/// TODO: write test program with A8JgviaEAByMVLBhcebpDQ7NMuZpqBTBigC1b83imEsd (inconvenient program id) +/// CU usage: +/// - sdk pre system program cpi 10,942 CU +/// - total with V2 tree: 45,758 CU +pub fn create_pda( + accounts: &[AccountInfo], + instruction_data: &[u8], +) -> Result<(), LightSdkError> { + let mut instruction_data = instruction_data; + let instruction_data = CreatePdaInstructionData::deserialize(&mut instruction_data) + .map_err(|_| LightSdkError::Borsh)?; + let config = CpiAccountsConfig::new(crate::LIGHT_CPI_SIGNER); + let cpi_accounts = CpiAccounts::try_new_with_config( + &accounts[0], + &accounts[instruction_data.system_accounts_offset as usize..], + config, + ) + .unwrap(); + + let address_tree_info = instruction_data.address_tree_info; + let (address, address_seed) = if BATCHED { + let address_seed = hashv_to_bn254_field_size_be_const_array::<3>(&[ + b"compressed", + instruction_data.data.as_slice(), + ]) + .unwrap(); + // to_bytes will go away as soon as we have a light_sdk::address::v2::derive_address + let address_tree_pubkey = address_tree_info.get_tree_pubkey(&cpi_accounts)?.to_bytes(); + let address = light_compressed_account::address::derive_address( + &address_seed, + &address_tree_pubkey, + &crate::ID.to_bytes(), + ); + (address, address_seed) + } else { + light_sdk::address::v1::derive_address( + &[b"compressed", instruction_data.data.as_slice()], + &address_tree_info.get_tree_pubkey(&cpi_accounts)?, + &crate::ID, + ) + }; + let new_address_params = address_tree_info.into_new_address_params_packed(address_seed); + + let mut my_compressed_account = LightAccount::<'_, MyCompressedAccount>::new_init( + &crate::ID, + Some(address), + instruction_data.output_merkle_tree_index, + ); + + my_compressed_account.data = instruction_data.data; + + let cpi_inputs = CpiInputs::new_with_address( + instruction_data.proof, + vec![my_compressed_account.to_account_info()?], + vec![new_address_params], + ); + cpi_inputs.invoke_light_system_program(cpi_accounts)?; + Ok(()) +} + +#[derive( + Clone, Debug, Default, LightHasher, LightDiscriminator, BorshDeserialize, BorshSerialize, +)] +pub struct MyCompressedAccount { + pub data: [u8; 31], +} + +#[derive(Clone, Debug, Default, BorshDeserialize, BorshSerialize)] +pub struct CreatePdaInstructionData { + pub proof: ValidityProof, + pub address_tree_info: PackedAddressTreeInfo, + pub output_merkle_tree_index: u8, + pub data: [u8; 31], + pub system_accounts_offset: u8, + pub tree_accounts_offset: u8, +} diff --git a/sdk-tests/sdk-test/src/lib.rs b/sdk-tests/sdk-test/src/lib.rs new file mode 100644 index 0000000000..8fb2b71b2c --- /dev/null +++ b/sdk-tests/sdk-test/src/lib.rs @@ -0,0 +1,49 @@ +use light_macros::pubkey; +use light_sdk::{cpi::CpiSigner, derive_light_cpi_signer, error::LightSdkError}; +use solana_program::{ + account_info::AccountInfo, entrypoint, program_error::ProgramError, pubkey::Pubkey, +}; + +pub mod create_pda; +pub mod update_pda; + +pub const ID: Pubkey = pubkey!("FNt7byTHev1k5x2cXZLBr8TdWiC3zoP5vcnZR4P682Uy"); +pub const LIGHT_CPI_SIGNER: CpiSigner = + derive_light_cpi_signer!("FNt7byTHev1k5x2cXZLBr8TdWiC3zoP5vcnZR4P682Uy"); + +entrypoint!(process_instruction); + +#[repr(u8)] +pub enum InstructionType { + CreatePdaBorsh = 0, + UpdatePdaBorsh = 1, +} + +impl TryFrom for InstructionType { + type Error = LightSdkError; + + fn try_from(value: u8) -> Result { + match value { + 0 => Ok(InstructionType::CreatePdaBorsh), + 1 => Ok(InstructionType::UpdatePdaBorsh), + _ => panic!("Invalid instruction discriminator."), + } + } +} + +pub fn process_instruction( + _program_id: &Pubkey, + accounts: &[AccountInfo], + instruction_data: &[u8], +) -> Result<(), ProgramError> { + let discriminator = InstructionType::try_from(instruction_data[0]).unwrap(); + match discriminator { + InstructionType::CreatePdaBorsh => { + create_pda::create_pda::(accounts, &instruction_data[1..]) + } + InstructionType::UpdatePdaBorsh => { + update_pda::update_pda::(accounts, &instruction_data[1..]) + } + }?; + Ok(()) +} diff --git a/sdk-tests/sdk-test/src/update_pda.rs b/sdk-tests/sdk-test/src/update_pda.rs new file mode 100644 index 0000000000..2e2fcd4257 --- /dev/null +++ b/sdk-tests/sdk-test/src/update_pda.rs @@ -0,0 +1,65 @@ +use borsh::{BorshDeserialize, BorshSerialize}; +use light_sdk::{ + account::LightAccount, + cpi::{CpiAccounts, CpiAccountsConfig, CpiInputs}, + error::LightSdkError, + instruction::{account_meta::CompressedAccountMeta, ValidityProof}, +}; +use solana_program::{account_info::AccountInfo, log::sol_log_compute_units}; + +use crate::create_pda::MyCompressedAccount; + +/// CU usage: +/// - sdk pre system program 9,183k CU +/// - total with V2 tree: 50,194 CU (proof by index) +/// - 51,609 +pub fn update_pda( + accounts: &[AccountInfo], + instruction_data: &[u8], +) -> Result<(), LightSdkError> { + sol_log_compute_units(); + let mut instruction_data = instruction_data; + let instruction_data = UpdatePdaInstructionData::deserialize(&mut instruction_data) + .map_err(|_| LightSdkError::Borsh)?; + + let mut my_compressed_account = LightAccount::<'_, MyCompressedAccount>::new_mut( + &crate::ID, + &instruction_data.my_compressed_account.meta, + MyCompressedAccount { + data: instruction_data.my_compressed_account.data, + }, + )?; + sol_log_compute_units(); + + my_compressed_account.data = instruction_data.new_data; + + let config = CpiAccountsConfig::new(crate::LIGHT_CPI_SIGNER); + sol_log_compute_units(); + let cpi_accounts = CpiAccounts::try_new_with_config( + &accounts[0], + &accounts[instruction_data.system_accounts_offset as usize..], + config, + )?; + sol_log_compute_units(); + let cpi_inputs = CpiInputs::new( + instruction_data.proof, + vec![my_compressed_account.to_account_info()?], + ); + sol_log_compute_units(); + cpi_inputs.invoke_light_system_program(cpi_accounts)?; + Ok(()) +} + +#[derive(Clone, Debug, Default, BorshDeserialize, BorshSerialize)] +pub struct UpdatePdaInstructionData { + pub proof: ValidityProof, + pub my_compressed_account: UpdateMyCompressedAccount, + pub new_data: [u8; 31], + pub system_accounts_offset: u8, +} + +#[derive(Clone, Debug, Default, BorshDeserialize, BorshSerialize)] +pub struct UpdateMyCompressedAccount { + pub meta: CompressedAccountMeta, + pub data: [u8; 31], +} diff --git a/sdk-tests/sdk-test/tests/test.rs b/sdk-tests/sdk-test/tests/test.rs new file mode 100644 index 0000000000..5008995923 --- /dev/null +++ b/sdk-tests/sdk-test/tests/test.rs @@ -0,0 +1,177 @@ +#![cfg(feature = "test-sbf")] + +use borsh::BorshSerialize; +use light_compressed_account::{ + address::derive_address, compressed_account::CompressedAccountWithMerkleContext, + hashv_to_bn254_field_size_be, +}; +use light_program_test::{ + program_test::LightProgramTest, AddressWithTree, Indexer, ProgramTestConfig, Rpc, RpcError, +}; +use light_sdk::instruction::{ + account_meta::CompressedAccountMeta, PackedAccounts, SystemAccountMetaConfig, +}; +use sdk_test::{ + create_pda::CreatePdaInstructionData, + update_pda::{UpdateMyCompressedAccount, UpdatePdaInstructionData}, +}; +use solana_sdk::{ + instruction::Instruction, + pubkey::Pubkey, + signature::{Keypair, Signer}, +}; + +#[tokio::test] +async fn test_sdk_test() { + let config = ProgramTestConfig::new_v2(true, Some(vec![("sdk_test", sdk_test::ID)])); + let mut rpc = LightProgramTest::new(config).await.unwrap(); + let payer = rpc.get_payer().insecure_clone(); + + let address_tree_pubkey = rpc.get_address_merkle_tree_v2(); + let account_data = [1u8; 31]; + + // // V1 trees + // let (address, _) = light_sdk::address::derive_address( + // &[b"compressed", &account_data], + // &address_tree_info, + // &sdk_test::ID, + // ); + // Batched trees + let address_seed = hashv_to_bn254_field_size_be(&[b"compressed", account_data.as_slice()]); + let address = derive_address( + &address_seed, + &address_tree_pubkey.to_bytes(), + &sdk_test::ID.to_bytes(), + ); + let ouput_queue = rpc.get_random_state_tree_info().unwrap().queue; + create_pda( + &payer, + &mut rpc, + &ouput_queue, + account_data, + address_tree_pubkey, + address, + ) + .await + .unwrap(); + + let compressed_pda = rpc + .indexer() + .unwrap() + .get_compressed_account(address, None) + .await + .unwrap() + .value + .clone(); + assert_eq!(compressed_pda.address.unwrap(), address); + + update_pda(&payer, &mut rpc, [2u8; 31], compressed_pda.into()) + .await + .unwrap(); +} + +pub async fn create_pda( + payer: &Keypair, + rpc: &mut LightProgramTest, + merkle_tree_pubkey: &Pubkey, + account_data: [u8; 31], + address_tree_pubkey: Pubkey, + address: [u8; 32], +) -> Result<(), RpcError> { + let system_account_meta_config = SystemAccountMetaConfig::new(sdk_test::ID); + let mut accounts = PackedAccounts::default(); + accounts.add_pre_accounts_signer(payer.pubkey()); + accounts.add_system_accounts(system_account_meta_config); + + let rpc_result = rpc + .get_validity_proof( + vec![], + vec![AddressWithTree { + address, + tree: address_tree_pubkey, + }], + None, + ) + .await? + .value; + + let output_merkle_tree_index = accounts.insert_or_get(*merkle_tree_pubkey); + let packed_address_tree_info = rpc_result.pack_tree_infos(&mut accounts).address_trees[0]; + let (accounts, system_accounts_offset, tree_accounts_offset) = accounts.to_account_metas(); + + let instruction_data = CreatePdaInstructionData { + proof: rpc_result.proof.0.unwrap().into(), + address_tree_info: packed_address_tree_info, + data: account_data, + output_merkle_tree_index, + system_accounts_offset: system_accounts_offset as u8, + tree_accounts_offset: tree_accounts_offset as u8, + }; + let inputs = instruction_data.try_to_vec().unwrap(); + + let instruction = Instruction { + program_id: sdk_test::ID, + accounts, + data: [&[0u8][..], &inputs[..]].concat(), + }; + + rpc.create_and_send_transaction(&[instruction], &payer.pubkey(), &[payer]) + .await?; + Ok(()) +} + +pub async fn update_pda( + payer: &Keypair, + rpc: &mut LightProgramTest, + new_account_data: [u8; 31], + compressed_account: CompressedAccountWithMerkleContext, +) -> Result<(), RpcError> { + let system_account_meta_config = SystemAccountMetaConfig::new(sdk_test::ID); + let mut accounts = PackedAccounts::default(); + accounts.add_pre_accounts_signer(payer.pubkey()); + accounts.add_system_accounts(system_account_meta_config); + + let rpc_result = rpc + .get_validity_proof(vec![compressed_account.hash().unwrap()], vec![], None) + .await? + .value; + + let packed_accounts = rpc_result + .pack_tree_infos(&mut accounts) + .state_trees + .unwrap(); + + let meta = CompressedAccountMeta { + tree_info: packed_accounts.packed_tree_infos[0], + address: compressed_account.compressed_account.address.unwrap(), + output_state_tree_index: packed_accounts.output_tree_index, + }; + + let (accounts, system_accounts_offset, _) = accounts.to_account_metas(); + let instruction_data = UpdatePdaInstructionData { + my_compressed_account: UpdateMyCompressedAccount { + meta, + data: compressed_account + .compressed_account + .data + .unwrap() + .data + .try_into() + .unwrap(), + }, + proof: rpc_result.proof, + new_data: new_account_data, + system_accounts_offset: system_accounts_offset as u8, + }; + let inputs = instruction_data.try_to_vec().unwrap(); + + let instruction = Instruction { + program_id: sdk_test::ID, + accounts, + data: [&[1u8][..], &inputs[..]].concat(), + }; + + rpc.create_and_send_transaction(&[instruction], &payer.pubkey(), &[payer]) + .await?; + Ok(()) +} From c8f8124ea8e9def9506e5c55ae6a2ceea4a31cd8 Mon Sep 17 00:00:00 2001 From: ananas-block Date: Fri, 15 Aug 2025 18:55:11 +0200 Subject: [PATCH 2/4] refactor: sdk-test to user array [u8;2000] --- sdk-tests/sdk-test/Cargo.toml | 1 + sdk-tests/sdk-test/src/create_pda.rs | 27 +++++++++++++++++++------- sdk-tests/sdk-test/src/lib.rs | 2 ++ sdk-tests/sdk-test/src/update_pda.rs | 29 +++++++++++++++++++++++----- sdk-tests/sdk-test/tests/test.rs | 11 ++++++----- 5 files changed, 53 insertions(+), 17 deletions(-) diff --git a/sdk-tests/sdk-test/Cargo.toml b/sdk-tests/sdk-test/Cargo.toml index 6929b36a55..8ca0da7072 100644 --- a/sdk-tests/sdk-test/Cargo.toml +++ b/sdk-tests/sdk-test/Cargo.toml @@ -26,6 +26,7 @@ solana-program = { workspace = true } light-macros = { workspace = true, features = ["solana"] } borsh = { workspace = true } light-compressed-account = { workspace = true, features = ["solana"] } +light-zero-copy = { workspace = true } [dev-dependencies] light-program-test = { workspace = true, features = ["devenv"] } diff --git a/sdk-tests/sdk-test/src/create_pda.rs b/sdk-tests/sdk-test/src/create_pda.rs index 95a7293589..3dac15deab 100644 --- a/sdk-tests/sdk-test/src/create_pda.rs +++ b/sdk-tests/sdk-test/src/create_pda.rs @@ -1,3 +1,4 @@ +use crate::ARRAY_LEN; use borsh::{BorshDeserialize, BorshSerialize}; use light_sdk::{ account::LightAccount, @@ -7,7 +8,9 @@ use light_sdk::{ light_hasher::hash_to_field_size::hashv_to_bn254_field_size_be_const_array, LightDiscriminator, LightHasher, }; + use solana_program::account_info::AccountInfo; +use solana_program::msg; /// TODO: write test program with A8JgviaEAByMVLBhcebpDQ7NMuZpqBTBigC1b83imEsd (inconvenient program id) /// CU usage: @@ -17,9 +20,11 @@ pub fn create_pda( accounts: &[AccountInfo], instruction_data: &[u8], ) -> Result<(), LightSdkError> { + msg!("pre instruction_data"); let mut instruction_data = instruction_data; let instruction_data = CreatePdaInstructionData::deserialize(&mut instruction_data) .map_err(|_| LightSdkError::Borsh)?; + msg!("pre config"); let config = CpiAccountsConfig::new(crate::LIGHT_CPI_SIGNER); let cpi_accounts = CpiAccounts::try_new_with_config( &accounts[0], @@ -51,7 +56,7 @@ pub fn create_pda( ) }; let new_address_params = address_tree_info.into_new_address_params_packed(address_seed); - + msg!("pre account"); let mut my_compressed_account = LightAccount::<'_, MyCompressedAccount>::new_init( &crate::ID, Some(address), @@ -69,19 +74,27 @@ pub fn create_pda( Ok(()) } -#[derive( - Clone, Debug, Default, LightHasher, LightDiscriminator, BorshDeserialize, BorshSerialize, -)] +#[derive(Clone, Debug, LightHasher, LightDiscriminator, BorshDeserialize, BorshSerialize)] pub struct MyCompressedAccount { - pub data: [u8; 31], + #[hash] + pub data: [u8; ARRAY_LEN], +} + +impl Default for MyCompressedAccount { + fn default() -> Self { + Self { + data: [0u8; ARRAY_LEN], + } + } } -#[derive(Clone, Debug, Default, BorshDeserialize, BorshSerialize)] +#[derive(Clone, Debug, BorshDeserialize, BorshSerialize)] +#[repr(C)] pub struct CreatePdaInstructionData { pub proof: ValidityProof, pub address_tree_info: PackedAddressTreeInfo, pub output_merkle_tree_index: u8, - pub data: [u8; 31], + pub data: [u8; ARRAY_LEN], pub system_accounts_offset: u8, pub tree_accounts_offset: u8, } diff --git a/sdk-tests/sdk-test/src/lib.rs b/sdk-tests/sdk-test/src/lib.rs index 8fb2b71b2c..098c2acd35 100644 --- a/sdk-tests/sdk-test/src/lib.rs +++ b/sdk-tests/sdk-test/src/lib.rs @@ -7,6 +7,8 @@ use solana_program::{ pub mod create_pda; pub mod update_pda; +pub const ARRAY_LEN: usize = 2200; + pub const ID: Pubkey = pubkey!("FNt7byTHev1k5x2cXZLBr8TdWiC3zoP5vcnZR4P682Uy"); pub const LIGHT_CPI_SIGNER: CpiSigner = derive_light_cpi_signer!("FNt7byTHev1k5x2cXZLBr8TdWiC3zoP5vcnZR4P682Uy"); diff --git a/sdk-tests/sdk-test/src/update_pda.rs b/sdk-tests/sdk-test/src/update_pda.rs index 2e2fcd4257..95d12e4fb7 100644 --- a/sdk-tests/sdk-test/src/update_pda.rs +++ b/sdk-tests/sdk-test/src/update_pda.rs @@ -7,7 +7,7 @@ use light_sdk::{ }; use solana_program::{account_info::AccountInfo, log::sol_log_compute_units}; -use crate::create_pda::MyCompressedAccount; +use crate::{create_pda::MyCompressedAccount, ARRAY_LEN}; /// CU usage: /// - sdk pre system program 9,183k CU @@ -50,16 +50,35 @@ pub fn update_pda( Ok(()) } -#[derive(Clone, Debug, Default, BorshDeserialize, BorshSerialize)] +#[derive(Clone, Debug, BorshDeserialize, BorshSerialize)] pub struct UpdatePdaInstructionData { pub proof: ValidityProof, pub my_compressed_account: UpdateMyCompressedAccount, - pub new_data: [u8; 31], + pub new_data: [u8; ARRAY_LEN], pub system_accounts_offset: u8, } +impl Default for UpdatePdaInstructionData { + fn default() -> Self { + Self { + new_data: [0u8; ARRAY_LEN], + my_compressed_account: UpdateMyCompressedAccount::default(), + system_accounts_offset: 0, + proof: ValidityProof::default(), + } + } +} -#[derive(Clone, Debug, Default, BorshDeserialize, BorshSerialize)] +#[derive(Clone, Debug, BorshDeserialize, BorshSerialize)] pub struct UpdateMyCompressedAccount { pub meta: CompressedAccountMeta, - pub data: [u8; 31], + pub data: [u8; ARRAY_LEN], +} + +impl Default for UpdateMyCompressedAccount { + fn default() -> Self { + Self { + meta: CompressedAccountMeta::default(), + data: [0u8; ARRAY_LEN], + } + } } diff --git a/sdk-tests/sdk-test/tests/test.rs b/sdk-tests/sdk-test/tests/test.rs index 5008995923..0615866a06 100644 --- a/sdk-tests/sdk-test/tests/test.rs +++ b/sdk-tests/sdk-test/tests/test.rs @@ -1,4 +1,4 @@ -#![cfg(feature = "test-sbf")] +//#![cfg(feature = "test-sbf")] use borsh::BorshSerialize; use light_compressed_account::{ @@ -14,6 +14,7 @@ use light_sdk::instruction::{ use sdk_test::{ create_pda::CreatePdaInstructionData, update_pda::{UpdateMyCompressedAccount, UpdatePdaInstructionData}, + ARRAY_LEN, }; use solana_sdk::{ instruction::Instruction, @@ -28,7 +29,7 @@ async fn test_sdk_test() { let payer = rpc.get_payer().insecure_clone(); let address_tree_pubkey = rpc.get_address_merkle_tree_v2(); - let account_data = [1u8; 31]; + let account_data = [1u8; ARRAY_LEN]; // // V1 trees // let (address, _) = light_sdk::address::derive_address( @@ -65,7 +66,7 @@ async fn test_sdk_test() { .clone(); assert_eq!(compressed_pda.address.unwrap(), address); - update_pda(&payer, &mut rpc, [2u8; 31], compressed_pda.into()) + update_pda(&payer, &mut rpc, [2u8; ARRAY_LEN], compressed_pda.into()) .await .unwrap(); } @@ -74,7 +75,7 @@ pub async fn create_pda( payer: &Keypair, rpc: &mut LightProgramTest, merkle_tree_pubkey: &Pubkey, - account_data: [u8; 31], + account_data: [u8; ARRAY_LEN], address_tree_pubkey: Pubkey, address: [u8; 32], ) -> Result<(), RpcError> { @@ -123,7 +124,7 @@ pub async fn create_pda( pub async fn update_pda( payer: &Keypair, rpc: &mut LightProgramTest, - new_account_data: [u8; 31], + new_account_data: [u8; ARRAY_LEN], compressed_account: CompressedAccountWithMerkleContext, ) -> Result<(), RpcError> { let system_account_meta_config = SystemAccountMetaConfig::new(sdk_test::ID); From afe9ccafc1018da0e091c17361062b50e8bd3bd4 Mon Sep 17 00:00:00 2001 From: ananas-block Date: Fri, 15 Aug 2025 18:55:44 +0200 Subject: [PATCH 3/4] chore: update Cargo.lock --- Cargo.lock | 744 +++++++++++++++++++++++++++++------------------------ 1 file changed, 414 insertions(+), 330 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 258c920a4d..dda4686d71 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -150,7 +150,7 @@ version = "1.1.0" dependencies = [ "proc-macro2", "quote", - "syn 2.0.103", + "syn 2.0.105", ] [[package]] @@ -394,9 +394,9 @@ dependencies = [ [[package]] name = "anstream" -version = "0.6.19" +version = "0.6.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "301af1932e46185686725e0fad2f8f2aa7da69dd70bf6ecc44d6b703844a3933" +checksum = "3ae563653d1938f79b1ab1b5e668c87c76a9930414574a6583a7b7e11a8e6192" dependencies = [ "anstyle", "anstyle-parse", @@ -424,29 +424,29 @@ dependencies = [ [[package]] name = "anstyle-query" -version = "1.1.3" +version = "1.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6c8bdeb6047d8983be085bab0ba1472e6dc604e7041dbf6fcd5e71523014fae9" +checksum = "9e231f6134f61b71076a3eab506c379d4f36122f2af15a9ff04415ea4c3339e2" dependencies = [ - "windows-sys 0.59.0", + "windows-sys 0.60.2", ] [[package]] name = "anstyle-wincon" -version = "3.0.9" +version = "3.0.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "403f75924867bb1033c59fbf0797484329750cfbe3c4325cd33127941fabc882" +checksum = "3e0633414522a32ffaac8ac6cc8f748e090c5717661fddeea04219e2344f5f2a" dependencies = [ "anstyle", "once_cell_polyfill", - "windows-sys 0.59.0", + "windows-sys 0.60.2", ] [[package]] name = "anyhow" -version = "1.0.98" +version = "1.0.99" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e16d2d3311acee920a9eb8d33b8cbc1787ce4a264e85f964c2404b969bdcd487" +checksum = "b0674a1ddeecb70197781e945de4b3b8ffb61fa939a5597bcf48503737663100" [[package]] name = "ark-bn254" @@ -500,7 +500,7 @@ dependencies = [ "ark-std 0.5.0", "educe 0.6.0", "fnv", - "hashbrown 0.15.4", + "hashbrown 0.15.5", "itertools 0.13.0", "num-bigint 0.4.6", "num-integer", @@ -565,7 +565,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "62945a2f7e6de02a31fe400aa489f0e0f5b2502e69f95f853adb82a96c7a6b60" dependencies = [ "quote", - "syn 2.0.103", + "syn 2.0.105", ] [[package]] @@ -591,7 +591,7 @@ dependencies = [ "num-traits", "proc-macro2", "quote", - "syn 2.0.103", + "syn 2.0.105", ] [[package]] @@ -619,7 +619,7 @@ dependencies = [ "ark-std 0.5.0", "educe 0.6.0", "fnv", - "hashbrown 0.15.4", + "hashbrown 0.15.5", ] [[package]] @@ -666,7 +666,7 @@ checksum = "213888f660fddcca0d257e88e54ac05bca01885f258ccdf695bafd77031bb69d" dependencies = [ "proc-macro2", "quote", - "syn 2.0.103", + "syn 2.0.105", ] [[package]] @@ -760,9 +760,9 @@ dependencies = [ [[package]] name = "async-compression" -version = "0.4.24" +version = "0.4.27" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d615619615a650c571269c00dca41db04b9210037fa76ed8239f70404ab56985" +checksum = "ddb939d66e4ae03cee6091612804ba446b12878410cfa17f785f4dd67d4014e8" dependencies = [ "brotli", "flate2", @@ -774,11 +774,11 @@ dependencies = [ [[package]] name = "async-lock" -version = "3.4.0" +version = "3.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ff6e472cdea888a4bd64f342f09b3f50e1886d32afe8df3d663c01140b811b18" +checksum = "5fd03604047cee9b6ce9de9f70c6cd540a0520c813cbd49bae61f33ab80ed1dc" dependencies = [ - "event-listener 5.4.0", + "event-listener 5.4.1", "event-listener-strategy", "pin-project-lite", ] @@ -802,18 +802,18 @@ checksum = "c7c24de15d275a1ecfd47a380fb4d5ec9bfe0933f309ed5e705b775596a3574d" dependencies = [ "proc-macro2", "quote", - "syn 2.0.103", + "syn 2.0.105", ] [[package]] name = "async-trait" -version = "0.1.88" +version = "0.1.89" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e539d3fca749fcee5236ab05e93a52867dd549cc157c8cb7f99595f3cedffdb5" +checksum = "9035ad2d096bed7955a320ee7e2230574d28fd3c3a0f186cbea1ff3c7eed5dbb" dependencies = [ "proc-macro2", "quote", - "syn 2.0.103", + "syn 2.0.105", ] [[package]] @@ -835,9 +835,9 @@ dependencies = [ [[package]] name = "autocfg" -version = "1.4.0" +version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ace50bade8e6234aa140d9a2f552bbee1db4d353f69b8217bc503490fc1a9f26" +checksum = "c08606f8c3cbf4ce6ec8e28fb0014a2c086708fe954eaa885384a6165172e7e8" [[package]] name = "backtrace" @@ -1001,7 +1001,7 @@ dependencies = [ "proc-macro-crate 3.3.0", "proc-macro2", "quote", - "syn 2.0.103", + "syn 2.0.105", ] [[package]] @@ -1058,9 +1058,9 @@ dependencies = [ [[package]] name = "bumpalo" -version = "3.18.1" +version = "3.19.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "793db76d6187cd04dff33004d8e6c9cc4e05cd330500379d2394209271b4aeee" +checksum = "46c5e41b57b8bba42a04676d81cb89e9ee8e859a1a66f80a5a72e1cb76b34d43" [[package]] name = "bv" @@ -1080,22 +1080,22 @@ checksum = "175812e0be2bccb6abe50bb8d566126198344f707e304f45c648fd8f2cc0365e" [[package]] name = "bytemuck" -version = "1.23.1" +version = "1.23.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5c76a5792e44e4abe34d3abf15636779261d45a7450612059293d1d2cfc63422" +checksum = "3995eaeebcdf32f91f980d360f78732ddc061097ab4e39991ae7a6ace9194677" dependencies = [ "bytemuck_derive", ] [[package]] name = "bytemuck_derive" -version = "1.9.3" +version = "1.10.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7ecc273b49b3205b83d648f0690daa588925572cc5063745bfe547fe7ec8e1a1" +checksum = "4f154e572231cb6ba2bd1176980827e3d5dc04cc183a75dea38109fbdd672d29" dependencies = [ "proc-macro2", "quote", - "syn 2.0.103", + "syn 2.0.105", ] [[package]] @@ -1132,9 +1132,9 @@ dependencies = [ [[package]] name = "cc" -version = "1.2.27" +version = "1.2.32" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d487aa071b5f64da6f19a3e848e3578944b726ee5a4854b82172f02aa876bfdc" +checksum = "2352e5597e9c544d5e6d9c95190d5d27738ade584fa8db0a16e130e5c2b5296e" dependencies = [ "jobserver", "libc", @@ -1167,7 +1167,7 @@ checksum = "45565fc9416b9896014f5732ac776f810ee53a66730c17e4020c3ec064a8f88f" dependencies = [ "proc-macro2", "quote", - "syn 2.0.103", + "syn 2.0.105", ] [[package]] @@ -1212,9 +1212,9 @@ dependencies = [ [[package]] name = "clap" -version = "4.5.40" +version = "4.5.45" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "40b6887a1d8685cebccf115538db5c0efe625ccac9696ad45c409d96566e910f" +checksum = "1fc0e74a703892159f5ae7d3aac52c8e6c392f5ae5f359c70b5881d60aaac318" dependencies = [ "clap_builder", "clap_derive", @@ -1222,9 +1222,9 @@ dependencies = [ [[package]] name = "clap_builder" -version = "4.5.40" +version = "4.5.44" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e0c66c08ce9f0c698cbce5c0279d0bb6ac936d8674174fe48f736533b964f59e" +checksum = "b3e7f4214277f3c7aa526a59dd3fbe306a370daee1f8b7b8c987069cd8e888a8" dependencies = [ "anstream", "anstyle", @@ -1234,14 +1234,14 @@ dependencies = [ [[package]] name = "clap_derive" -version = "4.5.40" +version = "4.5.45" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d2c7947ae4cc3d851207c1adb5b5e260ff0cca11446b1d6d1423788e442257ce" +checksum = "14cb31bb0a7d536caef2639baa7fad459e15c3144efefa6dbd1c84562c4739f6" dependencies = [ "heck 0.5.0", "proc-macro2", "quote", - "syn 2.0.103", + "syn 2.0.105", ] [[package]] @@ -1434,9 +1434,9 @@ dependencies = [ [[package]] name = "crc32fast" -version = "1.4.2" +version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a97769d94ddab943e4510d138150169a2758b5ef3eb191a9ee688de3e23ef7b3" +checksum = "9481c1c90cbf2ac953f07c8d4a58aa3945c425b7185c9154d67a65e4230da511" dependencies = [ "cfg-if", ] @@ -1490,9 +1490,9 @@ checksum = "d0a5c400df2834b80a4c3327b3aad3a4c4cd4de0629063962b03235697506a28" [[package]] name = "crunchy" -version = "0.2.3" +version = "0.2.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "43da5946c66ffcc7745f48db692ffbb10a83bfe0afd96235c5c2a4fb23994929" +checksum = "460fbee9c2c2f33933d720630a6a0bac33ba7053db5344fac858d4b8952d77d5" [[package]] name = "crypto-common" @@ -1563,7 +1563,7 @@ checksum = "f46882e17999c6cc590af592290432be3bce0428cb0d5f8b6715e4dc7b383eb3" dependencies = [ "proc-macro2", "quote", - "syn 2.0.103", + "syn 2.0.105", ] [[package]] @@ -1587,7 +1587,7 @@ dependencies = [ "proc-macro2", "quote", "strsim 0.11.1", - "syn 2.0.103", + "syn 2.0.105", ] [[package]] @@ -1598,7 +1598,7 @@ checksum = "fc34b93ccb385b40dc71c6fceac4b2ad23662c7eeb248cf10d529b7e055b6ead" dependencies = [ "darling_core", "quote", - "syn 2.0.103", + "syn 2.0.105", ] [[package]] @@ -1734,7 +1734,7 @@ checksum = "e01a3366d27ee9890022452ee61b2b63a67e6f13f58900b651ff5665f0bb1fab" dependencies = [ "libc", "option-ext", - "redox_users 0.5.0", + "redox_users 0.5.2", "windows-sys 0.60.2", ] @@ -1757,7 +1757,7 @@ checksum = "97369cbbc041bc366949bc74d34658d6cda5621039731c6310521892a3a20ae0" dependencies = [ "proc-macro2", "quote", - "syn 2.0.103", + "syn 2.0.105", ] [[package]] @@ -1780,7 +1780,7 @@ checksum = "a6cbae11b3de8fce2a456e8ea3dada226b35fe791f0dc1d360c0941f0bb681f3" dependencies = [ "proc-macro2", "quote", - "syn 2.0.103", + "syn 2.0.105", ] [[package]] @@ -1791,9 +1791,9 @@ checksum = "1aaf95b3e5c8f23aa320147307562d361db0ae0d51242340f558153b4eb2439b" [[package]] name = "dyn-clone" -version = "1.0.19" +version = "1.0.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1c7a8fb8a9fbf66c1f703fe16184d10ca0ee9d23be5b4436400408ba54a95005" +checksum = "d0881ea181b1df73ff77ffaaf9c7544ecc11e82fba9b5f27b262a3c73a332555" [[package]] name = "e2e-test" @@ -1872,7 +1872,7 @@ dependencies = [ "enum-ordinalize 4.3.0", "proc-macro2", "quote", - "syn 2.0.103", + "syn 2.0.105", ] [[package]] @@ -1913,7 +1913,7 @@ checksum = "a1ab991c1362ac86c61ab6f556cff143daa22e5a15e4e189df818b2fd19fe65b" dependencies = [ "proc-macro2", "quote", - "syn 2.0.103", + "syn 2.0.105", ] [[package]] @@ -1926,7 +1926,7 @@ dependencies = [ "num-traits", "proc-macro2", "quote", - "syn 2.0.103", + "syn 2.0.105", ] [[package]] @@ -1946,7 +1946,7 @@ checksum = "0d28318a75d4aead5c4db25382e8ef717932d0346600cacae6357eb5941bc5ff" dependencies = [ "proc-macro2", "quote", - "syn 2.0.103", + "syn 2.0.105", ] [[package]] @@ -1993,12 +1993,12 @@ checksum = "877a4ace8713b0bcf2a4e7eec82529c029f1d0619886d18145fea96c3ffe5c0f" [[package]] name = "errno" -version = "0.3.12" +version = "0.3.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cea14ef9355e3beab063703aa9dab15afd25f0667c341310c1e5274bb1d0da18" +checksum = "778e2ac28f6c47af28e4907f13ffd1e1ddbd400980a9abd7c8df189bf578a5ad" dependencies = [ "libc", - "windows-sys 0.59.0", + "windows-sys 0.60.2", ] [[package]] @@ -2009,9 +2009,9 @@ checksum = "0206175f82b8d6bf6652ff7d71a1e27fd2e4efde587fd368662814d6ec1d9ce0" [[package]] name = "event-listener" -version = "5.4.0" +version = "5.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3492acde4c3fc54c845eaab3eed8bd00c7a7d881f78bfc801e43a93dec1331ae" +checksum = "e13b66accf52311f30a0db42147dadea9850cb48cd070028831ae5f5d4b856ab" dependencies = [ "concurrent-queue", "parking", @@ -2024,7 +2024,7 @@ version = "0.5.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8be9f3dfaaffdae2972880079a491a1a8bb7cbed0b8dd7a347f668b4150a3b93" dependencies = [ - "event-listener 5.4.0", + "event-listener 5.4.1", "pin-project-lite", ] @@ -2035,7 +2035,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "27cea6e7f512d43b098939ff4d5a5d6fe3db07971e1d05176fe26c642d33f5b8" dependencies = [ "getrandom 0.3.3", - "rand 0.9.1", + "rand 0.9.2", "siphasher 1.0.1", "wide", ] @@ -2116,7 +2116,7 @@ dependencies = [ "bb8", "borsh 0.10.4", "bs58", - "clap 4.5.40", + "clap 4.5.45", "create-address-test-program", "dashmap 6.1.0", "dotenvy", @@ -2143,7 +2143,7 @@ dependencies = [ "photon-api", "prometheus", "rand 0.8.5", - "reqwest 0.12.20", + "reqwest 0.12.23", "scopeguard", "serde", "serde_json", @@ -2153,7 +2153,7 @@ dependencies = [ "solana-program", "solana-sdk", "solana-transaction-status", - "thiserror 2.0.12", + "thiserror 2.0.14", "tokio", "tracing", "tracing-appender", @@ -2189,11 +2189,11 @@ dependencies = [ "num-bigint 0.4.6", "num-traits", "rand 0.8.5", - "reqwest 0.12.20", + "reqwest 0.12.23", "serde", "serde_json", "solana-sdk", - "thiserror 2.0.12", + "thiserror 2.0.14", "tokio", "tracing", ] @@ -2269,7 +2269,7 @@ checksum = "162ee34ebcb7c64a8abebc059ce0fee27c2262618d7b60ed8faf72fef13c3650" dependencies = [ "proc-macro2", "quote", - "syn 2.0.103", + "syn 2.0.105", ] [[package]] @@ -2376,9 +2376,9 @@ checksum = "07e28edb80900c19c28f1072f2e8aeca7fa06b23cd4169cefe1af5aa3260783f" [[package]] name = "glob" -version = "0.3.2" +version = "0.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a8d1add55171497b4705a648c6b583acafb01d58050a51727785f0b2c8e0a2b2" +checksum = "0cc23270f6e1808e30a928bdc84dea0b9b4136a8bc82338574f23baf47bbd280" [[package]] name = "governor" @@ -2417,7 +2417,7 @@ dependencies = [ "parking_lot", "portable-atomic", "quanta", - "rand 0.9.1", + "rand 0.9.2", "smallvec", "spinning_top", "web-time", @@ -2440,9 +2440,9 @@ dependencies = [ [[package]] name = "h2" -version = "0.3.26" +version = "0.3.27" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "81fe527a889e1532da5c525686d96d4c2e74cdd345badf8dfef9f6b39dd5f5e8" +checksum = "0beca50380b1fc32983fc1cb4587bfa4bb9e78fc259aad4a0032d2080309222d" dependencies = [ "bytes", "fnv", @@ -2450,18 +2450,18 @@ dependencies = [ "futures-sink", "futures-util", "http 0.2.12", - "indexmap 2.9.0", + "indexmap 2.10.0", "slab", "tokio", - "tokio-util 0.7.15", + "tokio-util 0.7.16", "tracing", ] [[package]] name = "h2" -version = "0.4.10" +version = "0.4.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a9421a676d1b147b16b82c9225157dc629087ef8ec4d5e2960f9437a90dac0a5" +checksum = "f3c0b69cfcb4e1b9f1bf2f53f95f766e4661169728ec61cd3fe5a0166f2d1386" dependencies = [ "atomic-waker", "bytes", @@ -2469,10 +2469,10 @@ dependencies = [ "futures-core", "futures-sink", "http 1.3.1", - "indexmap 2.9.0", + "indexmap 2.10.0", "slab", "tokio", - "tokio-util 0.7.15", + "tokio-util 0.7.16", "tracing", ] @@ -2508,9 +2508,9 @@ checksum = "e5274423e17b7c9fc20b6e7e208532f9b19825d82dfd615708b70edd83df41f1" [[package]] name = "hashbrown" -version = "0.15.4" +version = "0.15.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5971ac85611da7067dbfcabef3c70ebb5606018acd9e2a3903a0da507521e0d5" +checksum = "9229cfe53dfd69f0609a49f65461bd93001ea1ef889cd5529dd176593f5338a1" dependencies = [ "allocator-api2", ] @@ -2708,14 +2708,14 @@ dependencies = [ "futures-channel", "futures-core", "futures-util", - "h2 0.3.26", + "h2 0.3.27", "http 0.2.12", "http-body 0.4.6", "httparse", "httpdate", "itoa", "pin-project-lite", - "socket2", + "socket2 0.5.10", "tokio", "tower-service", "tracing", @@ -2731,7 +2731,7 @@ dependencies = [ "bytes", "futures-channel", "futures-util", - "h2 0.4.10", + "h2 0.4.12", "http 1.3.1", "http-body 1.0.1", "httparse", @@ -2765,12 +2765,12 @@ dependencies = [ "http 1.3.1", "hyper 1.6.0", "hyper-util", - "rustls 0.23.27", + "rustls 0.23.31", "rustls-pki-types", "tokio", "tokio-rustls 0.26.2", "tower-service", - "webpki-roots 1.0.0", + "webpki-roots 1.0.2", ] [[package]] @@ -2804,9 +2804,9 @@ dependencies = [ [[package]] name = "hyper-util" -version = "0.1.14" +version = "0.1.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dc2fdfdbff08affe55bb779f33b053aa1fe5dd5b54c257343c17edfa55711bdb" +checksum = "8d9b05277c7e8da2c93a568989bb6207bef0112e8d17df7a6eda4a3cf143bc5e" dependencies = [ "base64 0.22.1", "bytes", @@ -2820,7 +2820,7 @@ dependencies = [ "libc", "percent-encoding", "pin-project-lite", - "socket2", + "socket2 0.6.0", "system-configuration 0.6.1", "tokio", "tower-service", @@ -2978,12 +2978,12 @@ dependencies = [ [[package]] name = "indexmap" -version = "2.9.0" +version = "2.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cea70ddb795996207ad57735b50c5982d8844f38ba9ee5f1aedcfb708a2aa11e" +checksum = "fe4cd85333e22411419a0bcae1297d25e58c9443848b11dc6a86fefe8c78a661" dependencies = [ "equivalent", - "hashbrown 0.15.4", + "hashbrown 0.15.5", "serde", ] @@ -3009,6 +3009,17 @@ dependencies = [ "generic-array", ] +[[package]] +name = "io-uring" +version = "0.7.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d93587f37623a1a17d94ef2bc9ada592f5465fe7732084ab7beefabe5c77c0c4" +dependencies = [ + "bitflags 2.9.1", + "cfg-if", + "libc", +] + [[package]] name = "ipnet" version = "2.11.0" @@ -3094,7 +3105,7 @@ checksum = "03343451ff899767262ec32146f6d559dd759fdadf42ff0e227c7c48f72594b4" dependencies = [ "proc-macro2", "quote", - "syn 2.0.103", + "syn 2.0.105", ] [[package]] @@ -3171,15 +3182,15 @@ checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe" [[package]] name = "libc" -version = "0.2.173" +version = "0.2.175" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d8cfeafaffdbc32176b64fb251369d52ea9f0a8fbc6f8759edffef7b525d64bb" +checksum = "6a82ae493e598baaea5209805c49bbf2ea7de956d50d7da0da1164f9c6d28543" [[package]] name = "libredox" -version = "0.1.3" +version = "0.1.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c0ff37bd590ca25063e35af745c343cb7a0271906fb7b37e4813e8f79f00268d" +checksum = "391290121bad3d37fbddad76d8f5d1c1c314cfc646d143d7e07a3086ddff0ce3" dependencies = [ "bitflags 2.9.1", "libc", @@ -3244,7 +3255,7 @@ dependencies = [ "solana-program-error", "solana-pubkey", "solana-sysvar", - "thiserror 2.0.12", + "thiserror 2.0.14", ] [[package]] @@ -3272,7 +3283,7 @@ dependencies = [ "solana-program-error", "solana-pubkey", "solana-sysvar", - "thiserror 2.0.12", + "thiserror 2.0.14", "tokio", "zerocopy", ] @@ -3288,7 +3299,7 @@ dependencies = [ "rand 0.8.5", "solana-nostd-keccak", "solana-program-error", - "thiserror 2.0.12", + "thiserror 2.0.14", ] [[package]] @@ -3343,7 +3354,7 @@ dependencies = [ "solana-transaction", "solana-transaction-error", "solana-transaction-status-client-types", - "thiserror 2.0.12", + "thiserror 2.0.14", "tokio", "tracing", ] @@ -3366,7 +3377,7 @@ dependencies = [ "rand 0.8.5", "solana-program-error", "solana-pubkey", - "thiserror 2.0.12", + "thiserror 2.0.14", "zerocopy", ] @@ -3408,7 +3419,7 @@ dependencies = [ "pinocchio", "rand 0.8.5", "solana-program-error", - "thiserror 2.0.12", + "thiserror 2.0.14", "tokio", ] @@ -3423,7 +3434,7 @@ dependencies = [ "num-traits", "rand 0.8.5", "solana-program-error", - "thiserror 2.0.12", + "thiserror 2.0.14", ] [[package]] @@ -3443,7 +3454,7 @@ dependencies = [ "solana-nostd-keccak", "solana-program-error", "solana-pubkey", - "thiserror 2.0.12", + "thiserror 2.0.14", ] [[package]] @@ -3461,7 +3472,7 @@ dependencies = [ "num-bigint 0.4.6", "num-traits", "rand 0.8.5", - "thiserror 2.0.12", + "thiserror 2.0.14", ] [[package]] @@ -3478,7 +3489,7 @@ dependencies = [ "pinocchio", "rand 0.8.5", "solana-program-error", - "thiserror 2.0.12", + "thiserror 2.0.14", ] [[package]] @@ -3488,7 +3499,7 @@ dependencies = [ "bs58", "proc-macro2", "quote", - "syn 2.0.103", + "syn 2.0.105", ] [[package]] @@ -3503,7 +3514,7 @@ dependencies = [ "solana-msg", "solana-program-error", "solana-sysvar", - "thiserror 2.0.12", + "thiserror 2.0.14", "zerocopy", ] @@ -3516,7 +3527,7 @@ dependencies = [ "num-bigint 0.4.6", "num-traits", "rand 0.8.5", - "thiserror 2.0.12", + "thiserror 2.0.14", ] [[package]] @@ -3571,7 +3582,7 @@ dependencies = [ "num-traits", "photon-api", "rand 0.8.5", - "reqwest 0.12.20", + "reqwest 0.12.23", "solana-account", "solana-banks-client", "solana-compute-budget", @@ -3604,7 +3615,7 @@ dependencies = [ "serde_json", "serial_test", "solana-bn254", - "thiserror 2.0.12", + "thiserror 2.0.14", "tokio", "tracing", ] @@ -3643,7 +3654,7 @@ dependencies = [ "solana-msg", "solana-program-error", "solana-pubkey", - "thiserror 2.0.12", + "thiserror 2.0.14", ] [[package]] @@ -3660,7 +3671,7 @@ dependencies = [ "proc-macro2", "quote", "solana-pubkey", - "syn 2.0.103", + "syn 2.0.105", ] [[package]] @@ -3677,7 +3688,7 @@ dependencies = [ "light-zero-copy", "pinocchio", "solana-pubkey", - "thiserror 2.0.12", + "thiserror 2.0.14", ] [[package]] @@ -3693,7 +3704,7 @@ dependencies = [ "light-zero-copy", "solana-msg", "solana-pubkey", - "thiserror 2.0.12", + "thiserror 2.0.14", ] [[package]] @@ -3706,7 +3717,7 @@ dependencies = [ "num-bigint 0.4.6", "num-traits", "rand 0.8.5", - "thiserror 2.0.12", + "thiserror 2.0.14", ] [[package]] @@ -3743,7 +3754,7 @@ dependencies = [ "rand 0.8.5", "solana-pubkey", "solana-security-txt", - "thiserror 2.0.12", + "thiserror 2.0.14", "zerocopy", ] @@ -3777,12 +3788,12 @@ dependencies = [ "num-bigint 0.4.6", "num-traits", "rand 0.8.5", - "reqwest 0.12.20", + "reqwest 0.12.23", "solana-banks-client", "solana-sdk", "spl-token", "spl-token-2022 7.0.0", - "thiserror 2.0.12", + "thiserror 2.0.14", ] [[package]] @@ -3794,7 +3805,7 @@ dependencies = [ "pinocchio", "solana-msg", "solana-program-error", - "thiserror 2.0.12", + "thiserror 2.0.14", ] [[package]] @@ -3819,7 +3830,7 @@ dependencies = [ "proc-macro2", "quote", "rand 0.8.5", - "syn 2.0.103", + "syn 2.0.105", "trybuild", "zerocopy", ] @@ -3844,7 +3855,7 @@ checksum = "bb7e5f4462f34439adcfcab58099bc7a89c67a17f8240b84a993b8b705c1becb" dependencies = [ "ansi_term", "bincode", - "indexmap 2.9.0", + "indexmap 2.10.0", "itertools 0.14.0", "log", "solana-account", @@ -3896,7 +3907,7 @@ dependencies = [ "solana-transaction-context", "solana-transaction-error", "solana-vote-program", - "thiserror 2.0.12", + "thiserror 2.0.14", ] [[package]] @@ -4149,7 +4160,7 @@ checksum = "ed3955f1a9c7c0c15e092f9c887db08b1fc683305fdf6eb6684f22555355e202" dependencies = [ "proc-macro2", "quote", - "syn 2.0.103", + "syn 2.0.105", ] [[package]] @@ -4205,23 +4216,24 @@ dependencies = [ [[package]] name = "num_enum" -version = "0.7.3" +version = "0.7.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4e613fc340b2220f734a8595782c551f1250e969d87d3be1ae0579e8d4065179" +checksum = "a973b4e44ce6cad84ce69d797acf9a044532e4184c4f267913d1b546a0727b7a" dependencies = [ "num_enum_derive", + "rustversion", ] [[package]] name = "num_enum_derive" -version = "0.7.3" +version = "0.7.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "af1844ef2428cc3e1cb900be36181049ef3d3193c63e43026cfe202983b27a56" +checksum = "77e878c846a8abae00dd069496dbe8751b16ac1c3d6bd2a7283a938e8228f90d" dependencies = [ "proc-macro-crate 3.3.0", "proc-macro2", "quote", - "syn 2.0.103", + "syn 2.0.105", ] [[package]] @@ -4289,7 +4301,7 @@ checksum = "a948666b637a0f465e8564c73e89d4dde00d72d4d473cc972f390fc3dcee7d9c" dependencies = [ "proc-macro2", "quote", - "syn 2.0.103", + "syn 2.0.105", ] [[package]] @@ -4433,7 +4445,7 @@ dependencies = [ name = "photon-api" version = "0.51.0" dependencies = [ - "reqwest 0.12.20", + "reqwest 0.12.23", "serde", "serde_derive", "serde_json", @@ -4459,7 +4471,7 @@ checksum = "6e918e4ff8c4549eb882f14b3a4bc8c8bc93de829416eacf579f1207a8fbf861" dependencies = [ "proc-macro2", "quote", - "syn 2.0.103", + "syn 2.0.105", ] [[package]] @@ -4565,12 +4577,12 @@ checksum = "c6fa0831dd7cc608c38a5e323422a0077678fa5744aa2be4ad91c4ece8eec8d5" [[package]] name = "prettyplease" -version = "0.2.34" +version = "0.2.36" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6837b9e10d61f45f987d50808f83d1ee3d206c66acf650c3e4ae2e1f6ddedf55" +checksum = "ff24dfcda44452b9816fff4cd4227e1bb73ff5a2f1bc1105aa92fb8565ce44d2" dependencies = [ "proc-macro2", - "syn 2.0.103", + "syn 2.0.105", ] [[package]] @@ -4610,14 +4622,14 @@ dependencies = [ "proc-macro-error-attr2", "proc-macro2", "quote", - "syn 2.0.103", + "syn 2.0.105", ] [[package]] name = "proc-macro2" -version = "1.0.95" +version = "1.0.97" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "02b3e5e68a3a1a02aad3ec490a98007cbc13c37cbe84a3cd7b8e406d76e7f778" +checksum = "d61789d7719defeb74ea5fe81f2fdfdbd28a803847077cecce2ff14e1472f6f1" dependencies = [ "unicode-ident", ] @@ -4660,7 +4672,7 @@ checksum = "9e2e25ee72f5b24d773cae88422baddefff7714f97aab68d96fe2b6fc4a28fb2" dependencies = [ "proc-macro2", "quote", - "syn 2.0.103", + "syn 2.0.105", ] [[package]] @@ -4690,9 +4702,9 @@ dependencies = [ "quinn-proto", "quinn-udp", "rustc-hash 2.1.1", - "rustls 0.23.27", - "socket2", - "thiserror 2.0.12", + "rustls 0.23.31", + "socket2 0.5.10", + "thiserror 2.0.14", "tokio", "tracing", "web-time", @@ -4708,14 +4720,14 @@ dependencies = [ "fastbloom", "getrandom 0.3.3", "lru-slab", - "rand 0.9.1", + "rand 0.9.2", "ring", "rustc-hash 2.1.1", - "rustls 0.23.27", + "rustls 0.23.31", "rustls-pki-types", "rustls-platform-verifier", "slab", - "thiserror 2.0.12", + "thiserror 2.0.14", "tinyvec", "tracing", "web-time", @@ -4723,14 +4735,14 @@ dependencies = [ [[package]] name = "quinn-udp" -version = "0.5.12" +version = "0.5.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ee4e529991f949c5e25755532370b8af5d114acae52326361d68d47af64aa842" +checksum = "fcebb1209ee276352ef14ff8732e24cc2b02bbac986cd74a4c81bcb2f9881970" dependencies = [ "cfg_aliases", "libc", "once_cell", - "socket2", + "socket2 0.5.10", "tracing", "windows-sys 0.59.0", ] @@ -4746,9 +4758,9 @@ dependencies = [ [[package]] name = "r-efi" -version = "5.2.0" +version = "5.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "74765f6d916ee2faa39bc8e68e4f3ed8949b48cccdac59983d287a7cb71ce9c5" +checksum = "69cdb34c158ceb288df11e18b4bd39de994f6657d83847bdffdbd7f346754b0f" [[package]] name = "radium" @@ -4782,9 +4794,9 @@ dependencies = [ [[package]] name = "rand" -version = "0.9.1" +version = "0.9.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9fbfd9d094a40bf3ae768db9361049ace4c0e04a4fd6b359518bd7b73a73dd97" +checksum = "6db2770f06117d490610c7488547d543617b21bfa07796d7a12f6f1bd53850d1" dependencies = [ "rand_chacha 0.9.0", "rand_core 0.9.3", @@ -4867,9 +4879,9 @@ dependencies = [ [[package]] name = "rayon" -version = "1.10.0" +version = "1.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b418a60154510ca1a002a752ca9714984e21e4241e804d32555251faf8b78ffa" +checksum = "368f01d005bf8fd9b1206fb6fa653e6c4a81ceb1466406b81792d87c5677a58f" dependencies = [ "either", "rayon-core", @@ -4877,9 +4889,9 @@ dependencies = [ [[package]] name = "rayon-core" -version = "1.12.1" +version = "1.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1465873a3dfdaa8ae7cb14b4383657caab0b3e8a0aa9ae8e04b044854c8dfce2" +checksum = "22e18b0f0062d30d4230b2e85ff77fdfe4326feb054b9783a3460d8435c8ab91" dependencies = [ "crossbeam-deque", "crossbeam-utils", @@ -4887,9 +4899,9 @@ dependencies = [ [[package]] name = "redox_syscall" -version = "0.5.13" +version = "0.5.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0d04b7d0ee6b4a0207a0a7adb104d23ecb0b47d6beae7152d0fa34b692b29fd6" +checksum = "5407465600fb0548f1442edf71dd20683c6ed326200ace4b1ef0763521bb3b77" dependencies = [ "bitflags 2.9.1", ] @@ -4907,13 +4919,13 @@ dependencies = [ [[package]] name = "redox_users" -version = "0.5.0" +version = "0.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dd6f9d3d47bdd2ad6945c5015a226ec6155d0bcdfd8f7cd29f86b71f8de99d2b" +checksum = "a4e608c6638b9c18977b00b475ac1f28d14e84b27d8d42f70e0bf1e3dec127ac" dependencies = [ "getrandom 0.2.16", "libredox", - "thiserror 2.0.12", + "thiserror 2.0.14", ] [[package]] @@ -4933,7 +4945,7 @@ checksum = "1165225c21bff1f3bbce98f5a1f889949bc902d3575308cc7b0de30b4f6d27c7" dependencies = [ "proc-macro2", "quote", - "syn 2.0.103", + "syn 2.0.105", ] [[package]] @@ -5013,7 +5025,7 @@ dependencies = [ "encoding_rs", "futures-core", "futures-util", - "h2 0.3.26", + "h2 0.3.27", "http 0.2.12", "http-body 0.4.6", "hyper 0.14.32", @@ -5038,7 +5050,7 @@ dependencies = [ "tokio", "tokio-native-tls", "tokio-rustls 0.24.1", - "tokio-util 0.7.15", + "tokio-util 0.7.16", "tower-service", "url", "wasm-bindgen", @@ -5050,9 +5062,9 @@ dependencies = [ [[package]] name = "reqwest" -version = "0.12.20" +version = "0.12.23" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eabf4c97d9130e2bf606614eb937e86edac8292eaa6f422f995d7e8de1eb1813" +checksum = "d429f34c8092b2d42c7c93cec323bb4adeb7c67698f70839adec842ec10c7ceb" dependencies = [ "base64 0.22.1", "bytes", @@ -5060,7 +5072,7 @@ dependencies = [ "futures-channel", "futures-core", "futures-util", - "h2 0.4.10", + "h2 0.4.12", "http 1.3.1", "http-body 1.0.1", "http-body-util", @@ -5076,7 +5088,7 @@ dependencies = [ "percent-encoding", "pin-project-lite", "quinn", - "rustls 0.23.27", + "rustls 0.23.31", "rustls-pki-types", "serde", "serde_json", @@ -5092,7 +5104,7 @@ dependencies = [ "wasm-bindgen", "wasm-bindgen-futures", "web-sys", - "webpki-roots 1.0.0", + "webpki-roots 1.0.2", ] [[package]] @@ -5147,9 +5159,9 @@ dependencies = [ [[package]] name = "rustc-demangle" -version = "0.1.25" +version = "0.1.26" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "989e6739f80c4ad5b13e0fd7fe89531180375b18520cc8c82080e4dc4035b84f" +checksum = "56f7d92ca342cea22a06f2121d944b4fd82af56988c270852495420f961d4ace" [[package]] name = "rustc-hash" @@ -5183,15 +5195,15 @@ dependencies = [ [[package]] name = "rustix" -version = "1.0.7" +version = "1.0.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c71e83d6afe7ff64890ec6b71d6a69bb8a610ab78ce364b3352876bb4c801266" +checksum = "11181fbabf243db407ef8df94a6ce0b2f9a733bd8be4ad02b4eda9602296cac8" dependencies = [ "bitflags 2.9.1", "errno", "libc", "linux-raw-sys", - "windows-sys 0.59.0", + "windows-sys 0.60.2", ] [[package]] @@ -5208,14 +5220,14 @@ dependencies = [ [[package]] name = "rustls" -version = "0.23.27" +version = "0.23.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "730944ca083c1c233a75c09f199e973ca499344a2b7ba9e755c457e86fb4a321" +checksum = "c0ebcbd2f03de0fc1122ad9bb24b127a5a6cd51d72604a3f3c50ac459762b6cc" dependencies = [ "once_cell", "ring", "rustls-pki-types", - "rustls-webpki 0.103.3", + "rustls-webpki 0.103.4", "subtle", "zeroize", ] @@ -5229,7 +5241,7 @@ dependencies = [ "openssl-probe", "rustls-pki-types", "schannel", - "security-framework 3.2.0", + "security-framework 3.3.0", ] [[package]] @@ -5262,11 +5274,11 @@ dependencies = [ "jni", "log", "once_cell", - "rustls 0.23.27", + "rustls 0.23.31", "rustls-native-certs", "rustls-platform-verifier-android", - "rustls-webpki 0.103.3", - "security-framework 3.2.0", + "rustls-webpki 0.103.4", + "security-framework 3.3.0", "security-framework-sys", "webpki-root-certs 0.26.11", "windows-sys 0.59.0", @@ -5290,9 +5302,9 @@ dependencies = [ [[package]] name = "rustls-webpki" -version = "0.103.3" +version = "0.103.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e4a72fe2bcf7a6ac6fd7d0b9e5cb68aeb7d4c0a0271730218b3e92d43b4eb435" +checksum = "0a17884ae0c1b773f1ccd2bd4a8c72f16da897310a98b0e84bf349ad5ead92fc" dependencies = [ "ring", "rustls-pki-types", @@ -5301,9 +5313,9 @@ dependencies = [ [[package]] name = "rustversion" -version = "1.0.21" +version = "1.0.22" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8a0d197bd2c9dc6e53b84da9556a69ba4cdfab8619eb41a8bd1cc2027a0f6b1d" +checksum = "b39cdef0fa800fc44525c84ccb54a029961a8215f9619753635a9c0d2538d46d" [[package]] name = "ryu" @@ -5359,6 +5371,18 @@ dependencies = [ "serde_json", ] +[[package]] +name = "schemars" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "82d20c4491bc164fa2f6c5d44565947a52ad80b9505d8e36f8d54c27c739fcd0" +dependencies = [ + "dyn-clone", + "ref-cast", + "serde", + "serde_json", +] + [[package]] name = "scoped-tls" version = "1.0.1" @@ -5383,9 +5407,9 @@ dependencies = [ [[package]] name = "sdd" -version = "3.0.8" +version = "3.0.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "584e070911c7017da6cb2eb0788d09f43d789029b5877d3e5ecc8acf86ceee21" +checksum = "490dcfcbfef26be6800d11870ff2df8774fa6e86d047e3e8c8a76b25655e41ca" [[package]] name = "sdk-anchor-test" @@ -5432,6 +5456,7 @@ dependencies = [ "light-program-test", "light-sdk", "light-sdk-types", + "light-zero-copy", "solana-program", "solana-sdk", "tokio", @@ -5452,9 +5477,9 @@ dependencies = [ [[package]] name = "security-framework" -version = "3.2.0" +version = "3.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "271720403f46ca04f7ba6f55d438f8bd878d6b8ca0a1046e8228c4145bcbb316" +checksum = "80fb1d92c5028aa318b4b8bd7302a5bfcf48be96a37fc6fc790f806b0004ee0c" dependencies = [ "bitflags 2.9.1", "core-foundation 0.10.1", @@ -5514,14 +5539,14 @@ checksum = "5b0276cf7f2c73365f7157c8123c21cd9a50fbbd844757af28ca1f5925fc2a00" dependencies = [ "proc-macro2", "quote", - "syn 2.0.103", + "syn 2.0.105", ] [[package]] name = "serde_json" -version = "1.0.140" +version = "1.0.142" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "20068b6e96dc6c9bd23e01df8827e6c7e1f2fddd43c21810382803c136b99373" +checksum = "030fedb782600dcbd6f02d479bf0d817ac3bb40d644745b769d6a96bc3afc5a7" dependencies = [ "itoa", "memchr", @@ -5538,6 +5563,15 @@ dependencies = [ "serde", ] +[[package]] +name = "serde_spanned" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "40734c41988f7306bb04f0ecf60ec0f3f1caa34290e4e8ea471dcd3346483b83" +dependencies = [ + "serde", +] + [[package]] name = "serde_urlencoded" version = "0.7.1" @@ -5552,16 +5586,17 @@ dependencies = [ [[package]] name = "serde_with" -version = "3.13.0" +version = "3.14.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bf65a400f8f66fb7b0552869ad70157166676db75ed8181f8104ea91cf9d0b42" +checksum = "f2c45cd61fefa9db6f254525d46e392b852e0e61d9a1fd36e5bd183450a556d5" dependencies = [ "base64 0.22.1", "chrono", "hex", "indexmap 1.9.3", - "indexmap 2.9.0", - "schemars", + "indexmap 2.10.0", + "schemars 0.9.0", + "schemars 1.0.4", "serde", "serde_derive", "serde_json", @@ -5571,14 +5606,14 @@ dependencies = [ [[package]] name = "serde_with_macros" -version = "3.13.0" +version = "3.14.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "81679d9ed988d5e9a5e6531dc3f2c28efbd639cbd1dfb628df08edea6004da77" +checksum = "de90945e6565ce0d9a25098082ed4ee4002e047cb59892c318d66821e14bb30f" dependencies = [ "darling", "proc-macro2", "quote", - "syn 2.0.103", + "syn 2.0.105", ] [[package]] @@ -5587,7 +5622,7 @@ version = "0.9.34+deprecated" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6a8b1a1a2ebf674015cc02edccce75287f1a0130d394307b36743c2f5d504b47" dependencies = [ - "indexmap 2.9.0", + "indexmap 2.10.0", "itoa", "ryu", "serde", @@ -5616,7 +5651,7 @@ checksum = "5d69265a08751de7844521fd15003ae0a888e035773ba05695c5c759a6f89eef" dependencies = [ "proc-macro2", "quote", - "syn 2.0.103", + "syn 2.0.105", ] [[package]] @@ -5697,9 +5732,9 @@ dependencies = [ [[package]] name = "signal-hook-registry" -version = "1.4.5" +version = "1.4.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9203b8055f63a2a00e2f593bb0510367fe707d7ff1e5c872de2f537b339e5410" +checksum = "b2a4719bff48cee6b39d12c020eeb490953ad2443b7055bd0b21fca26bd8c28b" dependencies = [ "libc", ] @@ -5724,12 +5759,9 @@ checksum = "56199f7ddabf13fe5074ce809e7d3f42b42ae711800501b5b16ea82ad029c39d" [[package]] name = "slab" -version = "0.4.9" +version = "0.4.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8f92a496fb766b417c996b9c5e57daf2f7ad3b0bebe1ccfca4856390e3d3bb67" -dependencies = [ - "autocfg", -] +checksum = "7a2ae44ef20feb57a68b23d846850f861394c2e02dc425a50098ae8c90267589" [[package]] name = "smallvec" @@ -5747,6 +5779,16 @@ dependencies = [ "windows-sys 0.52.0", ] +[[package]] +name = "socket2" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "233504af464074f9d066d7b5416c5f9b894a5862a6506e306f7b816cdd6f1807" +dependencies = [ + "libc", + "windows-sys 0.59.0", +] + [[package]] name = "solana-account" version = "2.2.1" @@ -5800,7 +5842,7 @@ dependencies = [ "spl-token-2022 7.0.0", "spl-token-group-interface", "spl-token-metadata-interface", - "thiserror 2.0.12", + "thiserror 2.0.14", "zstd", ] @@ -5872,7 +5914,7 @@ dependencies = [ "solana-pubkey", "solana-system-interface", "solana-transaction-context", - "thiserror 2.0.12", + "thiserror 2.0.14", ] [[package]] @@ -5896,7 +5938,7 @@ dependencies = [ "solana-program", "solana-sdk", "tarpc", - "thiserror 2.0.12", + "thiserror 2.0.14", "tokio", "tokio-serde", ] @@ -5959,7 +6001,7 @@ dependencies = [ "ark-serialize 0.4.2", "bytemuck", "solana-define-syscall", - "thiserror 2.0.12", + "thiserror 2.0.14", ] [[package]] @@ -6018,7 +6060,7 @@ dependencies = [ "solana-timings", "solana-transaction-context", "solana-type-overrides", - "thiserror 2.0.12", + "thiserror 2.0.14", ] [[package]] @@ -6089,7 +6131,7 @@ dependencies = [ "solana-seed-phrase", "solana-signature", "solana-signer", - "thiserror 2.0.12", + "thiserror 2.0.14", "tiny-bip39", "uriparse", "url", @@ -6165,7 +6207,7 @@ dependencies = [ "dashmap 5.5.3", "futures", "futures-util", - "indexmap 2.9.0", + "indexmap 2.10.0", "indicatif", "log", "quinn", @@ -6196,7 +6238,7 @@ dependencies = [ "solana-transaction", "solana-transaction-error", "solana-udp-client", - "thiserror 2.0.12", + "thiserror 2.0.14", "tokio", ] @@ -6283,7 +6325,7 @@ dependencies = [ "solana-sdk-ids", "solana-svm-transaction", "solana-transaction-error", - "thiserror 2.0.12", + "thiserror 2.0.14", ] [[package]] @@ -6343,7 +6385,7 @@ dependencies = [ "bincode", "crossbeam-channel", "futures-util", - "indexmap 2.9.0", + "indexmap 2.10.0", "log", "rand 0.8.5", "rayon", @@ -6353,7 +6395,7 @@ dependencies = [ "solana-net-utils", "solana-time-utils", "solana-transaction-error", - "thiserror 2.0.12", + "thiserror 2.0.14", "tokio", ] @@ -6382,7 +6424,7 @@ dependencies = [ "curve25519-dalek 4.1.3", "solana-define-syscall", "subtle", - "thiserror 2.0.12", + "thiserror 2.0.14", ] [[package]] @@ -6492,7 +6534,7 @@ dependencies = [ "solana-pubkey", "solana-sdk-ids", "solana-system-interface", - "thiserror 2.0.12", + "thiserror 2.0.14", ] [[package]] @@ -6856,7 +6898,7 @@ dependencies = [ "solana-cluster-type", "solana-sha256-hasher", "solana-time-utils", - "thiserror 2.0.12", + "thiserror 2.0.14", ] [[package]] @@ -6890,7 +6932,7 @@ dependencies = [ "rand 0.8.5", "serde", "serde_derive", - "socket2", + "socket2 0.5.10", "solana-serde", "tokio", "url", @@ -7012,7 +7054,7 @@ dependencies = [ "ark-bn254 0.4.0", "light-poseidon 0.2.0", "solana-define-syscall", - "thiserror 2.0.12", + "thiserror 2.0.14", ] [[package]] @@ -7129,7 +7171,7 @@ dependencies = [ "solana-sysvar", "solana-sysvar-id", "solana-vote-interface", - "thiserror 2.0.12", + "thiserror 2.0.14", "wasm-bindgen", ] @@ -7224,7 +7266,7 @@ dependencies = [ "solana-timings", "solana-transaction-context", "solana-type-overrides", - "thiserror 2.0.12", + "thiserror 2.0.14", ] [[package]] @@ -7273,7 +7315,7 @@ dependencies = [ "solana-pubkey", "solana-rpc-client-api", "solana-signature", - "thiserror 2.0.12", + "thiserror 2.0.14", "tokio", "tokio-stream", "tokio-tungstenite 0.20.1", @@ -7295,7 +7337,7 @@ dependencies = [ "log", "quinn", "quinn-proto", - "rustls 0.23.27", + "rustls 0.23.31", "solana-connection-cache", "solana-keypair", "solana-measure", @@ -7308,7 +7350,7 @@ dependencies = [ "solana-streamer", "solana-tls-utils", "solana-transaction-error", - "thiserror 2.0.12", + "thiserror 2.0.14", "tokio", ] @@ -7351,7 +7393,7 @@ dependencies = [ "solana-pubkey", "solana-signature", "solana-signer", - "thiserror 2.0.12", + "thiserror 2.0.14", "uriparse", ] @@ -7370,9 +7412,9 @@ dependencies = [ [[package]] name = "solana-rent-collector" -version = "2.2.1" +version = "2.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7c1e19f5d5108b0d824244425e43bc78bbb9476e2199e979b0230c9f632d3bf4" +checksum = "127e6dfa51e8c8ae3aa646d8b2672bc4ac901972a338a9e1cd249e030564fb9d" dependencies = [ "serde", "serde_derive", @@ -7483,7 +7525,7 @@ dependencies = [ "solana-transaction-error", "solana-transaction-status-client-types", "solana-version", - "thiserror 2.0.12", + "thiserror 2.0.14", ] [[package]] @@ -7500,7 +7542,7 @@ dependencies = [ "solana-pubkey", "solana-rpc-client", "solana-sdk-ids", - "thiserror 2.0.12", + "thiserror 2.0.14", ] [[package]] @@ -7593,7 +7635,7 @@ dependencies = [ "solana-transaction-context", "solana-transaction-error", "solana-validator-exit", - "thiserror 2.0.12", + "thiserror 2.0.14", "wasm-bindgen", ] @@ -7615,7 +7657,7 @@ dependencies = [ "bs58", "proc-macro2", "quote", - "syn 2.0.103", + "syn 2.0.105", ] [[package]] @@ -7645,7 +7687,7 @@ dependencies = [ "borsh 1.5.7", "libsecp256k1", "solana-define-syscall", - "thiserror 2.0.12", + "thiserror 2.0.14", ] [[package]] @@ -7874,7 +7916,7 @@ dependencies = [ "futures-util", "governor 0.6.3", "histogram", - "indexmap 2.9.0", + "indexmap 2.10.0", "itertools 0.12.1", "libc", "log", @@ -7884,9 +7926,9 @@ dependencies = [ "quinn", "quinn-proto", "rand 0.8.5", - "rustls 0.23.27", + "rustls 0.23.31", "smallvec", - "socket2", + "socket2 0.5.10", "solana-keypair", "solana-measure", "solana-metrics", @@ -7901,9 +7943,9 @@ dependencies = [ "solana-tls-utils", "solana-transaction-error", "solana-transaction-metrics-tracker", - "thiserror 2.0.12", + "thiserror 2.0.14", "tokio", - "tokio-util 0.7.15", + "tokio-util 0.7.16", "x509-parser", ] @@ -8077,7 +8119,7 @@ version = "2.2.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ec21c6c242ee93642aa50b829f5727470cdbdf6b461fb7323fe4bc31d1b54c08" dependencies = [ - "rustls 0.23.27", + "rustls 0.23.31", "solana-keypair", "solana-pubkey", "solana-signer", @@ -8093,7 +8135,7 @@ dependencies = [ "async-trait", "bincode", "futures-util", - "indexmap 2.9.0", + "indexmap 2.10.0", "indicatif", "log", "rayon", @@ -8114,7 +8156,7 @@ dependencies = [ "solana-signer", "solana-transaction", "solana-transaction-error", - "thiserror 2.0.12", + "thiserror 2.0.14", "tokio", ] @@ -8229,7 +8271,7 @@ dependencies = [ "spl-token-2022 7.0.0", "spl-token-group-interface", "spl-token-metadata-interface", - "thiserror 2.0.12", + "thiserror 2.0.14", ] [[package]] @@ -8252,7 +8294,7 @@ dependencies = [ "solana-transaction", "solana-transaction-context", "solana-transaction-error", - "thiserror 2.0.12", + "thiserror 2.0.14", ] [[package]] @@ -8277,7 +8319,7 @@ dependencies = [ "solana-net-utils", "solana-streamer", "solana-transaction-error", - "thiserror 2.0.12", + "thiserror 2.0.14", "tokio", ] @@ -8356,7 +8398,7 @@ dependencies = [ "solana-transaction", "solana-transaction-context", "solana-vote-interface", - "thiserror 2.0.12", + "thiserror 2.0.14", ] [[package]] @@ -8407,7 +8449,7 @@ dependencies = [ "solana-signature", "solana-signer", "subtle", - "thiserror 2.0.12", + "thiserror 2.0.14", "wasm-bindgen", "zeroize", ] @@ -8461,7 +8503,7 @@ dependencies = [ "solana-signature", "solana-signer", "subtle", - "thiserror 2.0.12", + "thiserror 2.0.14", "zeroize", ] @@ -8526,19 +8568,19 @@ checksum = "d9e8418ea6269dcfb01c712f0444d2c75542c04448b480e87de59d2865edc750" dependencies = [ "quote", "spl-discriminator-syn", - "syn 2.0.103", + "syn 2.0.105", ] [[package]] name = "spl-discriminator-syn" -version = "0.2.0" +version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8c1f05593b7ca9eac7caca309720f2eafb96355e037e6d373b909a80fe7b69b9" +checksum = "5d1dbc82ab91422345b6df40a79e2b78c7bce1ebb366da323572dd60b7076b67" dependencies = [ "proc-macro2", "quote", "sha2 0.10.9", - "syn 2.0.103", + "syn 2.0.105", "thiserror 1.0.69", ] @@ -8586,7 +8628,7 @@ dependencies = [ "solana-program-option", "solana-pubkey", "solana-zk-sdk", - "thiserror 2.0.12", + "thiserror 2.0.14", ] [[package]] @@ -8611,7 +8653,7 @@ dependencies = [ "proc-macro2", "quote", "sha2 0.10.9", - "syn 2.0.103", + "syn 2.0.105", ] [[package]] @@ -8704,7 +8746,7 @@ dependencies = [ "spl-token-metadata-interface", "spl-transfer-hook-interface", "spl-type-length-value", - "thiserror 2.0.12", + "thiserror 2.0.14", ] [[package]] @@ -8730,7 +8772,7 @@ dependencies = [ "solana-program", "solana-zk-sdk", "spl-pod", - "thiserror 2.0.12", + "thiserror 2.0.14", ] [[package]] @@ -8752,7 +8794,7 @@ checksum = "0e3597628b0d2fe94e7900fd17cdb4cfbb31ee35c66f82809d27d86e44b2848b" dependencies = [ "curve25519-dalek 4.1.3", "solana-zk-sdk", - "thiserror 2.0.12", + "thiserror 2.0.14", ] [[package]] @@ -8881,9 +8923,9 @@ dependencies = [ [[package]] name = "syn" -version = "2.0.103" +version = "2.0.105" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e4307e30089d6fd6aff212f2da3a1f9e32f3223b1f010fb09b7c95f90f3ca1e8" +checksum = "7bc3fcb250e53458e712715cf74285c1f889686520d79294a9ef3bd7aa1fc619" dependencies = [ "proc-macro2", "quote", @@ -8925,7 +8967,7 @@ checksum = "728a70f3dbaf5bab7f0c4b1ac8d7ae5ea60a4b5549c8a5914361c99147a709d2" dependencies = [ "proc-macro2", "quote", - "syn 2.0.103", + "syn 2.0.105", ] [[package]] @@ -9076,7 +9118,7 @@ dependencies = [ "proc-macro-error2", "proc-macro2", "quote", - "syn 2.0.103", + "syn 2.0.105", ] [[package]] @@ -9186,11 +9228,11 @@ dependencies = [ [[package]] name = "thiserror" -version = "2.0.12" +version = "2.0.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "567b8a2dae586314f7be2a752ec7474332959c6460e02bde30d702a66d488708" +checksum = "0b0949c3a6c842cbde3f1686d6eea5a010516deb7085f79db747562d4102f41e" dependencies = [ - "thiserror-impl 2.0.12", + "thiserror-impl 2.0.14", ] [[package]] @@ -9201,18 +9243,18 @@ checksum = "4fee6c4efc90059e10f81e6d42c60a18f76588c3d74cb83a0b242a2b6c7504c1" dependencies = [ "proc-macro2", "quote", - "syn 2.0.103", + "syn 2.0.105", ] [[package]] name = "thiserror-impl" -version = "2.0.12" +version = "2.0.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7f7cf42b4507d8ea322120659672cf1b9dbb93f8f2d4ecfd6e51350ff5b17a1d" +checksum = "cc5b44b4ab9c2fdd0e0512e6bece8388e214c0749f5862b114cc5b7a25daf227" dependencies = [ "proc-macro2", "quote", - "syn 2.0.103", + "syn 2.0.105", ] [[package]] @@ -9301,20 +9343,22 @@ checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" [[package]] name = "tokio" -version = "1.45.1" +version = "1.47.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "75ef51a33ef1da925cea3e4eb122833cb377c61439ca401b770f54902b806779" +checksum = "89e49afdadebb872d3145a5638b59eb0691ea23e46ca484037cfab3b76b95038" dependencies = [ "backtrace", "bytes", + "io-uring", "libc", "mio", "parking_lot", "pin-project-lite", "signal-hook-registry", - "socket2", + "slab", + "socket2 0.6.0", "tokio-macros", - "windows-sys 0.52.0", + "windows-sys 0.59.0", ] [[package]] @@ -9325,7 +9369,7 @@ checksum = "6e06d43f1345a3bcd39f6a56dbb7dcab2ba47e68e8ac134855e7e2bdbaf8cab8" dependencies = [ "proc-macro2", "quote", - "syn 2.0.103", + "syn 2.0.105", ] [[package]] @@ -9354,7 +9398,7 @@ version = "0.26.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8e727b36a1a0e8b74c376ac2211e40c2c8af09fb4013c60d910495810f008e9b" dependencies = [ - "rustls 0.23.27", + "rustls 0.23.31", "tokio", ] @@ -9429,9 +9473,9 @@ dependencies = [ [[package]] name = "tokio-util" -version = "0.7.15" +version = "0.7.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "66a539a9ad6d5d281510d5bd368c973d636c02dbf8a67300bfb6b950696ad7df" +checksum = "14307c986784f72ef81c89db7d9e28d6ac26d16213b109ea501696195e6e3ce5" dependencies = [ "bytes", "futures-core", @@ -9456,11 +9500,26 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "dc1beb996b9d83529a9e75c17a1686767d148d70663143c7854d8b4a09ced362" dependencies = [ "serde", - "serde_spanned", - "toml_datetime", + "serde_spanned 0.6.9", + "toml_datetime 0.6.11", "toml_edit", ] +[[package]] +name = "toml" +version = "0.9.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "75129e1dc5000bfbaa9fee9d1b21f974f9fbad9daec557a521ee6e080825f6e8" +dependencies = [ + "indexmap 2.10.0", + "serde", + "serde_spanned 1.0.0", + "toml_datetime 0.7.0", + "toml_parser", + "toml_writer", + "winnow", +] + [[package]] name = "toml_datetime" version = "0.6.11" @@ -9470,26 +9529,50 @@ dependencies = [ "serde", ] +[[package]] +name = "toml_datetime" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bade1c3e902f58d73d3f294cd7f20391c1cb2fbcb643b73566bc773971df91e3" +dependencies = [ + "serde", +] + [[package]] name = "toml_edit" version = "0.22.27" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "41fe8c660ae4257887cf66394862d21dbca4a6ddd26f04a3560410406a2f819a" dependencies = [ - "indexmap 2.9.0", + "indexmap 2.10.0", "serde", - "serde_spanned", - "toml_datetime", + "serde_spanned 0.6.9", + "toml_datetime 0.6.11", "toml_write", "winnow", ] +[[package]] +name = "toml_parser" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b551886f449aa90d4fe2bdaa9f4a2577ad2dde302c61ecf262d80b116db95c10" +dependencies = [ + "winnow", +] + [[package]] name = "toml_write" version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5d99f8c9a7727884afe522e9bd5edbfc91a3312b36a77b5fb8926e4c31a41801" +[[package]] +name = "toml_writer" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fcc842091f2def52017664b53082ecbbeb5c7731092bad69d2c63050401dfd64" + [[package]] name = "tower" version = "0.5.2" @@ -9561,13 +9644,13 @@ dependencies = [ [[package]] name = "tracing-attributes" -version = "0.1.29" +version = "0.1.30" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1b1ffbcf9c6f6b99d386e7444eb608ba646ae452a36b39737deb9663b610f662" +checksum = "81383ab64e72a7a8b8e13130c49e3dab29def6d0c7d76a03087b3cf71c5c6903" dependencies = [ "proc-macro2", "quote", - "syn 2.0.103", + "syn 2.0.105", ] [[package]] @@ -9643,9 +9726,9 @@ checksum = "e421abadd41a4225275504ea4d6566923418b7f05506fbc9c0fe86ba7396114b" [[package]] name = "trybuild" -version = "1.0.105" +version = "1.0.110" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1c9bf9513a2f4aeef5fdac8677d7d349c79fdbcc03b9c86da6e9d254f1e43be2" +checksum = "32e257d7246e7a9fd015fb0b28b330a8d4142151a33f03e6a497754f4b1f6a8e" dependencies = [ "glob", "serde", @@ -9653,7 +9736,7 @@ dependencies = [ "serde_json", "target-triple", "termcolor", - "toml 0.8.23", + "toml 0.9.5", ] [[package]] @@ -9819,9 +9902,9 @@ checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821" [[package]] name = "uuid" -version = "1.17.0" +version = "1.18.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3cf4199d1e5d15ddd86a694e4d0dffa9c323ce759fea589f00fef9d81cc1931d" +checksum = "f33196643e165781c20a5ead5582283a7dacbb87855d867fbc2df3f81eddc1be" dependencies = [ "getrandom 0.3.3", "js-sys", @@ -9902,7 +9985,7 @@ dependencies = [ "serde_urlencoded", "tokio", "tokio-tungstenite 0.21.0", - "tokio-util 0.7.15", + "tokio-util 0.7.16", "tower-service", "tracing", ] @@ -9950,7 +10033,7 @@ dependencies = [ "log", "proc-macro2", "quote", - "syn 2.0.103", + "syn 2.0.105", "wasm-bindgen-shared", ] @@ -9985,7 +10068,7 @@ checksum = "8ae87ea40c9f689fc23f209965b6fb8a99ad69aeeb0231408be24920604395de" dependencies = [ "proc-macro2", "quote", - "syn 2.0.103", + "syn 2.0.105", "wasm-bindgen-backend", "wasm-bindgen-shared", ] @@ -10025,14 +10108,14 @@ version = "0.26.11" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "75c7f0ef91146ebfb530314f5f1d24528d7f0767efbfd31dce919275413e393e" dependencies = [ - "webpki-root-certs 1.0.0", + "webpki-root-certs 1.0.2", ] [[package]] name = "webpki-root-certs" -version = "1.0.0" +version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "01a83f7e1a9f8712695c03eabe9ed3fbca0feff0152f33f12593e5a6303cb1a4" +checksum = "4e4ffd8df1c57e87c325000a3d6ef93db75279dc3a231125aac571650f22b12a" dependencies = [ "rustls-pki-types", ] @@ -10054,18 +10137,18 @@ checksum = "5f20c57d8d7db6d3b86154206ae5d8fba62dd39573114de97c2cb0578251f8e1" [[package]] name = "webpki-roots" -version = "1.0.0" +version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2853738d1cc4f2da3a225c18ec6c3721abb31961096e9dbf5ab35fa88b19cfdb" +checksum = "7e8983c3ab33d6fb807cfcdad2491c4ea8cbc8ed839181c7dfd9c67c83e261b2" dependencies = [ "rustls-pki-types", ] [[package]] name = "wide" -version = "0.7.32" +version = "0.7.33" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "41b5576b9a81633f3e8df296ce0063042a73507636cbe956c61133dd7034ab22" +checksum = "0ce5da8ecb62bcd8ec8b7ea19f69a51275e91299be594ea5cc6ef7819e16cd03" dependencies = [ "bytemuck", "safe_arch", @@ -10123,7 +10206,7 @@ checksum = "a47fddd13af08290e67f4acabf4b459f647552718f683a7b415d290ac744a836" dependencies = [ "proc-macro2", "quote", - "syn 2.0.103", + "syn 2.0.105", ] [[package]] @@ -10134,7 +10217,7 @@ checksum = "bd9211b69f8dcdfa817bfd14bf1c97c9188afa36f4750130fcdf3f400eca9fa8" dependencies = [ "proc-macro2", "quote", - "syn 2.0.103", + "syn 2.0.105", ] [[package]] @@ -10145,9 +10228,9 @@ checksum = "5e6ad25900d524eaabdbbb96d20b4311e1e7ae1699af4fb28c17ae66c80d798a" [[package]] name = "windows-registry" -version = "0.5.2" +version = "0.5.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b3bab093bdd303a1240bb99b8aba8ea8a69ee19d34c9e2ef9594e708a4878820" +checksum = "5b8a9ed28765efc97bbc954883f4e6796c33a06546ebafacbabee9696967499e" dependencies = [ "windows-link", "windows-result", @@ -10214,7 +10297,7 @@ version = "0.60.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f2f500e4d28234f72040990ec9d39e3a6b950f9f22d3dba18416c35882612bcb" dependencies = [ - "windows-targets 0.53.2", + "windows-targets 0.53.3", ] [[package]] @@ -10265,10 +10348,11 @@ dependencies = [ [[package]] name = "windows-targets" -version = "0.53.2" +version = "0.53.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c66f69fcc9ce11da9966ddb31a40968cad001c5bedeb5c2b82ede4253ab48aef" +checksum = "d5fe6031c4041849d7c496a8ded650796e7b6ecc19df1a431c1a363342e5dc91" dependencies = [ + "windows-link", "windows_aarch64_gnullvm 0.53.0", "windows_aarch64_msvc 0.53.0", "windows_i686_gnu 0.53.0", @@ -10461,9 +10545,9 @@ checksum = "271414315aff87387382ec3d271b52d7ae78726f5d44ac98b4f4030c91880486" [[package]] name = "winnow" -version = "0.7.11" +version = "0.7.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "74c7b26e3480b707944fc872477815d29a8e429d2f93a1ce000f5fa84a15cbcd" +checksum = "f3edebf492c8125044983378ecb5766203ad3b4c2f7a922bd7dd207f6d443e95" dependencies = [ "memchr", ] @@ -10528,7 +10612,7 @@ dependencies = [ "anyhow", "ark-bn254 0.5.0", "ark-ff 0.5.0", - "clap 4.5.40", + "clap 4.5.45", "dirs", "groth16-solana", "light-batched-merkle-tree", @@ -10575,28 +10659,28 @@ checksum = "38da3c9736e16c5d3c8c597a9aaa5d1fa565d0532ae05e27c24aa62fb32c0ab6" dependencies = [ "proc-macro2", "quote", - "syn 2.0.103", + "syn 2.0.105", "synstructure 0.13.2", ] [[package]] name = "zerocopy" -version = "0.8.25" +version = "0.8.26" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a1702d9583232ddb9174e01bb7c15a2ab8fb1bc6f227aa1233858c351a3ba0cb" +checksum = "1039dd0d3c310cf05de012d8a39ff557cb0d23087fd44cad61df08fc31907a2f" dependencies = [ "zerocopy-derive", ] [[package]] name = "zerocopy-derive" -version = "0.8.25" +version = "0.8.26" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "28a6e20d751156648aa063f3800b706ee209a32c0b4d9f24be3d980b01be55ef" +checksum = "9ecf5b4cc5364572d7f4c329661bcc82724222973f2cab6f050a4e5c22f75181" dependencies = [ "proc-macro2", "quote", - "syn 2.0.103", + "syn 2.0.105", ] [[package]] @@ -10616,7 +10700,7 @@ checksum = "d71e5d6e06ab090c67b5e44993ec16b72dcbaabc526db883a360057678b48502" dependencies = [ "proc-macro2", "quote", - "syn 2.0.103", + "syn 2.0.105", "synstructure 0.13.2", ] @@ -10637,7 +10721,7 @@ checksum = "ce36e65b0d2999d2aafac989fb249189a141aee1f53c612c1f37d72631959f69" dependencies = [ "proc-macro2", "quote", - "syn 2.0.103", + "syn 2.0.105", ] [[package]] @@ -10653,9 +10737,9 @@ dependencies = [ [[package]] name = "zerovec" -version = "0.11.2" +version = "0.11.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4a05eb080e015ba39cc9e23bbe5e7fb04d5fb040350f99f34e338d5fdd294428" +checksum = "e7aa2bd55086f1ab526693ecbe444205da57e25f4489879da80635a46d90e73b" dependencies = [ "yoke", "zerofrom", @@ -10670,7 +10754,7 @@ checksum = "5b96237efa0c878c64bd89c436f661be4e46b2f3eff1ebb976f7ef2321d2f58f" dependencies = [ "proc-macro2", "quote", - "syn 2.0.103", + "syn 2.0.105", ] [[package]] From 2fb42415a5aac75a7a794c7833d2f3e08af01bba Mon Sep 17 00:00:00 2001 From: ananas-block Date: Fri, 15 Aug 2025 18:58:18 +0200 Subject: [PATCH 4/4] remove moved tests --- program-tests/client-test/Cargo.toml | 67 -- program-tests/client-test/Xargo.toml | 2 - program-tests/client-test/src/lib.rs | 1 - .../client-test/tests/light_client.rs | 825 ------------------ .../client-test/tests/light_program_test.rs | 713 --------------- program-tests/client-test/tests/sdk_compat.rs | 112 --- program-tests/sdk-anchor-test/.gitignore | 7 - program-tests/sdk-anchor-test/.prettierignore | 8 - program-tests/sdk-anchor-test/Anchor.toml | 18 - program-tests/sdk-anchor-test/README.md | 1 - .../programs/sdk-anchor-test/Cargo.toml | 38 - .../programs/sdk-anchor-test/Xargo.toml | 2 - .../programs/sdk-anchor-test/src/lib.rs | 196 ----- .../programs/sdk-anchor-test/tests/test.rs | 196 ----- program-tests/sdk-anchor-test/tsconfig.json | 10 - program-tests/sdk-test/Cargo.toml | 40 - program-tests/sdk-test/Xargo.toml | 2 - program-tests/sdk-test/src/create_pda.rs | 87 -- program-tests/sdk-test/src/lib.rs | 49 -- program-tests/sdk-test/src/update_pda.rs | 65 -- program-tests/sdk-test/tests/test.rs | 177 ---- sdk-tests/sdk-anchor-test/package.json | 3 +- sdk-tests/sdk-test/src/create_pda.rs | 5 +- 23 files changed, 3 insertions(+), 2621 deletions(-) delete mode 100644 program-tests/client-test/Cargo.toml delete mode 100644 program-tests/client-test/Xargo.toml delete mode 100644 program-tests/client-test/src/lib.rs delete mode 100644 program-tests/client-test/tests/light_client.rs delete mode 100644 program-tests/client-test/tests/light_program_test.rs delete mode 100644 program-tests/client-test/tests/sdk_compat.rs delete mode 100644 program-tests/sdk-anchor-test/.gitignore delete mode 100644 program-tests/sdk-anchor-test/.prettierignore delete mode 100644 program-tests/sdk-anchor-test/Anchor.toml delete mode 100644 program-tests/sdk-anchor-test/README.md delete mode 100644 program-tests/sdk-anchor-test/programs/sdk-anchor-test/Cargo.toml delete mode 100644 program-tests/sdk-anchor-test/programs/sdk-anchor-test/Xargo.toml delete mode 100644 program-tests/sdk-anchor-test/programs/sdk-anchor-test/src/lib.rs delete mode 100644 program-tests/sdk-anchor-test/programs/sdk-anchor-test/tests/test.rs delete mode 100644 program-tests/sdk-anchor-test/tsconfig.json delete mode 100644 program-tests/sdk-test/Cargo.toml delete mode 100644 program-tests/sdk-test/Xargo.toml delete mode 100644 program-tests/sdk-test/src/create_pda.rs delete mode 100644 program-tests/sdk-test/src/lib.rs delete mode 100644 program-tests/sdk-test/src/update_pda.rs delete mode 100644 program-tests/sdk-test/tests/test.rs diff --git a/program-tests/client-test/Cargo.toml b/program-tests/client-test/Cargo.toml deleted file mode 100644 index 8436feda1b..0000000000 --- a/program-tests/client-test/Cargo.toml +++ /dev/null @@ -1,67 +0,0 @@ -[package] -name = "client-test" -version = "0.1.0" -description = "Tests for light-client and light-program-test." -repository = "https://github.com/Lightprotocol/light-protocol" -license = "Apache-2.0" -edition = "2021" - -[lib] -crate-type = ["cdylib", "lib"] -name = "client_test" - -[features] -test-sbf = [] - -[dev-dependencies] -light-client = { workspace = true, features = ["devenv"] } -light-program-test = { workspace = true, features = ["devenv"] } -light-prover-client = { workspace = true, features = ["devenv"] } -light-test-utils = { workspace = true } -light-sdk = { workspace = true } -light-sdk-pinocchio = { workspace = true } -light-sdk-types = { workspace = true } -light-zero-copy = { workspace = true } -light-hasher = { workspace = true } -light-compressed-account = { workspace = true } -light-compressed-token = { workspace = true } -light-indexed-array = { workspace = true } -light-merkle-tree-reference = { workspace = true } - -tokio = { workspace = true } -rand = { workspace = true } -num-bigint = { workspace = true } - -solana-sdk = { workspace = true } -spl-token = { workspace = true } -solana-rpc-client = { workspace = true } -solana-rpc-client-api = { workspace = true } -solana-transaction-status-client-types = { workspace = true } -solana-account-decoder-client-types = { workspace = true } -solana-pubkey = { workspace = true } -solana-instruction = { workspace = true } -solana-program-error = { workspace = true } -solana-transaction = { workspace = true } -solana-transaction-error = { workspace = true } -solana-hash = { workspace = true } -solana-clock = { workspace = true } -solana-signature = { workspace = true } -solana-commitment-config = { workspace = true } -solana-account = { workspace = true } -solana-signer = { workspace = true } -solana-epoch-info = { workspace = true } -solana-keypair = { workspace = true } -solana-compute-budget-interface = { workspace = true } -solana-address-lookup-table-interface = { version = "2.2.1", features = [ - "bytemuck", - "bincode", -] } -solana-system-interface = { workspace = true } - - -[lints.rust.unexpected_cfgs] -level = "allow" -check-cfg = [ - 'cfg(target_os, values("solana"))', - 'cfg(feature, values("frozen-abi", "no-entrypoint"))', -] diff --git a/program-tests/client-test/Xargo.toml b/program-tests/client-test/Xargo.toml deleted file mode 100644 index 475fb71ed1..0000000000 --- a/program-tests/client-test/Xargo.toml +++ /dev/null @@ -1,2 +0,0 @@ -[target.bpfel-unknown-unknown.dependencies.std] -features = [] diff --git a/program-tests/client-test/src/lib.rs b/program-tests/client-test/src/lib.rs deleted file mode 100644 index 10051c7680..0000000000 --- a/program-tests/client-test/src/lib.rs +++ /dev/null @@ -1 +0,0 @@ -// Placeholder diff --git a/program-tests/client-test/tests/light_client.rs b/program-tests/client-test/tests/light_client.rs deleted file mode 100644 index c63a4915e1..0000000000 --- a/program-tests/client-test/tests/light_client.rs +++ /dev/null @@ -1,825 +0,0 @@ -use light_client::{ - indexer::{ - AccountProofInputs, AddressProofInputs, AddressWithTree, - GetCompressedTokenAccountsByOwnerOrDelegateOptions, Hash, Indexer, IndexerRpcConfig, - MerkleProof, PaginatedOptions, RetryConfig, RootIndex, TreeInfo, ValidityProofWithContext, - }, - local_test_validator::{spawn_validator, LightValidatorConfig}, - rpc::{LightClient, LightClientConfig}, -}; -use light_compressed_account::{hash_to_bn254_field_size_be, TreeType}; -use light_compressed_token::mint_sdk::{ - create_create_token_pool_instruction, create_mint_to_instruction, -}; -use light_hasher::Poseidon; -use light_merkle_tree_reference::{indexed::IndexedMerkleTree, MerkleTree}; -use light_program_test::accounts::test_accounts::TestAccounts; -use light_prover_client::prover::ProverConfig; -use light_sdk::{ - address::{v1::derive_address, NewAddressParams}, - token::{AccountState, TokenData}, -}; -use light_test_utils::{system_program::create_invoke_instruction, Rpc, RpcError}; -use solana_compute_budget_interface::ComputeBudgetInstruction; -use solana_keypair::Keypair; -use solana_pubkey::Pubkey; -use solana_signature::Signature; -use solana_signer::Signer; -use solana_system_interface::instruction::create_account; -use solana_transaction::Transaction; - -// Constants -const LAMPORTS_PER_SOL: u64 = 1_000_000_000; - -/// Endpoints tested: -/// 1. get_compressed_accounts_by_owner -/// 2. get_multiple_compressed_accounts -/// 3. get_validity_proof -/// 4. get_compressed_account -/// 5. get_compressed_account_by_hash -/// 6. get_compressed_balance -/// 7. get_compressed_balance_by_owner -/// 8. get_compression_signatures_for_account -/// 9. get_compression_signatures_for_address -/// 10. get_compression_signatures_for_owner -/// 11. get_multiple_compressed_account_proofs -/// 12. get_multiple_new_address_proofs -/// 13. get_compressed_token_accounts_by_owner -/// 14. get_compressed_token_account_balance -/// 15. get_compressed_token_balances_by_owner_v2 -/// 16. get_compressed_mint_token_holders -/// 17. get_compression_signatures_for_token_owner -#[tokio::test(flavor = "multi_thread", worker_threads = 1)] -async fn test_all_endpoints() { - let config = LightValidatorConfig { - enable_indexer: true, - prover_config: Some(ProverConfig::default()), - wait_time: 75, - sbf_programs: vec![], - limit_ledger_size: None, - }; - - spawn_validator(config).await; - - let test_accounts = TestAccounts::get_local_test_validator_accounts(); - let mut rpc: LightClient = LightClient::new(LightClientConfig::local()).await.unwrap(); - - let payer_pubkey = rpc.get_payer().pubkey(); - rpc.airdrop_lamports(&payer_pubkey, 10 * LAMPORTS_PER_SOL) - .await - .unwrap(); - let mt = test_accounts.v1_state_trees[0].merkle_tree; - let _address_mt = test_accounts.v1_address_trees[0].merkle_tree; - - let lamports = LAMPORTS_PER_SOL / 2; - let lamports_1 = LAMPORTS_PER_SOL / 2 + 1; - let owner = rpc.get_payer().pubkey(); - - // create compressed account with address - let (address, signature) = create_address(&mut rpc, lamports, owner, mt).await.unwrap(); - let (address_1, signature_1) = create_address(&mut rpc, lamports_1, owner, mt) - .await - .unwrap(); - - // 1. get_compressed_accounts_by_owner - let initial_accounts = { - let accounts = rpc - .get_compressed_accounts_by_owner( - &payer_pubkey, - None, - Some(IndexerRpcConfig { - slot: rpc.client.get_slot().unwrap(), - retry_config: RetryConfig::default(), - }), - ) - .await - .unwrap() - .value; - assert_eq!(accounts.items.len(), 2); - assert_eq!(accounts.items[0].owner, owner); - assert_eq!(accounts.items[1].owner, owner); - - assert!(accounts - .items - .iter() - .any(|x| x.lamports == lamports && x.address == Some(address))); - - assert!(accounts - .items - .iter() - .any(|x| x.lamports == lamports_1 && x.address == Some(address_1))); - - accounts - }; - - let account_hashes: Vec = initial_accounts.items.iter().map(|a| a.hash).collect(); - let mut reference_tree = MerkleTree::::new(26, 10); - for hash in &account_hashes { - reference_tree.append(hash).unwrap(); - } - let account_addresses: Vec = initial_accounts - .items - .iter() - .map(|a| a.address.unwrap()) - .collect(); - - // Create reference address tree and add the addresses - let _reference_address_tree = IndexedMerkleTree::::new(26, 10).unwrap(); - - // Don't add the test address to the reference tree since we want non-inclusion proof - - // 2. get_multiple_compressed_accounts - let accounts = rpc - .get_multiple_compressed_accounts(None, Some(account_hashes.clone()), None) - .await - .unwrap() - .value; - - assert_eq!(accounts.items.len(), account_hashes.len()); - for item in accounts.items.iter() { - assert!(initial_accounts.items.iter().any(|x| x.hash == item.hash)); - } - // Currently fails because photon doesn't deliver cpi context accounts. - // for item in accounts.items.iter() { - // assert!(initial_accounts.items.iter().any(|x| *x == *item)); - // } - let accounts = rpc - .get_multiple_compressed_accounts(Some(account_addresses), None, None) - .await - .unwrap() - .value; - assert_eq!(accounts.items.len(), initial_accounts.items.len()); - for item in accounts.items.iter() { - assert!(initial_accounts.items.iter().any(|x| x.hash == item.hash)); - } - // Currently fails because photon doesn't deliver cpi context accounts. - // for item in accounts.items.iter() { - // assert!(initial_accounts.items.iter().any(|x| *x == *item)); - // } - // 3. get_validity_proof - { - let seed = rand::random::<[u8; 32]>(); - let new_addresses = vec![AddressWithTree { - address: hash_to_bn254_field_size_be(&seed), - tree: test_accounts.v1_address_trees[0].merkle_tree, - }]; - - let result = rpc - .get_validity_proof(account_hashes.clone(), new_addresses.clone(), None) - .await - .unwrap() - .value; - assert_eq!(result.accounts.len(), account_hashes.len()); - assert_eq!(result.addresses.len(), new_addresses.len()); - - println!("account_proof {:?}", result); - - // Build expected ValidityProofWithContext using reference tree - let expected_result = ValidityProofWithContext { - proof: result.proof, // Keep the actual proof as-is - accounts: account_hashes - .iter() - .enumerate() - .map(|(i, &hash)| AccountProofInputs { - hash, - root: reference_tree.root(), - root_index: RootIndex::new_some(2), - leaf_index: i as u64, - tree_info: TreeInfo { - cpi_context: None, - next_tree_info: None, - queue: test_accounts.v1_state_trees[0].nullifier_queue, - tree: mt, - tree_type: TreeType::StateV1, - }, - }) - .collect(), - addresses: new_addresses - .iter() - .enumerate() - .map(|(i, addr_with_tree)| { - // TODO: enable once photon bug is fixed - // let address_bigint = BigUint::from_bytes_be(&addr_with_tree.address); - // let non_inclusion_proof = reference_address_tree.get_non_inclusion_proof(&address_bigint).unwrap(); - AddressProofInputs { - address: addr_with_tree.address, - root: result.addresses[i].root, - root_index: 3, - tree_info: TreeInfo { - cpi_context: None, - next_tree_info: None, - queue: test_accounts.v1_address_trees[0].queue, - tree: addr_with_tree.tree, - tree_type: TreeType::AddressV1, - }, - } - }) - .collect(), - }; - - assert_eq!(result, expected_result); - } - // 4. get_compressed_account - let first_account = rpc - .get_compressed_account(accounts.items[0].address.unwrap(), None) - .await - .unwrap() - .value; - assert_eq!(first_account, accounts.items[0]); - - // 5. get_compressed_account_by_hash - { - let account = rpc - .get_compressed_account_by_hash(first_account.hash, None) - .await - .unwrap() - .value; - assert_eq!(account, first_account); - } - // 6. get_compressed_balance - { - let balance = rpc - .get_compressed_balance(None, Some(first_account.hash), None) - .await - .unwrap() - .value; - assert_eq!(balance, lamports); - } - // 7. get_compressed_balance_by_owner - { - let balance = rpc - .get_compressed_balance_by_owner(&payer_pubkey, None) - .await - .unwrap() - .value; - assert_eq!(balance, lamports + lamports_1); - } - // 8. get_compression_signatures_for_account - { - let signatures = rpc - .get_compression_signatures_for_account(first_account.hash, None) - .await - .unwrap() - .value; - assert_eq!(signatures.items[0].signature, signature.to_string()); - } - // 9. get_compression_signatures_for_address - { - let signatures = rpc - .get_compression_signatures_for_address(&first_account.address.unwrap(), None, None) - .await - .unwrap() - .value; - assert_eq!(signatures.items[0].signature, signature.to_string()); - } - // 10. get_compression_signatures_for_owner - { - let signatures = rpc - .get_compression_signatures_for_owner(&owner, None, None) - .await - .unwrap() - .value; - assert_eq!(signatures.items.len(), 2); - assert!(signatures - .items - .iter() - .any(|s| s.signature == signature.to_string())); - assert!(signatures - .items - .iter() - .any(|s| s.signature == signature_1.to_string())); - let options = PaginatedOptions { - limit: Some(1), - cursor: None, - }; - let signatures = rpc - .get_compression_signatures_for_owner(&owner, Some(options), None) - .await - .unwrap() - .value; - assert_eq!(signatures.items.len(), 1); - assert!(signatures.items.iter().any( - |s| s.signature == signature_1.to_string() || s.signature == signature.to_string() - )); - } - // 11. get_multiple_compressed_account_proofs - { - let proofs = rpc - .get_multiple_compressed_account_proofs(account_hashes.to_vec(), None) - .await - .unwrap() - .value; - assert!(!proofs.items.is_empty()); - assert_eq!(proofs.items[0].hash, account_hashes[0]); - - // Build expected Vec using reference tree - let expected_proofs: Vec = account_hashes - .iter() - .enumerate() - .map(|(i, &hash)| { - let expected_proof = reference_tree.get_proof_of_leaf(i, false).unwrap(); - MerkleProof { - hash, - leaf_index: i as u64, - merkle_tree: mt, - proof: expected_proof, - root_seq: 2, - root: reference_tree.root(), - } - }) - .collect(); - - assert_eq!(proofs.items, expected_proofs); - - // 12. get_multiple_new_address_proofs - let addresses = vec![address]; - let new_address_proofs = rpc - .get_multiple_new_address_proofs( - test_accounts.v1_address_trees[0].merkle_tree.to_bytes(), - addresses.clone(), - None, - ) - .await - .unwrap(); - assert!(!new_address_proofs.value.items.is_empty()); - // TODO: update once photon is ready - // Build expected Vec using reference address tree - // let expected_address_proofs: Vec = addresses - // .iter() - // .map(|&addr| { - // let address_bigint = BigUint::from_bytes_be(&addr); - // let non_inclusion_proof = reference_address_tree - // .get_non_inclusion_proof(&address_bigint) - // .unwrap(); - - // NewAddressProofWithContext { - // merkle_tree: address_mt, - // root: non_inclusion_proof.root, - // root_seq: 3, - // low_address_index: non_inclusion_proof.leaf_index as u64, - // low_address_value: non_inclusion_proof.leaf_lower_range_value, - // low_address_next_index: non_inclusion_proof.next_index as u64, - // low_address_next_value: non_inclusion_proof.leaf_higher_range_value, - // low_address_proof: non_inclusion_proof.merkle_proof, - // new_low_element: None, - // new_element: None, - // new_element_next_value: None, - // } - // }) - // .collect(); - assert_eq!(new_address_proofs.value.items.len(), 1); - } - - test_token_api(&rpc, &test_accounts).await; -} - -/// Token API endpoints tested: -/// 1. get_compressed_token_accounts_by_owner -/// 2. get_compressed_token_account_balance -/// 3. get_compressed_token_balances_by_owner_v2 -/// 4. get_compressed_mint_token_holders -/// 5. get_compression_signatures_for_token_owner -async fn test_token_api(rpc: &LightClient, test_accounts: &TestAccounts) { - let payer = rpc.get_payer().insecure_clone(); - let payer_pubkey = payer.pubkey(); - let mint_1 = Keypair::new(); - let mint_2 = Keypair::new(); - - create_two_mints(rpc, payer_pubkey, &mint_1, &mint_2); - let mint_1 = mint_1.pubkey(); - let mint_2 = mint_2.pubkey(); - let base_amount = 1_000_000; - let recipients = (0..5) - .map(|_| Pubkey::new_unique()) - .collect::>(); - let amounts = (0..5).map(|i| base_amount + i).collect::>(); - // Mint amounts to payer for both mints with and without lamports - let signatures = mint_to_token_accounts( - rpc, - test_accounts, - payer_pubkey, - mint_1, - mint_2, - base_amount, - &recipients, - &amounts, - ); - let slot = rpc.get_slot().await.unwrap(); - let config = IndexerRpcConfig { - slot, - retry_config: RetryConfig::default(), - }; - // 1. get_compressed_mint_token_holders - for mint in [mint_1, mint_2] { - let res = rpc - .get_compressed_mint_token_holders(&mint, None, Some(config.clone())) - .await - .unwrap() - .value - .items; - assert_eq!(res.len(), 5); - - let mut owners = res.iter().map(|x| x.owner).collect::>(); - owners.sort(); - owners.dedup(); - assert_eq!(owners.len(), 5); - for (amount, recipient) in amounts.iter().zip(recipients.iter()) { - // * 2 because we mint two times the same amount per token mint (with and without lamports) - assert!(res - .iter() - .any(|item| item.balance == (*amount * 2) && item.owner == *recipient)); - } - let option = PaginatedOptions { - limit: Some(1), - cursor: None, - }; - let res = rpc - .get_compressed_mint_token_holders(&mint, Some(option), None) - .await - .unwrap() - .value - .items; - assert_eq!(res.len(), 1); - } - - // 2. get_compression_signatures_for_token_owner - for recipient in &recipients { - let res = rpc - .get_compression_signatures_for_token_owner(recipient, None, None) - .await - .unwrap() - .value - .items; - assert_eq!(res.len(), 2); - assert_eq!(res[0].signature, signatures[1].to_string()); - assert_eq!(res[1].signature, signatures[0].to_string()); - let option = PaginatedOptions { - limit: Some(1), - cursor: None, - }; - let res = rpc - .get_compression_signatures_for_token_owner(recipient, Some(option), None) - .await - .unwrap() - .value - .items; - assert_eq!(res.len(), 1); - } - - // 3. get_compressed_token_accounts_by_owner - test_get_compressed_token_accounts_by_owner( - rpc, - mint_1, - mint_2, - base_amount, - &recipients, - &amounts, - ) - .await; - // 4. get_compressed_token_account_balance - { - let token_accounts = rpc - .get_compressed_token_accounts_by_owner(&recipients[0], None, None) - .await - .unwrap() - .value; - let hash = token_accounts.items[0].account.hash; - let balance = rpc - .get_compressed_token_account_balance(None, Some(hash), None) - .await - .unwrap() - .value; - assert_eq!(balance, amounts[0]); - assert_eq!(balance, token_accounts.items[0].token.amount); - } - // 5. get_compressed_token_balances_by_owner_v2 - { - // No options - test_get_compressed_token_balances_by_owner_v2( - rpc, - vec![mint_1, mint_2], - recipients.clone(), - amounts.clone(), - None, - ) - .await; - // Limit to mint1 - let options = Some(GetCompressedTokenAccountsByOwnerOrDelegateOptions { - mint: Some(mint_1), - cursor: None, - limit: None, - }); - test_get_compressed_token_balances_by_owner_v2( - rpc, - vec![mint_1], - recipients.clone(), - amounts.clone(), - options, - ) - .await; - - // Limit to mint2 - let options = Some(GetCompressedTokenAccountsByOwnerOrDelegateOptions { - mint: Some(mint_2), - cursor: None, - limit: None, - }); - test_get_compressed_token_balances_by_owner_v2( - rpc, - vec![mint_2], - recipients.clone(), - amounts.clone(), - options, - ) - .await; - } -} - -#[allow(clippy::too_many_arguments)] -fn mint_to_token_accounts( - rpc: &LightClient, - test_accounts: &TestAccounts, - payer_pubkey: Pubkey, - mint_1: Pubkey, - mint_2: Pubkey, - base_amount: u64, - recipients: &[Pubkey], - amounts: &[u64], -) -> [Signature; 2] { - let mut signatures = Vec::new(); - - for mint in [mint_1, mint_2] { - let mint_ix_with_lamports = create_mint_to_instruction( - &payer_pubkey, - &payer_pubkey, - &mint, - &test_accounts.v1_state_trees[0].merkle_tree, - amounts.to_vec(), - recipients.to_vec(), - Some(base_amount), - false, - 0, - ); - - let mint_ix_no_lamports = create_mint_to_instruction( - &payer_pubkey, - &payer_pubkey, - &mint, - &test_accounts.v1_state_trees[0].merkle_tree, - amounts.to_vec(), - recipients.to_vec(), - None, - false, - 0, - ); - - let compute_budget_ix = ComputeBudgetInstruction::set_compute_unit_limit(500_000); - - let tx = Transaction::new_signed_with_payer( - &[ - compute_budget_ix, - mint_ix_with_lamports, - mint_ix_no_lamports, - ], - Some(&payer_pubkey), - &[&rpc.get_payer()], - rpc.client.get_latest_blockhash().unwrap(), - ); - signatures.push(rpc.client.send_and_confirm_transaction(&tx).unwrap()); - } - signatures.try_into().unwrap() -} - -fn create_two_mints(rpc: &LightClient, payer_pubkey: Pubkey, mint_1: &Keypair, mint_2: &Keypair) { - let mint_rent = rpc - .client - .get_minimum_balance_for_rent_exemption(82) - .unwrap(); - let create_mint_ix = create_account( - &payer_pubkey, - &mint_1.pubkey(), - mint_rent, - 82, - &spl_token::id(), - ); - let create_mint_ix_2 = create_account( - &payer_pubkey, - &mint_2.pubkey(), - mint_rent, - 82, - &spl_token::id(), - ); - let init_mint_ix = spl_token::instruction::initialize_mint( - &spl_token::id(), - &mint_1.pubkey(), - &payer_pubkey, - None, - 9, - ) - .unwrap(); - let init_mint_ix_2 = spl_token::instruction::initialize_mint( - &spl_token::id(), - &mint_2.pubkey(), - &payer_pubkey, - None, - 2, - ) - .unwrap(); - // Create token pool for compression - let create_pool_ix = - create_create_token_pool_instruction(&payer_pubkey, &mint_1.pubkey(), false); - let create_pool_ix_2 = - create_create_token_pool_instruction(&payer_pubkey, &mint_2.pubkey(), false); - let compute_budget_ix = ComputeBudgetInstruction::set_compute_unit_limit(500_000); - let tx = Transaction::new_signed_with_payer( - &[ - compute_budget_ix, - create_mint_ix, - create_mint_ix_2, - init_mint_ix, - init_mint_ix_2, - create_pool_ix, - create_pool_ix_2, - ], - Some(&payer_pubkey), - &[rpc.get_payer(), mint_1, mint_2], - rpc.client.get_latest_blockhash().unwrap(), - ); - rpc.client.send_and_confirm_transaction(&tx).unwrap(); -} - -/// Tests: -/// 1. fetch all no options -/// 2. fetch only for mint 1, with limit 1 -async fn test_get_compressed_token_accounts_by_owner( - rpc: &LightClient, - mint_1: Pubkey, - mint_2: Pubkey, - base_amount: u64, - recipients: &[Pubkey], - amounts: &[u64], -) { - let slot = rpc.get_slot().await.unwrap(); - let indexer_config = IndexerRpcConfig { - slot, - retry_config: RetryConfig::default(), - }; - for (amount, recipient) in amounts.iter().zip(recipients.iter()) { - { - let token_accounts = &rpc - .indexer() - .unwrap() - .get_compressed_token_accounts_by_owner( - recipient, - None, - Some(indexer_config.clone()), - ) - .await - .unwrap() - .value; - // every recipient should have 4 token accounts - // 1. 2 with lamports and 2 without - // 2. 2 with mint 1 and 2 with mint 2 - let mut expected_token_data = TokenData { - mint: mint_1, - amount: *amount, - owner: *recipient, - delegate: None, - state: AccountState::Initialized, - tlv: None, - }; - assert_eq!( - token_accounts - .items - .iter() - .filter(|item| item.token == expected_token_data) - .count(), - 2 - ); - assert!(token_accounts - .items - .iter() - .any(|item| item.token == expected_token_data - && item.account.lamports == base_amount)); - expected_token_data.mint = mint_2; - assert_eq!( - token_accounts - .items - .iter() - .filter(|item| item.token == expected_token_data) - .count(), - 2 - ); - assert!(token_accounts - .items - .iter() - .any(|item| item.token == expected_token_data - && item.account.lamports == base_amount)); - } - // fetch only for mint 1, with limit 1 - { - let options = GetCompressedTokenAccountsByOwnerOrDelegateOptions { - mint: Some(mint_1), - cursor: None, - limit: Some(1), - }; - let token_accounts = &rpc - .indexer() - .unwrap() - .get_compressed_token_accounts_by_owner(recipient, Some(options.clone()), None) - .await - .unwrap() - .value; - assert_eq!(token_accounts.items.len(), 1); - assert_eq!(token_accounts.items[0].token.mint, options.mint.unwrap()); - } - } -} - -async fn create_address( - rpc: &mut LightClient, - lamports: u64, - owner: Pubkey, - merkle_tree: Pubkey, -) -> Result<([u8; 32], Signature), RpcError> { - let address_merkle_tree = rpc.get_address_tree_v1(); - let (address, address_seed) = derive_address( - &[Pubkey::new_unique().to_bytes().as_slice()], - &address_merkle_tree.tree, - &Pubkey::new_unique(), - ); - - let output_account = light_compressed_account::compressed_account::CompressedAccount { - lamports, - owner: owner.into(), - data: None, - address: Some(address), - }; - let rpc_proof_result = rpc - .get_validity_proof( - vec![], - vec![AddressWithTree { - address, - tree: address_merkle_tree.tree, - }], - None, - ) - .await - .unwrap(); - - let new_address_params = NewAddressParams { - seed: address_seed, - address_queue_pubkey: address_merkle_tree.queue.into(), - address_merkle_tree_pubkey: address_merkle_tree.tree.into(), - address_merkle_tree_root_index: rpc_proof_result.value.addresses[0].root_index, - }; - let compute_budget_ix = ComputeBudgetInstruction::set_compute_unit_limit(500_000); - let ix = create_invoke_instruction( - &rpc.get_payer().pubkey(), - &rpc.get_payer().pubkey(), - &[], - &[output_account], - &[], - &[merkle_tree], - &[], - &[new_address_params], - rpc_proof_result.value.proof.0, - Some(lamports), - true, - None, - true, - ); - - let tx_create_compressed_account = Transaction::new_signed_with_payer( - &[compute_budget_ix, ix], - Some(&rpc.get_payer().pubkey()), - &[&rpc.get_payer()], - rpc.client.get_latest_blockhash().unwrap(), - ); - let signature = rpc - .client - .send_and_confirm_transaction(&tx_create_compressed_account)?; - Ok((address, signature)) -} - -async fn test_get_compressed_token_balances_by_owner_v2( - rpc: &LightClient, - mints: Vec, - recipients: Vec, - amounts: Vec, - options: Option, -) { - for (amount, recipient) in amounts.iter().zip(recipients.iter()) { - let balances = rpc - .get_compressed_token_balances_by_owner_v2(recipient, options.clone(), None) - .await - .unwrap(); - let balances = balances.value.items; - assert_eq!(balances.len(), mints.len()); - for mint in mints.iter() { - assert!(balances - .iter() - .any(|balance| balance.mint == *mint && balance.balance == (*amount) * 2)); - } - } -} diff --git a/program-tests/client-test/tests/light_program_test.rs b/program-tests/client-test/tests/light_program_test.rs deleted file mode 100644 index 087674193a..0000000000 --- a/program-tests/client-test/tests/light_program_test.rs +++ /dev/null @@ -1,713 +0,0 @@ -#![cfg(feature = "test-sbf")] -use light_client::{ - indexer::{ - AddressWithTree, GetCompressedTokenAccountsByOwnerOrDelegateOptions, Hash, Indexer, - IndexerRpcConfig, RetryConfig, - }, - rpc::Rpc, -}; -use light_compressed_account::hash_to_bn254_field_size_be; -use light_compressed_token::mint_sdk::{ - create_create_token_pool_instruction, create_mint_to_instruction, -}; -use light_program_test::{ - accounts::test_accounts::TestAccounts, program_test::LightProgramTest, ProgramTestConfig, -}; -use light_sdk::{ - address::{v1::derive_address, NewAddressParams}, - token::{AccountState, TokenData}, -}; -use light_test_utils::{system_program::create_invoke_instruction, RpcError}; -use solana_sdk::{ - compute_budget::ComputeBudgetInstruction, - pubkey::Pubkey, - signature::{Keypair, Signature, Signer}, - system_instruction::create_account, - transaction::Transaction, -}; - -// Constants -const LAMPORTS_PER_SOL: u64 = 1_000_000_000; - -/// Endpoints tested: -/// 1. get_compressed_accounts_by_owner -/// 2. get_multiple_compressed_accounts -/// 3. get_validity_proof -/// 4. get_compressed_account -/// 5. get_compressed_account_by_hash -/// 6. get_compressed_balance -/// 7. get_compressed_balance_by_owner -/// 8. get_compression_signatures_for_account -/// 9. get_compression_signatures_for_address -/// 10. get_compression_signatures_for_owner -/// 11. get_multiple_compressed_account_proofs -/// 12. get_multiple_new_address_proofs -/// 13. get_compressed_token_accounts_by_owner -/// 14. get_compressed_token_account_balance -/// 15. get_compressed_token_balances_by_owner_v2 -/// 16. get_compressed_mint_token_holders -/// 17. get_compression_signatures_for_token_owner -#[tokio::test(flavor = "multi_thread", worker_threads = 1)] -async fn test_all_endpoints() { - let config = ProgramTestConfig::default(); - let mut rpc = LightProgramTest::new(config).await.unwrap(); - let test_accounts = rpc.test_accounts().clone(); - - let payer_pubkey = rpc.get_payer().pubkey(); - let mt = test_accounts.v1_state_trees[0].merkle_tree; - - let lamports = LAMPORTS_PER_SOL / 2; - let lamports_1 = LAMPORTS_PER_SOL / 2 + 1; - let owner = rpc.get_payer().pubkey(); - - // create compressed account with address - let (address, _signature) = create_address(&mut rpc, lamports, owner, mt).await.unwrap(); - let (address_1, _signature_1) = create_address(&mut rpc, lamports_1, owner, mt) - .await - .unwrap(); - - // 1. get_compressed_accounts_by_owner - let initial_accounts = { - let accounts = rpc - .get_compressed_accounts_by_owner(&payer_pubkey, None, None) - .await - .unwrap() - .value; - assert_eq!(accounts.items.len(), 2); - assert_eq!(accounts.items[0].owner, owner); - assert_eq!(accounts.items[1].owner, owner); - - assert!(accounts - .items - .iter() - .any(|x| x.lamports == lamports && x.address == Some(address))); - - assert!(accounts - .items - .iter() - .any(|x| x.lamports == lamports_1 && x.address == Some(address_1))); - - accounts - }; - - let account_hashes: Vec = initial_accounts.items.iter().map(|a| a.hash).collect(); - let account_addresses: Vec = initial_accounts - .items - .iter() - .map(|a| a.address.unwrap()) - .collect(); - - // 2. get_multiple_compressed_accounts - let accounts = rpc - .get_multiple_compressed_accounts(None, Some(account_hashes.clone()), None) - .await - .unwrap() - .value; - - assert_eq!(accounts.items.len(), account_hashes.len()); - for item in accounts.items.iter() { - assert!(initial_accounts.items.iter().any(|x| x.hash == item.hash)); - } - // Currently fails because photon doesn't deliver cpi context accounts. - // for item in accounts.items.iter() { - // assert!(initial_accounts.items.iter().any(|x| *x == *item)); - // } - let accounts = rpc - .get_multiple_compressed_accounts(Some(account_addresses), None, None) - .await - .unwrap() - .value; - assert_eq!(accounts.items.len(), initial_accounts.items.len()); - for item in accounts.items.iter() { - assert!(initial_accounts.items.iter().any(|x| x.hash == item.hash)); - } - // Currently fails because photon doesn't deliver cpi context accounts. - // for item in accounts.items.iter() { - // assert!(initial_accounts.items.iter().any(|x| *x == *item)); - // } - // 3. get_validity_proof - { - let seed = rand::random::<[u8; 32]>(); - let new_addresses = vec![AddressWithTree { - address: hash_to_bn254_field_size_be(&seed), - tree: test_accounts.v1_address_trees[0].merkle_tree, - }]; - - let result = rpc - .get_validity_proof(account_hashes.clone(), new_addresses.clone(), None) - .await - .unwrap() - .value; - assert_eq!(result.accounts.len(), account_hashes.len()); - assert_eq!(result.addresses.len(), new_addresses.len()); - } - // 4. get_compressed_account - let first_account = rpc - .get_compressed_account(accounts.items[0].address.unwrap(), None) - .await - .unwrap() - .value; - assert_eq!(first_account, accounts.items[0]); - - // 5. get_compressed_account_by_hash - { - let account = rpc - .get_compressed_account_by_hash(first_account.hash, None) - .await - .unwrap() - .value; - assert_eq!(account, first_account); - } - // 6. get_compressed_balance - { - let balance = rpc - .get_compressed_balance(None, Some(first_account.hash), None) - .await - .unwrap() - .value; - assert_eq!(balance, first_account.lamports); - } - // // 7. get_compressed_balance_by_owner - // { - // let balance = rpc - // .get_compressed_balance_by_owner(&payer_pubkey, None) - // .await - // .unwrap() - // .value; - // assert_eq!(balance, lamports + lamports_1); - // } - // // 8. get_compression_signatures_for_account - // { - // let signatures = rpc - // .get_compression_signatures_for_account(first_account.hash, None) - // .await - // .unwrap() - // .value; - // assert_eq!(signatures.items[0].signature, signature.to_string()); - // } - // // 9. get_compression_signatures_for_address - // { - // let signatures = rpc - // .get_compression_signatures_for_address(&first_account.address.unwrap(), None, None) - // .await - // .unwrap() - // .value; - // assert_eq!(signatures.items[0].signature, signature.to_string()); - // } - // // 10. get_compression_signatures_for_owner - // { - // let signatures = rpc - // .get_compression_signatures_for_owner(&owner, None, None) - // .await - // .unwrap() - // .value; - // assert_eq!(signatures.items.len(), 2); - // assert!(signatures - // .items - // .iter() - // .any(|s| s.signature == signature.to_string())); - // assert!(signatures - // .items - // .iter() - // .any(|s| s.signature == signature_1.to_string())); - // let options = PaginatedOptions { - // limit: Some(1), - // cursor: None, - // }; - // let signatures = rpc - // .get_compression_signatures_for_owner(&owner, Some(options), None) - // .await - // .unwrap() - // .value; - // assert_eq!(signatures.items.len(), 1); - // assert!(signatures.items.iter().any( - // |s| s.signature == signature_1.to_string() || s.signature == signature.to_string() - // )); - // } - // 11. get_multiple_compressed_account_proofs - { - let proofs = rpc - .get_multiple_compressed_account_proofs(account_hashes.to_vec(), None) - .await - .unwrap() - .value; - assert!(!proofs.items.is_empty()); - assert_eq!(proofs.items[0].hash, account_hashes[0]); - - // 12. get_multiple_new_address_proofs - let addresses = vec![address]; - let new_address_proofs = rpc - .get_multiple_new_address_proofs( - test_accounts.v1_address_trees[0].merkle_tree.to_bytes(), - addresses, - None, - ) - .await - .unwrap(); - assert!(!new_address_proofs.value.items.is_empty()); - assert_eq!( - new_address_proofs.value.items[0].merkle_tree.to_bytes(), - test_accounts.v1_address_trees[0].merkle_tree.to_bytes() - ); - } - - test_token_api(&mut rpc, &test_accounts).await; -} - -/// Token API endpoints tested: -/// 1. get_compressed_token_accounts_by_owner -/// 2. get_compressed_token_account_balance -/// 3. get_compressed_token_balances_by_owner_v2 -/// 4. get_compressed_mint_token_holders -/// 5. get_compression_signatures_for_token_owner -async fn test_token_api(rpc: &mut LightProgramTest, test_accounts: &TestAccounts) { - let payer = rpc.get_payer().insecure_clone(); - let payer_pubkey = payer.pubkey(); - let mint_1 = Keypair::new(); - let mint_2 = Keypair::new(); - - create_two_mints(rpc, payer_pubkey, &mint_1, &mint_2).await; - let mint_1 = mint_1.pubkey(); - let mint_2 = mint_2.pubkey(); - let base_amount = 1_000_000; - let recipients = (0..5) - .map(|_| Pubkey::new_unique()) - .collect::>(); - let amounts = (0..5).map(|i| base_amount + i).collect::>(); - // Mint amounts to payer for both mints with and without lamports - let _signatures = mint_to_token_accounts( - rpc, - test_accounts, - payer_pubkey, - mint_1, - mint_2, - base_amount, - &recipients, - &amounts, - ) - .await; - // // 1. get_compressed_mint_token_holders - // for mint in [mint_1, mint_2] { - // let res = rpc - // .get_compressed_mint_token_holders(&mint, None, None) - // .await - // .unwrap() - // .value - // .items; - // assert_eq!(res.len(), 5); - - // let mut owners = res.iter().map(|x| x.owner).collect::>(); - // owners.sort(); - // owners.dedup(); - // assert_eq!(owners.len(), 5); - // for (amount, recipient) in amounts.iter().zip(recipients.iter()) { - // // * 2 because we mint two times the same amount per token mint (with and without lamports) - // assert!(res - // .iter() - // .any(|item| item.balance == (*amount * 2) && item.owner == *recipient)); - // } - // let option = PaginatedOptions { - // limit: Some(1), - // cursor: None, - // }; - // let res = rpc - // .get_compressed_mint_token_holders(&mint, Some(option), None) - // .await - // .unwrap() - // .value - // .items; - // assert_eq!(res.len(), 1); - // } - - // // 2. get_compression_signatures_for_token_owner - // for recipient in &recipients { - // let res = rpc - // .get_compression_signatures_for_token_owner(recipient, None, None) - // .await - // .unwrap() - // .value - // .items; - // assert_eq!(res.len(), 2); - // assert_eq!(res[0].signature, signatures[1].to_string()); - // assert_eq!(res[1].signature, signatures[0].to_string()); - // let option = PaginatedOptions { - // limit: Some(1), - // cursor: None, - // }; - // let res = rpc - // .get_compression_signatures_for_token_owner(recipient, Some(option), None) - // .await - // .unwrap() - // .value - // .items; - // assert_eq!(res.len(), 1); - // } - - // 3. get_compressed_token_accounts_by_owner - test_get_compressed_token_accounts_by_owner( - rpc, - mint_1, - mint_2, - base_amount, - &recipients, - &amounts, - ) - .await; - // 4. get_compressed_token_account_balance - { - let token_accounts = rpc - .get_compressed_token_accounts_by_owner(&recipients[0], None, None) - .await - .unwrap() - .value; - let hash = token_accounts.items[0].account.hash; - let balance = rpc - .get_compressed_token_account_balance(None, Some(hash), None) - .await - .unwrap() - .value; - assert_eq!(balance, amounts[0]); - assert_eq!(balance, token_accounts.items[0].token.amount); - } - // 5. get_compressed_token_balances_by_owner_v2 - { - // No options - test_get_compressed_token_balances_by_owner_v2( - rpc, - vec![mint_1, mint_2], - recipients.clone(), - amounts.clone(), - None, - ) - .await; - // Limit to mint1 - let options = Some(GetCompressedTokenAccountsByOwnerOrDelegateOptions { - mint: Some(mint_1), - cursor: None, - limit: None, - }); - test_get_compressed_token_balances_by_owner_v2( - rpc, - vec![mint_1], - recipients.clone(), - amounts.clone(), - options, - ) - .await; - - // Limit to mint2 - let options = Some(GetCompressedTokenAccountsByOwnerOrDelegateOptions { - mint: Some(mint_2), - cursor: None, - limit: None, - }); - test_get_compressed_token_balances_by_owner_v2( - rpc, - vec![mint_2], - recipients.clone(), - amounts.clone(), - options, - ) - .await; - } -} - -#[allow(clippy::too_many_arguments)] -async fn mint_to_token_accounts( - rpc: &mut LightProgramTest, - test_accounts: &TestAccounts, - payer_pubkey: Pubkey, - mint_1: Pubkey, - mint_2: Pubkey, - base_amount: u64, - recipients: &[Pubkey], - amounts: &[u64], -) -> [Signature; 2] { - let mut signatures = Vec::new(); - - for mint in [mint_1, mint_2] { - let mint_ix_with_lamports = create_mint_to_instruction( - &payer_pubkey, - &payer_pubkey, - &mint, - &test_accounts.v1_state_trees[0].merkle_tree, - amounts.to_vec(), - recipients.to_vec(), - Some(base_amount), - false, - 0, - ); - - let mint_ix_no_lamports = create_mint_to_instruction( - &payer_pubkey, - &payer_pubkey, - &mint, - &test_accounts.v1_state_trees[0].merkle_tree, - amounts.to_vec(), - recipients.to_vec(), - None, - false, - 0, - ); - - let compute_budget_ix = ComputeBudgetInstruction::set_compute_unit_limit(500_000); - let blockhash = rpc.get_latest_blockhash().await.unwrap().0; - let payer = rpc.get_payer().insecure_clone(); - - let tx = Transaction::new_signed_with_payer( - &[ - compute_budget_ix, - mint_ix_with_lamports, - mint_ix_no_lamports, - ], - Some(&payer_pubkey), - &[&payer], - blockhash, - ); - signatures.push(rpc.process_transaction(tx).await.unwrap()); - } - signatures.try_into().unwrap() -} - -async fn create_two_mints( - rpc: &mut LightProgramTest, - payer_pubkey: Pubkey, - mint_1: &Keypair, - mint_2: &Keypair, -) { - let mint_rent = rpc - .get_minimum_balance_for_rent_exemption(82) - .await - .unwrap(); - let create_mint_ix = create_account( - &payer_pubkey, - &mint_1.pubkey(), - mint_rent, - 82, - &spl_token::id(), - ); - let create_mint_ix_2 = create_account( - &payer_pubkey, - &mint_2.pubkey(), - mint_rent, - 82, - &spl_token::id(), - ); - let init_mint_ix = spl_token::instruction::initialize_mint( - &spl_token::id(), - &mint_1.pubkey(), - &payer_pubkey, - None, - 9, - ) - .unwrap(); - let init_mint_ix_2 = spl_token::instruction::initialize_mint( - &spl_token::id(), - &mint_2.pubkey(), - &payer_pubkey, - None, - 2, - ) - .unwrap(); - // Create token pool for compression - let create_pool_ix = - create_create_token_pool_instruction(&payer_pubkey, &mint_1.pubkey(), false); - let create_pool_ix_2 = - create_create_token_pool_instruction(&payer_pubkey, &mint_2.pubkey(), false); - let compute_budget_ix = ComputeBudgetInstruction::set_compute_unit_limit(500_000); - let blockhash = rpc.get_latest_blockhash().await.unwrap().0; - let payer = rpc.get_payer().insecure_clone(); - let tx = Transaction::new_signed_with_payer( - &[ - compute_budget_ix, - create_mint_ix, - create_mint_ix_2, - init_mint_ix, - init_mint_ix_2, - create_pool_ix, - create_pool_ix_2, - ], - Some(&payer_pubkey), - &[&payer, mint_1, mint_2], - blockhash, - ); - rpc.process_transaction(tx).await.unwrap(); -} - -/// Tests: -/// 1. fetch all no options -/// 2. fetch only for mint 1, with limit 1 -async fn test_get_compressed_token_accounts_by_owner( - rpc: &mut LightProgramTest, - mint_1: Pubkey, - mint_2: Pubkey, - base_amount: u64, - recipients: &[Pubkey], - amounts: &[u64], -) { - let slot = rpc.get_slot().await.unwrap(); - let indexer_config = IndexerRpcConfig { - slot, - retry_config: RetryConfig::default(), - }; - for (amount, recipient) in amounts.iter().zip(recipients.iter()) { - { - let token_accounts = &rpc - .indexer() - .unwrap() - .get_compressed_token_accounts_by_owner( - recipient, - None, - Some(indexer_config.clone()), - ) - .await - .unwrap() - .value; - // every recipient should have 4 token accounts - // 1. 2 with lamports and 2 without - // 2. 2 with mint 1 and 2 with mint 2 - let mut expected_token_data = TokenData { - mint: mint_1, - amount: *amount, - owner: *recipient, - delegate: None, - state: AccountState::Initialized, - tlv: None, - }; - assert_eq!( - token_accounts - .items - .iter() - .filter(|item| item.token == expected_token_data) - .count(), - 2 - ); - assert!(token_accounts - .items - .iter() - .any(|item| item.token == expected_token_data - && item.account.lamports == base_amount)); - expected_token_data.mint = mint_2; - assert_eq!( - token_accounts - .items - .iter() - .filter(|item| item.token == expected_token_data) - .count(), - 2 - ); - assert!(token_accounts - .items - .iter() - .any(|item| item.token == expected_token_data - && item.account.lamports == base_amount)); - } - // fetch only for mint 1, with limit 1 - { - let options = GetCompressedTokenAccountsByOwnerOrDelegateOptions { - mint: Some(mint_1), - cursor: None, - limit: Some(1), - }; - let token_accounts = &rpc - .indexer() - .unwrap() - .get_compressed_token_accounts_by_owner(recipient, Some(options.clone()), None) - .await - .unwrap() - .value; - assert_eq!(token_accounts.items.len(), 1); - assert_eq!(token_accounts.items[0].token.mint, options.mint.unwrap()); - } - } -} - -async fn create_address( - rpc: &mut LightProgramTest, - lamports: u64, - owner: Pubkey, - merkle_tree: Pubkey, -) -> Result<([u8; 32], Signature), RpcError> { - let address_merkle_tree = rpc.get_address_tree_v1(); - let (address, address_seed) = derive_address( - &[Pubkey::new_unique().to_bytes().as_slice()], - &address_merkle_tree.tree, - &Pubkey::new_unique(), - ); - - let output_account = light_compressed_account::compressed_account::CompressedAccount { - lamports, - owner: owner.into(), - data: None, - address: Some(address), - }; - let rpc_proof_result = rpc - .get_validity_proof( - vec![], - vec![AddressWithTree { - address, - tree: address_merkle_tree.tree, - }], - None, - ) - .await - .unwrap(); - - let new_address_params = NewAddressParams { - seed: address_seed, - address_queue_pubkey: address_merkle_tree.queue.into(), - address_merkle_tree_pubkey: address_merkle_tree.tree.into(), - address_merkle_tree_root_index: rpc_proof_result.value.addresses[0].root_index, - }; - let compute_budget_ix = ComputeBudgetInstruction::set_compute_unit_limit(500_000); - let ix = create_invoke_instruction( - &rpc.get_payer().pubkey(), - &rpc.get_payer().pubkey(), - &[], - &[output_account], - &[], - &[merkle_tree], - &[], - &[new_address_params], - rpc_proof_result.value.proof.0, - Some(lamports), - true, - None, - true, - ); - - let blockhash = rpc.get_latest_blockhash().await.unwrap().0; - let payer = rpc.get_payer().insecure_clone(); - let tx_create_compressed_account = Transaction::new_signed_with_payer( - &[compute_budget_ix, ix], - Some(&payer.pubkey()), - &[&payer], - blockhash, - ); - let signature = rpc - .process_transaction(tx_create_compressed_account) - .await?; - Ok((address, signature)) -} - -async fn test_get_compressed_token_balances_by_owner_v2( - rpc: &mut LightProgramTest, - mints: Vec, - recipients: Vec, - amounts: Vec, - options: Option, -) { - for (amount, recipient) in amounts.iter().zip(recipients.iter()) { - let balances = rpc - .get_compressed_token_balances_by_owner_v2(recipient, options.clone(), None) - .await - .unwrap(); - let balances = balances.value.items; - assert_eq!(balances.len(), mints.len()); - for mint in mints.iter() { - assert!(balances - .iter() - .any(|balance| balance.mint == *mint && balance.balance == (*amount) * 2)); - } - } -} diff --git a/program-tests/client-test/tests/sdk_compat.rs b/program-tests/client-test/tests/sdk_compat.rs deleted file mode 100644 index 0c893b622c..0000000000 --- a/program-tests/client-test/tests/sdk_compat.rs +++ /dev/null @@ -1,112 +0,0 @@ -use light_hasher::HasherError; -use light_sdk::error::LightSdkError as SolanaLightSdkError; -use light_sdk_pinocchio::error::LightSdkError as PinocchioLightSdkError; -use light_zero_copy::errors::ZeroCopyError; - -fn generate_all_solana_errors() -> Vec { - vec![ - SolanaLightSdkError::ConstraintViolation, - SolanaLightSdkError::InvalidLightSystemProgram, - SolanaLightSdkError::ExpectedAccounts, - SolanaLightSdkError::ExpectedAddressTreeInfo, - SolanaLightSdkError::ExpectedAddressRootIndex, - SolanaLightSdkError::ExpectedData, - SolanaLightSdkError::ExpectedDiscriminator, - SolanaLightSdkError::ExpectedHash, - SolanaLightSdkError::ExpectedLightSystemAccount("test".to_string()), - SolanaLightSdkError::ExpectedMerkleContext, - SolanaLightSdkError::ExpectedRootIndex, - SolanaLightSdkError::TransferFromNoInput, - SolanaLightSdkError::TransferFromNoLamports, - SolanaLightSdkError::TransferFromInsufficientLamports, - SolanaLightSdkError::TransferIntegerOverflow, - SolanaLightSdkError::Borsh, - SolanaLightSdkError::FewerAccountsThanSystemAccounts, - SolanaLightSdkError::InvalidCpiSignerAccount, - SolanaLightSdkError::MissingField("test".to_string()), - SolanaLightSdkError::OutputStateTreeIndexIsNone, - SolanaLightSdkError::InitAddressIsNone, - SolanaLightSdkError::InitWithAddressIsNone, - SolanaLightSdkError::InitWithAddressOutputIsNone, - SolanaLightSdkError::MetaMutAddressIsNone, - SolanaLightSdkError::MetaMutInputIsNone, - SolanaLightSdkError::MetaMutOutputLamportsIsNone, - SolanaLightSdkError::MetaMutOutputIsNone, - SolanaLightSdkError::MetaCloseAddressIsNone, - SolanaLightSdkError::MetaCloseInputIsNone, - SolanaLightSdkError::CpiAccountsIndexOutOfBounds(1), - SolanaLightSdkError::Hasher(HasherError::IntegerOverflow), - SolanaLightSdkError::ZeroCopy(ZeroCopyError::Full), - ] -} - -fn generate_all_pinocchio_errors() -> Vec { - vec![ - PinocchioLightSdkError::ConstraintViolation, - PinocchioLightSdkError::InvalidLightSystemProgram, - PinocchioLightSdkError::ExpectedAccounts, - PinocchioLightSdkError::ExpectedAddressTreeInfo, - PinocchioLightSdkError::ExpectedAddressRootIndex, - PinocchioLightSdkError::ExpectedData, - PinocchioLightSdkError::ExpectedDiscriminator, - PinocchioLightSdkError::ExpectedHash, - PinocchioLightSdkError::ExpectedLightSystemAccount("test".to_string()), - PinocchioLightSdkError::ExpectedMerkleContext, - PinocchioLightSdkError::ExpectedRootIndex, - PinocchioLightSdkError::TransferFromNoInput, - PinocchioLightSdkError::TransferFromNoLamports, - PinocchioLightSdkError::TransferFromInsufficientLamports, - PinocchioLightSdkError::TransferIntegerOverflow, - PinocchioLightSdkError::Borsh, - PinocchioLightSdkError::FewerAccountsThanSystemAccounts, - PinocchioLightSdkError::InvalidCpiSignerAccount, - PinocchioLightSdkError::MissingField("test".to_string()), - PinocchioLightSdkError::OutputStateTreeIndexIsNone, - PinocchioLightSdkError::InitAddressIsNone, - PinocchioLightSdkError::InitWithAddressIsNone, - PinocchioLightSdkError::InitWithAddressOutputIsNone, - PinocchioLightSdkError::MetaMutAddressIsNone, - PinocchioLightSdkError::MetaMutInputIsNone, - PinocchioLightSdkError::MetaMutOutputLamportsIsNone, - PinocchioLightSdkError::MetaMutOutputIsNone, - PinocchioLightSdkError::MetaCloseAddressIsNone, - PinocchioLightSdkError::MetaCloseInputIsNone, - PinocchioLightSdkError::CpiAccountsIndexOutOfBounds(1), - PinocchioLightSdkError::Hasher(HasherError::IntegerOverflow), - PinocchioLightSdkError::ZeroCopy(ZeroCopyError::Full), - ] -} - -#[test] -fn test_error_compatibility() { - let solana_errors = generate_all_solana_errors(); - let pinocchio_errors = generate_all_pinocchio_errors(); - - // Ensure both SDKs have the same number of error variants - assert_eq!( - solana_errors.len(), - pinocchio_errors.len(), - "SDKs have different number of error variants" - ); - - // Test string representations - for (solana_error, pinocchio_error) in solana_errors.iter().zip(pinocchio_errors.iter()) { - assert_eq!( - solana_error.to_string(), - pinocchio_error.to_string(), - "String representations differ for error variants" - ); - } - - // Test error codes (consuming the values) - for (solana_error, pinocchio_error) in - solana_errors.into_iter().zip(pinocchio_errors.into_iter()) - { - let solana_code: u32 = solana_error.into(); - let pinocchio_code: u32 = pinocchio_error.into(); - assert_eq!( - solana_code, pinocchio_code, - "Error codes differ for error variants" - ); - } -} diff --git a/program-tests/sdk-anchor-test/.gitignore b/program-tests/sdk-anchor-test/.gitignore deleted file mode 100644 index 2e0446b07f..0000000000 --- a/program-tests/sdk-anchor-test/.gitignore +++ /dev/null @@ -1,7 +0,0 @@ -.anchor -.DS_Store -target -**/*.rs.bk -node_modules -test-ledger -.yarn diff --git a/program-tests/sdk-anchor-test/.prettierignore b/program-tests/sdk-anchor-test/.prettierignore deleted file mode 100644 index c1a0b75f09..0000000000 --- a/program-tests/sdk-anchor-test/.prettierignore +++ /dev/null @@ -1,8 +0,0 @@ - -.anchor -.DS_Store -target -node_modules -dist -build -test-ledger diff --git a/program-tests/sdk-anchor-test/Anchor.toml b/program-tests/sdk-anchor-test/Anchor.toml deleted file mode 100644 index a443e6fb8c..0000000000 --- a/program-tests/sdk-anchor-test/Anchor.toml +++ /dev/null @@ -1,18 +0,0 @@ -[toolchain] - -[features] -seeds = false -skip-lint = false - -[programs.localnet] -sdk_test = "2tzfijPBGbrR5PboyFUFKzfEoLTwdDSHUjANCw929wyt" - -[registry] -url = "https://api.apr.dev" - -[provider] -cluster = "Localnet" -wallet = "~/.config/solana/id.json" - -[scripts] -test = "yarn run ts-mocha -p ./tsconfig.json -t 1000000 tests/**/*.ts" diff --git a/program-tests/sdk-anchor-test/README.md b/program-tests/sdk-anchor-test/README.md deleted file mode 100644 index 8c768e8b2c..0000000000 --- a/program-tests/sdk-anchor-test/README.md +++ /dev/null @@ -1 +0,0 @@ -# SDK test program diff --git a/program-tests/sdk-anchor-test/programs/sdk-anchor-test/Cargo.toml b/program-tests/sdk-anchor-test/programs/sdk-anchor-test/Cargo.toml deleted file mode 100644 index f0faca1233..0000000000 --- a/program-tests/sdk-anchor-test/programs/sdk-anchor-test/Cargo.toml +++ /dev/null @@ -1,38 +0,0 @@ -[package] -name = "sdk-anchor-test" -version = "0.7.0" -description = "Test program for Light SDK and Light Macros" -edition = "2021" -license = "Apache-2.0" - -[lib] -crate-type = ["cdylib", "lib"] -name = "sdk_anchor_test" - -[features] -no-entrypoint = [] -no-idl = [] -no-log-ix-name = [] -cpi = ["no-entrypoint"] -default = ["idl-build"] -test-sbf = [] -bench-sbf = [] -idl-build = ["anchor-lang/idl-build", "light-sdk/idl-build"] - -[dependencies] -# Needs to be imported for LightHasher -light-hasher = { workspace = true, features = ["solana"] } -anchor-lang = { workspace = true } -light-sdk = { workspace = true, features = ["anchor", "v2"] } -light-sdk-types = { workspace = true } - -[target.'cfg(not(target_os = "solana"))'.dependencies] -solana-sdk = { workspace = true } - -[dev-dependencies] -light-client = { workspace = true, features = ["devenv"] } -light-program-test = { workspace = true, features = ["devenv"] } -light-test-utils = { workspace = true, features = ["devenv"] } -light-prover-client = { workspace = true, features = ["devenv"] } -tokio = { workspace = true } -light-compressed-account = { workspace = true, features = ["solana"] } diff --git a/program-tests/sdk-anchor-test/programs/sdk-anchor-test/Xargo.toml b/program-tests/sdk-anchor-test/programs/sdk-anchor-test/Xargo.toml deleted file mode 100644 index 475fb71ed1..0000000000 --- a/program-tests/sdk-anchor-test/programs/sdk-anchor-test/Xargo.toml +++ /dev/null @@ -1,2 +0,0 @@ -[target.bpfel-unknown-unknown.dependencies.std] -features = [] diff --git a/program-tests/sdk-anchor-test/programs/sdk-anchor-test/src/lib.rs b/program-tests/sdk-anchor-test/programs/sdk-anchor-test/src/lib.rs deleted file mode 100644 index 9f5f0367d5..0000000000 --- a/program-tests/sdk-anchor-test/programs/sdk-anchor-test/src/lib.rs +++ /dev/null @@ -1,196 +0,0 @@ -#![allow(unexpected_cfgs)] - -use anchor_lang::{prelude::*, Discriminator}; -use light_sdk::{ - account::LightAccount, - address::v1::derive_address, - cpi::{CpiAccounts, CpiInputs, CpiSigner}, - derive_light_cpi_signer, - instruction::{account_meta::CompressedAccountMeta, PackedAddressTreeInfo, ValidityProof}, - LightDiscriminator, LightHasher, -}; - -declare_id!("2tzfijPBGbrR5PboyFUFKzfEoLTwdDSHUjANCw929wyt"); - -pub const LIGHT_CPI_SIGNER: CpiSigner = - derive_light_cpi_signer!("2tzfijPBGbrR5PboyFUFKzfEoLTwdDSHUjANCw929wyt"); - -#[program] -pub mod sdk_anchor_test { - - use super::*; - - pub fn create_compressed_account<'info>( - ctx: Context<'_, '_, '_, 'info, WithNestedData<'info>>, - proof: ValidityProof, - address_tree_info: PackedAddressTreeInfo, - output_tree_index: u8, - name: String, - ) -> Result<()> { - let light_cpi_accounts = CpiAccounts::new( - ctx.accounts.signer.as_ref(), - ctx.remaining_accounts, - crate::LIGHT_CPI_SIGNER, - ); - - let (address, address_seed) = derive_address( - &[b"compressed", name.as_bytes()], - &address_tree_info - .get_tree_pubkey(&light_cpi_accounts) - .map_err(|_| ErrorCode::AccountNotEnoughKeys)?, - &crate::ID, - ); - let new_address_params = address_tree_info.into_new_address_params_packed(address_seed); - - let mut my_compressed_account = LightAccount::<'_, MyCompressedAccount>::new_init( - &crate::ID, - Some(address), - output_tree_index, - ); - - my_compressed_account.name = name; - my_compressed_account.nested = NestedData::default(); - - let cpi_inputs = CpiInputs::new_with_address( - proof, - vec![my_compressed_account - .to_account_info() - .map_err(ProgramError::from)?], - vec![new_address_params], - ); - - cpi_inputs - .invoke_light_system_program(light_cpi_accounts) - .map_err(ProgramError::from)?; - - Ok(()) - } - - pub fn update_compressed_account<'info>( - ctx: Context<'_, '_, '_, 'info, UpdateNestedData<'info>>, - proof: ValidityProof, - my_compressed_account: MyCompressedAccount, - account_meta: CompressedAccountMeta, - nested_data: NestedData, - ) -> Result<()> { - let mut my_compressed_account = LightAccount::<'_, MyCompressedAccount>::new_mut( - &crate::ID, - &account_meta, - my_compressed_account, - ) - .map_err(ProgramError::from)?; - - my_compressed_account.nested = nested_data; - - let light_cpi_accounts = CpiAccounts::new( - ctx.accounts.signer.as_ref(), - ctx.remaining_accounts, - crate::LIGHT_CPI_SIGNER, - ); - - let cpi_inputs = CpiInputs::new( - proof, - vec![my_compressed_account - .to_account_info() - .map_err(ProgramError::from)?], - ); - - cpi_inputs - .invoke_light_system_program(light_cpi_accounts) - .map_err(ProgramError::from)?; - - Ok(()) - } - - pub fn without_compressed_account<'info>( - ctx: Context<'_, '_, '_, 'info, WithoutCompressedAccount<'info>>, - name: String, - ) -> Result<()> { - ctx.accounts.my_regular_account.name = name; - Ok(()) - } -} - -#[event] -#[derive(Clone, Debug, Default, LightHasher, LightDiscriminator)] -pub struct MyCompressedAccount { - #[hash] - pub name: String, - pub nested: NestedData, -} - -// Illustrates nested hashing feature. -#[derive(LightHasher, Clone, Debug, AnchorSerialize, AnchorDeserialize)] -pub struct NestedData { - pub one: u16, - pub two: u16, - pub three: u16, - pub four: u16, - pub five: u16, - pub six: u16, - pub seven: u16, - pub eight: u16, - pub nine: u16, - pub ten: u16, - pub eleven: u16, - pub twelve: u16, -} - -impl Default for NestedData { - fn default() -> Self { - Self { - one: 1, - two: 2, - three: 3, - four: 4, - five: 5, - six: 6, - seven: 7, - eight: 8, - nine: 9, - ten: 10, - eleven: 11, - twelve: 12, - } - } -} - -#[account] -pub struct MyRegularAccount { - name: String, -} - -#[derive(Accounts)] -#[instruction(name: String)] -pub struct WithCompressedAccount<'info> { - #[account(mut)] - pub signer: Signer<'info>, -} - -#[derive(Accounts)] -pub struct WithNestedData<'info> { - #[account(mut)] - pub signer: Signer<'info>, -} - -#[derive(Accounts)] -pub struct UpdateNestedData<'info> { - #[account(mut)] - pub signer: Signer<'info>, -} - -#[derive(Accounts)] -#[instruction(name: String)] -pub struct WithoutCompressedAccount<'info> { - #[account(mut)] - pub signer: Signer<'info>, - #[account( - init, - seeds = [b"compressed".as_slice(), name.as_bytes()], - bump, - payer = signer, - space = 8 + 8, - )] - pub my_regular_account: Account<'info, MyRegularAccount>, - pub system_program: Program<'info, System>, -} diff --git a/program-tests/sdk-anchor-test/programs/sdk-anchor-test/tests/test.rs b/program-tests/sdk-anchor-test/programs/sdk-anchor-test/tests/test.rs deleted file mode 100644 index 96949c26e5..0000000000 --- a/program-tests/sdk-anchor-test/programs/sdk-anchor-test/tests/test.rs +++ /dev/null @@ -1,196 +0,0 @@ -#![cfg(feature = "test-sbf")] - -use anchor_lang::AnchorDeserialize; -use light_client::indexer::CompressedAccount; -use light_program_test::{ - indexer::TestIndexerExtensions, program_test::LightProgramTest, AddressWithTree, Indexer, - ProgramTestConfig, -}; -use light_sdk::{ - address::v1::derive_address, - instruction::{account_meta::CompressedAccountMeta, PackedAccounts, SystemAccountMetaConfig}, -}; -use light_test_utils::{Rpc, RpcError}; -use sdk_anchor_test::{MyCompressedAccount, NestedData}; -use solana_sdk::{ - instruction::{AccountMeta, Instruction}, - signature::{Keypair, Signature, Signer}, -}; - -#[tokio::test] -async fn test_sdk_test() { - let config = - ProgramTestConfig::new_v2(true, Some(vec![("sdk_anchor_test", sdk_anchor_test::ID)])); - let mut rpc = LightProgramTest::new(config).await.unwrap(); - let payer = rpc.get_payer().insecure_clone(); - - let address_tree_info = rpc.get_address_tree_v1(); - - let (address, _) = derive_address( - &[b"compressed", b"test".as_slice()], - &address_tree_info.tree, - &sdk_anchor_test::ID, - ); - - create_compressed_account("test".to_string(), &mut rpc, &payer, &address) - .await - .unwrap(); - - // Check that it was created correctly. - let compressed_account = rpc - .get_compressed_account(address, None) - .await - .unwrap() - .value; - - let record = &compressed_account.data.as_ref().unwrap().data; - let record = MyCompressedAccount::deserialize(&mut &record[..]).unwrap(); - assert_eq!(record.nested.one, 1); - - update_compressed_account( - &mut rpc, - NestedData { - one: 2, - two: 3, - three: 3, - four: 4, - five: 5, - six: 6, - seven: 7, - eight: 8, - nine: 9, - ten: 10, - eleven: 11, - twelve: 12, - }, - &payer, - compressed_account, - ) - .await - .unwrap(); - - // Check that it was updated correctly. - let compressed_accounts = - rpc.get_compressed_accounts_with_merkle_context_by_owner(&sdk_anchor_test::ID); - assert_eq!(compressed_accounts.len(), 1); - let compressed_account = &compressed_accounts[0]; - let record = &compressed_account - .compressed_account - .data - .as_ref() - .unwrap() - .data; - let record = MyCompressedAccount::deserialize(&mut &record[..]).unwrap(); - assert_eq!(record.nested.one, 2); -} - -async fn create_compressed_account( - name: String, - rpc: &mut LightProgramTest, - payer: &Keypair, - address: &[u8; 32], -) -> Result { - let config = SystemAccountMetaConfig::new(sdk_anchor_test::ID); - let mut remaining_accounts = PackedAccounts::default(); - remaining_accounts.add_system_accounts(config); - - let address_merkle_tree_info = rpc.get_address_tree_v1(); - - let rpc_result = rpc - .get_validity_proof( - vec![], - vec![AddressWithTree { - address: *address, - tree: address_merkle_tree_info.tree, - }], - None, - ) - .await? - .value; - let packed_accounts = rpc_result.pack_tree_infos(&mut remaining_accounts); - - let output_tree_index = rpc - .get_random_state_tree_info() - .unwrap() - .pack_output_tree_index(&mut remaining_accounts) - .unwrap(); - - let (remaining_accounts, _, _) = remaining_accounts.to_account_metas(); - - let instruction = Instruction { - program_id: sdk_anchor_test::ID, - accounts: [ - vec![AccountMeta::new(payer.pubkey(), true)], - remaining_accounts, - ] - .concat(), - data: { - use anchor_lang::InstructionData; - sdk_anchor_test::instruction::CreateCompressedAccount { - proof: rpc_result.proof, - address_tree_info: packed_accounts.address_trees[0], - output_tree_index, - name, - } - .data() - }, - }; - - rpc.create_and_send_transaction(&[instruction], &payer.pubkey(), &[payer]) - .await -} - -async fn update_compressed_account( - rpc: &mut LightProgramTest, - nested_data: NestedData, - payer: &Keypair, - mut compressed_account: CompressedAccount, -) -> Result { - let mut remaining_accounts = PackedAccounts::default(); - - let config = SystemAccountMetaConfig::new(sdk_anchor_test::ID); - remaining_accounts.add_system_accounts(config); - let hash = compressed_account.hash; - - let rpc_result = rpc - .get_validity_proof(vec![hash], vec![], None) - .await? - .value; - - let packed_tree_accounts = rpc_result - .pack_tree_infos(&mut remaining_accounts) - .state_trees - .unwrap(); - - let (remaining_accounts, _, _) = remaining_accounts.to_account_metas(); - - let my_compressed_account = MyCompressedAccount::deserialize( - &mut compressed_account.data.as_mut().unwrap().data.as_slice(), - ) - .unwrap(); - let instruction = Instruction { - program_id: sdk_anchor_test::ID, - accounts: [ - vec![AccountMeta::new(payer.pubkey(), true)], - remaining_accounts, - ] - .concat(), - data: { - use anchor_lang::InstructionData; - sdk_anchor_test::instruction::UpdateCompressedAccount { - proof: rpc_result.proof, - my_compressed_account, - account_meta: CompressedAccountMeta { - tree_info: packed_tree_accounts.packed_tree_infos[0], - address: compressed_account.address.unwrap(), - output_state_tree_index: packed_tree_accounts.output_tree_index, - }, - nested_data, - } - .data() - }, - }; - - rpc.create_and_send_transaction(&[instruction], &payer.pubkey(), &[payer]) - .await -} diff --git a/program-tests/sdk-anchor-test/tsconfig.json b/program-tests/sdk-anchor-test/tsconfig.json deleted file mode 100644 index cd5d2e3d06..0000000000 --- a/program-tests/sdk-anchor-test/tsconfig.json +++ /dev/null @@ -1,10 +0,0 @@ -{ - "compilerOptions": { - "types": ["mocha", "chai"], - "typeRoots": ["./node_modules/@types"], - "lib": ["es2015"], - "module": "commonjs", - "target": "es6", - "esModuleInterop": true - } -} diff --git a/program-tests/sdk-test/Cargo.toml b/program-tests/sdk-test/Cargo.toml deleted file mode 100644 index 6929b36a55..0000000000 --- a/program-tests/sdk-test/Cargo.toml +++ /dev/null @@ -1,40 +0,0 @@ -[package] -name = "sdk-test" -version = "1.0.0" -description = "Test program using generalized account compression" -repository = "https://github.com/Lightprotocol/light-protocol" -license = "Apache-2.0" -edition = "2021" - -[lib] -crate-type = ["cdylib", "lib"] -name = "sdk_test" - -[features] -no-entrypoint = [] -no-idl = [] -no-log-ix-name = [] -cpi = ["no-entrypoint"] -test-sbf = [] -default = [] - -[dependencies] -light-sdk = { workspace = true } -light-sdk-types = { workspace = true } -light-hasher = { workspace = true, features = ["solana"] } -solana-program = { workspace = true } -light-macros = { workspace = true, features = ["solana"] } -borsh = { workspace = true } -light-compressed-account = { workspace = true, features = ["solana"] } - -[dev-dependencies] -light-program-test = { workspace = true, features = ["devenv"] } -tokio = { workspace = true } -solana-sdk = { workspace = true } - -[lints.rust.unexpected_cfgs] -level = "allow" -check-cfg = [ - 'cfg(target_os, values("solana"))', - 'cfg(feature, values("frozen-abi", "no-entrypoint"))', -] diff --git a/program-tests/sdk-test/Xargo.toml b/program-tests/sdk-test/Xargo.toml deleted file mode 100644 index 475fb71ed1..0000000000 --- a/program-tests/sdk-test/Xargo.toml +++ /dev/null @@ -1,2 +0,0 @@ -[target.bpfel-unknown-unknown.dependencies.std] -features = [] diff --git a/program-tests/sdk-test/src/create_pda.rs b/program-tests/sdk-test/src/create_pda.rs deleted file mode 100644 index 95a7293589..0000000000 --- a/program-tests/sdk-test/src/create_pda.rs +++ /dev/null @@ -1,87 +0,0 @@ -use borsh::{BorshDeserialize, BorshSerialize}; -use light_sdk::{ - account::LightAccount, - cpi::{CpiAccounts, CpiAccountsConfig, CpiInputs}, - error::LightSdkError, - instruction::{PackedAddressTreeInfo, ValidityProof}, - light_hasher::hash_to_field_size::hashv_to_bn254_field_size_be_const_array, - LightDiscriminator, LightHasher, -}; -use solana_program::account_info::AccountInfo; - -/// TODO: write test program with A8JgviaEAByMVLBhcebpDQ7NMuZpqBTBigC1b83imEsd (inconvenient program id) -/// CU usage: -/// - sdk pre system program cpi 10,942 CU -/// - total with V2 tree: 45,758 CU -pub fn create_pda( - accounts: &[AccountInfo], - instruction_data: &[u8], -) -> Result<(), LightSdkError> { - let mut instruction_data = instruction_data; - let instruction_data = CreatePdaInstructionData::deserialize(&mut instruction_data) - .map_err(|_| LightSdkError::Borsh)?; - let config = CpiAccountsConfig::new(crate::LIGHT_CPI_SIGNER); - let cpi_accounts = CpiAccounts::try_new_with_config( - &accounts[0], - &accounts[instruction_data.system_accounts_offset as usize..], - config, - ) - .unwrap(); - - let address_tree_info = instruction_data.address_tree_info; - let (address, address_seed) = if BATCHED { - let address_seed = hashv_to_bn254_field_size_be_const_array::<3>(&[ - b"compressed", - instruction_data.data.as_slice(), - ]) - .unwrap(); - // to_bytes will go away as soon as we have a light_sdk::address::v2::derive_address - let address_tree_pubkey = address_tree_info.get_tree_pubkey(&cpi_accounts)?.to_bytes(); - let address = light_compressed_account::address::derive_address( - &address_seed, - &address_tree_pubkey, - &crate::ID.to_bytes(), - ); - (address, address_seed) - } else { - light_sdk::address::v1::derive_address( - &[b"compressed", instruction_data.data.as_slice()], - &address_tree_info.get_tree_pubkey(&cpi_accounts)?, - &crate::ID, - ) - }; - let new_address_params = address_tree_info.into_new_address_params_packed(address_seed); - - let mut my_compressed_account = LightAccount::<'_, MyCompressedAccount>::new_init( - &crate::ID, - Some(address), - instruction_data.output_merkle_tree_index, - ); - - my_compressed_account.data = instruction_data.data; - - let cpi_inputs = CpiInputs::new_with_address( - instruction_data.proof, - vec![my_compressed_account.to_account_info()?], - vec![new_address_params], - ); - cpi_inputs.invoke_light_system_program(cpi_accounts)?; - Ok(()) -} - -#[derive( - Clone, Debug, Default, LightHasher, LightDiscriminator, BorshDeserialize, BorshSerialize, -)] -pub struct MyCompressedAccount { - pub data: [u8; 31], -} - -#[derive(Clone, Debug, Default, BorshDeserialize, BorshSerialize)] -pub struct CreatePdaInstructionData { - pub proof: ValidityProof, - pub address_tree_info: PackedAddressTreeInfo, - pub output_merkle_tree_index: u8, - pub data: [u8; 31], - pub system_accounts_offset: u8, - pub tree_accounts_offset: u8, -} diff --git a/program-tests/sdk-test/src/lib.rs b/program-tests/sdk-test/src/lib.rs deleted file mode 100644 index 8fb2b71b2c..0000000000 --- a/program-tests/sdk-test/src/lib.rs +++ /dev/null @@ -1,49 +0,0 @@ -use light_macros::pubkey; -use light_sdk::{cpi::CpiSigner, derive_light_cpi_signer, error::LightSdkError}; -use solana_program::{ - account_info::AccountInfo, entrypoint, program_error::ProgramError, pubkey::Pubkey, -}; - -pub mod create_pda; -pub mod update_pda; - -pub const ID: Pubkey = pubkey!("FNt7byTHev1k5x2cXZLBr8TdWiC3zoP5vcnZR4P682Uy"); -pub const LIGHT_CPI_SIGNER: CpiSigner = - derive_light_cpi_signer!("FNt7byTHev1k5x2cXZLBr8TdWiC3zoP5vcnZR4P682Uy"); - -entrypoint!(process_instruction); - -#[repr(u8)] -pub enum InstructionType { - CreatePdaBorsh = 0, - UpdatePdaBorsh = 1, -} - -impl TryFrom for InstructionType { - type Error = LightSdkError; - - fn try_from(value: u8) -> Result { - match value { - 0 => Ok(InstructionType::CreatePdaBorsh), - 1 => Ok(InstructionType::UpdatePdaBorsh), - _ => panic!("Invalid instruction discriminator."), - } - } -} - -pub fn process_instruction( - _program_id: &Pubkey, - accounts: &[AccountInfo], - instruction_data: &[u8], -) -> Result<(), ProgramError> { - let discriminator = InstructionType::try_from(instruction_data[0]).unwrap(); - match discriminator { - InstructionType::CreatePdaBorsh => { - create_pda::create_pda::(accounts, &instruction_data[1..]) - } - InstructionType::UpdatePdaBorsh => { - update_pda::update_pda::(accounts, &instruction_data[1..]) - } - }?; - Ok(()) -} diff --git a/program-tests/sdk-test/src/update_pda.rs b/program-tests/sdk-test/src/update_pda.rs deleted file mode 100644 index 2e2fcd4257..0000000000 --- a/program-tests/sdk-test/src/update_pda.rs +++ /dev/null @@ -1,65 +0,0 @@ -use borsh::{BorshDeserialize, BorshSerialize}; -use light_sdk::{ - account::LightAccount, - cpi::{CpiAccounts, CpiAccountsConfig, CpiInputs}, - error::LightSdkError, - instruction::{account_meta::CompressedAccountMeta, ValidityProof}, -}; -use solana_program::{account_info::AccountInfo, log::sol_log_compute_units}; - -use crate::create_pda::MyCompressedAccount; - -/// CU usage: -/// - sdk pre system program 9,183k CU -/// - total with V2 tree: 50,194 CU (proof by index) -/// - 51,609 -pub fn update_pda( - accounts: &[AccountInfo], - instruction_data: &[u8], -) -> Result<(), LightSdkError> { - sol_log_compute_units(); - let mut instruction_data = instruction_data; - let instruction_data = UpdatePdaInstructionData::deserialize(&mut instruction_data) - .map_err(|_| LightSdkError::Borsh)?; - - let mut my_compressed_account = LightAccount::<'_, MyCompressedAccount>::new_mut( - &crate::ID, - &instruction_data.my_compressed_account.meta, - MyCompressedAccount { - data: instruction_data.my_compressed_account.data, - }, - )?; - sol_log_compute_units(); - - my_compressed_account.data = instruction_data.new_data; - - let config = CpiAccountsConfig::new(crate::LIGHT_CPI_SIGNER); - sol_log_compute_units(); - let cpi_accounts = CpiAccounts::try_new_with_config( - &accounts[0], - &accounts[instruction_data.system_accounts_offset as usize..], - config, - )?; - sol_log_compute_units(); - let cpi_inputs = CpiInputs::new( - instruction_data.proof, - vec![my_compressed_account.to_account_info()?], - ); - sol_log_compute_units(); - cpi_inputs.invoke_light_system_program(cpi_accounts)?; - Ok(()) -} - -#[derive(Clone, Debug, Default, BorshDeserialize, BorshSerialize)] -pub struct UpdatePdaInstructionData { - pub proof: ValidityProof, - pub my_compressed_account: UpdateMyCompressedAccount, - pub new_data: [u8; 31], - pub system_accounts_offset: u8, -} - -#[derive(Clone, Debug, Default, BorshDeserialize, BorshSerialize)] -pub struct UpdateMyCompressedAccount { - pub meta: CompressedAccountMeta, - pub data: [u8; 31], -} diff --git a/program-tests/sdk-test/tests/test.rs b/program-tests/sdk-test/tests/test.rs deleted file mode 100644 index 5008995923..0000000000 --- a/program-tests/sdk-test/tests/test.rs +++ /dev/null @@ -1,177 +0,0 @@ -#![cfg(feature = "test-sbf")] - -use borsh::BorshSerialize; -use light_compressed_account::{ - address::derive_address, compressed_account::CompressedAccountWithMerkleContext, - hashv_to_bn254_field_size_be, -}; -use light_program_test::{ - program_test::LightProgramTest, AddressWithTree, Indexer, ProgramTestConfig, Rpc, RpcError, -}; -use light_sdk::instruction::{ - account_meta::CompressedAccountMeta, PackedAccounts, SystemAccountMetaConfig, -}; -use sdk_test::{ - create_pda::CreatePdaInstructionData, - update_pda::{UpdateMyCompressedAccount, UpdatePdaInstructionData}, -}; -use solana_sdk::{ - instruction::Instruction, - pubkey::Pubkey, - signature::{Keypair, Signer}, -}; - -#[tokio::test] -async fn test_sdk_test() { - let config = ProgramTestConfig::new_v2(true, Some(vec![("sdk_test", sdk_test::ID)])); - let mut rpc = LightProgramTest::new(config).await.unwrap(); - let payer = rpc.get_payer().insecure_clone(); - - let address_tree_pubkey = rpc.get_address_merkle_tree_v2(); - let account_data = [1u8; 31]; - - // // V1 trees - // let (address, _) = light_sdk::address::derive_address( - // &[b"compressed", &account_data], - // &address_tree_info, - // &sdk_test::ID, - // ); - // Batched trees - let address_seed = hashv_to_bn254_field_size_be(&[b"compressed", account_data.as_slice()]); - let address = derive_address( - &address_seed, - &address_tree_pubkey.to_bytes(), - &sdk_test::ID.to_bytes(), - ); - let ouput_queue = rpc.get_random_state_tree_info().unwrap().queue; - create_pda( - &payer, - &mut rpc, - &ouput_queue, - account_data, - address_tree_pubkey, - address, - ) - .await - .unwrap(); - - let compressed_pda = rpc - .indexer() - .unwrap() - .get_compressed_account(address, None) - .await - .unwrap() - .value - .clone(); - assert_eq!(compressed_pda.address.unwrap(), address); - - update_pda(&payer, &mut rpc, [2u8; 31], compressed_pda.into()) - .await - .unwrap(); -} - -pub async fn create_pda( - payer: &Keypair, - rpc: &mut LightProgramTest, - merkle_tree_pubkey: &Pubkey, - account_data: [u8; 31], - address_tree_pubkey: Pubkey, - address: [u8; 32], -) -> Result<(), RpcError> { - let system_account_meta_config = SystemAccountMetaConfig::new(sdk_test::ID); - let mut accounts = PackedAccounts::default(); - accounts.add_pre_accounts_signer(payer.pubkey()); - accounts.add_system_accounts(system_account_meta_config); - - let rpc_result = rpc - .get_validity_proof( - vec![], - vec![AddressWithTree { - address, - tree: address_tree_pubkey, - }], - None, - ) - .await? - .value; - - let output_merkle_tree_index = accounts.insert_or_get(*merkle_tree_pubkey); - let packed_address_tree_info = rpc_result.pack_tree_infos(&mut accounts).address_trees[0]; - let (accounts, system_accounts_offset, tree_accounts_offset) = accounts.to_account_metas(); - - let instruction_data = CreatePdaInstructionData { - proof: rpc_result.proof.0.unwrap().into(), - address_tree_info: packed_address_tree_info, - data: account_data, - output_merkle_tree_index, - system_accounts_offset: system_accounts_offset as u8, - tree_accounts_offset: tree_accounts_offset as u8, - }; - let inputs = instruction_data.try_to_vec().unwrap(); - - let instruction = Instruction { - program_id: sdk_test::ID, - accounts, - data: [&[0u8][..], &inputs[..]].concat(), - }; - - rpc.create_and_send_transaction(&[instruction], &payer.pubkey(), &[payer]) - .await?; - Ok(()) -} - -pub async fn update_pda( - payer: &Keypair, - rpc: &mut LightProgramTest, - new_account_data: [u8; 31], - compressed_account: CompressedAccountWithMerkleContext, -) -> Result<(), RpcError> { - let system_account_meta_config = SystemAccountMetaConfig::new(sdk_test::ID); - let mut accounts = PackedAccounts::default(); - accounts.add_pre_accounts_signer(payer.pubkey()); - accounts.add_system_accounts(system_account_meta_config); - - let rpc_result = rpc - .get_validity_proof(vec![compressed_account.hash().unwrap()], vec![], None) - .await? - .value; - - let packed_accounts = rpc_result - .pack_tree_infos(&mut accounts) - .state_trees - .unwrap(); - - let meta = CompressedAccountMeta { - tree_info: packed_accounts.packed_tree_infos[0], - address: compressed_account.compressed_account.address.unwrap(), - output_state_tree_index: packed_accounts.output_tree_index, - }; - - let (accounts, system_accounts_offset, _) = accounts.to_account_metas(); - let instruction_data = UpdatePdaInstructionData { - my_compressed_account: UpdateMyCompressedAccount { - meta, - data: compressed_account - .compressed_account - .data - .unwrap() - .data - .try_into() - .unwrap(), - }, - proof: rpc_result.proof, - new_data: new_account_data, - system_accounts_offset: system_accounts_offset as u8, - }; - let inputs = instruction_data.try_to_vec().unwrap(); - - let instruction = Instruction { - program_id: sdk_test::ID, - accounts, - data: [&[1u8][..], &inputs[..]].concat(), - }; - - rpc.create_and_send_transaction(&[instruction], &payer.pubkey(), &[payer]) - .await?; - Ok(()) -} diff --git a/sdk-tests/sdk-anchor-test/package.json b/sdk-tests/sdk-anchor-test/package.json index 665fce3d8c..a248fd9fff 100644 --- a/sdk-tests/sdk-anchor-test/package.json +++ b/sdk-tests/sdk-anchor-test/package.json @@ -7,14 +7,13 @@ }, "devDependencies": { "@lightprotocol/zk-compression-cli": "workspace:*", - "chai": "^5.2.0", "mocha": "^11.7.1", "ts-mocha": "^11.1.0", "@types/bn.js": "^5.2.0", "@types/chai": "^5.2.2", "@types/mocha": "^10.0.10", - "typescript": "^5.8.3", + "typescript": "^5.9.2", "prettier": "^3.6.2" } } diff --git a/sdk-tests/sdk-test/src/create_pda.rs b/sdk-tests/sdk-test/src/create_pda.rs index 3dac15deab..27f3ba12a5 100644 --- a/sdk-tests/sdk-test/src/create_pda.rs +++ b/sdk-tests/sdk-test/src/create_pda.rs @@ -1,4 +1,3 @@ -use crate::ARRAY_LEN; use borsh::{BorshDeserialize, BorshSerialize}; use light_sdk::{ account::LightAccount, @@ -8,9 +7,9 @@ use light_sdk::{ light_hasher::hash_to_field_size::hashv_to_bn254_field_size_be_const_array, LightDiscriminator, LightHasher, }; +use solana_program::{account_info::AccountInfo, msg}; -use solana_program::account_info::AccountInfo; -use solana_program::msg; +use crate::ARRAY_LEN; /// TODO: write test program with A8JgviaEAByMVLBhcebpDQ7NMuZpqBTBigC1b83imEsd (inconvenient program id) /// CU usage: