From 1b51dedbf19e5b1f5a385ab07c1a96d09311c818 Mon Sep 17 00:00:00 2001 From: Sergey Timoshin Date: Sat, 14 Mar 2026 16:32:06 +0000 Subject: [PATCH 01/23] feat: optimize address batch pipeline --- .../utils/src/test_batch_forester.rs | 4 +++- .../program-test/src/indexer/test_indexer.rs | 20 ++++++++++++------- 2 files changed, 16 insertions(+), 8 deletions(-) diff --git a/program-tests/utils/src/test_batch_forester.rs b/program-tests/utils/src/test_batch_forester.rs index a28efa9ca3..0952a7fd76 100644 --- a/program-tests/utils/src/test_batch_forester.rs +++ b/program-tests/utils/src/test_batch_forester.rs @@ -165,7 +165,9 @@ pub async fn create_append_batch_ix_data( bundle.merkle_tree.root() ); let proof_client = ProofClient::local(); - let inputs_json = BatchAppendInputsJson::from_inputs(&circuit_inputs).to_string(); + let inputs_json = BatchAppendInputsJson::from_inputs(&circuit_inputs) + .to_string() + ; match proof_client.generate_proof(inputs_json).await { Ok(compressed_proof) => ( diff --git a/sdk-libs/program-test/src/indexer/test_indexer.rs b/sdk-libs/program-test/src/indexer/test_indexer.rs index c51298b9cd..15401eebf7 100644 --- a/sdk-libs/program-test/src/indexer/test_indexer.rs +++ b/sdk-libs/program-test/src/indexer/test_indexer.rs @@ -2172,18 +2172,20 @@ impl TestIndexer { let inclusion_proof_inputs = InclusionProofInputs::new(inclusion_proofs.as_slice()).unwrap(); ( - Some(BatchInclusionJsonStruct::from_inclusion_proof_inputs( - &inclusion_proof_inputs, - )), + Some( + BatchInclusionJsonStruct::from_inclusion_proof_inputs(&inclusion_proof_inputs), + ), None, ) } else if height == STATE_MERKLE_TREE_HEIGHT as usize { let inclusion_proof_inputs = InclusionProofInputsLegacy(inclusion_proofs.as_slice()); ( None, - Some(BatchInclusionJsonStructLegacy::from_inclusion_proof_inputs( - &inclusion_proof_inputs, - )), + Some( + BatchInclusionJsonStructLegacy::from_inclusion_proof_inputs( + &inclusion_proof_inputs, + ), + ), ) } else { return Err(IndexerError::CustomError( @@ -2360,7 +2362,11 @@ impl TestIndexer { if let Some(payload) = payload { (indices, Vec::new(), payload.to_string()) } else { - (indices, Vec::new(), payload_legacy.unwrap().to_string()) + ( + indices, + Vec::new(), + payload_legacy.unwrap().to_string(), + ) } } (None, Some(addresses)) => { From 208ade3b75c7ea11eb40a5daaf63b36a99d42ec2 Mon Sep 17 00:00:00 2001 From: Sergey Timoshin Date: Sat, 14 Mar 2026 19:30:35 +0000 Subject: [PATCH 02/23] format --- .../utils/src/test_batch_forester.rs | 4 +--- .../program-test/src/indexer/test_indexer.rs | 20 +++++++------------ .../tests/integration_tests.rs | 2 +- 3 files changed, 9 insertions(+), 17 deletions(-) diff --git a/program-tests/utils/src/test_batch_forester.rs b/program-tests/utils/src/test_batch_forester.rs index 0952a7fd76..a28efa9ca3 100644 --- a/program-tests/utils/src/test_batch_forester.rs +++ b/program-tests/utils/src/test_batch_forester.rs @@ -165,9 +165,7 @@ pub async fn create_append_batch_ix_data( bundle.merkle_tree.root() ); let proof_client = ProofClient::local(); - let inputs_json = BatchAppendInputsJson::from_inputs(&circuit_inputs) - .to_string() - ; + let inputs_json = BatchAppendInputsJson::from_inputs(&circuit_inputs).to_string(); match proof_client.generate_proof(inputs_json).await { Ok(compressed_proof) => ( diff --git a/sdk-libs/program-test/src/indexer/test_indexer.rs b/sdk-libs/program-test/src/indexer/test_indexer.rs index 15401eebf7..c51298b9cd 100644 --- a/sdk-libs/program-test/src/indexer/test_indexer.rs +++ b/sdk-libs/program-test/src/indexer/test_indexer.rs @@ -2172,20 +2172,18 @@ impl TestIndexer { let inclusion_proof_inputs = InclusionProofInputs::new(inclusion_proofs.as_slice()).unwrap(); ( - Some( - BatchInclusionJsonStruct::from_inclusion_proof_inputs(&inclusion_proof_inputs), - ), + Some(BatchInclusionJsonStruct::from_inclusion_proof_inputs( + &inclusion_proof_inputs, + )), None, ) } else if height == STATE_MERKLE_TREE_HEIGHT as usize { let inclusion_proof_inputs = InclusionProofInputsLegacy(inclusion_proofs.as_slice()); ( None, - Some( - BatchInclusionJsonStructLegacy::from_inclusion_proof_inputs( - &inclusion_proof_inputs, - ), - ), + Some(BatchInclusionJsonStructLegacy::from_inclusion_proof_inputs( + &inclusion_proof_inputs, + )), ) } else { return Err(IndexerError::CustomError( @@ -2362,11 +2360,7 @@ impl TestIndexer { if let Some(payload) = payload { (indices, Vec::new(), payload.to_string()) } else { - ( - indices, - Vec::new(), - payload_legacy.unwrap().to_string(), - ) + (indices, Vec::new(), payload_legacy.unwrap().to_string()) } } (None, Some(addresses)) => { diff --git a/sdk-tests/csdk-anchor-full-derived-test/tests/integration_tests.rs b/sdk-tests/csdk-anchor-full-derived-test/tests/integration_tests.rs index 9b40b900e5..2c3e82972a 100644 --- a/sdk-tests/csdk-anchor-full-derived-test/tests/integration_tests.rs +++ b/sdk-tests/csdk-anchor-full-derived-test/tests/integration_tests.rs @@ -3863,7 +3863,7 @@ async fn test_d9_edge_many_literals() { #[tokio::test] async fn test_d9_edge_mixed() { use csdk_anchor_full_derived_test::d9_seeds::{ - edge_cases::{AB, SEED_123, _UNDERSCORE_CONST}, + edge_cases::{_UNDERSCORE_CONST, AB, SEED_123}, D9EdgeMixedParams, }; From 57e4d497088abe07e511da4b3a11823eae6a2099 Mon Sep 17 00:00:00 2001 From: Sergey Timoshin Date: Sat, 14 Mar 2026 19:42:28 +0000 Subject: [PATCH 03/23] feat: stabilize address batch pipeline --- .../csdk-anchor-full-derived-test/tests/integration_tests.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sdk-tests/csdk-anchor-full-derived-test/tests/integration_tests.rs b/sdk-tests/csdk-anchor-full-derived-test/tests/integration_tests.rs index 2c3e82972a..9b40b900e5 100644 --- a/sdk-tests/csdk-anchor-full-derived-test/tests/integration_tests.rs +++ b/sdk-tests/csdk-anchor-full-derived-test/tests/integration_tests.rs @@ -3863,7 +3863,7 @@ async fn test_d9_edge_many_literals() { #[tokio::test] async fn test_d9_edge_mixed() { use csdk_anchor_full_derived_test::d9_seeds::{ - edge_cases::{_UNDERSCORE_CONST, AB, SEED_123}, + edge_cases::{AB, SEED_123, _UNDERSCORE_CONST}, D9EdgeMixedParams, }; From a8f93dcf1943c60deb29ff5e155c7a8ca7fd6164 Mon Sep 17 00:00:00 2001 From: Sergey Timoshin Date: Sat, 14 Mar 2026 16:32:39 +0000 Subject: [PATCH 04/23] feat: batch cold account loads in light client --- sdk-libs/client/src/indexer/photon_indexer.rs | 21 ++- sdk-libs/client/src/indexer/types/queue.rs | 26 +++- .../client/src/interface/load_accounts.rs | 125 +++++++++++++----- 3 files changed, 123 insertions(+), 49 deletions(-) diff --git a/sdk-libs/client/src/indexer/photon_indexer.rs b/sdk-libs/client/src/indexer/photon_indexer.rs index 26d16ae235..5698719c8f 100644 --- a/sdk-libs/client/src/indexer/photon_indexer.rs +++ b/sdk-libs/client/src/indexer/photon_indexer.rs @@ -1142,17 +1142,16 @@ impl Indexer for PhotonIndexer { .value .iter() .map(|x| { - let mut proof_vec = x.proof.clone(); - if proof_vec.len() < STATE_MERKLE_TREE_CANOPY_DEPTH { + if x.proof.len() < STATE_MERKLE_TREE_CANOPY_DEPTH { return Err(IndexerError::InvalidParameters(format!( "Merkle proof length ({}) is less than canopy depth ({})", - proof_vec.len(), + x.proof.len(), STATE_MERKLE_TREE_CANOPY_DEPTH, ))); } - proof_vec.truncate(proof_vec.len() - STATE_MERKLE_TREE_CANOPY_DEPTH); + let proof_len = x.proof.len() - STATE_MERKLE_TREE_CANOPY_DEPTH; - let proof = proof_vec + let proof = x.proof[..proof_len] .iter() .map(|s| Hash::from_base58(s)) .collect::, IndexerError>>() @@ -1703,15 +1702,13 @@ impl Indexer for PhotonIndexer { async fn get_subtrees( &self, - _merkle_tree_pubkey: [u8; 32], + merkle_tree_pubkey: [u8; 32], _config: Option, ) -> Result>, IndexerError> { - #[cfg(not(feature = "v2"))] - unimplemented!(); - #[cfg(feature = "v2")] - { - todo!(); - } + Err(IndexerError::NotImplemented(format!( + "PhotonIndexer::get_subtrees is not implemented for merkle tree {}", + solana_pubkey::Pubkey::new_from_array(merkle_tree_pubkey) + ))) } } diff --git a/sdk-libs/client/src/indexer/types/queue.rs b/sdk-libs/client/src/indexer/types/queue.rs index a52fd71d04..bdecce1b40 100644 --- a/sdk-libs/client/src/indexer/types/queue.rs +++ b/sdk-libs/client/src/indexer/types/queue.rs @@ -81,6 +81,7 @@ impl AddressQueueData { &self, address_range: std::ops::Range, ) -> Result, IndexerError> { + self.validate_proof_height::()?; let node_lookup = self.build_node_lookup(); let mut proofs = Vec::with_capacity(address_range.len()); @@ -95,16 +96,16 @@ impl AddressQueueData { pub fn reconstruct_all_proofs( &self, ) -> Result, IndexerError> { + self.validate_proof_height::()?; self.reconstruct_proofs::(0..self.addresses.len()) } fn build_node_lookup(&self) -> HashMap { - self.nodes - .iter() - .copied() - .enumerate() - .map(|(idx, node)| (node, idx)) - .collect() + let mut lookup = HashMap::with_capacity(self.nodes.len()); + for (idx, node) in self.nodes.iter().copied().enumerate() { + lookup.entry(node).or_insert(idx); + } + lookup } fn reconstruct_proof_with_lookup( @@ -112,6 +113,7 @@ impl AddressQueueData { address_idx: usize, node_lookup: &HashMap, ) -> Result<[[u8; 32]; HEIGHT], IndexerError> { + self.validate_proof_height::()?; let leaf_index = *self.low_element_indices.get(address_idx).ok_or_else(|| { IndexerError::MissingResult { context: "reconstruct_proof".to_string(), @@ -164,6 +166,18 @@ impl AddressQueueData { fn encode_node_index(level: usize, position: u64) -> u64 { ((level as u64) << 56) | position } + + fn validate_proof_height(&self) -> Result<(), IndexerError> { + if HEIGHT == Self::ADDRESS_TREE_HEIGHT { + return Ok(()); + } + + Err(IndexerError::InvalidParameters(format!( + "address queue proofs require HEIGHT={} but got HEIGHT={}", + Self::ADDRESS_TREE_HEIGHT, + HEIGHT + ))) + } } #[cfg(test)] diff --git a/sdk-libs/client/src/interface/load_accounts.rs b/sdk-libs/client/src/interface/load_accounts.rs index 061ad5074b..c70088dd40 100644 --- a/sdk-libs/client/src/interface/load_accounts.rs +++ b/sdk-libs/client/src/interface/load_accounts.rs @@ -53,6 +53,9 @@ pub enum LoadAccountsError { #[error("Cold PDA at index {index} (pubkey {pubkey}) missing data")] MissingPdaCompressed { index: usize, pubkey: Pubkey }, + #[error("Cold PDA (pubkey {pubkey}) missing data")] + MissingPdaCompressedData { pubkey: Pubkey }, + #[error("Cold ATA at index {index} (pubkey {pubkey}) missing data")] MissingAtaCompressed { index: usize, pubkey: Pubkey }, @@ -67,6 +70,7 @@ pub enum LoadAccountsError { } const MAX_ATAS_PER_IX: usize = 8; +const MAX_PDAS_PER_IX: usize = 8; /// Build load instructions for cold accounts. Returns empty vec if all hot. /// @@ -113,14 +117,18 @@ where }) .collect(); - let pda_hashes = collect_pda_hashes(&cold_pdas)?; + let pda_groups = group_pda_specs(&cold_pdas, MAX_PDAS_PER_IX); + let pda_hashes = pda_groups + .iter() + .map(|group| collect_pda_hashes(group)) + .collect::, _>>()?; let ata_hashes = collect_ata_hashes(&cold_atas)?; let mint_hashes = collect_mint_hashes(&cold_mints)?; let (pda_proofs, ata_proofs, mint_proofs) = futures::join!( - fetch_proofs(&pda_hashes, indexer), + fetch_proof_batches(&pda_hashes, indexer), fetch_proofs_batched(&ata_hashes, MAX_ATAS_PER_IX, indexer), - fetch_proofs(&mint_hashes, indexer), + fetch_individual_proofs(&mint_hashes, indexer), ); let pda_proofs = pda_proofs?; @@ -136,9 +144,9 @@ where // 2. DecompressAccountsIdempotent for all cold PDAs (including token PDAs). // Token PDAs are created on-chain via CPI inside DecompressVariant. - for (spec, proof) in cold_pdas.iter().zip(pda_proofs) { + for (group, proof) in pda_groups.into_iter().zip(pda_proofs) { out.push(build_pda_load( - &[spec], + &group, proof, fee_payer, compression_config, @@ -146,8 +154,7 @@ where } // 3. ATA loads (CreateAssociatedTokenAccount + Transfer2) - requires mint to exist - let ata_chunks: Vec<_> = cold_atas.chunks(MAX_ATAS_PER_IX).collect(); - for (chunk, proof) in ata_chunks.into_iter().zip(ata_proofs) { + for (chunk, proof) in cold_atas.chunks(MAX_ATAS_PER_IX).zip(ata_proofs) { out.extend(build_ata_load(chunk, proof, fee_payer)?); } @@ -195,23 +202,77 @@ fn collect_mint_hashes(ifaces: &[&AccountInterface]) -> Result, Lo .collect() } -async fn fetch_proofs( +/// Groups already-ordered PDA specs into contiguous runs of the same program id. +/// +/// This preserves input order rather than globally regrouping by program. Callers that +/// want maximal batching across interleaved program ids should sort before calling. +fn group_pda_specs<'a, V>( + specs: &[&'a PdaSpec], + max_per_group: usize, +) -> Vec>> { + assert!(max_per_group > 0, "max_per_group must be non-zero"); + if specs.is_empty() { + return Vec::new(); + } + + let mut groups = Vec::new(); + let mut current = Vec::with_capacity(max_per_group); + let mut current_program: Option = None; + + for spec in specs { + let program_id = spec.program_id(); + let should_split = current_program + .map(|existing| existing != program_id || current.len() >= max_per_group) + .unwrap_or(false); + + if should_split { + groups.push(current); + current = Vec::with_capacity(max_per_group); + } + + current_program = Some(program_id); + current.push(*spec); + } + + if !current.is_empty() { + groups.push(current); + } + + groups +} + +async fn fetch_individual_proofs( hashes: &[[u8; 32]], indexer: &I, ) -> Result, IndexerError> { if hashes.is_empty() { return Ok(vec![]); } - let mut proofs = Vec::with_capacity(hashes.len()); - for hash in hashes { - proofs.push( - indexer - .get_validity_proof(vec![*hash], vec![], None) - .await? - .value, - ); + + futures::future::try_join_all(hashes.iter().map(|hash| async move { + indexer + .get_validity_proof(vec![*hash], vec![], None) + .await + .map(|response| response.value) + })) + .await +} + +async fn fetch_proof_batches( + hash_batches: &[Vec<[u8; 32]>], + indexer: &I, +) -> Result, IndexerError> { + if hash_batches.is_empty() { + return Ok(vec![]); } - Ok(proofs) + + futures::future::try_join_all(hash_batches.iter().map(|hashes| async move { + indexer + .get_validity_proof(hashes.clone(), vec![], None) + .await + .map(|response| response.value) + })) + .await } async fn fetch_proofs_batched( @@ -222,16 +283,13 @@ async fn fetch_proofs_batched( if hashes.is_empty() { return Ok(vec![]); } - let mut proofs = Vec::with_capacity(hashes.len().div_ceil(batch_size)); - for chunk in hashes.chunks(batch_size) { - proofs.push( - indexer - .get_validity_proof(chunk.to_vec(), vec![], None) - .await? - .value, - ); - } - Ok(proofs) + + let hash_batches = hashes + .chunks(batch_size) + .map(|chunk| chunk.to_vec()) + .collect::>(); + + fetch_proof_batches(&hash_batches, indexer).await } fn build_pda_load( @@ -262,11 +320,16 @@ where let hot_addresses: Vec = specs.iter().map(|s| s.address()).collect(); let cold_accounts: Vec<(CompressedAccount, V)> = specs .iter() - .map(|s| { - let compressed = s.compressed().expect("cold spec must have data").clone(); - (compressed, s.variant.clone()) + .map(|s| -> Result<_, LoadAccountsError> { + let compressed = + s.compressed() + .cloned() + .ok_or(LoadAccountsError::MissingPdaCompressedData { + pubkey: s.address(), + })?; + Ok((compressed, s.variant.clone())) }) - .collect(); + .collect::, _>>()?; let program_id = specs.first().map(|s| s.program_id()).unwrap_or_default(); From 5f63379a5b5bf2da2caa29d40b7a8e37ffe7c627 Mon Sep 17 00:00:00 2001 From: Sergey Timoshin Date: Sun, 15 Mar 2026 14:42:54 +0000 Subject: [PATCH 05/23] fix: harden load batching and mixed decompression --- forester/src/processor/v2/helpers.rs | 29 ++- forester/src/processor/v2/processor.rs | 6 +- forester/src/processor/v2/proof_worker.rs | 18 +- forester/src/processor/v2/strategy/address.rs | 2 +- program-tests/utils/src/e2e_test_env.rs | 3 +- .../utils/src/mock_batched_forester.rs | 9 +- .../utils/src/test_batch_forester.rs | 8 +- prover/client/src/helpers.rs | 4 +- prover/client/src/proof_client.rs | 31 ++- .../batch_address_append/proof_inputs.rs | 22 +- .../proof_types/batch_append/proof_inputs.rs | 2 +- .../proof_types/batch_update/proof_inputs.rs | 2 +- prover/client/src/prover.rs | 200 +++++++++++++++--- prover/client/tests/batch_address_append.rs | 131 ++++++++---- sdk-libs/client/src/indexer/photon_indexer.rs | 19 +- sdk-libs/client/src/indexer/types/queue.rs | 21 ++ .../client/src/interface/load_accounts.rs | 50 +++-- .../program-test/src/indexer/test_indexer.rs | 5 +- .../interface/program/decompression/pda.rs | 11 +- .../program/decompression/processor.rs | 15 +- .../interface/program/decompression/token.rs | 5 +- 21 files changed, 434 insertions(+), 159 deletions(-) diff --git a/forester/src/processor/v2/helpers.rs b/forester/src/processor/v2/helpers.rs index a0f3e3bb5b..a9fa2e290d 100644 --- a/forester/src/processor/v2/helpers.rs +++ b/forester/src/processor/v2/helpers.rs @@ -493,12 +493,29 @@ impl StreamingAddressQueue { hashchain_idx: usize, ) -> crate::Result>> { let available = self.wait_for_batch(end); - if start >= available { + if available < end || start >= end { return Ok(None); } - let actual_end = end.min(available); + let actual_end = end; let data = lock_recover(&self.data, "streaming_address_queue.data"); + for (name, len) in [ + ("addresses", data.addresses.len()), + ("low_element_values", data.low_element_values.len()), + ("low_element_next_values", data.low_element_next_values.len()), + ("low_element_indices", data.low_element_indices.len()), + ("low_element_next_indices", data.low_element_next_indices.len()), + ] { + if len < actual_end { + return Err(anyhow!( + "incomplete batch data: {} len {} < required end {}", + name, + len, + actual_end + )); + } + } + let addresses = data.addresses[start..actual_end].to_vec(); if addresses.is_empty() { return Err(anyhow!("Empty batch at start={}", start)); @@ -528,7 +545,9 @@ impl StreamingAddressQueue { low_element_next_values: data.low_element_next_values[start..actual_end].to_vec(), low_element_indices: data.low_element_indices[start..actual_end].to_vec(), low_element_next_indices: data.low_element_next_indices[start..actual_end].to_vec(), - low_element_proofs: data.reconstruct_proofs::(start..actual_end)?, + low_element_proofs: data.reconstruct_proofs::(start..actual_end).map_err( + |error| anyhow!("incomplete batch data: failed to reconstruct proofs: {error}"), + )?, addresses, leaves_hashchain, })) @@ -566,6 +585,10 @@ impl StreamingAddressQueue { lock_recover(&self.data, "streaming_address_queue.data").start_index } + pub fn tree_next_insertion_index(&self) -> u64 { + lock_recover(&self.data, "streaming_address_queue.data").tree_next_insertion_index + } + pub fn subtrees(&self) -> Vec<[u8; 32]> { lock_recover(&self.data, "streaming_address_queue.data") .subtrees diff --git a/forester/src/processor/v2/processor.rs b/forester/src/processor/v2/processor.rs index 3de6dea860..372a800e0e 100644 --- a/forester/src/processor/v2/processor.rs +++ b/forester/src/processor/v2/processor.rs @@ -132,7 +132,7 @@ where } if self.worker_pool.is_none() { - let job_tx = spawn_proof_workers(&self.context.prover_config); + let job_tx = spawn_proof_workers(&self.context.prover_config)?; self.worker_pool = Some(WorkerPool { job_tx }); } @@ -532,7 +532,7 @@ where ((queue_size / self.zkp_batch_size) as usize).min(self.context.max_batches_per_tree); if self.worker_pool.is_none() { - let job_tx = spawn_proof_workers(&self.context.prover_config); + let job_tx = spawn_proof_workers(&self.context.prover_config)?; self.worker_pool = Some(WorkerPool { job_tx }); } @@ -561,7 +561,7 @@ where let max_batches = max_batches.min(self.context.max_batches_per_tree); if self.worker_pool.is_none() { - let job_tx = spawn_proof_workers(&self.context.prover_config); + let job_tx = spawn_proof_workers(&self.context.prover_config)?; self.worker_pool = Some(WorkerPool { job_tx }); } diff --git a/forester/src/processor/v2/proof_worker.rs b/forester/src/processor/v2/proof_worker.rs index b7afeacf0b..ded9fcedc8 100644 --- a/forester/src/processor/v2/proof_worker.rs +++ b/forester/src/processor/v2/proof_worker.rs @@ -132,27 +132,27 @@ struct ProofClients { } impl ProofClients { - fn new(config: &ProverConfig) -> Self { - Self { + fn new(config: &ProverConfig) -> crate::Result { + Ok(Self { append_client: ProofClient::with_config( config.append_url.clone(), config.polling_interval, config.max_wait_time, config.api_key.clone(), - ), + )?, nullify_client: ProofClient::with_config( config.update_url.clone(), config.polling_interval, config.max_wait_time, config.api_key.clone(), - ), + )?, address_append_client: ProofClient::with_config( config.address_append_url.clone(), config.polling_interval, config.max_wait_time, config.api_key.clone(), - ), - } + )?, + }) } fn get_client(&self, input: &ProofInput) -> &ProofClient { @@ -164,11 +164,11 @@ impl ProofClients { } } -pub fn spawn_proof_workers(config: &ProverConfig) -> async_channel::Sender { +pub fn spawn_proof_workers(config: &ProverConfig) -> crate::Result> { let (job_tx, job_rx) = async_channel::bounded::(256); - let clients = Arc::new(ProofClients::new(config)); + let clients = Arc::new(ProofClients::new(config)?); tokio::spawn(async move { run_proof_pipeline(job_rx, clients).await }); - job_tx + Ok(job_tx) } async fn run_proof_pipeline( diff --git a/forester/src/processor/v2/strategy/address.rs b/forester/src/processor/v2/strategy/address.rs index 51ab05143a..51236c389b 100644 --- a/forester/src/processor/v2/strategy/address.rs +++ b/forester/src/processor/v2/strategy/address.rs @@ -167,7 +167,7 @@ impl TreeStrategy for AddressTreeStrategy { } let initial_root = streaming_queue.initial_root(); - let start_index = streaming_queue.start_index(); + let start_index = streaming_queue.tree_next_insertion_index(); let subtrees_arr: [[u8; 32]; DEFAULT_BATCH_ADDRESS_TREE_HEIGHT as usize] = subtrees.try_into().map_err(|v: Vec<[u8; 32]>| { diff --git a/program-tests/utils/src/e2e_test_env.rs b/program-tests/utils/src/e2e_test_env.rs index 097ae1f9a9..6c9fdb5d5e 100644 --- a/program-tests/utils/src/e2e_test_env.rs +++ b/program-tests/utils/src/e2e_test_env.rs @@ -764,7 +764,8 @@ where // // local_leaves_hash_chain is only used for a test assertion. // let local_nullifier_hash_chain = create_hash_chain_from_array(&addresses); // assert_eq!(leaves_hash_chain, local_nullifier_hash_chain); - let start_index = address_queue.start_index as usize; + let start_index = + address_queue.tree_next_insertion_index as usize; assert!( start_index >= 2, "start index should be greater than 2 else tree is not inited" diff --git a/program-tests/utils/src/mock_batched_forester.rs b/program-tests/utils/src/mock_batched_forester.rs index 0101b235aa..8ea51b7169 100644 --- a/program-tests/utils/src/mock_batched_forester.rs +++ b/program-tests/utils/src/mock_batched_forester.rs @@ -132,7 +132,8 @@ impl MockBatchedForester { assert_eq!(computed_new_root, self.merkle_tree.root()); - let proof_result = match ProofClient::local() + let proof_client = ProofClient::local()?; + let proof_result = match proof_client .generate_batch_append_proof(circuit_inputs) .await { @@ -207,7 +208,8 @@ impl MockBatchedForester { batch_size, &[], )?; - let proof_result = ProofClient::local() + let proof_client = ProofClient::local()?; + let proof_result = proof_client .generate_batch_update_proof(inputs) .await?; let new_root = self.merkle_tree.root(); @@ -318,7 +320,8 @@ impl MockBatchedAddressForester { ))); } }; - let proof_result = match ProofClient::local() + let proof_client = ProofClient::local()?; + let proof_result = match proof_client .generate_batch_address_append_proof(inputs) .await { diff --git a/program-tests/utils/src/test_batch_forester.rs b/program-tests/utils/src/test_batch_forester.rs index a28efa9ca3..8cec32757f 100644 --- a/program-tests/utils/src/test_batch_forester.rs +++ b/program-tests/utils/src/test_batch_forester.rs @@ -164,7 +164,7 @@ pub async fn create_append_batch_ix_data( bigint_to_be_bytes_array::<32>(&circuit_inputs.new_root.to_biguint().unwrap()).unwrap(), bundle.merkle_tree.root() ); - let proof_client = ProofClient::local(); + let proof_client = ProofClient::local().unwrap(); let inputs_json = BatchAppendInputsJson::from_inputs(&circuit_inputs).to_string(); match proof_client.generate_proof(inputs_json).await { @@ -293,7 +293,7 @@ pub async fn get_batched_nullify_ix_data( &[], ) .unwrap(); - let proof_client = ProofClient::local(); + let proof_client = ProofClient::local().unwrap(); let circuit_inputs_new_root = bigint_to_be_bytes_array::<32>(&inputs.new_root.to_biguint().unwrap()).unwrap(); let inputs_json = update_inputs_string(&inputs); @@ -670,7 +670,7 @@ pub async fn create_batch_update_address_tree_instruction_data_with_proof= 1, "start index should be greater than 2 else tree is not inited" @@ -715,7 +715,7 @@ pub async fn create_batch_update_address_tree_instruction_data_with_proof(&inputs.new_root).unwrap(); let inputs_json = to_json(&inputs); diff --git a/prover/client/src/helpers.rs b/prover/client/src/helpers.rs index 98457479e2..9a20b8958e 100644 --- a/prover/client/src/helpers.rs +++ b/prover/client/src/helpers.rs @@ -49,9 +49,9 @@ pub fn bigint_to_u8_32(n: &BigInt) -> Result<[u8; 32], Box( leaf: [u8; 32], path_elements: &[[u8; 32]; HEIGHT], - path_index: u32, + path_index: usize, ) -> Result<([u8; 32], ChangelogEntry), ProverClientError> { - let mut changelog_entry = ChangelogEntry::default_with_index(path_index as usize); + let mut changelog_entry = ChangelogEntry::default_with_index(path_index); let mut current_hash = leaf; let mut current_index = path_index; diff --git a/prover/client/src/proof_client.rs b/prover/client/src/proof_client.rs index 1d557407bd..820c9fe07d 100644 --- a/prover/client/src/proof_client.rs +++ b/prover/client/src/proof_client.rs @@ -6,7 +6,7 @@ use tokio::time::sleep; use tracing::{debug, error, info, trace, warn}; use crate::{ - constants::PROVE_PATH, + constants::{PROVE_PATH, SERVER_ADDRESS}, errors::ProverClientError, proof::{ compress_proof, deserialize_gnark_proof_json, proof_from_json_struct, ProofCompressed, @@ -17,14 +17,13 @@ use crate::{ batch_append::{BatchAppendInputsJson, BatchAppendsCircuitInputs}, batch_update::{update_inputs_string, BatchUpdateCircuitInputs}, }, + prover::build_http_client, }; const MAX_RETRIES: u32 = 10; const BASE_RETRY_DELAY_SECS: u64 = 1; const DEFAULT_POLLING_INTERVAL_MS: u64 = 100; const DEFAULT_MAX_WAIT_TIME_SECS: u64 = 600; -const DEFAULT_LOCAL_SERVER: &str = "http://localhost:3001"; - const INITIAL_POLL_DELAY_SMALL_CIRCUIT_MS: u64 = 200; const INITIAL_POLL_DELAY_LARGE_CIRCUIT_MS: u64 = 200; @@ -68,15 +67,15 @@ pub struct ProofClient { } impl ProofClient { - pub fn local() -> Self { - Self { - client: Client::new(), - server_address: DEFAULT_LOCAL_SERVER.to_string(), + pub fn local() -> Result { + Ok(Self { + client: build_http_client()?, + server_address: SERVER_ADDRESS.to_string(), polling_interval: Duration::from_millis(DEFAULT_POLLING_INTERVAL_MS), max_wait_time: Duration::from_secs(DEFAULT_MAX_WAIT_TIME_SECS), api_key: None, initial_poll_delay: Duration::from_millis(INITIAL_POLL_DELAY_SMALL_CIRCUIT_MS), - } + }) } #[allow(unused)] @@ -85,21 +84,21 @@ impl ProofClient { polling_interval: Duration, max_wait_time: Duration, api_key: Option, - ) -> Self { + ) -> Result { let initial_poll_delay = if api_key.is_some() { Duration::from_millis(INITIAL_POLL_DELAY_LARGE_CIRCUIT_MS) } else { Duration::from_millis(INITIAL_POLL_DELAY_SMALL_CIRCUIT_MS) }; - Self { - client: Client::new(), + Ok(Self { + client: build_http_client()?, server_address, polling_interval, max_wait_time, api_key, initial_poll_delay, - } + }) } #[allow(unused)] @@ -109,15 +108,15 @@ impl ProofClient { max_wait_time: Duration, api_key: Option, initial_poll_delay: Duration, - ) -> Self { - Self { - client: Client::new(), + ) -> Result { + Ok(Self { + client: build_http_client()?, server_address, polling_interval, max_wait_time, api_key, initial_poll_delay, - } + }) } pub async fn submit_proof_async( diff --git a/prover/client/src/proof_types/batch_address_append/proof_inputs.rs b/prover/client/src/proof_types/batch_address_append/proof_inputs.rs index 5b3321427d..3dd7a35c46 100644 --- a/prover/client/src/proof_types/batch_address_append/proof_inputs.rs +++ b/prover/client/src/proof_types/batch_address_append/proof_inputs.rs @@ -221,12 +221,12 @@ pub fn get_batch_address_append_circuit_inputs( } let new_element_values = &new_element_values[..zkp_batch_size]; let mut new_root = [0u8; 32]; - let mut low_element_circuit_merkle_proofs = Vec::with_capacity(new_element_values.len()); - let mut new_element_circuit_merkle_proofs = Vec::with_capacity(new_element_values.len()); - let mut patched_low_element_next_values = Vec::with_capacity(new_element_values.len()); - let mut patched_low_element_next_indices = Vec::with_capacity(new_element_values.len()); - let mut patched_low_element_values = Vec::with_capacity(new_element_values.len()); - let mut patched_low_element_indices = Vec::with_capacity(new_element_values.len()); + let mut low_element_circuit_merkle_proofs = Vec::with_capacity(batch_len); + let mut new_element_circuit_merkle_proofs = Vec::with_capacity(batch_len); + let mut patched_low_element_next_values = Vec::with_capacity(batch_len); + let mut patched_low_element_next_indices = Vec::with_capacity(batch_len); + let mut patched_low_element_values = Vec::with_capacity(batch_len); + let mut patched_low_element_indices = Vec::with_capacity(batch_len); let computed_hashchain = create_hash_chain_from_slice(new_element_values).map_err(|e| { ProverClientError::GenericError(format!("Failed to compute hashchain: {}", e)) @@ -261,7 +261,7 @@ pub fn get_batch_address_append_circuit_inputs( let is_first_batch = indexed_changelog.is_empty(); let mut expected_root_for_low = current_root; - for i in 0..new_element_values.len() { + for i in 0..batch_len { let mut changelog_index = 0; let low_element_index = low_element_indices[i].try_into().map_err(|_| { ProverClientError::IntegerConversion(format!( @@ -342,7 +342,7 @@ pub fn get_batch_address_append_circuit_inputs( let (computed_root, _) = compute_root_from_merkle_proof::( old_low_leaf_hash, &merkle_proof, - low_element.index as u32, + low_element.index, )?; if computed_root != expected_root_for_low { let low_value_bytes = bigint_to_be_bytes_array::<32>(&low_element.value) @@ -383,7 +383,7 @@ pub fn get_batch_address_append_circuit_inputs( compute_root_from_merkle_proof::( new_low_leaf_hash, &merkle_proof, - new_low_element.index as u32, + new_low_element.index, )?; patcher.push_changelog_entry::(changelog, changelog_entry); @@ -424,7 +424,7 @@ pub fn get_batch_address_append_circuit_inputs( let (updated_root, changelog_entry) = compute_root_from_merkle_proof( new_element_leaf_hash, &merkle_proof_array, - current_index as u32, + current_index, )?; if i == 0 && changelog.len() == 1 { @@ -451,7 +451,7 @@ pub fn get_batch_address_append_circuit_inputs( let (root_with_zero, _) = compute_root_from_merkle_proof::( zero_hash, &merkle_proof_array, - current_index as u32, + current_index, )?; if root_with_zero != intermediate_root { tracing::error!( diff --git a/prover/client/src/proof_types/batch_append/proof_inputs.rs b/prover/client/src/proof_types/batch_append/proof_inputs.rs index 7dd578e599..41a6dcfcd6 100644 --- a/prover/client/src/proof_types/batch_append/proof_inputs.rs +++ b/prover/client/src/proof_types/batch_append/proof_inputs.rs @@ -190,7 +190,7 @@ pub fn get_batch_append_inputs( let (updated_root, changelog_entry) = compute_root_from_merkle_proof( final_leaf, &merkle_proof_array, - start_index + i as u32, + start_index as usize + i, )?; new_root = updated_root; changelog.push(changelog_entry); diff --git a/prover/client/src/proof_types/batch_update/proof_inputs.rs b/prover/client/src/proof_types/batch_update/proof_inputs.rs index 7f8c08e0d1..2ada02b92b 100644 --- a/prover/client/src/proof_types/batch_update/proof_inputs.rs +++ b/prover/client/src/proof_types/batch_update/proof_inputs.rs @@ -175,7 +175,7 @@ pub fn get_batch_update_inputs( index_bytes[28..].copy_from_slice(&(*index).to_be_bytes()); let nullifier = Poseidon::hashv(&[leaf, &index_bytes, &tx_hashes[i]]).unwrap(); let (root, changelog_entry) = - compute_root_from_merkle_proof(nullifier, &merkle_proof_array, *index)?; + compute_root_from_merkle_proof(nullifier, &merkle_proof_array, *index as usize)?; new_root = root; changelog.push(changelog_entry); circuit_merkle_proofs.push( diff --git a/prover/client/src/prover.rs b/prover/client/src/prover.rs index 56ae20d98a..5b5cfacc77 100644 --- a/prover/client/src/prover.rs +++ b/prover/client/src/prover.rs @@ -1,19 +1,120 @@ use std::{ - process::Command, + io::{Read, Write}, + net::{TcpStream, ToSocketAddrs}, + process::{Command, Stdio}, sync::atomic::{AtomicBool, Ordering}, - thread::sleep, time::Duration, }; use tracing::info; +use tokio::time::sleep; use crate::{ constants::{HEALTH_CHECK, SERVER_ADDRESS}, + errors::ProverClientError, helpers::get_project_root, }; static IS_LOADING: AtomicBool = AtomicBool::new(false); +pub(crate) fn build_http_client() -> Result { + reqwest::Client::builder() + .no_proxy() + .build() + .map_err(|error| { + ProverClientError::GenericError(format!("failed to build HTTP client: {error}")) + }) +} + +fn health_check_once(timeout: Duration) -> bool { + if prover_listener_present() { + return true; + } + + let endpoint = SERVER_ADDRESS + .strip_prefix("http://") + .or_else(|| SERVER_ADDRESS.strip_prefix("https://")) + .unwrap_or(SERVER_ADDRESS); + let addr = match endpoint.to_socket_addrs().ok().and_then(|mut addrs| addrs.next()) { + Some(addr) => addr, + None => return false, + }; + + let mut stream = match TcpStream::connect_timeout(&addr, timeout) { + Ok(stream) => stream, + Err(error) => { + tracing::debug!(?error, endpoint, "prover health TCP connect failed"); + return health_check_once_with_curl(timeout); + } + }; + + let _ = stream.set_read_timeout(Some(timeout)); + let _ = stream.set_write_timeout(Some(timeout)); + + let host = endpoint.split(':').next().unwrap_or("127.0.0.1"); + let request = + format!("GET {} HTTP/1.1\r\nHost: {}\r\nConnection: close\r\n\r\n", HEALTH_CHECK, host); + if let Err(error) = stream.write_all(request.as_bytes()) { + tracing::debug!(?error, "failed to write prover health request"); + return health_check_once_with_curl(timeout); + } + + let mut response = [0u8; 512]; + let bytes_read = match stream.read(&mut response) { + Ok(bytes_read) => bytes_read, + Err(error) => { + tracing::debug!(?error, "failed to read prover health response"); + return health_check_once_with_curl(timeout); + } + }; + + if bytes_read == 0 { + return false; + } + + let response = std::str::from_utf8(&response[..bytes_read]).unwrap_or_default(); + response.contains("200 OK") + || response.contains("{\"status\":\"ok\"}") + || health_check_once_with_curl(timeout) +} + +fn prover_listener_present() -> bool { + let endpoint = SERVER_ADDRESS + .strip_prefix("http://") + .or_else(|| SERVER_ADDRESS.strip_prefix("https://")) + .unwrap_or(SERVER_ADDRESS); + let port = endpoint.rsplit(':').next().unwrap_or("3001"); + + match Command::new("lsof") + .args(["-nP", &format!("-iTCP:{port}"), "-sTCP:LISTEN"]) + .output() + { + Ok(output) => output.status.success() && !output.stdout.is_empty(), + Err(error) => { + tracing::debug!(?error, "failed to execute lsof prover listener check"); + false + } + } +} + +fn health_check_once_with_curl(timeout: Duration) -> bool { + let timeout_secs = timeout.as_secs().max(1).to_string(); + let url = format!("{}{}", SERVER_ADDRESS, HEALTH_CHECK); + match Command::new("curl") + .args(["-sS", "-m", timeout_secs.as_str(), url.as_str()]) + .output() + { + Ok(output) => { + output.status.success() + && String::from_utf8_lossy(&output.stdout).contains("{\"status\":\"ok\"}") + } + Err(error) => { + tracing::debug!(?error, "failed to execute curl prover health check"); + false + } + } +} + pub async fn spawn_prover() { if let Some(_project_root) = get_project_root() { let prover_path: &str = { @@ -28,48 +129,81 @@ pub async fn spawn_prover() { } }; - if !health_check(10, 1).await && !IS_LOADING.load(Ordering::Relaxed) { - IS_LOADING.store(true, Ordering::Relaxed); + if health_check(10, 1).await { + return; + } + + if IS_LOADING + .compare_exchange(false, true, Ordering::AcqRel, Ordering::Acquire) + .is_err() + { + if health_check(120, 1).await { + return; + } + panic!("Failed to start prover, health check failed."); + } + + let spawn_result = async { + let mut command = Command::new(prover_path); + command.arg("start-prover").stdout(Stdio::piped()).stderr(Stdio::piped()); + let mut child = command.spawn().expect("Failed to start prover process"); + let mut child_exit_status = None; - let command = Command::new(prover_path) - .arg("start-prover") - .spawn() - .expect("Failed to start prover process"); + for _ in 0..120 { + if health_check(1, 1).await { + info!("Prover started successfully"); + return; + } - let _ = command.wait_with_output(); + if child_exit_status.is_none() { + match child.try_wait() { + Ok(Some(status)) => { + tracing::warn!( + ?status, + "prover launcher exited before health check succeeded; continuing to poll for detached prover" + ); + child_exit_status = Some(status); + } + Ok(None) => {} + Err(error) => { + tracing::error!(?error, "failed to poll prover child process"); + } + } + } - let health_result = health_check(120, 1).await; - if health_result { - info!("Prover started successfully"); - } else { - panic!("Failed to start prover, health check failed."); + sleep(Duration::from_secs(1)).await; } + + if let Some(status) = child_exit_status { + panic!( + "Failed to start prover, health check failed after launcher exited with status {status}." + ); + } + + panic!("Failed to start prover, health check failed."); } + .await; + + IS_LOADING.store(false, Ordering::Release); + spawn_result } else { panic!("Failed to find project root."); }; } pub async fn health_check(retries: usize, timeout: usize) -> bool { - let client = match reqwest::Client::builder().no_proxy().build() { - Ok(client) => client, - Err(_) => return false, - }; - let mut result = false; - for _ in 0..retries { - match client - .get(format!("{}{}", SERVER_ADDRESS, HEALTH_CHECK)) - .send() - .await - { - Ok(_) => { - result = true; - break; - } - Err(_) => { - sleep(Duration::from_secs(timeout as u64)); - } + let timeout = Duration::from_secs(timeout as u64); + let retry_delay = timeout; + + for attempt in 0..retries { + if health_check_once(timeout) { + return true; + } + + if attempt + 1 < retries { + sleep(retry_delay).await; } } - result + + false } diff --git a/prover/client/tests/batch_address_append.rs b/prover/client/tests/batch_address_append.rs index ac73c3809e..8a02c363ff 100644 --- a/prover/client/tests/batch_address_append.rs +++ b/prover/client/tests/batch_address_append.rs @@ -26,53 +26,55 @@ async fn prove_batch_address_append() { spawn_prover().await; // Initialize test data - let mut new_element_values = vec![]; - let zkp_batch_size = 10; - for i in 1..zkp_batch_size + 1 { - new_element_values.push(num_bigint::ToBigUint::to_biguint(&i).unwrap()); - } + let total_batch_size = 10usize; + let warmup_batch_size = 1usize; + let prior_value = 999_u32.to_biguint().unwrap(); + let new_element_values = (1..=total_batch_size) + .map(|i| num_bigint::ToBigUint::to_biguint(&i).unwrap()) + .collect::>(); // Initialize indexing structures - let relayer_merkle_tree = + let mut relayer_merkle_tree = IndexedMerkleTree::::new(DEFAULT_BATCH_ADDRESS_TREE_HEIGHT as usize, 0) .unwrap(); - let start_index = relayer_merkle_tree.merkle_tree.rightmost_index; - let current_root = relayer_merkle_tree.root(); + let collect_non_inclusion_data = + |tree: &IndexedMerkleTree, values: &[BigUint]| { + let mut low_element_values = Vec::with_capacity(values.len()); + let mut low_element_indices = Vec::with_capacity(values.len()); + let mut low_element_next_indices = Vec::with_capacity(values.len()); + let mut low_element_next_values = Vec::with_capacity(values.len()); + let mut low_element_proofs: Vec< + [[u8; 32]; DEFAULT_BATCH_ADDRESS_TREE_HEIGHT as usize], + > = Vec::with_capacity(values.len()); - // Prepare proof components - let mut low_element_values = Vec::new(); - let mut low_element_indices = Vec::new(); - let mut low_element_next_indices = Vec::new(); - let mut low_element_next_values = Vec::new(); - let mut low_element_proofs: Vec<[[u8; 32]; DEFAULT_BATCH_ADDRESS_TREE_HEIGHT as usize]> = - Vec::new(); + for new_element_value in values { + let non_inclusion_proof = tree.get_non_inclusion_proof(new_element_value).unwrap(); - // Generate non-inclusion proofs for each element - for new_element_value in &new_element_values { - let non_inclusion_proof = relayer_merkle_tree - .get_non_inclusion_proof(new_element_value) - .unwrap(); + low_element_values.push(non_inclusion_proof.leaf_lower_range_value); + low_element_indices.push(non_inclusion_proof.leaf_index); + low_element_next_indices.push(non_inclusion_proof.next_index); + low_element_next_values.push(non_inclusion_proof.leaf_higher_range_value); + low_element_proofs.push( + non_inclusion_proof + .merkle_proof + .as_slice() + .try_into() + .unwrap(), + ); + } - low_element_values.push(non_inclusion_proof.leaf_lower_range_value); - low_element_indices.push(non_inclusion_proof.leaf_index); - low_element_next_indices.push(non_inclusion_proof.next_index); - low_element_next_values.push(non_inclusion_proof.leaf_higher_range_value); - low_element_proofs.push( - non_inclusion_proof - .merkle_proof - .as_slice() - .try_into() - .unwrap(), - ); - } + ( + low_element_values, + low_element_indices, + low_element_next_indices, + low_element_next_values, + low_element_proofs, + ) + }; - // Convert big integers to byte arrays - let new_element_values = new_element_values - .iter() - .map(|v| bigint_to_be_bytes_array::<32>(v).unwrap()) - .collect::>(); - let hash_chain = create_hash_chain_from_slice(&new_element_values).unwrap(); + let initial_start_index = relayer_merkle_tree.merkle_tree.rightmost_index; + let initial_root = relayer_merkle_tree.root(); let subtrees: [[u8; 32]; DEFAULT_BATCH_ADDRESS_TREE_HEIGHT as usize] = relayer_merkle_tree .merkle_tree @@ -82,7 +84,7 @@ async fn prove_batch_address_append() { let mut sparse_merkle_tree = SparseMerkleTree::< Poseidon, { DEFAULT_BATCH_ADDRESS_TREE_HEIGHT as usize }, - >::new(subtrees, start_index); + >::new(subtrees, initial_start_index); let mut changelog: Vec> = Vec::new(); @@ -90,6 +92,55 @@ async fn prove_batch_address_append() { IndexedChangelogEntry, > = Vec::new(); + let warmup_values = vec![prior_value.clone()]; + let ( + warmup_low_element_values, + warmup_low_element_indices, + warmup_low_element_next_indices, + warmup_low_element_next_values, + warmup_low_element_proofs, + ) = collect_non_inclusion_data(&relayer_merkle_tree, &warmup_values); + let warmup_values = warmup_values + .iter() + .map(|v| bigint_to_be_bytes_array::<32>(v).unwrap()) + .collect::>(); + let warmup_hash_chain = create_hash_chain_from_slice(&warmup_values).unwrap(); + + get_batch_address_append_circuit_inputs::<{ DEFAULT_BATCH_ADDRESS_TREE_HEIGHT as usize }>( + initial_start_index, + initial_root, + &warmup_low_element_values, + &warmup_low_element_next_values, + &warmup_low_element_indices, + &warmup_low_element_next_indices, + &warmup_low_element_proofs, + &warmup_values, + &mut sparse_merkle_tree, + warmup_hash_chain, + warmup_batch_size, + &mut changelog, + &mut indexed_changelog, + ) + .unwrap(); + + relayer_merkle_tree.append(&prior_value).unwrap(); + + let remaining_values = &new_element_values[..]; + let ( + low_element_values, + low_element_indices, + low_element_next_indices, + low_element_next_values, + low_element_proofs, + ) = collect_non_inclusion_data(&relayer_merkle_tree, remaining_values); + let new_element_values = remaining_values + .iter() + .map(|v| bigint_to_be_bytes_array::<32>(v).unwrap()) + .collect::>(); + let hash_chain = create_hash_chain_from_slice(&new_element_values).unwrap(); + let start_index = relayer_merkle_tree.merkle_tree.rightmost_index; + let current_root = relayer_merkle_tree.root(); + let inputs = get_batch_address_append_circuit_inputs::<{ DEFAULT_BATCH_ADDRESS_TREE_HEIGHT as usize }>( start_index, @@ -102,7 +153,7 @@ async fn prove_batch_address_append() { &new_element_values, &mut sparse_merkle_tree, hash_chain, - zkp_batch_size, + total_batch_size, &mut changelog, &mut indexed_changelog, ) diff --git a/sdk-libs/client/src/indexer/photon_indexer.rs b/sdk-libs/client/src/indexer/photon_indexer.rs index 5698719c8f..eb8890d6b7 100644 --- a/sdk-libs/client/src/indexer/photon_indexer.rs +++ b/sdk-libs/client/src/indexer/photon_indexer.rs @@ -2,7 +2,7 @@ use std::{fmt::Debug, time::Duration}; use async_trait::async_trait; use bs58; -use light_sdk_types::constants::STATE_MERKLE_TREE_CANOPY_DEPTH; +use light_sdk_types::constants::{STATE_MERKLE_TREE_CANOPY_DEPTH, STATE_MERKLE_TREE_HEIGHT}; use photon_api::apis::configuration::Configuration; use solana_pubkey::Pubkey; use tracing::{error, trace, warn}; @@ -1142,14 +1142,24 @@ impl Indexer for PhotonIndexer { .value .iter() .map(|x| { - if x.proof.len() < STATE_MERKLE_TREE_CANOPY_DEPTH { + let expected_siblings = + STATE_MERKLE_TREE_HEIGHT - STATE_MERKLE_TREE_CANOPY_DEPTH; + let expected_total = STATE_MERKLE_TREE_CANOPY_DEPTH + expected_siblings; + if x.proof.len() != expected_total { return Err(IndexerError::InvalidParameters(format!( - "Merkle proof length ({}) is less than canopy depth ({})", + "Merkle proof length ({}) does not match expected total proof length ({})", x.proof.len(), - STATE_MERKLE_TREE_CANOPY_DEPTH, + expected_total, ))); } let proof_len = x.proof.len() - STATE_MERKLE_TREE_CANOPY_DEPTH; + if proof_len != expected_siblings { + return Err(IndexerError::InvalidParameters(format!( + "Merkle proof sibling count ({}) does not match expected sibling count ({})", + proof_len, + expected_siblings, + ))); + } let proof = x.proof[..proof_len] .iter() @@ -1681,6 +1691,7 @@ impl Indexer for PhotonIndexer { .map(|h| super::base58::decode_base58_to_fixed_array(&h.0)) .collect::, _>>()?, start_index: aq.start_index, + tree_next_insertion_index: aq.start_index, root_seq: aq.root_seq, }) } else { diff --git a/sdk-libs/client/src/indexer/types/queue.rs b/sdk-libs/client/src/indexer/types/queue.rs index bdecce1b40..fc4de7a924 100644 --- a/sdk-libs/client/src/indexer/types/queue.rs +++ b/sdk-libs/client/src/indexer/types/queue.rs @@ -61,7 +61,10 @@ pub struct AddressQueueData { pub initial_root: [u8; 32], pub leaves_hash_chains: Vec<[u8; 32]>, pub subtrees: Vec<[u8; 32]>, + /// Pagination offset for the returned queue slice. pub start_index: u64, + /// Sparse tree insertion point / next index used to initialize staging trees. + pub tree_next_insertion_index: u64, pub root_seq: u64, } @@ -82,6 +85,19 @@ impl AddressQueueData { address_range: std::ops::Range, ) -> Result, IndexerError> { self.validate_proof_height::()?; + let available = self.proof_count(); + if address_range.start > address_range.end { + return Err(IndexerError::InvalidParameters(format!( + "invalid address proof range {}..{}", + address_range.start, address_range.end + ))); + } + if address_range.end > available { + return Err(IndexerError::InvalidParameters(format!( + "address proof range {}..{} exceeds available proofs {}", + address_range.start, address_range.end, available + ))); + } let node_lookup = self.build_node_lookup(); let mut proofs = Vec::with_capacity(address_range.len()); @@ -108,6 +124,10 @@ impl AddressQueueData { lookup } + fn proof_count(&self) -> usize { + self.addresses.len().min(self.low_element_indices.len()) + } + fn reconstruct_proof_with_lookup( &self, address_idx: usize, @@ -231,6 +251,7 @@ mod tests { leaves_hash_chains: vec![[3u8; 32]; num_addresses.max(1)], subtrees: vec![[4u8; 32]; HEIGHT], start_index: 0, + tree_next_insertion_index: 0, root_seq: 0, } } diff --git a/sdk-libs/client/src/interface/load_accounts.rs b/sdk-libs/client/src/interface/load_accounts.rs index c70088dd40..0d564734a2 100644 --- a/sdk-libs/client/src/interface/load_accounts.rs +++ b/sdk-libs/client/src/interface/load_accounts.rs @@ -1,5 +1,6 @@ //! Load cold accounts API. +use futures::{stream, StreamExt, TryStreamExt}; use light_account::{derive_rent_sponsor_pda, Pack}; use light_compressed_account::{ compressed_account::PackedMerkleContext, instruction_data::compressed_proof::ValidityProof, @@ -71,6 +72,7 @@ pub enum LoadAccountsError { const MAX_ATAS_PER_IX: usize = 8; const MAX_PDAS_PER_IX: usize = 8; +const PROOF_FETCH_CONCURRENCY: usize = 8; /// Build load instructions for cold accounts. Returns empty vec if all hot. /// @@ -118,9 +120,14 @@ where .collect(); let pda_groups = group_pda_specs(&cold_pdas, MAX_PDAS_PER_IX); + let mut pda_offset = 0usize; let pda_hashes = pda_groups .iter() - .map(|group| collect_pda_hashes(group)) + .map(|group| { + let hashes = collect_pda_hashes(group, pda_offset)?; + pda_offset += group.len(); + Ok::<_, LoadAccountsError>(hashes) + }) .collect::, _>>()?; let ata_hashes = collect_ata_hashes(&cold_atas)?; let mint_hashes = collect_mint_hashes(&cold_mints)?; @@ -161,13 +168,16 @@ where Ok(out) } -fn collect_pda_hashes(specs: &[&PdaSpec]) -> Result, LoadAccountsError> { +fn collect_pda_hashes( + specs: &[&PdaSpec], + start_index: usize, +) -> Result, LoadAccountsError> { specs .iter() .enumerate() .map(|(i, s)| { s.hash().ok_or(LoadAccountsError::MissingPdaCompressed { - index: i, + index: start_index + i, pubkey: s.address(), }) }) @@ -249,13 +259,16 @@ async fn fetch_individual_proofs( return Ok(vec![]); } - futures::future::try_join_all(hashes.iter().map(|hash| async move { - indexer - .get_validity_proof(vec![*hash], vec![], None) - .await - .map(|response| response.value) - })) - .await + stream::iter(hashes.iter().copied()) + .map(|hash| async move { + indexer + .get_validity_proof(vec![hash], vec![], None) + .await + .map(|response| response.value) + }) + .buffered(PROOF_FETCH_CONCURRENCY) + .try_collect() + .await } async fn fetch_proof_batches( @@ -266,13 +279,16 @@ async fn fetch_proof_batches( return Ok(vec![]); } - futures::future::try_join_all(hash_batches.iter().map(|hashes| async move { - indexer - .get_validity_proof(hashes.clone(), vec![], None) - .await - .map(|response| response.value) - })) - .await + stream::iter(hash_batches.iter().cloned()) + .map(|hashes| async move { + indexer + .get_validity_proof(hashes, vec![], None) + .await + .map(|response| response.value) + }) + .buffered(PROOF_FETCH_CONCURRENCY) + .try_collect() + .await } async fn fetch_proofs_batched( diff --git a/sdk-libs/program-test/src/indexer/test_indexer.rs b/sdk-libs/program-test/src/indexer/test_indexer.rs index c51298b9cd..e799d3f29e 100644 --- a/sdk-libs/program-test/src/indexer/test_indexer.rs +++ b/sdk-libs/program-test/src/indexer/test_indexer.rs @@ -726,9 +726,8 @@ impl Indexer for TestIndexer { initial_root: address_tree_bundle.root(), leaves_hash_chains: Vec::new(), subtrees: address_tree_bundle.get_subtrees(), - // Consumers use start_index as the sparse tree's next insertion index, - // not the pagination offset used for queue slicing. - start_index: address_tree_bundle.right_most_index() as u64, + start_index: start as u64, + tree_next_insertion_index: address_tree_bundle.right_most_index() as u64, root_seq: address_tree_bundle.sequence_number(), }) } else { diff --git a/sdk-libs/sdk-types/src/interface/program/decompression/pda.rs b/sdk-libs/sdk-types/src/interface/program/decompression/pda.rs index 3e32ec6ef3..8819724f59 100644 --- a/sdk-libs/sdk-types/src/interface/program/decompression/pda.rs +++ b/sdk-libs/sdk-types/src/interface/program/decompression/pda.rs @@ -143,12 +143,21 @@ where let address = derive_address(&pda_key, &ctx.light_config.address_space[0], ctx.program_id); // 10. Build CompressedAccountInfo for CPI + // When PDA decompression is only the first phase of a later token Transfer2 execution, + // the stored input queue index must match that later execution basis, not the original + // packed proof basis. The mixed PDA+token flow uses `output_queue_index` for that. + let input_queue_index = if ctx.cpi_accounts.config().cpi_context { + output_queue_index + } else { + tree_info.queue_pubkey_index + }; + let input = InAccountInfo { data_hash: input_data_hash, lamports: 0, merkle_context: PackedMerkleContext { merkle_tree_pubkey_index: tree_info.merkle_tree_pubkey_index, - queue_pubkey_index: tree_info.queue_pubkey_index, + queue_pubkey_index: input_queue_index, leaf_index: tree_info.leaf_index, prove_by_index: tree_info.prove_by_index, }, diff --git a/sdk-libs/sdk-types/src/interface/program/decompression/processor.rs b/sdk-libs/sdk-types/src/interface/program/decompression/processor.rs index 2fc7cfc811..2fc1f037b8 100644 --- a/sdk-libs/sdk-types/src/interface/program/decompression/processor.rs +++ b/sdk-libs/sdk-types/src/interface/program/decompression/processor.rs @@ -126,7 +126,7 @@ pub struct DecompressCtx<'a, AI: AccountInfoTrait + Clone> { #[cfg(feature = "token")] pub in_tlv: Option>>, #[cfg(feature = "token")] - pub token_seeds: Vec>, + pub token_seeds: Vec>>, } // ============================================================================ @@ -296,7 +296,7 @@ pub struct DecompressAccountsBuilt<'a, AI: AccountInfoTrait + Clone> { pub cpi_context: bool, pub in_token_data: Vec, pub in_tlv: Option>>, - pub token_seeds: Vec>, + pub token_seeds: Vec>>, } /// Validates accounts, dispatches all variants, and collects CPI inputs for @@ -649,13 +649,20 @@ where .map_err(|e| LightSdkTypesError::ProgramError(e.into()))?; } else { // At least one regular token account - use invoke_signed with PDA seeds - let signer_seed_refs: Vec<&[u8]> = token_seeds.iter().map(|s| s.as_slice()).collect(); + let signer_seed_storage: Vec> = token_seeds + .iter() + .map(|seed_group| seed_group.iter().map(|seed| seed.as_slice()).collect()) + .collect(); + let signer_seed_refs: Vec<&[&[u8]]> = signer_seed_storage + .iter() + .map(|seed_group| seed_group.as_slice()) + .collect(); AI::invoke_cpi( &LIGHT_TOKEN_PROGRAM_ID, &transfer2_data, &account_metas, remaining_accounts, - &[signer_seed_refs.as_slice()], + signer_seed_refs.as_slice(), ) .map_err(|e| LightSdkTypesError::ProgramError(e.into()))?; } diff --git a/sdk-libs/sdk-types/src/interface/program/decompression/token.rs b/sdk-libs/sdk-types/src/interface/program/decompression/token.rs index 153943e275..2b6fa37a7a 100644 --- a/sdk-libs/sdk-types/src/interface/program/decompression/token.rs +++ b/sdk-libs/sdk-types/src/interface/program/decompression/token.rs @@ -148,8 +148,9 @@ where ) .map_err(|e| LightSdkTypesError::ProgramError(e.into()))?; - // Push seeds for the Transfer2 CPI (needed for invoke_signed) - ctx.token_seeds.extend(seeds.iter().map(|s| s.to_vec())); + // Push one signer seed group per vault PDA for the later Transfer2 CPI. + ctx.token_seeds + .push(seeds.iter().map(|seed| seed.to_vec()).collect()); } // Push token data for the Transfer2 CPI (common for both ATA and regular paths) From c43ad66fe6a9afa4b69ce8cd9b182e6045d43741 Mon Sep 17 00:00:00 2001 From: Sergey Timoshin Date: Mon, 16 Mar 2026 14:50:22 +0000 Subject: [PATCH 06/23] Fix prover startup and decompression load flow --- prover/client/src/errors.rs | 1 - prover/client/src/prover.rs | 81 +++----- sdk-libs/client/src/interface/instructions.rs | 10 +- .../program-test/src/indexer/test_indexer.rs | 191 ++++++++++++++---- .../src/interface/account/token_seeds.rs | 4 +- .../interface/program/decompression/pda.rs | 16 +- .../tests/basic_test.rs | 9 +- 7 files changed, 200 insertions(+), 112 deletions(-) diff --git a/prover/client/src/errors.rs b/prover/client/src/errors.rs index e095bf3579..859cae32b8 100644 --- a/prover/client/src/errors.rs +++ b/prover/client/src/errors.rs @@ -39,7 +39,6 @@ pub enum ProverClientError { #[error("Integer conversion failed: {0}")] IntegerConversion(String), - #[error("Hashchain mismatch: computed {computed:?} != expected {expected:?} (batch_size={batch_size}, next_index={next_index})")] HashchainMismatch { computed: [u8; 32], diff --git a/prover/client/src/prover.rs b/prover/client/src/prover.rs index 5b5cfacc77..e0f9d4060d 100644 --- a/prover/client/src/prover.rs +++ b/prover/client/src/prover.rs @@ -1,13 +1,13 @@ use std::{ io::{Read, Write}, net::{TcpStream, ToSocketAddrs}, - process::{Command, Stdio}, + process::Command, sync::atomic::{AtomicBool, Ordering}, time::Duration, }; -use tracing::info; use tokio::time::sleep; +use tracing::info; use crate::{ constants::{HEALTH_CHECK, SERVER_ADDRESS}, @@ -16,6 +16,18 @@ use crate::{ }; static IS_LOADING: AtomicBool = AtomicBool::new(false); +const STARTUP_HEALTH_CHECK_RETRIES: usize = 300; + +fn has_http_ok_status(response: &[u8]) -> bool { + response + .split(|&byte| byte == b'\n') + .next() + .map(|status_line| { + status_line.starts_with(b"HTTP/") + && status_line.windows(5).any(|window| window == b" 200 ") + }) + .unwrap_or(false) +} pub(crate) fn build_http_client() -> Result { reqwest::Client::builder() @@ -59,7 +71,7 @@ fn health_check_once(timeout: Duration) -> bool { return health_check_once_with_curl(timeout); } - let mut response = [0u8; 512]; + let mut response = [0_u8; 512]; let bytes_read = match stream.read(&mut response) { Ok(bytes_read) => bytes_read, Err(error) => { @@ -68,14 +80,8 @@ fn health_check_once(timeout: Duration) -> bool { } }; - if bytes_read == 0 { - return false; - } - - let response = std::str::from_utf8(&response[..bytes_read]).unwrap_or_default(); - response.contains("200 OK") - || response.contains("{\"status\":\"ok\"}") - || health_check_once_with_curl(timeout) + bytes_read > 0 + && (has_http_ok_status(&response[..bytes_read]) || health_check_once_with_curl(timeout)) } fn prover_listener_present() -> bool { @@ -117,15 +123,15 @@ fn health_check_once_with_curl(timeout: Duration) -> bool { pub async fn spawn_prover() { if let Some(_project_root) = get_project_root() { - let prover_path: &str = { + let prover_path = { #[cfg(feature = "devenv")] { - &format!("{}/{}", _project_root.trim(), "cli/test_bin/run") + format!("{}/{}", _project_root.trim(), "cli/test_bin/run") } #[cfg(not(feature = "devenv"))] { println!("Running in production mode, using prover binary"); - "light" + "light".to_string() } }; @@ -137,50 +143,23 @@ pub async fn spawn_prover() { .compare_exchange(false, true, Ordering::AcqRel, Ordering::Acquire) .is_err() { - if health_check(120, 1).await { + if health_check(STARTUP_HEALTH_CHECK_RETRIES, 1).await { return; } panic!("Failed to start prover, health check failed."); } let spawn_result = async { - let mut command = Command::new(prover_path); - command.arg("start-prover").stdout(Stdio::piped()).stderr(Stdio::piped()); - let mut child = command.spawn().expect("Failed to start prover process"); - let mut child_exit_status = None; - - for _ in 0..120 { - if health_check(1, 1).await { - info!("Prover started successfully"); - return; - } - - if child_exit_status.is_none() { - match child.try_wait() { - Ok(Some(status)) => { - tracing::warn!( - ?status, - "prover launcher exited before health check succeeded; continuing to poll for detached prover" - ); - child_exit_status = Some(status); - } - Ok(None) => {} - Err(error) => { - tracing::error!(?error, "failed to poll prover child process"); - } - } - } - - sleep(Duration::from_secs(1)).await; - } - - if let Some(status) = child_exit_status { - panic!( - "Failed to start prover, health check failed after launcher exited with status {status}." - ); + Command::new(&prover_path) + .arg("start-prover") + .spawn() + .unwrap_or_else(|error| panic!("Failed to start prover process: {error}")); + + if health_check(STARTUP_HEALTH_CHECK_RETRIES, 1).await { + info!("Prover started successfully"); + } else { + panic!("Failed to start prover, health check failed."); } - - panic!("Failed to start prover, health check failed."); } .await; diff --git a/sdk-libs/client/src/interface/instructions.rs b/sdk-libs/client/src/interface/instructions.rs index f6d754b9b1..e80e7b72c1 100644 --- a/sdk-libs/client/src/interface/instructions.rs +++ b/sdk-libs/client/src/interface/instructions.rs @@ -8,7 +8,7 @@ use light_account::{ CompressedAccountData, InitializeLightConfigParams, Pack, UpdateLightConfigParams, }; use light_sdk::instruction::{ - account_meta::CompressedAccountMetaNoLamportsNoAddress, PackedAccounts, + account_meta::CompressedAccountMetaNoLamportsNoAddress, PackedAccounts, PackedStateTreeInfo, SystemAccountMetaConfig, ValidityProof, }; use light_token::constants::{ @@ -247,11 +247,15 @@ where // Process PDAs first, then tokens, to match on-chain split_at(token_accounts_offset). for &i in pda_indices.iter().chain(token_indices.iter()) { let (acc, data) = &cold_accounts[i]; - let _queue_index = remaining_accounts.insert_or_get(acc.tree_info.queue); - let tree_info = tree_infos + let proof_tree_info = tree_infos .get(i) .copied() .ok_or("tree info index out of bounds")?; + let queue_index = remaining_accounts.insert_or_get(acc.tree_info.queue); + let tree_info = PackedStateTreeInfo { + queue_pubkey_index: queue_index, + ..proof_tree_info + }; let packed_data = data.pack(&mut remaining_accounts)?; typed_accounts.push(CompressedAccountData { diff --git a/sdk-libs/program-test/src/indexer/test_indexer.rs b/sdk-libs/program-test/src/indexer/test_indexer.rs index e799d3f29e..6e61c3bd98 100644 --- a/sdk-libs/program-test/src/indexer/test_indexer.rs +++ b/sdk-libs/program-test/src/indexer/test_indexer.rs @@ -472,8 +472,6 @@ impl Indexer for TestIndexer { let account_data = account.value.ok_or(IndexerError::AccountNotFound)?; state_merkle_tree_pubkeys.push(account_data.tree_info.tree); } - println!("state_merkle_tree_pubkeys {:?}", state_merkle_tree_pubkeys); - println!("hashes {:?}", hashes); let mut proof_inputs = vec![]; let mut indices_to_remove = Vec::new(); @@ -495,14 +493,7 @@ impl Indexer for TestIndexer { .output_queue_elements .iter() .find(|(hash, _)| hash == compressed_account); - println!("queue_element {:?}", queue_element); - if let Some((_, index)) = queue_element { - println!("index {:?}", index); - println!( - "accounts.output_queue_batch_size {:?}", - accounts.output_queue_batch_size - ); if accounts.output_queue_batch_size.is_some() && accounts.leaf_index_in_queue_range(*index as usize)? { @@ -513,12 +504,7 @@ impl Indexer for TestIndexer { hash: *compressed_account, root: [0u8; 32], root_index: RootIndex::new_none(), - leaf_index: accounts - .output_queue_elements - .iter() - .position(|(x, _)| x == compressed_account) - .unwrap() - as u64, + leaf_index: *index, tree_info: light_client::indexer::TreeInfo { cpi_context: Some(accounts.accounts.cpi_context), tree: accounts.accounts.merkle_tree, @@ -2085,6 +2071,106 @@ impl TestIndexer { } } +#[cfg(all(test, feature = "v2"))] +mod tests { + use super::*; + use light_compressed_account::compressed_account::CompressedAccount; + + fn queued_account( + owner: [u8; 32], + merkle_tree: Pubkey, + queue: Pubkey, + leaf_index: u32, + ) -> CompressedAccountWithMerkleContext { + CompressedAccountWithMerkleContext { + compressed_account: CompressedAccount { + owner: owner.into(), + lamports: 0, + address: None, + data: None, + }, + merkle_context: MerkleContext { + merkle_tree_pubkey: merkle_tree.to_bytes().into(), + queue_pubkey: queue.to_bytes().into(), + leaf_index, + prove_by_index: false, + tree_type: TreeType::StateV2, + }, + } + } + + #[tokio::test] + async fn get_validity_proof_preserves_sparse_queue_leaf_indices() { + let merkle_tree = Pubkey::new_unique(); + let queue = Pubkey::new_unique(); + let sparse_leaf_indices = [5_u32, 1, 0, 4]; + + let compressed_accounts: Vec<_> = sparse_leaf_indices + .iter() + .enumerate() + .map(|(i, &leaf_index)| { + queued_account([i as u8 + 1; 32], merkle_tree, queue, leaf_index) + }) + .collect(); + let hashes: Vec<_> = compressed_accounts + .iter() + .map(|account| account.hash().unwrap()) + .collect(); + + let output_queue_elements = hashes + .iter() + .zip(sparse_leaf_indices.iter()) + .map(|(hash, &leaf_index)| (*hash, leaf_index as u64)) + .collect(); + + let indexer = TestIndexer { + state_merkle_trees: vec![StateMerkleTreeBundle { + rollover_fee: 0, + network_fee: 0, + merkle_tree: Box::new(MerkleTree::::new_with_history( + DEFAULT_BATCH_STATE_TREE_HEIGHT, + 0, + 0, + DEFAULT_BATCH_ROOT_HISTORY_LEN, + )), + accounts: StateMerkleTreeAccounts { + merkle_tree, + nullifier_queue: queue, + cpi_context: Pubkey::new_unique(), + tree_type: TreeType::StateV2, + }, + tree_type: TreeType::StateV2, + output_queue_elements, + input_leaf_indices: vec![], + output_queue_batch_size: Some(500), + num_inserted_batches: 0, + }], + address_merkle_trees: vec![], + payer: Keypair::new(), + governance_authority: Keypair::new(), + group_pda: Pubkey::new_unique(), + compressed_accounts, + nullified_compressed_accounts: vec![], + token_compressed_accounts: vec![], + token_nullified_compressed_accounts: vec![], + events: vec![], + onchain_pubkey_index: HashMap::new(), + }; + + let response = Indexer::get_validity_proof(&indexer, hashes, vec![], None) + .await + .unwrap(); + let leaf_indices: Vec = response + .value + .accounts + .iter() + .map(|account| account.leaf_index) + .collect(); + + assert_eq!(leaf_indices, sparse_leaf_indices.map(u64::from)); + } +} + impl TestIndexer { async fn process_inclusion_proofs( &self, @@ -2346,7 +2432,16 @@ impl TestIndexer { new_addresses.unwrap().len() ))); } - let client = Client::new(); + let client = Client::builder() + .no_proxy() + .connect_timeout(Duration::from_secs(5)) + .timeout(Duration::from_secs(120)) + .build() + .map_err(|error| { + IndexerError::CustomError(format!( + "failed to build prover HTTP client: {error}" + )) + })?; let (account_proof_inputs, address_proof_inputs, json_payload) = match (compressed_accounts, new_addresses) { (Some(accounts), None) => { @@ -2471,6 +2566,7 @@ impl TestIndexer { }; let mut retries = 3; + let mut last_error = "Failed to get proof from server".to_string(); while retries > 0 { let response_result = client .post(format!("{}{}", SERVER_ADDRESS, PROVE_PATH)) @@ -2478,33 +2574,50 @@ impl TestIndexer { .body(json_payload.clone()) .send() .await; - if let Ok(response_result) = response_result { - if response_result.status().is_success() { - let body = response_result.text().await.unwrap(); - let proof_json = deserialize_gnark_proof_json(&body).unwrap(); - let (proof_a, proof_b, proof_c) = proof_from_json_struct(proof_json); - let (proof_a, proof_b, proof_c) = - compress_proof(&proof_a, &proof_b, &proof_c); - return Ok(ValidityProofWithContext { - accounts: account_proof_inputs, - addresses: address_proof_inputs, - proof: CompressedProof { - a: proof_a, - b: proof_b, - c: proof_c, - } - .into(), - }); + match response_result { + Ok(response_result) => { + let status = response_result.status(); + let body = response_result.text().await.map_err(|error| { + IndexerError::CustomError(format!( + "failed to read prover response body: {error}" + )) + })?; + + if status.is_success() { + let proof_json = deserialize_gnark_proof_json(&body) + .map_err(|error| IndexerError::CustomError(error.to_string()))?; + let (proof_a, proof_b, proof_c) = proof_from_json_struct(proof_json); + let (proof_a, proof_b, proof_c) = + compress_proof(&proof_a, &proof_b, &proof_c); + return Ok(ValidityProofWithContext { + accounts: account_proof_inputs, + addresses: address_proof_inputs, + proof: CompressedProof { + a: proof_a, + b: proof_b, + c: proof_c, + } + .into(), + }); + } + + let body_preview: String = body.chars().take(512).collect(); + last_error = format!( + "prover returned HTTP {status} for validity proof request: {body_preview}" + ); } - } else { - println!("Error: {:#?}", response_result); + Err(error) => { + last_error = + format!("failed to contact prover for validity proof: {error}"); + } + } + + retries -= 1; + if retries > 0 { tokio::time::sleep(Duration::from_secs(5)).await; - retries -= 1; } } - Err(IndexerError::CustomError( - "Failed to get proof from server".to_string(), - )) + Err(IndexerError::CustomError(last_error)) } } } diff --git a/sdk-libs/sdk-types/src/interface/account/token_seeds.rs b/sdk-libs/sdk-types/src/interface/account/token_seeds.rs index f22657590a..2bd0ee7bdc 100644 --- a/sdk-libs/sdk-types/src/interface/account/token_seeds.rs +++ b/sdk-libs/sdk-types/src/interface/account/token_seeds.rs @@ -265,7 +265,7 @@ where fn into_in_token_data( &self, tree_info: &PackedStateTreeInfo, - output_queue_index: u8, + _output_queue_index: u8, ) -> Result { Ok(MultiInputTokenDataWithContext { amount: self.token_data.amount, @@ -277,7 +277,7 @@ where root_index: tree_info.root_index, merkle_context: PackedMerkleContext { merkle_tree_pubkey_index: tree_info.merkle_tree_pubkey_index, - queue_pubkey_index: output_queue_index, + queue_pubkey_index: tree_info.queue_pubkey_index, leaf_index: tree_info.leaf_index, prove_by_index: tree_info.prove_by_index, }, diff --git a/sdk-libs/sdk-types/src/interface/program/decompression/pda.rs b/sdk-libs/sdk-types/src/interface/program/decompression/pda.rs index 8819724f59..cc7aa4ba1f 100644 --- a/sdk-libs/sdk-types/src/interface/program/decompression/pda.rs +++ b/sdk-libs/sdk-types/src/interface/program/decompression/pda.rs @@ -142,22 +142,16 @@ where let pda_key = pda_account.key(); let address = derive_address(&pda_key, &ctx.light_config.address_space[0], ctx.program_id); - // 10. Build CompressedAccountInfo for CPI - // When PDA decompression is only the first phase of a later token Transfer2 execution, - // the stored input queue index must match that later execution basis, not the original - // packed proof basis. The mixed PDA+token flow uses `output_queue_index` for that. - let input_queue_index = if ctx.cpi_accounts.config().cpi_context { - output_queue_index - } else { - tree_info.queue_pubkey_index - }; - + // 10. Build CompressedAccountInfo for CPI. + // Input nullifiers must keep their original queue basis. The later system-program path + // groups nullifiers by queue index, so rewriting mixed PDA+token inputs onto a shared + // output queue drops whole tree/queue pairs from insertion. let input = InAccountInfo { data_hash: input_data_hash, lamports: 0, merkle_context: PackedMerkleContext { merkle_tree_pubkey_index: tree_info.merkle_tree_pubkey_index, - queue_pubkey_index: input_queue_index, + queue_pubkey_index: tree_info.queue_pubkey_index, leaf_index: tree_info.leaf_index, prove_by_index: tree_info.prove_by_index, }, diff --git a/sdk-tests/csdk-anchor-full-derived-test/tests/basic_test.rs b/sdk-tests/csdk-anchor-full-derived-test/tests/basic_test.rs index 747c75ce32..585a828f03 100644 --- a/sdk-tests/csdk-anchor-full-derived-test/tests/basic_test.rs +++ b/sdk-tests/csdk-anchor-full-derived-test/tests/basic_test.rs @@ -472,13 +472,12 @@ async fn test_create_pdas_and_mint_auto() { .await .expect("create_load_instructions should succeed"); - println!("all_instructions.len() = {:?}", all_instructions); - - // Expected: 1 PDA+Token ix + 2 ATA ixs (1 create_ata + 1 decompress) + 1 mint ix = 4 + // Expected: 1 mint load, 1 grouped PDA/token load, and 2 ATA instructions + // (create ATA + Transfer2 decompression) = 4 total. assert_eq!( all_instructions.len(), - 6, - "Should have 6 instructions: 1 PDA, 1 Token, 2 create_ata, 1 decompress_ata, 1 mint" + 4, + "Should have 4 instructions: 1 mint, 1 grouped PDA/token load, 1 create_ata, 1 ATA Transfer2" ); // Capture rent sponsor balance before decompression From f8562bd2d26d6c1e8d6308f121b54f9eac9aab80 Mon Sep 17 00:00:00 2001 From: Sergey Timoshin Date: Mon, 16 Mar 2026 16:17:20 +0000 Subject: [PATCH 07/23] cleanup: harden prover startup polling --- prover/client/src/prover.rs | 99 +++++++++++++++++++++++++------------ 1 file changed, 67 insertions(+), 32 deletions(-) diff --git a/prover/client/src/prover.rs b/prover/client/src/prover.rs index e0f9d4060d..49b9f5aceb 100644 --- a/prover/client/src/prover.rs +++ b/prover/client/src/prover.rs @@ -1,7 +1,7 @@ use std::{ io::{Read, Write}, net::{TcpStream, ToSocketAddrs}, - process::Command, + process::{Child, Command}, sync::atomic::{AtomicBool, Ordering}, time::Duration, }; @@ -39,15 +39,15 @@ pub(crate) fn build_http_client() -> Result } fn health_check_once(timeout: Duration) -> bool { - if prover_listener_present() { - return true; - } - let endpoint = SERVER_ADDRESS .strip_prefix("http://") .or_else(|| SERVER_ADDRESS.strip_prefix("https://")) .unwrap_or(SERVER_ADDRESS); - let addr = match endpoint.to_socket_addrs().ok().and_then(|mut addrs| addrs.next()) { + let addr = match endpoint + .to_socket_addrs() + .ok() + .and_then(|mut addrs| addrs.next()) + { Some(addr) => addr, None => return false, }; @@ -64,8 +64,10 @@ fn health_check_once(timeout: Duration) -> bool { let _ = stream.set_write_timeout(Some(timeout)); let host = endpoint.split(':').next().unwrap_or("127.0.0.1"); - let request = - format!("GET {} HTTP/1.1\r\nHost: {}\r\nConnection: close\r\n\r\n", HEALTH_CHECK, host); + let request = format!( + "GET {} HTTP/1.1\r\nHost: {}\r\nConnection: close\r\n\r\n", + HEALTH_CHECK, host + ); if let Err(error) = stream.write_all(request.as_bytes()) { tracing::debug!(?error, "failed to write prover health request"); return health_check_once_with_curl(timeout); @@ -84,25 +86,6 @@ fn health_check_once(timeout: Duration) -> bool { && (has_http_ok_status(&response[..bytes_read]) || health_check_once_with_curl(timeout)) } -fn prover_listener_present() -> bool { - let endpoint = SERVER_ADDRESS - .strip_prefix("http://") - .or_else(|| SERVER_ADDRESS.strip_prefix("https://")) - .unwrap_or(SERVER_ADDRESS); - let port = endpoint.rsplit(':').next().unwrap_or("3001"); - - match Command::new("lsof") - .args(["-nP", &format!("-iTCP:{port}"), "-sTCP:LISTEN"]) - .output() - { - Ok(output) => output.status.success() && !output.stdout.is_empty(), - Err(error) => { - tracing::debug!(?error, "failed to execute lsof prover listener check"); - false - } - } -} - fn health_check_once_with_curl(timeout: Duration) -> bool { let timeout_secs = timeout.as_secs().max(1).to_string(); let url = format!("{}{}", SERVER_ADDRESS, HEALTH_CHECK); @@ -121,6 +104,46 @@ fn health_check_once_with_curl(timeout: Duration) -> bool { } } +async fn wait_for_prover_health( + retries: usize, + timeout: Duration, + child: &mut Child, +) -> Result<(), String> { + for attempt in 0..retries { + if health_check_once(timeout) { + return Ok(()); + } + + match child.try_wait() { + Ok(Some(status)) => { + return Err(format!( + "prover process exited before health check succeeded with status {status}" + )); + } + Ok(None) => {} + Err(error) => { + return Err(format!("failed to poll prover process status: {error}")); + } + } + + if attempt + 1 < retries { + sleep(timeout).await; + } + } + + Err(format!( + "prover health check failed after {} attempts", + retries + )) +} + +fn monitor_prover_child(mut child: Child) { + std::thread::spawn(move || match child.wait() { + Ok(status) => tracing::debug!(?status, "prover launcher exited"), + Err(error) => tracing::warn!(?error, "failed to wait on prover launcher"), + }); +} + pub async fn spawn_prover() { if let Some(_project_root) = get_project_root() { let prover_path = { @@ -150,15 +173,27 @@ pub async fn spawn_prover() { } let spawn_result = async { - Command::new(&prover_path) + let mut child = Command::new(&prover_path) .arg("start-prover") .spawn() .unwrap_or_else(|error| panic!("Failed to start prover process: {error}")); - if health_check(STARTUP_HEALTH_CHECK_RETRIES, 1).await { - info!("Prover started successfully"); - } else { - panic!("Failed to start prover, health check failed."); + match wait_for_prover_health( + STARTUP_HEALTH_CHECK_RETRIES, + Duration::from_secs(1), + &mut child, + ) + .await + { + Ok(()) => { + monitor_prover_child(child); + info!("Prover started successfully"); + } + Err(error) => { + let _ = child.kill(); + let _ = child.wait(); + panic!("Failed to start prover: {error}"); + } } } .await; From 9b588cf59c1510e56b2413085ff8190caecca852 Mon Sep 17 00:00:00 2001 From: Sergey Timoshin Date: Mon, 16 Mar 2026 16:47:21 +0000 Subject: [PATCH 08/23] format --- forester/src/processor/v2/helpers.rs | 18 +++-- forester/src/processor/v2/proof_worker.rs | 4 +- program-tests/utils/src/e2e_test_env.rs | 3 +- .../utils/src/mock_batched_forester.rs | 4 +- prover/client/tests/batch_address_append.rs | 67 +++++++++---------- .../program-test/src/indexer/test_indexer.rs | 3 +- .../tests/integration_tests.rs | 2 +- 7 files changed, 54 insertions(+), 47 deletions(-) diff --git a/forester/src/processor/v2/helpers.rs b/forester/src/processor/v2/helpers.rs index a9fa2e290d..e6cd8092ea 100644 --- a/forester/src/processor/v2/helpers.rs +++ b/forester/src/processor/v2/helpers.rs @@ -502,9 +502,15 @@ impl StreamingAddressQueue { for (name, len) in [ ("addresses", data.addresses.len()), ("low_element_values", data.low_element_values.len()), - ("low_element_next_values", data.low_element_next_values.len()), + ( + "low_element_next_values", + data.low_element_next_values.len(), + ), ("low_element_indices", data.low_element_indices.len()), - ("low_element_next_indices", data.low_element_next_indices.len()), + ( + "low_element_next_indices", + data.low_element_next_indices.len(), + ), ] { if len < actual_end { return Err(anyhow!( @@ -545,9 +551,11 @@ impl StreamingAddressQueue { low_element_next_values: data.low_element_next_values[start..actual_end].to_vec(), low_element_indices: data.low_element_indices[start..actual_end].to_vec(), low_element_next_indices: data.low_element_next_indices[start..actual_end].to_vec(), - low_element_proofs: data.reconstruct_proofs::(start..actual_end).map_err( - |error| anyhow!("incomplete batch data: failed to reconstruct proofs: {error}"), - )?, + low_element_proofs: data + .reconstruct_proofs::(start..actual_end) + .map_err(|error| { + anyhow!("incomplete batch data: failed to reconstruct proofs: {error}") + })?, addresses, leaves_hashchain, })) diff --git a/forester/src/processor/v2/proof_worker.rs b/forester/src/processor/v2/proof_worker.rs index ded9fcedc8..603fa3f19b 100644 --- a/forester/src/processor/v2/proof_worker.rs +++ b/forester/src/processor/v2/proof_worker.rs @@ -164,7 +164,9 @@ impl ProofClients { } } -pub fn spawn_proof_workers(config: &ProverConfig) -> crate::Result> { +pub fn spawn_proof_workers( + config: &ProverConfig, +) -> crate::Result> { let (job_tx, job_rx) = async_channel::bounded::(256); let clients = Arc::new(ProofClients::new(config)?); tokio::spawn(async move { run_proof_pipeline(job_rx, clients).await }); diff --git a/program-tests/utils/src/e2e_test_env.rs b/program-tests/utils/src/e2e_test_env.rs index 6c9fdb5d5e..edb94fdf48 100644 --- a/program-tests/utils/src/e2e_test_env.rs +++ b/program-tests/utils/src/e2e_test_env.rs @@ -764,8 +764,7 @@ where // // local_leaves_hash_chain is only used for a test assertion. // let local_nullifier_hash_chain = create_hash_chain_from_array(&addresses); // assert_eq!(leaves_hash_chain, local_nullifier_hash_chain); - let start_index = - address_queue.tree_next_insertion_index as usize; + let start_index = address_queue.tree_next_insertion_index as usize; assert!( start_index >= 2, "start index should be greater than 2 else tree is not inited" diff --git a/program-tests/utils/src/mock_batched_forester.rs b/program-tests/utils/src/mock_batched_forester.rs index 8ea51b7169..f3ad76cdbe 100644 --- a/program-tests/utils/src/mock_batched_forester.rs +++ b/program-tests/utils/src/mock_batched_forester.rs @@ -209,9 +209,7 @@ impl MockBatchedForester { &[], )?; let proof_client = ProofClient::local()?; - let proof_result = proof_client - .generate_batch_update_proof(inputs) - .await?; + let proof_result = proof_client.generate_batch_update_proof(inputs).await?; let new_root = self.merkle_tree.root(); let proof = CompressedProof { a: proof_result.0.proof.a, diff --git a/prover/client/tests/batch_address_append.rs b/prover/client/tests/batch_address_append.rs index 8a02c363ff..7b8ceaa5f9 100644 --- a/prover/client/tests/batch_address_append.rs +++ b/prover/client/tests/batch_address_append.rs @@ -38,40 +38,39 @@ async fn prove_batch_address_append() { IndexedMerkleTree::::new(DEFAULT_BATCH_ADDRESS_TREE_HEIGHT as usize, 0) .unwrap(); - let collect_non_inclusion_data = - |tree: &IndexedMerkleTree, values: &[BigUint]| { - let mut low_element_values = Vec::with_capacity(values.len()); - let mut low_element_indices = Vec::with_capacity(values.len()); - let mut low_element_next_indices = Vec::with_capacity(values.len()); - let mut low_element_next_values = Vec::with_capacity(values.len()); - let mut low_element_proofs: Vec< - [[u8; 32]; DEFAULT_BATCH_ADDRESS_TREE_HEIGHT as usize], - > = Vec::with_capacity(values.len()); - - for new_element_value in values { - let non_inclusion_proof = tree.get_non_inclusion_proof(new_element_value).unwrap(); - - low_element_values.push(non_inclusion_proof.leaf_lower_range_value); - low_element_indices.push(non_inclusion_proof.leaf_index); - low_element_next_indices.push(non_inclusion_proof.next_index); - low_element_next_values.push(non_inclusion_proof.leaf_higher_range_value); - low_element_proofs.push( - non_inclusion_proof - .merkle_proof - .as_slice() - .try_into() - .unwrap(), - ); - } - - ( - low_element_values, - low_element_indices, - low_element_next_indices, - low_element_next_values, - low_element_proofs, - ) - }; + let collect_non_inclusion_data = |tree: &IndexedMerkleTree, + values: &[BigUint]| { + let mut low_element_values = Vec::with_capacity(values.len()); + let mut low_element_indices = Vec::with_capacity(values.len()); + let mut low_element_next_indices = Vec::with_capacity(values.len()); + let mut low_element_next_values = Vec::with_capacity(values.len()); + let mut low_element_proofs: Vec<[[u8; 32]; DEFAULT_BATCH_ADDRESS_TREE_HEIGHT as usize]> = + Vec::with_capacity(values.len()); + + for new_element_value in values { + let non_inclusion_proof = tree.get_non_inclusion_proof(new_element_value).unwrap(); + + low_element_values.push(non_inclusion_proof.leaf_lower_range_value); + low_element_indices.push(non_inclusion_proof.leaf_index); + low_element_next_indices.push(non_inclusion_proof.next_index); + low_element_next_values.push(non_inclusion_proof.leaf_higher_range_value); + low_element_proofs.push( + non_inclusion_proof + .merkle_proof + .as_slice() + .try_into() + .unwrap(), + ); + } + + ( + low_element_values, + low_element_indices, + low_element_next_indices, + low_element_next_values, + low_element_proofs, + ) + }; let initial_start_index = relayer_merkle_tree.merkle_tree.rightmost_index; let initial_root = relayer_merkle_tree.root(); diff --git a/sdk-libs/program-test/src/indexer/test_indexer.rs b/sdk-libs/program-test/src/indexer/test_indexer.rs index 6e61c3bd98..584a684a59 100644 --- a/sdk-libs/program-test/src/indexer/test_indexer.rs +++ b/sdk-libs/program-test/src/indexer/test_indexer.rs @@ -2073,9 +2073,10 @@ impl TestIndexer { #[cfg(all(test, feature = "v2"))] mod tests { - use super::*; use light_compressed_account::compressed_account::CompressedAccount; + use super::*; + fn queued_account( owner: [u8; 32], merkle_tree: Pubkey, diff --git a/sdk-tests/csdk-anchor-full-derived-test/tests/integration_tests.rs b/sdk-tests/csdk-anchor-full-derived-test/tests/integration_tests.rs index 9b40b900e5..2c3e82972a 100644 --- a/sdk-tests/csdk-anchor-full-derived-test/tests/integration_tests.rs +++ b/sdk-tests/csdk-anchor-full-derived-test/tests/integration_tests.rs @@ -3863,7 +3863,7 @@ async fn test_d9_edge_many_literals() { #[tokio::test] async fn test_d9_edge_mixed() { use csdk_anchor_full_derived_test::d9_seeds::{ - edge_cases::{AB, SEED_123, _UNDERSCORE_CONST}, + edge_cases::{_UNDERSCORE_CONST, AB, SEED_123}, D9EdgeMixedParams, }; From 4f60065c9fb8732103a202961ba587ebf9b3674d Mon Sep 17 00:00:00 2001 From: Sergey Timoshin Date: Mon, 16 Mar 2026 17:11:55 +0000 Subject: [PATCH 09/23] format --- .../csdk-anchor-full-derived-test/tests/integration_tests.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sdk-tests/csdk-anchor-full-derived-test/tests/integration_tests.rs b/sdk-tests/csdk-anchor-full-derived-test/tests/integration_tests.rs index 2c3e82972a..9b40b900e5 100644 --- a/sdk-tests/csdk-anchor-full-derived-test/tests/integration_tests.rs +++ b/sdk-tests/csdk-anchor-full-derived-test/tests/integration_tests.rs @@ -3863,7 +3863,7 @@ async fn test_d9_edge_many_literals() { #[tokio::test] async fn test_d9_edge_mixed() { use csdk_anchor_full_derived_test::d9_seeds::{ - edge_cases::{_UNDERSCORE_CONST, AB, SEED_123}, + edge_cases::{AB, SEED_123, _UNDERSCORE_CONST}, D9EdgeMixedParams, }; From ae3327605f481966ba1aa99195f5298da8edab62 Mon Sep 17 00:00:00 2001 From: Sergey Timoshin Date: Tue, 24 Mar 2026 16:35:53 +0000 Subject: [PATCH 10/23] cleanup --- forester/src/processor/v2/processor.rs | 6 +- forester/src/processor/v2/proof_worker.rs | 20 +- .../utils/src/mock_batched_forester.rs | 6 +- .../utils/src/test_batch_forester.rs | 6 +- prover/client/src/proof_client.rs | 24 +-- .../batch_address_append/proof_inputs.rs | 14 +- prover/client/src/prover.rs | 181 +++--------------- 7 files changed, 67 insertions(+), 190 deletions(-) diff --git a/forester/src/processor/v2/processor.rs b/forester/src/processor/v2/processor.rs index 372a800e0e..3de6dea860 100644 --- a/forester/src/processor/v2/processor.rs +++ b/forester/src/processor/v2/processor.rs @@ -132,7 +132,7 @@ where } if self.worker_pool.is_none() { - let job_tx = spawn_proof_workers(&self.context.prover_config)?; + let job_tx = spawn_proof_workers(&self.context.prover_config); self.worker_pool = Some(WorkerPool { job_tx }); } @@ -532,7 +532,7 @@ where ((queue_size / self.zkp_batch_size) as usize).min(self.context.max_batches_per_tree); if self.worker_pool.is_none() { - let job_tx = spawn_proof_workers(&self.context.prover_config)?; + let job_tx = spawn_proof_workers(&self.context.prover_config); self.worker_pool = Some(WorkerPool { job_tx }); } @@ -561,7 +561,7 @@ where let max_batches = max_batches.min(self.context.max_batches_per_tree); if self.worker_pool.is_none() { - let job_tx = spawn_proof_workers(&self.context.prover_config)?; + let job_tx = spawn_proof_workers(&self.context.prover_config); self.worker_pool = Some(WorkerPool { job_tx }); } diff --git a/forester/src/processor/v2/proof_worker.rs b/forester/src/processor/v2/proof_worker.rs index 603fa3f19b..b7afeacf0b 100644 --- a/forester/src/processor/v2/proof_worker.rs +++ b/forester/src/processor/v2/proof_worker.rs @@ -132,27 +132,27 @@ struct ProofClients { } impl ProofClients { - fn new(config: &ProverConfig) -> crate::Result { - Ok(Self { + fn new(config: &ProverConfig) -> Self { + Self { append_client: ProofClient::with_config( config.append_url.clone(), config.polling_interval, config.max_wait_time, config.api_key.clone(), - )?, + ), nullify_client: ProofClient::with_config( config.update_url.clone(), config.polling_interval, config.max_wait_time, config.api_key.clone(), - )?, + ), address_append_client: ProofClient::with_config( config.address_append_url.clone(), config.polling_interval, config.max_wait_time, config.api_key.clone(), - )?, - }) + ), + } } fn get_client(&self, input: &ProofInput) -> &ProofClient { @@ -164,13 +164,11 @@ impl ProofClients { } } -pub fn spawn_proof_workers( - config: &ProverConfig, -) -> crate::Result> { +pub fn spawn_proof_workers(config: &ProverConfig) -> async_channel::Sender { let (job_tx, job_rx) = async_channel::bounded::(256); - let clients = Arc::new(ProofClients::new(config)?); + let clients = Arc::new(ProofClients::new(config)); tokio::spawn(async move { run_proof_pipeline(job_rx, clients).await }); - Ok(job_tx) + job_tx } async fn run_proof_pipeline( diff --git a/program-tests/utils/src/mock_batched_forester.rs b/program-tests/utils/src/mock_batched_forester.rs index f3ad76cdbe..7d0669a6d8 100644 --- a/program-tests/utils/src/mock_batched_forester.rs +++ b/program-tests/utils/src/mock_batched_forester.rs @@ -132,7 +132,7 @@ impl MockBatchedForester { assert_eq!(computed_new_root, self.merkle_tree.root()); - let proof_client = ProofClient::local()?; + let proof_client = ProofClient::local(); let proof_result = match proof_client .generate_batch_append_proof(circuit_inputs) .await @@ -208,7 +208,7 @@ impl MockBatchedForester { batch_size, &[], )?; - let proof_client = ProofClient::local()?; + let proof_client = ProofClient::local(); let proof_result = proof_client.generate_batch_update_proof(inputs).await?; let new_root = self.merkle_tree.root(); let proof = CompressedProof { @@ -318,7 +318,7 @@ impl MockBatchedAddressForester { ))); } }; - let proof_client = ProofClient::local()?; + let proof_client = ProofClient::local(); let proof_result = match proof_client .generate_batch_address_append_proof(inputs) .await diff --git a/program-tests/utils/src/test_batch_forester.rs b/program-tests/utils/src/test_batch_forester.rs index 8cec32757f..e148e918d4 100644 --- a/program-tests/utils/src/test_batch_forester.rs +++ b/program-tests/utils/src/test_batch_forester.rs @@ -164,7 +164,7 @@ pub async fn create_append_batch_ix_data( bigint_to_be_bytes_array::<32>(&circuit_inputs.new_root.to_biguint().unwrap()).unwrap(), bundle.merkle_tree.root() ); - let proof_client = ProofClient::local().unwrap(); + let proof_client = ProofClient::local(); let inputs_json = BatchAppendInputsJson::from_inputs(&circuit_inputs).to_string(); match proof_client.generate_proof(inputs_json).await { @@ -293,7 +293,7 @@ pub async fn get_batched_nullify_ix_data( &[], ) .unwrap(); - let proof_client = ProofClient::local().unwrap(); + let proof_client = ProofClient::local(); let circuit_inputs_new_root = bigint_to_be_bytes_array::<32>(&inputs.new_root.to_biguint().unwrap()).unwrap(); let inputs_json = update_inputs_string(&inputs); @@ -715,7 +715,7 @@ pub async fn create_batch_update_address_tree_instruction_data_with_proof(&inputs.new_root).unwrap(); let inputs_json = to_json(&inputs); diff --git a/prover/client/src/proof_client.rs b/prover/client/src/proof_client.rs index 820c9fe07d..859ea4917f 100644 --- a/prover/client/src/proof_client.rs +++ b/prover/client/src/proof_client.rs @@ -67,15 +67,15 @@ pub struct ProofClient { } impl ProofClient { - pub fn local() -> Result { - Ok(Self { - client: build_http_client()?, + pub fn local() -> Self { + Self { + client: build_http_client(), server_address: SERVER_ADDRESS.to_string(), polling_interval: Duration::from_millis(DEFAULT_POLLING_INTERVAL_MS), max_wait_time: Duration::from_secs(DEFAULT_MAX_WAIT_TIME_SECS), api_key: None, initial_poll_delay: Duration::from_millis(INITIAL_POLL_DELAY_SMALL_CIRCUIT_MS), - }) + } } #[allow(unused)] @@ -84,21 +84,21 @@ impl ProofClient { polling_interval: Duration, max_wait_time: Duration, api_key: Option, - ) -> Result { + ) -> Self { let initial_poll_delay = if api_key.is_some() { Duration::from_millis(INITIAL_POLL_DELAY_LARGE_CIRCUIT_MS) } else { Duration::from_millis(INITIAL_POLL_DELAY_SMALL_CIRCUIT_MS) }; - Ok(Self { - client: build_http_client()?, + Self { + client: build_http_client(), server_address, polling_interval, max_wait_time, api_key, initial_poll_delay, - }) + } } #[allow(unused)] @@ -108,15 +108,15 @@ impl ProofClient { max_wait_time: Duration, api_key: Option, initial_poll_delay: Duration, - ) -> Result { - Ok(Self { - client: build_http_client()?, + ) -> Self { + Self { + client: build_http_client(), server_address, polling_interval, max_wait_time, api_key, initial_poll_delay, - }) + } } pub async fn submit_proof_async( diff --git a/prover/client/src/proof_types/batch_address_append/proof_inputs.rs b/prover/client/src/proof_types/batch_address_append/proof_inputs.rs index 3dd7a35c46..fdc50621cc 100644 --- a/prover/client/src/proof_types/batch_address_append/proof_inputs.rs +++ b/prover/client/src/proof_types/batch_address_append/proof_inputs.rs @@ -221,12 +221,12 @@ pub fn get_batch_address_append_circuit_inputs( } let new_element_values = &new_element_values[..zkp_batch_size]; let mut new_root = [0u8; 32]; - let mut low_element_circuit_merkle_proofs = Vec::with_capacity(batch_len); - let mut new_element_circuit_merkle_proofs = Vec::with_capacity(batch_len); - let mut patched_low_element_next_values = Vec::with_capacity(batch_len); - let mut patched_low_element_next_indices = Vec::with_capacity(batch_len); - let mut patched_low_element_values = Vec::with_capacity(batch_len); - let mut patched_low_element_indices = Vec::with_capacity(batch_len); + let mut low_element_circuit_merkle_proofs = Vec::with_capacity(zkp_batch_size); + let mut new_element_circuit_merkle_proofs = Vec::with_capacity(zkp_batch_size); + let mut patched_low_element_next_values = Vec::with_capacity(zkp_batch_size); + let mut patched_low_element_next_indices = Vec::with_capacity(zkp_batch_size); + let mut patched_low_element_values = Vec::with_capacity(zkp_batch_size); + let mut patched_low_element_indices = Vec::with_capacity(zkp_batch_size); let computed_hashchain = create_hash_chain_from_slice(new_element_values).map_err(|e| { ProverClientError::GenericError(format!("Failed to compute hashchain: {}", e)) @@ -261,7 +261,7 @@ pub fn get_batch_address_append_circuit_inputs( let is_first_batch = indexed_changelog.is_empty(); let mut expected_root_for_low = current_root; - for i in 0..batch_len { + for i in 0..zkp_batch_size { let mut changelog_index = 0; let low_element_index = low_element_indices[i].try_into().map_err(|_| { ProverClientError::IntegerConversion(format!( diff --git a/prover/client/src/prover.rs b/prover/client/src/prover.rs index 49b9f5aceb..5e8748299c 100644 --- a/prover/client/src/prover.rs +++ b/prover/client/src/prover.rs @@ -1,6 +1,4 @@ use std::{ - io::{Read, Write}, - net::{TcpStream, ToSocketAddrs}, process::{Child, Command}, sync::atomic::{AtomicBool, Ordering}, time::Duration, @@ -11,130 +9,17 @@ use tracing::info; use crate::{ constants::{HEALTH_CHECK, SERVER_ADDRESS}, - errors::ProverClientError, helpers::get_project_root, }; static IS_LOADING: AtomicBool = AtomicBool::new(false); const STARTUP_HEALTH_CHECK_RETRIES: usize = 300; -fn has_http_ok_status(response: &[u8]) -> bool { - response - .split(|&byte| byte == b'\n') - .next() - .map(|status_line| { - status_line.starts_with(b"HTTP/") - && status_line.windows(5).any(|window| window == b" 200 ") - }) - .unwrap_or(false) -} - -pub(crate) fn build_http_client() -> Result { +pub(crate) fn build_http_client() -> reqwest::Client { reqwest::Client::builder() .no_proxy() .build() - .map_err(|error| { - ProverClientError::GenericError(format!("failed to build HTTP client: {error}")) - }) -} - -fn health_check_once(timeout: Duration) -> bool { - let endpoint = SERVER_ADDRESS - .strip_prefix("http://") - .or_else(|| SERVER_ADDRESS.strip_prefix("https://")) - .unwrap_or(SERVER_ADDRESS); - let addr = match endpoint - .to_socket_addrs() - .ok() - .and_then(|mut addrs| addrs.next()) - { - Some(addr) => addr, - None => return false, - }; - - let mut stream = match TcpStream::connect_timeout(&addr, timeout) { - Ok(stream) => stream, - Err(error) => { - tracing::debug!(?error, endpoint, "prover health TCP connect failed"); - return health_check_once_with_curl(timeout); - } - }; - - let _ = stream.set_read_timeout(Some(timeout)); - let _ = stream.set_write_timeout(Some(timeout)); - - let host = endpoint.split(':').next().unwrap_or("127.0.0.1"); - let request = format!( - "GET {} HTTP/1.1\r\nHost: {}\r\nConnection: close\r\n\r\n", - HEALTH_CHECK, host - ); - if let Err(error) = stream.write_all(request.as_bytes()) { - tracing::debug!(?error, "failed to write prover health request"); - return health_check_once_with_curl(timeout); - } - - let mut response = [0_u8; 512]; - let bytes_read = match stream.read(&mut response) { - Ok(bytes_read) => bytes_read, - Err(error) => { - tracing::debug!(?error, "failed to read prover health response"); - return health_check_once_with_curl(timeout); - } - }; - - bytes_read > 0 - && (has_http_ok_status(&response[..bytes_read]) || health_check_once_with_curl(timeout)) -} - -fn health_check_once_with_curl(timeout: Duration) -> bool { - let timeout_secs = timeout.as_secs().max(1).to_string(); - let url = format!("{}{}", SERVER_ADDRESS, HEALTH_CHECK); - match Command::new("curl") - .args(["-sS", "-m", timeout_secs.as_str(), url.as_str()]) - .output() - { - Ok(output) => { - output.status.success() - && String::from_utf8_lossy(&output.stdout).contains("{\"status\":\"ok\"}") - } - Err(error) => { - tracing::debug!(?error, "failed to execute curl prover health check"); - false - } - } -} - -async fn wait_for_prover_health( - retries: usize, - timeout: Duration, - child: &mut Child, -) -> Result<(), String> { - for attempt in 0..retries { - if health_check_once(timeout) { - return Ok(()); - } - - match child.try_wait() { - Ok(Some(status)) => { - return Err(format!( - "prover process exited before health check succeeded with status {status}" - )); - } - Ok(None) => {} - Err(error) => { - return Err(format!("failed to poll prover process status: {error}")); - } - } - - if attempt + 1 < retries { - sleep(timeout).await; - } - } - - Err(format!( - "prover health check failed after {} attempts", - retries - )) + .expect("failed to build HTTP client") } fn monitor_prover_child(mut child: Child) { @@ -172,50 +57,44 @@ pub async fn spawn_prover() { panic!("Failed to start prover, health check failed."); } - let spawn_result = async { - let mut child = Command::new(&prover_path) - .arg("start-prover") - .spawn() - .unwrap_or_else(|error| panic!("Failed to start prover process: {error}")); - - match wait_for_prover_health( - STARTUP_HEALTH_CHECK_RETRIES, - Duration::from_secs(1), - &mut child, - ) - .await - { - Ok(()) => { - monitor_prover_child(child); - info!("Prover started successfully"); - } - Err(error) => { - let _ = child.kill(); - let _ = child.wait(); - panic!("Failed to start prover: {error}"); - } - } - } - .await; + let mut child = Command::new(&prover_path) + .arg("start-prover") + .spawn() + .unwrap_or_else(|error| panic!("Failed to start prover process: {error}")); + let health_result = health_check(STARTUP_HEALTH_CHECK_RETRIES, 1).await; IS_LOADING.store(false, Ordering::Release); - spawn_result + + if health_result { + monitor_prover_child(child); + info!("Prover started successfully"); + } else { + let _ = child.kill(); + let _ = child.wait(); + panic!("Failed to start prover, health check failed."); + } } else { panic!("Failed to find project root."); }; } pub async fn health_check(retries: usize, timeout: usize) -> bool { - let timeout = Duration::from_secs(timeout as u64); - let retry_delay = timeout; + let client = build_http_client(); + let timeout_duration = Duration::from_secs(timeout as u64); for attempt in 0..retries { - if health_check_once(timeout) { - return true; - } - - if attempt + 1 < retries { - sleep(retry_delay).await; + match client + .get(format!("{}{}", SERVER_ADDRESS, HEALTH_CHECK)) + .timeout(timeout_duration) + .send() + .await + { + Ok(_) => return true, + Err(_) => { + if attempt + 1 < retries { + sleep(timeout_duration).await; + } + } } } From 09894c99a5d1f8356d61448a6a4dfac2cd8eae59 Mon Sep 17 00:00:00 2001 From: Sergey Timoshin Date: Fri, 27 Mar 2026 10:25:59 +0000 Subject: [PATCH 11/23] cleanup --- sdk-libs/client/src/indexer/types/queue.rs | 3 + sdk-libs/photon-api/src/codegen.rs | 3628 ++++++++++++++------ 2 files changed, 2587 insertions(+), 1044 deletions(-) diff --git a/sdk-libs/client/src/indexer/types/queue.rs b/sdk-libs/client/src/indexer/types/queue.rs index fc4de7a924..8a9cd479a3 100644 --- a/sdk-libs/client/src/indexer/types/queue.rs +++ b/sdk-libs/client/src/indexer/types/queue.rs @@ -69,6 +69,9 @@ pub struct AddressQueueData { } impl AddressQueueData { + pub const ADDRESS_TREE_HEIGHT: usize = + light_prover_client::constants::DEFAULT_BATCH_ADDRESS_TREE_HEIGHT as usize; + /// Reconstruct a single merkle proof for a given address index. #[cfg(test)] fn reconstruct_proof( diff --git a/sdk-libs/photon-api/src/codegen.rs b/sdk-libs/photon-api/src/codegen.rs index 4dd88bda05..0936da0ea0 100644 --- a/sdk-libs/photon-api/src/codegen.rs +++ b/sdk-libs/photon-api/src/codegen.rs @@ -1550,6 +1550,96 @@ All endpoints return AccountV2.*/ Default::default() } } + /**Parameters for requesting input queue leaf indices. +Returns (hash, queue_index, leaf_index) for nullifier queue items.*/ + /// + ///
JSON schema + /// + /// ```json + ///{ + /// "description": "Parameters for requesting input queue leaf indices.\nReturns (hash, queue_index, leaf_index) for nullifier queue items.", + /// "type": "object", + /// "required": [ + /// "limit", + /// "tree" + /// ], + /// "properties": { + /// "limit": { + /// "type": "integer", + /// "format": "uint16", + /// "minimum": 0.0 + /// }, + /// "startIndex": { + /// "type": [ + /// "integer", + /// "null" + /// ], + /// "format": "uint64", + /// "minimum": 0.0 + /// }, + /// "tree": { + /// "$ref": "#/components/schemas/Hash" + /// } + /// }, + /// "additionalProperties": false + ///} + /// ``` + ///
+ #[derive(::serde::Deserialize, ::serde::Serialize, Clone, Debug)] + #[serde(deny_unknown_fields)] + pub struct GetQueueLeafIndicesRequest { + pub limit: u16, + #[serde( + rename = "startIndex", + default, + skip_serializing_if = "::std::option::Option::is_none" + )] + pub start_index: ::std::option::Option, + pub tree: Hash, + } + impl GetQueueLeafIndicesRequest { + pub fn builder() -> builder::GetQueueLeafIndicesRequest { + Default::default() + } + } + ///Response containing queue leaf indices + /// + ///
JSON schema + /// + /// ```json + ///{ + /// "description": "Response containing queue leaf indices", + /// "type": "object", + /// "required": [ + /// "context", + /// "value" + /// ], + /// "properties": { + /// "context": { + /// "$ref": "#/components/schemas/Context" + /// }, + /// "value": { + /// "type": "array", + /// "items": { + /// "$ref": "#/components/schemas/QueueLeafIndex" + /// } + /// } + /// }, + /// "additionalProperties": false + ///} + /// ``` + ///
+ #[derive(::serde::Deserialize, ::serde::Serialize, Clone, Debug)] + #[serde(deny_unknown_fields)] + pub struct GetQueueLeafIndicesResponse { + pub context: Context, + pub value: ::std::vec::Vec, + } + impl GetQueueLeafIndicesResponse { + pub fn builder() -> builder::GetQueueLeafIndicesResponse { + Default::default() + } + } ///A 32-byte hash represented as a base58 string. /// ///
JSON schema @@ -24678,7 +24768,7 @@ All endpoints return AccountV2.*/ Default::default() } } - ///`PostGetTransactionWithCompressionInfoBody` + ///`PostGetQueueLeafIndicesBody` /// ///
JSON schema /// @@ -24710,17 +24800,32 @@ All endpoints return AccountV2.*/ /// "description": "The name of the method to invoke.", /// "type": "string", /// "enum": [ - /// "getTransactionWithCompressionInfo" + /// "getQueueLeafIndices" /// ] /// }, /// "params": { + /// "description": "Parameters for requesting input queue leaf indices.\nReturns (hash, queue_index, leaf_index) for nullifier queue items.", /// "type": "object", /// "required": [ - /// "signature" + /// "limit", + /// "tree" /// ], /// "properties": { - /// "signature": { - /// "$ref": "#/components/schemas/SerializableSignature" + /// "limit": { + /// "type": "integer", + /// "format": "uint16", + /// "minimum": 0.0 + /// }, + /// "startIndex": { + /// "type": [ + /// "integer", + /// "null" + /// ], + /// "format": "uint64", + /// "minimum": 0.0 + /// }, + /// "tree": { + /// "$ref": "#/components/schemas/Hash" /// } /// }, /// "additionalProperties": false @@ -24730,17 +24835,17 @@ All endpoints return AccountV2.*/ /// ``` ///
#[derive(::serde::Deserialize, ::serde::Serialize, Clone, Debug)] - pub struct PostGetTransactionWithCompressionInfoBody { + pub struct PostGetQueueLeafIndicesBody { ///An ID to identify the request. - pub id: PostGetTransactionWithCompressionInfoBodyId, + pub id: PostGetQueueLeafIndicesBodyId, ///The version of the JSON-RPC protocol. - pub jsonrpc: PostGetTransactionWithCompressionInfoBodyJsonrpc, + pub jsonrpc: PostGetQueueLeafIndicesBodyJsonrpc, ///The name of the method to invoke. - pub method: PostGetTransactionWithCompressionInfoBodyMethod, - pub params: PostGetTransactionWithCompressionInfoBodyParams, + pub method: PostGetQueueLeafIndicesBodyMethod, + pub params: PostGetQueueLeafIndicesBodyParams, } - impl PostGetTransactionWithCompressionInfoBody { - pub fn builder() -> builder::PostGetTransactionWithCompressionInfoBody { + impl PostGetQueueLeafIndicesBody { + pub fn builder() -> builder::PostGetQueueLeafIndicesBody { Default::default() } } @@ -24770,18 +24875,18 @@ All endpoints return AccountV2.*/ PartialEq, PartialOrd )] - pub enum PostGetTransactionWithCompressionInfoBodyId { + pub enum PostGetQueueLeafIndicesBodyId { #[serde(rename = "test-account")] TestAccount, } - impl ::std::fmt::Display for PostGetTransactionWithCompressionInfoBodyId { + impl ::std::fmt::Display for PostGetQueueLeafIndicesBodyId { fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result { match *self { Self::TestAccount => f.write_str("test-account"), } } } - impl ::std::str::FromStr for PostGetTransactionWithCompressionInfoBodyId { + impl ::std::str::FromStr for PostGetQueueLeafIndicesBodyId { type Err = self::error::ConversionError; fn from_str( value: &str, @@ -24792,7 +24897,7 @@ All endpoints return AccountV2.*/ } } } - impl ::std::convert::TryFrom<&str> for PostGetTransactionWithCompressionInfoBodyId { + impl ::std::convert::TryFrom<&str> for PostGetQueueLeafIndicesBodyId { type Error = self::error::ConversionError; fn try_from( value: &str, @@ -24801,7 +24906,7 @@ All endpoints return AccountV2.*/ } } impl ::std::convert::TryFrom<&::std::string::String> - for PostGetTransactionWithCompressionInfoBodyId { + for PostGetQueueLeafIndicesBodyId { type Error = self::error::ConversionError; fn try_from( value: &::std::string::String, @@ -24810,7 +24915,7 @@ All endpoints return AccountV2.*/ } } impl ::std::convert::TryFrom<::std::string::String> - for PostGetTransactionWithCompressionInfoBodyId { + for PostGetQueueLeafIndicesBodyId { type Error = self::error::ConversionError; fn try_from( value: ::std::string::String, @@ -24844,18 +24949,18 @@ All endpoints return AccountV2.*/ PartialEq, PartialOrd )] - pub enum PostGetTransactionWithCompressionInfoBodyJsonrpc { + pub enum PostGetQueueLeafIndicesBodyJsonrpc { #[serde(rename = "2.0")] X20, } - impl ::std::fmt::Display for PostGetTransactionWithCompressionInfoBodyJsonrpc { + impl ::std::fmt::Display for PostGetQueueLeafIndicesBodyJsonrpc { fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result { match *self { Self::X20 => f.write_str("2.0"), } } } - impl ::std::str::FromStr for PostGetTransactionWithCompressionInfoBodyJsonrpc { + impl ::std::str::FromStr for PostGetQueueLeafIndicesBodyJsonrpc { type Err = self::error::ConversionError; fn from_str( value: &str, @@ -24866,8 +24971,7 @@ All endpoints return AccountV2.*/ } } } - impl ::std::convert::TryFrom<&str> - for PostGetTransactionWithCompressionInfoBodyJsonrpc { + impl ::std::convert::TryFrom<&str> for PostGetQueueLeafIndicesBodyJsonrpc { type Error = self::error::ConversionError; fn try_from( value: &str, @@ -24876,7 +24980,7 @@ All endpoints return AccountV2.*/ } } impl ::std::convert::TryFrom<&::std::string::String> - for PostGetTransactionWithCompressionInfoBodyJsonrpc { + for PostGetQueueLeafIndicesBodyJsonrpc { type Error = self::error::ConversionError; fn try_from( value: &::std::string::String, @@ -24885,7 +24989,7 @@ All endpoints return AccountV2.*/ } } impl ::std::convert::TryFrom<::std::string::String> - for PostGetTransactionWithCompressionInfoBodyJsonrpc { + for PostGetQueueLeafIndicesBodyJsonrpc { type Error = self::error::ConversionError; fn try_from( value: ::std::string::String, @@ -24902,7 +25006,7 @@ All endpoints return AccountV2.*/ /// "description": "The name of the method to invoke.", /// "type": "string", /// "enum": [ - /// "getTransactionWithCompressionInfo" + /// "getQueueLeafIndices" /// ] ///} /// ``` @@ -24919,34 +25023,29 @@ All endpoints return AccountV2.*/ PartialEq, PartialOrd )] - pub enum PostGetTransactionWithCompressionInfoBodyMethod { - #[serde(rename = "getTransactionWithCompressionInfo")] - GetTransactionWithCompressionInfo, + pub enum PostGetQueueLeafIndicesBodyMethod { + #[serde(rename = "getQueueLeafIndices")] + GetQueueLeafIndices, } - impl ::std::fmt::Display for PostGetTransactionWithCompressionInfoBodyMethod { + impl ::std::fmt::Display for PostGetQueueLeafIndicesBodyMethod { fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result { match *self { - Self::GetTransactionWithCompressionInfo => { - f.write_str("getTransactionWithCompressionInfo") - } + Self::GetQueueLeafIndices => f.write_str("getQueueLeafIndices"), } } } - impl ::std::str::FromStr for PostGetTransactionWithCompressionInfoBodyMethod { + impl ::std::str::FromStr for PostGetQueueLeafIndicesBodyMethod { type Err = self::error::ConversionError; fn from_str( value: &str, ) -> ::std::result::Result { match value { - "getTransactionWithCompressionInfo" => { - Ok(Self::GetTransactionWithCompressionInfo) - } + "getQueueLeafIndices" => Ok(Self::GetQueueLeafIndices), _ => Err("invalid value".into()), } } } - impl ::std::convert::TryFrom<&str> - for PostGetTransactionWithCompressionInfoBodyMethod { + impl ::std::convert::TryFrom<&str> for PostGetQueueLeafIndicesBodyMethod { type Error = self::error::ConversionError; fn try_from( value: &str, @@ -24955,7 +25054,7 @@ All endpoints return AccountV2.*/ } } impl ::std::convert::TryFrom<&::std::string::String> - for PostGetTransactionWithCompressionInfoBodyMethod { + for PostGetQueueLeafIndicesBodyMethod { type Error = self::error::ConversionError; fn try_from( value: &::std::string::String, @@ -24964,7 +25063,7 @@ All endpoints return AccountV2.*/ } } impl ::std::convert::TryFrom<::std::string::String> - for PostGetTransactionWithCompressionInfoBodyMethod { + for PostGetQueueLeafIndicesBodyMethod { type Error = self::error::ConversionError; fn try_from( value: ::std::string::String, @@ -24972,19 +25071,35 @@ All endpoints return AccountV2.*/ value.parse() } } - ///`PostGetTransactionWithCompressionInfoBodyParams` + /**Parameters for requesting input queue leaf indices. +Returns (hash, queue_index, leaf_index) for nullifier queue items.*/ /// ///
JSON schema /// /// ```json ///{ + /// "description": "Parameters for requesting input queue leaf indices.\nReturns (hash, queue_index, leaf_index) for nullifier queue items.", /// "type": "object", /// "required": [ - /// "signature" + /// "limit", + /// "tree" /// ], /// "properties": { - /// "signature": { - /// "$ref": "#/components/schemas/SerializableSignature" + /// "limit": { + /// "type": "integer", + /// "format": "uint16", + /// "minimum": 0.0 + /// }, + /// "startIndex": { + /// "type": [ + /// "integer", + /// "null" + /// ], + /// "format": "uint64", + /// "minimum": 0.0 + /// }, + /// "tree": { + /// "$ref": "#/components/schemas/Hash" /// } /// }, /// "additionalProperties": false @@ -24993,15 +25108,22 @@ All endpoints return AccountV2.*/ ///
#[derive(::serde::Deserialize, ::serde::Serialize, Clone, Debug)] #[serde(deny_unknown_fields)] - pub struct PostGetTransactionWithCompressionInfoBodyParams { - pub signature: SerializableSignature, + pub struct PostGetQueueLeafIndicesBodyParams { + pub limit: u16, + #[serde( + rename = "startIndex", + default, + skip_serializing_if = "::std::option::Option::is_none" + )] + pub start_index: ::std::option::Option, + pub tree: Hash, } - impl PostGetTransactionWithCompressionInfoBodyParams { - pub fn builder() -> builder::PostGetTransactionWithCompressionInfoBodyParams { + impl PostGetQueueLeafIndicesBodyParams { + pub fn builder() -> builder::PostGetQueueLeafIndicesBodyParams { Default::default() } } - ///`PostGetTransactionWithCompressionInfoResponse` + ///`PostGetQueueLeafIndicesResponse` /// ///
JSON schema /// @@ -25039,62 +25161,46 @@ All endpoints return AccountV2.*/ /// ] /// }, /// "result": { - /// "description": "A Solana transaction with additional compression information", + /// "description": "Response containing queue leaf indices", /// "type": "object", + /// "required": [ + /// "context", + /// "value" + /// ], /// "properties": { - /// "compression_info": { - /// "type": "object", - /// "required": [ - /// "closedAccounts", - /// "openedAccounts" - /// ], - /// "properties": { - /// "closedAccounts": { - /// "type": "array", - /// "items": { - /// "$ref": "#/components/schemas/AccountWithOptionalTokenData" - /// } - /// }, - /// "openedAccounts": { - /// "type": "array", - /// "items": { - /// "$ref": "#/components/schemas/AccountWithOptionalTokenData" - /// } - /// } - /// }, - /// "additionalProperties": false + /// "context": { + /// "$ref": "#/components/schemas/Context" /// }, - /// "transaction": { - /// "description": "An encoded confirmed transaction with status meta", - /// "type": "object" + /// "value": { + /// "type": "array", + /// "items": { + /// "$ref": "#/components/schemas/QueueLeafIndex" + /// } /// } - /// } + /// }, + /// "additionalProperties": false /// } /// } ///} /// ``` ///
#[derive(::serde::Deserialize, ::serde::Serialize, Clone, Debug)] - pub struct PostGetTransactionWithCompressionInfoResponse { + pub struct PostGetQueueLeafIndicesResponse { #[serde(default, skip_serializing_if = "::std::option::Option::is_none")] - pub error: ::std::option::Option< - PostGetTransactionWithCompressionInfoResponseError, - >, + pub error: ::std::option::Option, ///An ID to identify the response. - pub id: PostGetTransactionWithCompressionInfoResponseId, + pub id: PostGetQueueLeafIndicesResponseId, ///The version of the JSON-RPC protocol. - pub jsonrpc: PostGetTransactionWithCompressionInfoResponseJsonrpc, + pub jsonrpc: PostGetQueueLeafIndicesResponseJsonrpc, #[serde(default, skip_serializing_if = "::std::option::Option::is_none")] - pub result: ::std::option::Option< - PostGetTransactionWithCompressionInfoResponseResult, - >, + pub result: ::std::option::Option, } - impl PostGetTransactionWithCompressionInfoResponse { - pub fn builder() -> builder::PostGetTransactionWithCompressionInfoResponse { + impl PostGetQueueLeafIndicesResponse { + pub fn builder() -> builder::PostGetQueueLeafIndicesResponse { Default::default() } } - ///`PostGetTransactionWithCompressionInfoResponseError` + ///`PostGetQueueLeafIndicesResponseError` /// ///
JSON schema /// @@ -25113,13 +25219,13 @@ All endpoints return AccountV2.*/ /// ``` ///
#[derive(::serde::Deserialize, ::serde::Serialize, Clone, Debug)] - pub struct PostGetTransactionWithCompressionInfoResponseError { + pub struct PostGetQueueLeafIndicesResponseError { #[serde(default, skip_serializing_if = "::std::option::Option::is_none")] pub code: ::std::option::Option, #[serde(default, skip_serializing_if = "::std::option::Option::is_none")] pub message: ::std::option::Option<::std::string::String>, } - impl ::std::default::Default for PostGetTransactionWithCompressionInfoResponseError { + impl ::std::default::Default for PostGetQueueLeafIndicesResponseError { fn default() -> Self { Self { code: Default::default(), @@ -25127,8 +25233,8 @@ All endpoints return AccountV2.*/ } } } - impl PostGetTransactionWithCompressionInfoResponseError { - pub fn builder() -> builder::PostGetTransactionWithCompressionInfoResponseError { + impl PostGetQueueLeafIndicesResponseError { + pub fn builder() -> builder::PostGetQueueLeafIndicesResponseError { Default::default() } } @@ -25158,18 +25264,18 @@ All endpoints return AccountV2.*/ PartialEq, PartialOrd )] - pub enum PostGetTransactionWithCompressionInfoResponseId { + pub enum PostGetQueueLeafIndicesResponseId { #[serde(rename = "test-account")] TestAccount, } - impl ::std::fmt::Display for PostGetTransactionWithCompressionInfoResponseId { + impl ::std::fmt::Display for PostGetQueueLeafIndicesResponseId { fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result { match *self { Self::TestAccount => f.write_str("test-account"), } } } - impl ::std::str::FromStr for PostGetTransactionWithCompressionInfoResponseId { + impl ::std::str::FromStr for PostGetQueueLeafIndicesResponseId { type Err = self::error::ConversionError; fn from_str( value: &str, @@ -25180,8 +25286,7 @@ All endpoints return AccountV2.*/ } } } - impl ::std::convert::TryFrom<&str> - for PostGetTransactionWithCompressionInfoResponseId { + impl ::std::convert::TryFrom<&str> for PostGetQueueLeafIndicesResponseId { type Error = self::error::ConversionError; fn try_from( value: &str, @@ -25190,7 +25295,7 @@ All endpoints return AccountV2.*/ } } impl ::std::convert::TryFrom<&::std::string::String> - for PostGetTransactionWithCompressionInfoResponseId { + for PostGetQueueLeafIndicesResponseId { type Error = self::error::ConversionError; fn try_from( value: &::std::string::String, @@ -25199,7 +25304,7 @@ All endpoints return AccountV2.*/ } } impl ::std::convert::TryFrom<::std::string::String> - for PostGetTransactionWithCompressionInfoResponseId { + for PostGetQueueLeafIndicesResponseId { type Error = self::error::ConversionError; fn try_from( value: ::std::string::String, @@ -25233,18 +25338,18 @@ All endpoints return AccountV2.*/ PartialEq, PartialOrd )] - pub enum PostGetTransactionWithCompressionInfoResponseJsonrpc { + pub enum PostGetQueueLeafIndicesResponseJsonrpc { #[serde(rename = "2.0")] X20, } - impl ::std::fmt::Display for PostGetTransactionWithCompressionInfoResponseJsonrpc { + impl ::std::fmt::Display for PostGetQueueLeafIndicesResponseJsonrpc { fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result { match *self { Self::X20 => f.write_str("2.0"), } } } - impl ::std::str::FromStr for PostGetTransactionWithCompressionInfoResponseJsonrpc { + impl ::std::str::FromStr for PostGetQueueLeafIndicesResponseJsonrpc { type Err = self::error::ConversionError; fn from_str( value: &str, @@ -25255,8 +25360,7 @@ All endpoints return AccountV2.*/ } } } - impl ::std::convert::TryFrom<&str> - for PostGetTransactionWithCompressionInfoResponseJsonrpc { + impl ::std::convert::TryFrom<&str> for PostGetQueueLeafIndicesResponseJsonrpc { type Error = self::error::ConversionError; fn try_from( value: &str, @@ -25265,7 +25369,7 @@ All endpoints return AccountV2.*/ } } impl ::std::convert::TryFrom<&::std::string::String> - for PostGetTransactionWithCompressionInfoResponseJsonrpc { + for PostGetQueueLeafIndicesResponseJsonrpc { type Error = self::error::ConversionError; fn try_from( value: &::std::string::String, @@ -25274,7 +25378,7 @@ All endpoints return AccountV2.*/ } } impl ::std::convert::TryFrom<::std::string::String> - for PostGetTransactionWithCompressionInfoResponseJsonrpc { + for PostGetQueueLeafIndicesResponseJsonrpc { type Error = self::error::ConversionError; fn try_from( value: ::std::string::String, @@ -25282,91 +25386,26 @@ All endpoints return AccountV2.*/ value.parse() } } - ///A Solana transaction with additional compression information - /// - ///
JSON schema - /// - /// ```json - ///{ - /// "description": "A Solana transaction with additional compression information", - /// "type": "object", - /// "properties": { - /// "compression_info": { - /// "type": "object", - /// "required": [ - /// "closedAccounts", - /// "openedAccounts" - /// ], - /// "properties": { - /// "closedAccounts": { - /// "type": "array", - /// "items": { - /// "$ref": "#/components/schemas/AccountWithOptionalTokenData" - /// } - /// }, - /// "openedAccounts": { - /// "type": "array", - /// "items": { - /// "$ref": "#/components/schemas/AccountWithOptionalTokenData" - /// } - /// } - /// }, - /// "additionalProperties": false - /// }, - /// "transaction": { - /// "description": "An encoded confirmed transaction with status meta", - /// "type": "object" - /// } - /// } - ///} - /// ``` - ///
- #[derive(::serde::Deserialize, ::serde::Serialize, Clone, Debug)] - pub struct PostGetTransactionWithCompressionInfoResponseResult { - #[serde(default, skip_serializing_if = "::std::option::Option::is_none")] - pub compression_info: ::std::option::Option< - PostGetTransactionWithCompressionInfoResponseResultCompressionInfo, - >, - ///An encoded confirmed transaction with status meta - #[serde(default, skip_serializing_if = "::serde_json::Map::is_empty")] - pub transaction: ::serde_json::Map<::std::string::String, ::serde_json::Value>, - } - impl ::std::default::Default - for PostGetTransactionWithCompressionInfoResponseResult { - fn default() -> Self { - Self { - compression_info: Default::default(), - transaction: Default::default(), - } - } - } - impl PostGetTransactionWithCompressionInfoResponseResult { - pub fn builder() -> builder::PostGetTransactionWithCompressionInfoResponseResult { - Default::default() - } - } - ///`PostGetTransactionWithCompressionInfoResponseResultCompressionInfo` + ///Response containing queue leaf indices /// ///
JSON schema /// /// ```json ///{ + /// "description": "Response containing queue leaf indices", /// "type": "object", /// "required": [ - /// "closedAccounts", - /// "openedAccounts" + /// "context", + /// "value" /// ], /// "properties": { - /// "closedAccounts": { - /// "type": "array", - /// "items": { - /// "$ref": "#/components/schemas/AccountWithOptionalTokenData" - /// } + /// "context": { + /// "$ref": "#/components/schemas/Context" /// }, - /// "openedAccounts": { + /// "value": { /// "type": "array", /// "items": { - /// "$ref": "#/components/schemas/AccountWithOptionalTokenData" + /// "$ref": "#/components/schemas/QueueLeafIndex" /// } /// } /// }, @@ -25376,18 +25415,16 @@ All endpoints return AccountV2.*/ ///
#[derive(::serde::Deserialize, ::serde::Serialize, Clone, Debug)] #[serde(deny_unknown_fields)] - pub struct PostGetTransactionWithCompressionInfoResponseResultCompressionInfo { - #[serde(rename = "closedAccounts")] - pub closed_accounts: ::std::vec::Vec, - #[serde(rename = "openedAccounts")] - pub opened_accounts: ::std::vec::Vec, + pub struct PostGetQueueLeafIndicesResponseResult { + pub context: Context, + pub value: ::std::vec::Vec, } - impl PostGetTransactionWithCompressionInfoResponseResultCompressionInfo { - pub fn builder() -> builder::PostGetTransactionWithCompressionInfoResponseResultCompressionInfo { + impl PostGetQueueLeafIndicesResponseResult { + pub fn builder() -> builder::PostGetQueueLeafIndicesResponseResult { Default::default() } } - ///`PostGetTransactionWithCompressionInfoV2Body` + ///`PostGetTransactionWithCompressionInfoBody` /// ///
JSON schema /// @@ -25419,7 +25456,7 @@ All endpoints return AccountV2.*/ /// "description": "The name of the method to invoke.", /// "type": "string", /// "enum": [ - /// "getTransactionWithCompressionInfoV2" + /// "getTransactionWithCompressionInfo" /// ] /// }, /// "params": { @@ -25439,17 +25476,17 @@ All endpoints return AccountV2.*/ /// ``` ///
#[derive(::serde::Deserialize, ::serde::Serialize, Clone, Debug)] - pub struct PostGetTransactionWithCompressionInfoV2Body { + pub struct PostGetTransactionWithCompressionInfoBody { ///An ID to identify the request. - pub id: PostGetTransactionWithCompressionInfoV2BodyId, + pub id: PostGetTransactionWithCompressionInfoBodyId, ///The version of the JSON-RPC protocol. - pub jsonrpc: PostGetTransactionWithCompressionInfoV2BodyJsonrpc, + pub jsonrpc: PostGetTransactionWithCompressionInfoBodyJsonrpc, ///The name of the method to invoke. - pub method: PostGetTransactionWithCompressionInfoV2BodyMethod, - pub params: PostGetTransactionWithCompressionInfoV2BodyParams, + pub method: PostGetTransactionWithCompressionInfoBodyMethod, + pub params: PostGetTransactionWithCompressionInfoBodyParams, } - impl PostGetTransactionWithCompressionInfoV2Body { - pub fn builder() -> builder::PostGetTransactionWithCompressionInfoV2Body { + impl PostGetTransactionWithCompressionInfoBody { + pub fn builder() -> builder::PostGetTransactionWithCompressionInfoBody { Default::default() } } @@ -25479,18 +25516,18 @@ All endpoints return AccountV2.*/ PartialEq, PartialOrd )] - pub enum PostGetTransactionWithCompressionInfoV2BodyId { + pub enum PostGetTransactionWithCompressionInfoBodyId { #[serde(rename = "test-account")] TestAccount, } - impl ::std::fmt::Display for PostGetTransactionWithCompressionInfoV2BodyId { + impl ::std::fmt::Display for PostGetTransactionWithCompressionInfoBodyId { fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result { match *self { Self::TestAccount => f.write_str("test-account"), } } } - impl ::std::str::FromStr for PostGetTransactionWithCompressionInfoV2BodyId { + impl ::std::str::FromStr for PostGetTransactionWithCompressionInfoBodyId { type Err = self::error::ConversionError; fn from_str( value: &str, @@ -25501,8 +25538,7 @@ All endpoints return AccountV2.*/ } } } - impl ::std::convert::TryFrom<&str> - for PostGetTransactionWithCompressionInfoV2BodyId { + impl ::std::convert::TryFrom<&str> for PostGetTransactionWithCompressionInfoBodyId { type Error = self::error::ConversionError; fn try_from( value: &str, @@ -25511,7 +25547,7 @@ All endpoints return AccountV2.*/ } } impl ::std::convert::TryFrom<&::std::string::String> - for PostGetTransactionWithCompressionInfoV2BodyId { + for PostGetTransactionWithCompressionInfoBodyId { type Error = self::error::ConversionError; fn try_from( value: &::std::string::String, @@ -25520,7 +25556,7 @@ All endpoints return AccountV2.*/ } } impl ::std::convert::TryFrom<::std::string::String> - for PostGetTransactionWithCompressionInfoV2BodyId { + for PostGetTransactionWithCompressionInfoBodyId { type Error = self::error::ConversionError; fn try_from( value: ::std::string::String, @@ -25554,18 +25590,18 @@ All endpoints return AccountV2.*/ PartialEq, PartialOrd )] - pub enum PostGetTransactionWithCompressionInfoV2BodyJsonrpc { + pub enum PostGetTransactionWithCompressionInfoBodyJsonrpc { #[serde(rename = "2.0")] X20, } - impl ::std::fmt::Display for PostGetTransactionWithCompressionInfoV2BodyJsonrpc { + impl ::std::fmt::Display for PostGetTransactionWithCompressionInfoBodyJsonrpc { fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result { match *self { Self::X20 => f.write_str("2.0"), } } } - impl ::std::str::FromStr for PostGetTransactionWithCompressionInfoV2BodyJsonrpc { + impl ::std::str::FromStr for PostGetTransactionWithCompressionInfoBodyJsonrpc { type Err = self::error::ConversionError; fn from_str( value: &str, @@ -25577,7 +25613,7 @@ All endpoints return AccountV2.*/ } } impl ::std::convert::TryFrom<&str> - for PostGetTransactionWithCompressionInfoV2BodyJsonrpc { + for PostGetTransactionWithCompressionInfoBodyJsonrpc { type Error = self::error::ConversionError; fn try_from( value: &str, @@ -25586,7 +25622,7 @@ All endpoints return AccountV2.*/ } } impl ::std::convert::TryFrom<&::std::string::String> - for PostGetTransactionWithCompressionInfoV2BodyJsonrpc { + for PostGetTransactionWithCompressionInfoBodyJsonrpc { type Error = self::error::ConversionError; fn try_from( value: &::std::string::String, @@ -25595,7 +25631,7 @@ All endpoints return AccountV2.*/ } } impl ::std::convert::TryFrom<::std::string::String> - for PostGetTransactionWithCompressionInfoV2BodyJsonrpc { + for PostGetTransactionWithCompressionInfoBodyJsonrpc { type Error = self::error::ConversionError; fn try_from( value: ::std::string::String, @@ -25612,7 +25648,7 @@ All endpoints return AccountV2.*/ /// "description": "The name of the method to invoke.", /// "type": "string", /// "enum": [ - /// "getTransactionWithCompressionInfoV2" + /// "getTransactionWithCompressionInfo" /// ] ///} /// ``` @@ -25629,34 +25665,34 @@ All endpoints return AccountV2.*/ PartialEq, PartialOrd )] - pub enum PostGetTransactionWithCompressionInfoV2BodyMethod { - #[serde(rename = "getTransactionWithCompressionInfoV2")] - GetTransactionWithCompressionInfoV2, + pub enum PostGetTransactionWithCompressionInfoBodyMethod { + #[serde(rename = "getTransactionWithCompressionInfo")] + GetTransactionWithCompressionInfo, } - impl ::std::fmt::Display for PostGetTransactionWithCompressionInfoV2BodyMethod { + impl ::std::fmt::Display for PostGetTransactionWithCompressionInfoBodyMethod { fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result { match *self { - Self::GetTransactionWithCompressionInfoV2 => { - f.write_str("getTransactionWithCompressionInfoV2") + Self::GetTransactionWithCompressionInfo => { + f.write_str("getTransactionWithCompressionInfo") } } } } - impl ::std::str::FromStr for PostGetTransactionWithCompressionInfoV2BodyMethod { + impl ::std::str::FromStr for PostGetTransactionWithCompressionInfoBodyMethod { type Err = self::error::ConversionError; fn from_str( value: &str, ) -> ::std::result::Result { match value { - "getTransactionWithCompressionInfoV2" => { - Ok(Self::GetTransactionWithCompressionInfoV2) + "getTransactionWithCompressionInfo" => { + Ok(Self::GetTransactionWithCompressionInfo) } _ => Err("invalid value".into()), } } } impl ::std::convert::TryFrom<&str> - for PostGetTransactionWithCompressionInfoV2BodyMethod { + for PostGetTransactionWithCompressionInfoBodyMethod { type Error = self::error::ConversionError; fn try_from( value: &str, @@ -25665,7 +25701,7 @@ All endpoints return AccountV2.*/ } } impl ::std::convert::TryFrom<&::std::string::String> - for PostGetTransactionWithCompressionInfoV2BodyMethod { + for PostGetTransactionWithCompressionInfoBodyMethod { type Error = self::error::ConversionError; fn try_from( value: &::std::string::String, @@ -25674,7 +25710,7 @@ All endpoints return AccountV2.*/ } } impl ::std::convert::TryFrom<::std::string::String> - for PostGetTransactionWithCompressionInfoV2BodyMethod { + for PostGetTransactionWithCompressionInfoBodyMethod { type Error = self::error::ConversionError; fn try_from( value: ::std::string::String, @@ -25682,7 +25718,7 @@ All endpoints return AccountV2.*/ value.parse() } } - ///`PostGetTransactionWithCompressionInfoV2BodyParams` + ///`PostGetTransactionWithCompressionInfoBodyParams` /// ///
JSON schema /// @@ -25703,15 +25739,15 @@ All endpoints return AccountV2.*/ ///
#[derive(::serde::Deserialize, ::serde::Serialize, Clone, Debug)] #[serde(deny_unknown_fields)] - pub struct PostGetTransactionWithCompressionInfoV2BodyParams { + pub struct PostGetTransactionWithCompressionInfoBodyParams { pub signature: SerializableSignature, } - impl PostGetTransactionWithCompressionInfoV2BodyParams { - pub fn builder() -> builder::PostGetTransactionWithCompressionInfoV2BodyParams { + impl PostGetTransactionWithCompressionInfoBodyParams { + pub fn builder() -> builder::PostGetTransactionWithCompressionInfoBodyParams { Default::default() } } - ///`PostGetTransactionWithCompressionInfoV2Response` + ///`PostGetTransactionWithCompressionInfoResponse` /// ///
JSON schema /// @@ -25762,13 +25798,13 @@ All endpoints return AccountV2.*/ /// "closedAccounts": { /// "type": "array", /// "items": { - /// "$ref": "#/components/schemas/ClosedAccountWithOptionalTokenDataV2" + /// "$ref": "#/components/schemas/AccountWithOptionalTokenData" /// } /// }, /// "openedAccounts": { /// "type": "array", /// "items": { - /// "$ref": "#/components/schemas/AccountWithOptionalTokenDataV2" + /// "$ref": "#/components/schemas/AccountWithOptionalTokenData" /// } /// } /// }, @@ -25785,26 +25821,26 @@ All endpoints return AccountV2.*/ /// ``` ///
#[derive(::serde::Deserialize, ::serde::Serialize, Clone, Debug)] - pub struct PostGetTransactionWithCompressionInfoV2Response { + pub struct PostGetTransactionWithCompressionInfoResponse { #[serde(default, skip_serializing_if = "::std::option::Option::is_none")] pub error: ::std::option::Option< - PostGetTransactionWithCompressionInfoV2ResponseError, + PostGetTransactionWithCompressionInfoResponseError, >, ///An ID to identify the response. - pub id: PostGetTransactionWithCompressionInfoV2ResponseId, + pub id: PostGetTransactionWithCompressionInfoResponseId, ///The version of the JSON-RPC protocol. - pub jsonrpc: PostGetTransactionWithCompressionInfoV2ResponseJsonrpc, + pub jsonrpc: PostGetTransactionWithCompressionInfoResponseJsonrpc, #[serde(default, skip_serializing_if = "::std::option::Option::is_none")] pub result: ::std::option::Option< - PostGetTransactionWithCompressionInfoV2ResponseResult, + PostGetTransactionWithCompressionInfoResponseResult, >, } - impl PostGetTransactionWithCompressionInfoV2Response { - pub fn builder() -> builder::PostGetTransactionWithCompressionInfoV2Response { + impl PostGetTransactionWithCompressionInfoResponse { + pub fn builder() -> builder::PostGetTransactionWithCompressionInfoResponse { Default::default() } } - ///`PostGetTransactionWithCompressionInfoV2ResponseError` + ///`PostGetTransactionWithCompressionInfoResponseError` /// ///
JSON schema /// @@ -25823,14 +25859,13 @@ All endpoints return AccountV2.*/ /// ``` ///
#[derive(::serde::Deserialize, ::serde::Serialize, Clone, Debug)] - pub struct PostGetTransactionWithCompressionInfoV2ResponseError { + pub struct PostGetTransactionWithCompressionInfoResponseError { #[serde(default, skip_serializing_if = "::std::option::Option::is_none")] pub code: ::std::option::Option, #[serde(default, skip_serializing_if = "::std::option::Option::is_none")] pub message: ::std::option::Option<::std::string::String>, } - impl ::std::default::Default - for PostGetTransactionWithCompressionInfoV2ResponseError { + impl ::std::default::Default for PostGetTransactionWithCompressionInfoResponseError { fn default() -> Self { Self { code: Default::default(), @@ -25838,8 +25873,8 @@ All endpoints return AccountV2.*/ } } } - impl PostGetTransactionWithCompressionInfoV2ResponseError { - pub fn builder() -> builder::PostGetTransactionWithCompressionInfoV2ResponseError { + impl PostGetTransactionWithCompressionInfoResponseError { + pub fn builder() -> builder::PostGetTransactionWithCompressionInfoResponseError { Default::default() } } @@ -25869,18 +25904,18 @@ All endpoints return AccountV2.*/ PartialEq, PartialOrd )] - pub enum PostGetTransactionWithCompressionInfoV2ResponseId { + pub enum PostGetTransactionWithCompressionInfoResponseId { #[serde(rename = "test-account")] TestAccount, } - impl ::std::fmt::Display for PostGetTransactionWithCompressionInfoV2ResponseId { + impl ::std::fmt::Display for PostGetTransactionWithCompressionInfoResponseId { fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result { match *self { Self::TestAccount => f.write_str("test-account"), } } } - impl ::std::str::FromStr for PostGetTransactionWithCompressionInfoV2ResponseId { + impl ::std::str::FromStr for PostGetTransactionWithCompressionInfoResponseId { type Err = self::error::ConversionError; fn from_str( value: &str, @@ -25892,7 +25927,7 @@ All endpoints return AccountV2.*/ } } impl ::std::convert::TryFrom<&str> - for PostGetTransactionWithCompressionInfoV2ResponseId { + for PostGetTransactionWithCompressionInfoResponseId { type Error = self::error::ConversionError; fn try_from( value: &str, @@ -25901,7 +25936,7 @@ All endpoints return AccountV2.*/ } } impl ::std::convert::TryFrom<&::std::string::String> - for PostGetTransactionWithCompressionInfoV2ResponseId { + for PostGetTransactionWithCompressionInfoResponseId { type Error = self::error::ConversionError; fn try_from( value: &::std::string::String, @@ -25910,7 +25945,7 @@ All endpoints return AccountV2.*/ } } impl ::std::convert::TryFrom<::std::string::String> - for PostGetTransactionWithCompressionInfoV2ResponseId { + for PostGetTransactionWithCompressionInfoResponseId { type Error = self::error::ConversionError; fn try_from( value: ::std::string::String, @@ -25944,18 +25979,18 @@ All endpoints return AccountV2.*/ PartialEq, PartialOrd )] - pub enum PostGetTransactionWithCompressionInfoV2ResponseJsonrpc { + pub enum PostGetTransactionWithCompressionInfoResponseJsonrpc { #[serde(rename = "2.0")] X20, } - impl ::std::fmt::Display for PostGetTransactionWithCompressionInfoV2ResponseJsonrpc { + impl ::std::fmt::Display for PostGetTransactionWithCompressionInfoResponseJsonrpc { fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result { match *self { Self::X20 => f.write_str("2.0"), } } } - impl ::std::str::FromStr for PostGetTransactionWithCompressionInfoV2ResponseJsonrpc { + impl ::std::str::FromStr for PostGetTransactionWithCompressionInfoResponseJsonrpc { type Err = self::error::ConversionError; fn from_str( value: &str, @@ -25967,7 +26002,7 @@ All endpoints return AccountV2.*/ } } impl ::std::convert::TryFrom<&str> - for PostGetTransactionWithCompressionInfoV2ResponseJsonrpc { + for PostGetTransactionWithCompressionInfoResponseJsonrpc { type Error = self::error::ConversionError; fn try_from( value: &str, @@ -25976,7 +26011,7 @@ All endpoints return AccountV2.*/ } } impl ::std::convert::TryFrom<&::std::string::String> - for PostGetTransactionWithCompressionInfoV2ResponseJsonrpc { + for PostGetTransactionWithCompressionInfoResponseJsonrpc { type Error = self::error::ConversionError; fn try_from( value: &::std::string::String, @@ -25985,7 +26020,7 @@ All endpoints return AccountV2.*/ } } impl ::std::convert::TryFrom<::std::string::String> - for PostGetTransactionWithCompressionInfoV2ResponseJsonrpc { + for PostGetTransactionWithCompressionInfoResponseJsonrpc { type Error = self::error::ConversionError; fn try_from( value: ::std::string::String, @@ -26012,13 +26047,13 @@ All endpoints return AccountV2.*/ /// "closedAccounts": { /// "type": "array", /// "items": { - /// "$ref": "#/components/schemas/ClosedAccountWithOptionalTokenDataV2" + /// "$ref": "#/components/schemas/AccountWithOptionalTokenData" /// } /// }, /// "openedAccounts": { /// "type": "array", /// "items": { - /// "$ref": "#/components/schemas/AccountWithOptionalTokenDataV2" + /// "$ref": "#/components/schemas/AccountWithOptionalTokenData" /// } /// } /// }, @@ -26033,17 +26068,17 @@ All endpoints return AccountV2.*/ /// ``` ///
#[derive(::serde::Deserialize, ::serde::Serialize, Clone, Debug)] - pub struct PostGetTransactionWithCompressionInfoV2ResponseResult { + pub struct PostGetTransactionWithCompressionInfoResponseResult { #[serde(default, skip_serializing_if = "::std::option::Option::is_none")] pub compression_info: ::std::option::Option< - PostGetTransactionWithCompressionInfoV2ResponseResultCompressionInfo, + PostGetTransactionWithCompressionInfoResponseResultCompressionInfo, >, ///An encoded confirmed transaction with status meta #[serde(default, skip_serializing_if = "::serde_json::Map::is_empty")] pub transaction: ::serde_json::Map<::std::string::String, ::serde_json::Value>, } impl ::std::default::Default - for PostGetTransactionWithCompressionInfoV2ResponseResult { + for PostGetTransactionWithCompressionInfoResponseResult { fn default() -> Self { Self { compression_info: Default::default(), @@ -26051,12 +26086,12 @@ All endpoints return AccountV2.*/ } } } - impl PostGetTransactionWithCompressionInfoV2ResponseResult { - pub fn builder() -> builder::PostGetTransactionWithCompressionInfoV2ResponseResult { + impl PostGetTransactionWithCompressionInfoResponseResult { + pub fn builder() -> builder::PostGetTransactionWithCompressionInfoResponseResult { Default::default() } } - ///`PostGetTransactionWithCompressionInfoV2ResponseResultCompressionInfo` + ///`PostGetTransactionWithCompressionInfoResponseResultCompressionInfo` /// ///
JSON schema /// @@ -26071,13 +26106,13 @@ All endpoints return AccountV2.*/ /// "closedAccounts": { /// "type": "array", /// "items": { - /// "$ref": "#/components/schemas/ClosedAccountWithOptionalTokenDataV2" + /// "$ref": "#/components/schemas/AccountWithOptionalTokenData" /// } /// }, /// "openedAccounts": { /// "type": "array", /// "items": { - /// "$ref": "#/components/schemas/AccountWithOptionalTokenDataV2" + /// "$ref": "#/components/schemas/AccountWithOptionalTokenData" /// } /// } /// }, @@ -26087,18 +26122,18 @@ All endpoints return AccountV2.*/ ///
#[derive(::serde::Deserialize, ::serde::Serialize, Clone, Debug)] #[serde(deny_unknown_fields)] - pub struct PostGetTransactionWithCompressionInfoV2ResponseResultCompressionInfo { + pub struct PostGetTransactionWithCompressionInfoResponseResultCompressionInfo { #[serde(rename = "closedAccounts")] - pub closed_accounts: ::std::vec::Vec, + pub closed_accounts: ::std::vec::Vec, #[serde(rename = "openedAccounts")] - pub opened_accounts: ::std::vec::Vec, + pub opened_accounts: ::std::vec::Vec, } - impl PostGetTransactionWithCompressionInfoV2ResponseResultCompressionInfo { - pub fn builder() -> builder::PostGetTransactionWithCompressionInfoV2ResponseResultCompressionInfo { + impl PostGetTransactionWithCompressionInfoResponseResultCompressionInfo { + pub fn builder() -> builder::PostGetTransactionWithCompressionInfoResponseResultCompressionInfo { Default::default() } } - ///`PostGetValidityProofBody` + ///`PostGetTransactionWithCompressionInfoV2Body` /// ///
JSON schema /// @@ -26130,23 +26165,17 @@ All endpoints return AccountV2.*/ /// "description": "The name of the method to invoke.", /// "type": "string", /// "enum": [ - /// "getValidityProof" + /// "getTransactionWithCompressionInfoV2" /// ] /// }, /// "params": { /// "type": "object", + /// "required": [ + /// "signature" + /// ], /// "properties": { - /// "hashes": { - /// "type": "array", - /// "items": { - /// "$ref": "#/components/schemas/Hash" - /// } - /// }, - /// "newAddressesWithTrees": { - /// "type": "array", - /// "items": { - /// "$ref": "#/components/schemas/AddressWithTree" - /// } + /// "signature": { + /// "$ref": "#/components/schemas/SerializableSignature" /// } /// }, /// "additionalProperties": false @@ -26156,17 +26185,17 @@ All endpoints return AccountV2.*/ /// ``` ///
#[derive(::serde::Deserialize, ::serde::Serialize, Clone, Debug)] - pub struct PostGetValidityProofBody { + pub struct PostGetTransactionWithCompressionInfoV2Body { ///An ID to identify the request. - pub id: PostGetValidityProofBodyId, + pub id: PostGetTransactionWithCompressionInfoV2BodyId, ///The version of the JSON-RPC protocol. - pub jsonrpc: PostGetValidityProofBodyJsonrpc, + pub jsonrpc: PostGetTransactionWithCompressionInfoV2BodyJsonrpc, ///The name of the method to invoke. - pub method: PostGetValidityProofBodyMethod, - pub params: PostGetValidityProofBodyParams, + pub method: PostGetTransactionWithCompressionInfoV2BodyMethod, + pub params: PostGetTransactionWithCompressionInfoV2BodyParams, } - impl PostGetValidityProofBody { - pub fn builder() -> builder::PostGetValidityProofBody { + impl PostGetTransactionWithCompressionInfoV2Body { + pub fn builder() -> builder::PostGetTransactionWithCompressionInfoV2Body { Default::default() } } @@ -26196,18 +26225,18 @@ All endpoints return AccountV2.*/ PartialEq, PartialOrd )] - pub enum PostGetValidityProofBodyId { + pub enum PostGetTransactionWithCompressionInfoV2BodyId { #[serde(rename = "test-account")] TestAccount, } - impl ::std::fmt::Display for PostGetValidityProofBodyId { + impl ::std::fmt::Display for PostGetTransactionWithCompressionInfoV2BodyId { fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result { match *self { Self::TestAccount => f.write_str("test-account"), } } } - impl ::std::str::FromStr for PostGetValidityProofBodyId { + impl ::std::str::FromStr for PostGetTransactionWithCompressionInfoV2BodyId { type Err = self::error::ConversionError; fn from_str( value: &str, @@ -26218,7 +26247,8 @@ All endpoints return AccountV2.*/ } } } - impl ::std::convert::TryFrom<&str> for PostGetValidityProofBodyId { + impl ::std::convert::TryFrom<&str> + for PostGetTransactionWithCompressionInfoV2BodyId { type Error = self::error::ConversionError; fn try_from( value: &str, @@ -26226,7 +26256,8 @@ All endpoints return AccountV2.*/ value.parse() } } - impl ::std::convert::TryFrom<&::std::string::String> for PostGetValidityProofBodyId { + impl ::std::convert::TryFrom<&::std::string::String> + for PostGetTransactionWithCompressionInfoV2BodyId { type Error = self::error::ConversionError; fn try_from( value: &::std::string::String, @@ -26234,7 +26265,8 @@ All endpoints return AccountV2.*/ value.parse() } } - impl ::std::convert::TryFrom<::std::string::String> for PostGetValidityProofBodyId { + impl ::std::convert::TryFrom<::std::string::String> + for PostGetTransactionWithCompressionInfoV2BodyId { type Error = self::error::ConversionError; fn try_from( value: ::std::string::String, @@ -26268,18 +26300,18 @@ All endpoints return AccountV2.*/ PartialEq, PartialOrd )] - pub enum PostGetValidityProofBodyJsonrpc { + pub enum PostGetTransactionWithCompressionInfoV2BodyJsonrpc { #[serde(rename = "2.0")] X20, } - impl ::std::fmt::Display for PostGetValidityProofBodyJsonrpc { + impl ::std::fmt::Display for PostGetTransactionWithCompressionInfoV2BodyJsonrpc { fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result { match *self { Self::X20 => f.write_str("2.0"), } } } - impl ::std::str::FromStr for PostGetValidityProofBodyJsonrpc { + impl ::std::str::FromStr for PostGetTransactionWithCompressionInfoV2BodyJsonrpc { type Err = self::error::ConversionError; fn from_str( value: &str, @@ -26290,7 +26322,8 @@ All endpoints return AccountV2.*/ } } } - impl ::std::convert::TryFrom<&str> for PostGetValidityProofBodyJsonrpc { + impl ::std::convert::TryFrom<&str> + for PostGetTransactionWithCompressionInfoV2BodyJsonrpc { type Error = self::error::ConversionError; fn try_from( value: &str, @@ -26299,7 +26332,7 @@ All endpoints return AccountV2.*/ } } impl ::std::convert::TryFrom<&::std::string::String> - for PostGetValidityProofBodyJsonrpc { + for PostGetTransactionWithCompressionInfoV2BodyJsonrpc { type Error = self::error::ConversionError; fn try_from( value: &::std::string::String, @@ -26308,7 +26341,7 @@ All endpoints return AccountV2.*/ } } impl ::std::convert::TryFrom<::std::string::String> - for PostGetValidityProofBodyJsonrpc { + for PostGetTransactionWithCompressionInfoV2BodyJsonrpc { type Error = self::error::ConversionError; fn try_from( value: ::std::string::String, @@ -26325,7 +26358,7 @@ All endpoints return AccountV2.*/ /// "description": "The name of the method to invoke.", /// "type": "string", /// "enum": [ - /// "getValidityProof" + /// "getTransactionWithCompressionInfoV2" /// ] ///} /// ``` @@ -26342,29 +26375,34 @@ All endpoints return AccountV2.*/ PartialEq, PartialOrd )] - pub enum PostGetValidityProofBodyMethod { - #[serde(rename = "getValidityProof")] - GetValidityProof, + pub enum PostGetTransactionWithCompressionInfoV2BodyMethod { + #[serde(rename = "getTransactionWithCompressionInfoV2")] + GetTransactionWithCompressionInfoV2, } - impl ::std::fmt::Display for PostGetValidityProofBodyMethod { + impl ::std::fmt::Display for PostGetTransactionWithCompressionInfoV2BodyMethod { fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result { match *self { - Self::GetValidityProof => f.write_str("getValidityProof"), + Self::GetTransactionWithCompressionInfoV2 => { + f.write_str("getTransactionWithCompressionInfoV2") + } } } } - impl ::std::str::FromStr for PostGetValidityProofBodyMethod { + impl ::std::str::FromStr for PostGetTransactionWithCompressionInfoV2BodyMethod { type Err = self::error::ConversionError; fn from_str( value: &str, ) -> ::std::result::Result { match value { - "getValidityProof" => Ok(Self::GetValidityProof), + "getTransactionWithCompressionInfoV2" => { + Ok(Self::GetTransactionWithCompressionInfoV2) + } _ => Err("invalid value".into()), } } } - impl ::std::convert::TryFrom<&str> for PostGetValidityProofBodyMethod { + impl ::std::convert::TryFrom<&str> + for PostGetTransactionWithCompressionInfoV2BodyMethod { type Error = self::error::ConversionError; fn try_from( value: &str, @@ -26373,7 +26411,7 @@ All endpoints return AccountV2.*/ } } impl ::std::convert::TryFrom<&::std::string::String> - for PostGetValidityProofBodyMethod { + for PostGetTransactionWithCompressionInfoV2BodyMethod { type Error = self::error::ConversionError; fn try_from( value: &::std::string::String, @@ -26382,7 +26420,7 @@ All endpoints return AccountV2.*/ } } impl ::std::convert::TryFrom<::std::string::String> - for PostGetValidityProofBodyMethod { + for PostGetTransactionWithCompressionInfoV2BodyMethod { type Error = self::error::ConversionError; fn try_from( value: ::std::string::String, @@ -26390,25 +26428,19 @@ All endpoints return AccountV2.*/ value.parse() } } - ///`PostGetValidityProofBodyParams` + ///`PostGetTransactionWithCompressionInfoV2BodyParams` /// ///
JSON schema /// /// ```json ///{ /// "type": "object", + /// "required": [ + /// "signature" + /// ], /// "properties": { - /// "hashes": { - /// "type": "array", - /// "items": { - /// "$ref": "#/components/schemas/Hash" - /// } - /// }, - /// "newAddressesWithTrees": { - /// "type": "array", - /// "items": { - /// "$ref": "#/components/schemas/AddressWithTree" - /// } + /// "signature": { + /// "$ref": "#/components/schemas/SerializableSignature" /// } /// }, /// "additionalProperties": false @@ -26417,30 +26449,15 @@ All endpoints return AccountV2.*/ ///
#[derive(::serde::Deserialize, ::serde::Serialize, Clone, Debug)] #[serde(deny_unknown_fields)] - pub struct PostGetValidityProofBodyParams { - #[serde(default, skip_serializing_if = "::std::vec::Vec::is_empty")] - pub hashes: ::std::vec::Vec, - #[serde( - rename = "newAddressesWithTrees", - default, - skip_serializing_if = "::std::vec::Vec::is_empty" - )] - pub new_addresses_with_trees: ::std::vec::Vec, - } - impl ::std::default::Default for PostGetValidityProofBodyParams { - fn default() -> Self { - Self { - hashes: Default::default(), - new_addresses_with_trees: Default::default(), - } - } + pub struct PostGetTransactionWithCompressionInfoV2BodyParams { + pub signature: SerializableSignature, } - impl PostGetValidityProofBodyParams { - pub fn builder() -> builder::PostGetValidityProofBodyParams { + impl PostGetTransactionWithCompressionInfoV2BodyParams { + pub fn builder() -> builder::PostGetTransactionWithCompressionInfoV2BodyParams { Default::default() } } - ///`PostGetValidityProofResponse` + ///`PostGetTransactionWithCompressionInfoV2Response` /// ///
JSON schema /// @@ -26478,42 +26495,62 @@ All endpoints return AccountV2.*/ /// ] /// }, /// "result": { + /// "description": "A Solana transaction with additional compression information", /// "type": "object", - /// "required": [ - /// "context", - /// "value" - /// ], /// "properties": { - /// "context": { - /// "$ref": "#/components/schemas/Context" + /// "compression_info": { + /// "type": "object", + /// "required": [ + /// "closedAccounts", + /// "openedAccounts" + /// ], + /// "properties": { + /// "closedAccounts": { + /// "type": "array", + /// "items": { + /// "$ref": "#/components/schemas/ClosedAccountWithOptionalTokenDataV2" + /// } + /// }, + /// "openedAccounts": { + /// "type": "array", + /// "items": { + /// "$ref": "#/components/schemas/AccountWithOptionalTokenDataV2" + /// } + /// } + /// }, + /// "additionalProperties": false /// }, - /// "value": { - /// "$ref": "#/components/schemas/CompressedProofWithContext" + /// "transaction": { + /// "description": "An encoded confirmed transaction with status meta", + /// "type": "object" /// } - /// }, - /// "additionalProperties": false + /// } /// } /// } ///} /// ``` ///
#[derive(::serde::Deserialize, ::serde::Serialize, Clone, Debug)] - pub struct PostGetValidityProofResponse { + pub struct PostGetTransactionWithCompressionInfoV2Response { #[serde(default, skip_serializing_if = "::std::option::Option::is_none")] - pub error: ::std::option::Option, + pub error: ::std::option::Option< + PostGetTransactionWithCompressionInfoV2ResponseError, + >, ///An ID to identify the response. - pub id: PostGetValidityProofResponseId, + pub id: PostGetTransactionWithCompressionInfoV2ResponseId, ///The version of the JSON-RPC protocol. - pub jsonrpc: PostGetValidityProofResponseJsonrpc, + pub jsonrpc: PostGetTransactionWithCompressionInfoV2ResponseJsonrpc, #[serde(default, skip_serializing_if = "::std::option::Option::is_none")] - pub result: ::std::option::Option, + pub result: ::std::option::Option< + PostGetTransactionWithCompressionInfoV2ResponseResult, + >, } - impl PostGetValidityProofResponse { - pub fn builder() -> builder::PostGetValidityProofResponse { + impl PostGetTransactionWithCompressionInfoV2Response { + pub fn builder() -> builder::PostGetTransactionWithCompressionInfoV2Response { Default::default() } } - ///`PostGetValidityProofResponseError` + ///`PostGetTransactionWithCompressionInfoV2ResponseError` /// ///
JSON schema /// @@ -26532,13 +26569,14 @@ All endpoints return AccountV2.*/ /// ``` ///
#[derive(::serde::Deserialize, ::serde::Serialize, Clone, Debug)] - pub struct PostGetValidityProofResponseError { + pub struct PostGetTransactionWithCompressionInfoV2ResponseError { #[serde(default, skip_serializing_if = "::std::option::Option::is_none")] pub code: ::std::option::Option, #[serde(default, skip_serializing_if = "::std::option::Option::is_none")] pub message: ::std::option::Option<::std::string::String>, } - impl ::std::default::Default for PostGetValidityProofResponseError { + impl ::std::default::Default + for PostGetTransactionWithCompressionInfoV2ResponseError { fn default() -> Self { Self { code: Default::default(), @@ -26546,8 +26584,8 @@ All endpoints return AccountV2.*/ } } } - impl PostGetValidityProofResponseError { - pub fn builder() -> builder::PostGetValidityProofResponseError { + impl PostGetTransactionWithCompressionInfoV2ResponseError { + pub fn builder() -> builder::PostGetTransactionWithCompressionInfoV2ResponseError { Default::default() } } @@ -26577,18 +26615,18 @@ All endpoints return AccountV2.*/ PartialEq, PartialOrd )] - pub enum PostGetValidityProofResponseId { + pub enum PostGetTransactionWithCompressionInfoV2ResponseId { #[serde(rename = "test-account")] TestAccount, } - impl ::std::fmt::Display for PostGetValidityProofResponseId { + impl ::std::fmt::Display for PostGetTransactionWithCompressionInfoV2ResponseId { fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result { match *self { Self::TestAccount => f.write_str("test-account"), } } } - impl ::std::str::FromStr for PostGetValidityProofResponseId { + impl ::std::str::FromStr for PostGetTransactionWithCompressionInfoV2ResponseId { type Err = self::error::ConversionError; fn from_str( value: &str, @@ -26599,7 +26637,8 @@ All endpoints return AccountV2.*/ } } } - impl ::std::convert::TryFrom<&str> for PostGetValidityProofResponseId { + impl ::std::convert::TryFrom<&str> + for PostGetTransactionWithCompressionInfoV2ResponseId { type Error = self::error::ConversionError; fn try_from( value: &str, @@ -26608,7 +26647,7 @@ All endpoints return AccountV2.*/ } } impl ::std::convert::TryFrom<&::std::string::String> - for PostGetValidityProofResponseId { + for PostGetTransactionWithCompressionInfoV2ResponseId { type Error = self::error::ConversionError; fn try_from( value: &::std::string::String, @@ -26617,7 +26656,7 @@ All endpoints return AccountV2.*/ } } impl ::std::convert::TryFrom<::std::string::String> - for PostGetValidityProofResponseId { + for PostGetTransactionWithCompressionInfoV2ResponseId { type Error = self::error::ConversionError; fn try_from( value: ::std::string::String, @@ -26651,18 +26690,18 @@ All endpoints return AccountV2.*/ PartialEq, PartialOrd )] - pub enum PostGetValidityProofResponseJsonrpc { + pub enum PostGetTransactionWithCompressionInfoV2ResponseJsonrpc { #[serde(rename = "2.0")] X20, } - impl ::std::fmt::Display for PostGetValidityProofResponseJsonrpc { + impl ::std::fmt::Display for PostGetTransactionWithCompressionInfoV2ResponseJsonrpc { fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result { match *self { Self::X20 => f.write_str("2.0"), } } } - impl ::std::str::FromStr for PostGetValidityProofResponseJsonrpc { + impl ::std::str::FromStr for PostGetTransactionWithCompressionInfoV2ResponseJsonrpc { type Err = self::error::ConversionError; fn from_str( value: &str, @@ -26673,7 +26712,8 @@ All endpoints return AccountV2.*/ } } } - impl ::std::convert::TryFrom<&str> for PostGetValidityProofResponseJsonrpc { + impl ::std::convert::TryFrom<&str> + for PostGetTransactionWithCompressionInfoV2ResponseJsonrpc { type Error = self::error::ConversionError; fn try_from( value: &str, @@ -26682,7 +26722,7 @@ All endpoints return AccountV2.*/ } } impl ::std::convert::TryFrom<&::std::string::String> - for PostGetValidityProofResponseJsonrpc { + for PostGetTransactionWithCompressionInfoV2ResponseJsonrpc { type Error = self::error::ConversionError; fn try_from( value: &::std::string::String, @@ -26691,7 +26731,7 @@ All endpoints return AccountV2.*/ } } impl ::std::convert::TryFrom<::std::string::String> - for PostGetValidityProofResponseJsonrpc { + for PostGetTransactionWithCompressionInfoV2ResponseJsonrpc { type Error = self::error::ConversionError; fn try_from( value: ::std::string::String, @@ -26699,7 +26739,70 @@ All endpoints return AccountV2.*/ value.parse() } } - ///`PostGetValidityProofResponseResult` + ///A Solana transaction with additional compression information + /// + ///
JSON schema + /// + /// ```json + ///{ + /// "description": "A Solana transaction with additional compression information", + /// "type": "object", + /// "properties": { + /// "compression_info": { + /// "type": "object", + /// "required": [ + /// "closedAccounts", + /// "openedAccounts" + /// ], + /// "properties": { + /// "closedAccounts": { + /// "type": "array", + /// "items": { + /// "$ref": "#/components/schemas/ClosedAccountWithOptionalTokenDataV2" + /// } + /// }, + /// "openedAccounts": { + /// "type": "array", + /// "items": { + /// "$ref": "#/components/schemas/AccountWithOptionalTokenDataV2" + /// } + /// } + /// }, + /// "additionalProperties": false + /// }, + /// "transaction": { + /// "description": "An encoded confirmed transaction with status meta", + /// "type": "object" + /// } + /// } + ///} + /// ``` + ///
+ #[derive(::serde::Deserialize, ::serde::Serialize, Clone, Debug)] + pub struct PostGetTransactionWithCompressionInfoV2ResponseResult { + #[serde(default, skip_serializing_if = "::std::option::Option::is_none")] + pub compression_info: ::std::option::Option< + PostGetTransactionWithCompressionInfoV2ResponseResultCompressionInfo, + >, + ///An encoded confirmed transaction with status meta + #[serde(default, skip_serializing_if = "::serde_json::Map::is_empty")] + pub transaction: ::serde_json::Map<::std::string::String, ::serde_json::Value>, + } + impl ::std::default::Default + for PostGetTransactionWithCompressionInfoV2ResponseResult { + fn default() -> Self { + Self { + compression_info: Default::default(), + transaction: Default::default(), + } + } + } + impl PostGetTransactionWithCompressionInfoV2ResponseResult { + pub fn builder() -> builder::PostGetTransactionWithCompressionInfoV2ResponseResult { + Default::default() + } + } + ///`PostGetTransactionWithCompressionInfoV2ResponseResultCompressionInfo` /// ///
JSON schema /// @@ -26707,15 +26810,21 @@ All endpoints return AccountV2.*/ ///{ /// "type": "object", /// "required": [ - /// "context", - /// "value" + /// "closedAccounts", + /// "openedAccounts" /// ], /// "properties": { - /// "context": { - /// "$ref": "#/components/schemas/Context" + /// "closedAccounts": { + /// "type": "array", + /// "items": { + /// "$ref": "#/components/schemas/ClosedAccountWithOptionalTokenDataV2" + /// } /// }, - /// "value": { - /// "$ref": "#/components/schemas/CompressedProofWithContext" + /// "openedAccounts": { + /// "type": "array", + /// "items": { + /// "$ref": "#/components/schemas/AccountWithOptionalTokenDataV2" + /// } /// } /// }, /// "additionalProperties": false @@ -26724,16 +26833,18 @@ All endpoints return AccountV2.*/ ///
#[derive(::serde::Deserialize, ::serde::Serialize, Clone, Debug)] #[serde(deny_unknown_fields)] - pub struct PostGetValidityProofResponseResult { - pub context: Context, - pub value: CompressedProofWithContext, + pub struct PostGetTransactionWithCompressionInfoV2ResponseResultCompressionInfo { + #[serde(rename = "closedAccounts")] + pub closed_accounts: ::std::vec::Vec, + #[serde(rename = "openedAccounts")] + pub opened_accounts: ::std::vec::Vec, } - impl PostGetValidityProofResponseResult { - pub fn builder() -> builder::PostGetValidityProofResponseResult { + impl PostGetTransactionWithCompressionInfoV2ResponseResultCompressionInfo { + pub fn builder() -> builder::PostGetTransactionWithCompressionInfoV2ResponseResultCompressionInfo { Default::default() } } - ///`PostGetValidityProofV2Body` + ///`PostGetValidityProofBody` /// ///
JSON schema /// @@ -26765,7 +26876,7 @@ All endpoints return AccountV2.*/ /// "description": "The name of the method to invoke.", /// "type": "string", /// "enum": [ - /// "getValidityProofV2" + /// "getValidityProof" /// ] /// }, /// "params": { @@ -26791,17 +26902,17 @@ All endpoints return AccountV2.*/ /// ``` ///
#[derive(::serde::Deserialize, ::serde::Serialize, Clone, Debug)] - pub struct PostGetValidityProofV2Body { + pub struct PostGetValidityProofBody { ///An ID to identify the request. - pub id: PostGetValidityProofV2BodyId, + pub id: PostGetValidityProofBodyId, ///The version of the JSON-RPC protocol. - pub jsonrpc: PostGetValidityProofV2BodyJsonrpc, + pub jsonrpc: PostGetValidityProofBodyJsonrpc, ///The name of the method to invoke. - pub method: PostGetValidityProofV2BodyMethod, - pub params: PostGetValidityProofV2BodyParams, + pub method: PostGetValidityProofBodyMethod, + pub params: PostGetValidityProofBodyParams, } - impl PostGetValidityProofV2Body { - pub fn builder() -> builder::PostGetValidityProofV2Body { + impl PostGetValidityProofBody { + pub fn builder() -> builder::PostGetValidityProofBody { Default::default() } } @@ -26831,18 +26942,18 @@ All endpoints return AccountV2.*/ PartialEq, PartialOrd )] - pub enum PostGetValidityProofV2BodyId { + pub enum PostGetValidityProofBodyId { #[serde(rename = "test-account")] TestAccount, } - impl ::std::fmt::Display for PostGetValidityProofV2BodyId { + impl ::std::fmt::Display for PostGetValidityProofBodyId { fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result { match *self { Self::TestAccount => f.write_str("test-account"), } } } - impl ::std::str::FromStr for PostGetValidityProofV2BodyId { + impl ::std::str::FromStr for PostGetValidityProofBodyId { type Err = self::error::ConversionError; fn from_str( value: &str, @@ -26853,7 +26964,7 @@ All endpoints return AccountV2.*/ } } } - impl ::std::convert::TryFrom<&str> for PostGetValidityProofV2BodyId { + impl ::std::convert::TryFrom<&str> for PostGetValidityProofBodyId { type Error = self::error::ConversionError; fn try_from( value: &str, @@ -26861,8 +26972,7 @@ All endpoints return AccountV2.*/ value.parse() } } - impl ::std::convert::TryFrom<&::std::string::String> - for PostGetValidityProofV2BodyId { + impl ::std::convert::TryFrom<&::std::string::String> for PostGetValidityProofBodyId { type Error = self::error::ConversionError; fn try_from( value: &::std::string::String, @@ -26870,8 +26980,7 @@ All endpoints return AccountV2.*/ value.parse() } } - impl ::std::convert::TryFrom<::std::string::String> - for PostGetValidityProofV2BodyId { + impl ::std::convert::TryFrom<::std::string::String> for PostGetValidityProofBodyId { type Error = self::error::ConversionError; fn try_from( value: ::std::string::String, @@ -26905,18 +27014,18 @@ All endpoints return AccountV2.*/ PartialEq, PartialOrd )] - pub enum PostGetValidityProofV2BodyJsonrpc { + pub enum PostGetValidityProofBodyJsonrpc { #[serde(rename = "2.0")] X20, } - impl ::std::fmt::Display for PostGetValidityProofV2BodyJsonrpc { + impl ::std::fmt::Display for PostGetValidityProofBodyJsonrpc { fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result { match *self { Self::X20 => f.write_str("2.0"), } } } - impl ::std::str::FromStr for PostGetValidityProofV2BodyJsonrpc { + impl ::std::str::FromStr for PostGetValidityProofBodyJsonrpc { type Err = self::error::ConversionError; fn from_str( value: &str, @@ -26927,7 +27036,7 @@ All endpoints return AccountV2.*/ } } } - impl ::std::convert::TryFrom<&str> for PostGetValidityProofV2BodyJsonrpc { + impl ::std::convert::TryFrom<&str> for PostGetValidityProofBodyJsonrpc { type Error = self::error::ConversionError; fn try_from( value: &str, @@ -26936,7 +27045,7 @@ All endpoints return AccountV2.*/ } } impl ::std::convert::TryFrom<&::std::string::String> - for PostGetValidityProofV2BodyJsonrpc { + for PostGetValidityProofBodyJsonrpc { type Error = self::error::ConversionError; fn try_from( value: &::std::string::String, @@ -26945,7 +27054,7 @@ All endpoints return AccountV2.*/ } } impl ::std::convert::TryFrom<::std::string::String> - for PostGetValidityProofV2BodyJsonrpc { + for PostGetValidityProofBodyJsonrpc { type Error = self::error::ConversionError; fn try_from( value: ::std::string::String, @@ -26962,7 +27071,7 @@ All endpoints return AccountV2.*/ /// "description": "The name of the method to invoke.", /// "type": "string", /// "enum": [ - /// "getValidityProofV2" + /// "getValidityProof" /// ] ///} /// ``` @@ -26979,29 +27088,29 @@ All endpoints return AccountV2.*/ PartialEq, PartialOrd )] - pub enum PostGetValidityProofV2BodyMethod { - #[serde(rename = "getValidityProofV2")] - GetValidityProofV2, + pub enum PostGetValidityProofBodyMethod { + #[serde(rename = "getValidityProof")] + GetValidityProof, } - impl ::std::fmt::Display for PostGetValidityProofV2BodyMethod { + impl ::std::fmt::Display for PostGetValidityProofBodyMethod { fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result { match *self { - Self::GetValidityProofV2 => f.write_str("getValidityProofV2"), + Self::GetValidityProof => f.write_str("getValidityProof"), } } } - impl ::std::str::FromStr for PostGetValidityProofV2BodyMethod { + impl ::std::str::FromStr for PostGetValidityProofBodyMethod { type Err = self::error::ConversionError; fn from_str( value: &str, ) -> ::std::result::Result { match value { - "getValidityProofV2" => Ok(Self::GetValidityProofV2), + "getValidityProof" => Ok(Self::GetValidityProof), _ => Err("invalid value".into()), } } } - impl ::std::convert::TryFrom<&str> for PostGetValidityProofV2BodyMethod { + impl ::std::convert::TryFrom<&str> for PostGetValidityProofBodyMethod { type Error = self::error::ConversionError; fn try_from( value: &str, @@ -27010,7 +27119,7 @@ All endpoints return AccountV2.*/ } } impl ::std::convert::TryFrom<&::std::string::String> - for PostGetValidityProofV2BodyMethod { + for PostGetValidityProofBodyMethod { type Error = self::error::ConversionError; fn try_from( value: &::std::string::String, @@ -27019,7 +27128,7 @@ All endpoints return AccountV2.*/ } } impl ::std::convert::TryFrom<::std::string::String> - for PostGetValidityProofV2BodyMethod { + for PostGetValidityProofBodyMethod { type Error = self::error::ConversionError; fn try_from( value: ::std::string::String, @@ -27027,7 +27136,7 @@ All endpoints return AccountV2.*/ value.parse() } } - ///`PostGetValidityProofV2BodyParams` + ///`PostGetValidityProofBodyParams` /// ///
JSON schema /// @@ -27054,7 +27163,7 @@ All endpoints return AccountV2.*/ ///
#[derive(::serde::Deserialize, ::serde::Serialize, Clone, Debug)] #[serde(deny_unknown_fields)] - pub struct PostGetValidityProofV2BodyParams { + pub struct PostGetValidityProofBodyParams { #[serde(default, skip_serializing_if = "::std::vec::Vec::is_empty")] pub hashes: ::std::vec::Vec, #[serde( @@ -27064,7 +27173,7 @@ All endpoints return AccountV2.*/ )] pub new_addresses_with_trees: ::std::vec::Vec, } - impl ::std::default::Default for PostGetValidityProofV2BodyParams { + impl ::std::default::Default for PostGetValidityProofBodyParams { fn default() -> Self { Self { hashes: Default::default(), @@ -27072,12 +27181,649 @@ All endpoints return AccountV2.*/ } } } - impl PostGetValidityProofV2BodyParams { - pub fn builder() -> builder::PostGetValidityProofV2BodyParams { + impl PostGetValidityProofBodyParams { + pub fn builder() -> builder::PostGetValidityProofBodyParams { Default::default() } } - ///`PostGetValidityProofV2Response` + ///`PostGetValidityProofResponse` + /// + ///
JSON schema + /// + /// ```json + ///{ + /// "type": "object", + /// "required": [ + /// "id", + /// "jsonrpc" + /// ], + /// "properties": { + /// "error": { + /// "type": "object", + /// "properties": { + /// "code": { + /// "type": "integer" + /// }, + /// "message": { + /// "type": "string" + /// } + /// } + /// }, + /// "id": { + /// "description": "An ID to identify the response.", + /// "type": "string", + /// "enum": [ + /// "test-account" + /// ] + /// }, + /// "jsonrpc": { + /// "description": "The version of the JSON-RPC protocol.", + /// "type": "string", + /// "enum": [ + /// "2.0" + /// ] + /// }, + /// "result": { + /// "type": "object", + /// "required": [ + /// "context", + /// "value" + /// ], + /// "properties": { + /// "context": { + /// "$ref": "#/components/schemas/Context" + /// }, + /// "value": { + /// "$ref": "#/components/schemas/CompressedProofWithContext" + /// } + /// }, + /// "additionalProperties": false + /// } + /// } + ///} + /// ``` + ///
+ #[derive(::serde::Deserialize, ::serde::Serialize, Clone, Debug)] + pub struct PostGetValidityProofResponse { + #[serde(default, skip_serializing_if = "::std::option::Option::is_none")] + pub error: ::std::option::Option, + ///An ID to identify the response. + pub id: PostGetValidityProofResponseId, + ///The version of the JSON-RPC protocol. + pub jsonrpc: PostGetValidityProofResponseJsonrpc, + #[serde(default, skip_serializing_if = "::std::option::Option::is_none")] + pub result: ::std::option::Option, + } + impl PostGetValidityProofResponse { + pub fn builder() -> builder::PostGetValidityProofResponse { + Default::default() + } + } + ///`PostGetValidityProofResponseError` + /// + ///
JSON schema + /// + /// ```json + ///{ + /// "type": "object", + /// "properties": { + /// "code": { + /// "type": "integer" + /// }, + /// "message": { + /// "type": "string" + /// } + /// } + ///} + /// ``` + ///
+ #[derive(::serde::Deserialize, ::serde::Serialize, Clone, Debug)] + pub struct PostGetValidityProofResponseError { + #[serde(default, skip_serializing_if = "::std::option::Option::is_none")] + pub code: ::std::option::Option, + #[serde(default, skip_serializing_if = "::std::option::Option::is_none")] + pub message: ::std::option::Option<::std::string::String>, + } + impl ::std::default::Default for PostGetValidityProofResponseError { + fn default() -> Self { + Self { + code: Default::default(), + message: Default::default(), + } + } + } + impl PostGetValidityProofResponseError { + pub fn builder() -> builder::PostGetValidityProofResponseError { + Default::default() + } + } + ///An ID to identify the response. + /// + ///
JSON schema + /// + /// ```json + ///{ + /// "description": "An ID to identify the response.", + /// "type": "string", + /// "enum": [ + /// "test-account" + /// ] + ///} + /// ``` + ///
+ #[derive( + ::serde::Deserialize, + ::serde::Serialize, + Clone, + Copy, + Debug, + Eq, + Hash, + Ord, + PartialEq, + PartialOrd + )] + pub enum PostGetValidityProofResponseId { + #[serde(rename = "test-account")] + TestAccount, + } + impl ::std::fmt::Display for PostGetValidityProofResponseId { + fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result { + match *self { + Self::TestAccount => f.write_str("test-account"), + } + } + } + impl ::std::str::FromStr for PostGetValidityProofResponseId { + type Err = self::error::ConversionError; + fn from_str( + value: &str, + ) -> ::std::result::Result { + match value { + "test-account" => Ok(Self::TestAccount), + _ => Err("invalid value".into()), + } + } + } + impl ::std::convert::TryFrom<&str> for PostGetValidityProofResponseId { + type Error = self::error::ConversionError; + fn try_from( + value: &str, + ) -> ::std::result::Result { + value.parse() + } + } + impl ::std::convert::TryFrom<&::std::string::String> + for PostGetValidityProofResponseId { + type Error = self::error::ConversionError; + fn try_from( + value: &::std::string::String, + ) -> ::std::result::Result { + value.parse() + } + } + impl ::std::convert::TryFrom<::std::string::String> + for PostGetValidityProofResponseId { + type Error = self::error::ConversionError; + fn try_from( + value: ::std::string::String, + ) -> ::std::result::Result { + value.parse() + } + } + ///The version of the JSON-RPC protocol. + /// + ///
JSON schema + /// + /// ```json + ///{ + /// "description": "The version of the JSON-RPC protocol.", + /// "type": "string", + /// "enum": [ + /// "2.0" + /// ] + ///} + /// ``` + ///
+ #[derive( + ::serde::Deserialize, + ::serde::Serialize, + Clone, + Copy, + Debug, + Eq, + Hash, + Ord, + PartialEq, + PartialOrd + )] + pub enum PostGetValidityProofResponseJsonrpc { + #[serde(rename = "2.0")] + X20, + } + impl ::std::fmt::Display for PostGetValidityProofResponseJsonrpc { + fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result { + match *self { + Self::X20 => f.write_str("2.0"), + } + } + } + impl ::std::str::FromStr for PostGetValidityProofResponseJsonrpc { + type Err = self::error::ConversionError; + fn from_str( + value: &str, + ) -> ::std::result::Result { + match value { + "2.0" => Ok(Self::X20), + _ => Err("invalid value".into()), + } + } + } + impl ::std::convert::TryFrom<&str> for PostGetValidityProofResponseJsonrpc { + type Error = self::error::ConversionError; + fn try_from( + value: &str, + ) -> ::std::result::Result { + value.parse() + } + } + impl ::std::convert::TryFrom<&::std::string::String> + for PostGetValidityProofResponseJsonrpc { + type Error = self::error::ConversionError; + fn try_from( + value: &::std::string::String, + ) -> ::std::result::Result { + value.parse() + } + } + impl ::std::convert::TryFrom<::std::string::String> + for PostGetValidityProofResponseJsonrpc { + type Error = self::error::ConversionError; + fn try_from( + value: ::std::string::String, + ) -> ::std::result::Result { + value.parse() + } + } + ///`PostGetValidityProofResponseResult` + /// + ///
JSON schema + /// + /// ```json + ///{ + /// "type": "object", + /// "required": [ + /// "context", + /// "value" + /// ], + /// "properties": { + /// "context": { + /// "$ref": "#/components/schemas/Context" + /// }, + /// "value": { + /// "$ref": "#/components/schemas/CompressedProofWithContext" + /// } + /// }, + /// "additionalProperties": false + ///} + /// ``` + ///
+ #[derive(::serde::Deserialize, ::serde::Serialize, Clone, Debug)] + #[serde(deny_unknown_fields)] + pub struct PostGetValidityProofResponseResult { + pub context: Context, + pub value: CompressedProofWithContext, + } + impl PostGetValidityProofResponseResult { + pub fn builder() -> builder::PostGetValidityProofResponseResult { + Default::default() + } + } + ///`PostGetValidityProofV2Body` + /// + ///
JSON schema + /// + /// ```json + ///{ + /// "type": "object", + /// "required": [ + /// "id", + /// "jsonrpc", + /// "method", + /// "params" + /// ], + /// "properties": { + /// "id": { + /// "description": "An ID to identify the request.", + /// "type": "string", + /// "enum": [ + /// "test-account" + /// ] + /// }, + /// "jsonrpc": { + /// "description": "The version of the JSON-RPC protocol.", + /// "type": "string", + /// "enum": [ + /// "2.0" + /// ] + /// }, + /// "method": { + /// "description": "The name of the method to invoke.", + /// "type": "string", + /// "enum": [ + /// "getValidityProofV2" + /// ] + /// }, + /// "params": { + /// "type": "object", + /// "properties": { + /// "hashes": { + /// "type": "array", + /// "items": { + /// "$ref": "#/components/schemas/Hash" + /// } + /// }, + /// "newAddressesWithTrees": { + /// "type": "array", + /// "items": { + /// "$ref": "#/components/schemas/AddressWithTree" + /// } + /// } + /// }, + /// "additionalProperties": false + /// } + /// } + ///} + /// ``` + ///
+ #[derive(::serde::Deserialize, ::serde::Serialize, Clone, Debug)] + pub struct PostGetValidityProofV2Body { + ///An ID to identify the request. + pub id: PostGetValidityProofV2BodyId, + ///The version of the JSON-RPC protocol. + pub jsonrpc: PostGetValidityProofV2BodyJsonrpc, + ///The name of the method to invoke. + pub method: PostGetValidityProofV2BodyMethod, + pub params: PostGetValidityProofV2BodyParams, + } + impl PostGetValidityProofV2Body { + pub fn builder() -> builder::PostGetValidityProofV2Body { + Default::default() + } + } + ///An ID to identify the request. + /// + ///
JSON schema + /// + /// ```json + ///{ + /// "description": "An ID to identify the request.", + /// "type": "string", + /// "enum": [ + /// "test-account" + /// ] + ///} + /// ``` + ///
+ #[derive( + ::serde::Deserialize, + ::serde::Serialize, + Clone, + Copy, + Debug, + Eq, + Hash, + Ord, + PartialEq, + PartialOrd + )] + pub enum PostGetValidityProofV2BodyId { + #[serde(rename = "test-account")] + TestAccount, + } + impl ::std::fmt::Display for PostGetValidityProofV2BodyId { + fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result { + match *self { + Self::TestAccount => f.write_str("test-account"), + } + } + } + impl ::std::str::FromStr for PostGetValidityProofV2BodyId { + type Err = self::error::ConversionError; + fn from_str( + value: &str, + ) -> ::std::result::Result { + match value { + "test-account" => Ok(Self::TestAccount), + _ => Err("invalid value".into()), + } + } + } + impl ::std::convert::TryFrom<&str> for PostGetValidityProofV2BodyId { + type Error = self::error::ConversionError; + fn try_from( + value: &str, + ) -> ::std::result::Result { + value.parse() + } + } + impl ::std::convert::TryFrom<&::std::string::String> + for PostGetValidityProofV2BodyId { + type Error = self::error::ConversionError; + fn try_from( + value: &::std::string::String, + ) -> ::std::result::Result { + value.parse() + } + } + impl ::std::convert::TryFrom<::std::string::String> + for PostGetValidityProofV2BodyId { + type Error = self::error::ConversionError; + fn try_from( + value: ::std::string::String, + ) -> ::std::result::Result { + value.parse() + } + } + ///The version of the JSON-RPC protocol. + /// + ///
JSON schema + /// + /// ```json + ///{ + /// "description": "The version of the JSON-RPC protocol.", + /// "type": "string", + /// "enum": [ + /// "2.0" + /// ] + ///} + /// ``` + ///
+ #[derive( + ::serde::Deserialize, + ::serde::Serialize, + Clone, + Copy, + Debug, + Eq, + Hash, + Ord, + PartialEq, + PartialOrd + )] + pub enum PostGetValidityProofV2BodyJsonrpc { + #[serde(rename = "2.0")] + X20, + } + impl ::std::fmt::Display for PostGetValidityProofV2BodyJsonrpc { + fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result { + match *self { + Self::X20 => f.write_str("2.0"), + } + } + } + impl ::std::str::FromStr for PostGetValidityProofV2BodyJsonrpc { + type Err = self::error::ConversionError; + fn from_str( + value: &str, + ) -> ::std::result::Result { + match value { + "2.0" => Ok(Self::X20), + _ => Err("invalid value".into()), + } + } + } + impl ::std::convert::TryFrom<&str> for PostGetValidityProofV2BodyJsonrpc { + type Error = self::error::ConversionError; + fn try_from( + value: &str, + ) -> ::std::result::Result { + value.parse() + } + } + impl ::std::convert::TryFrom<&::std::string::String> + for PostGetValidityProofV2BodyJsonrpc { + type Error = self::error::ConversionError; + fn try_from( + value: &::std::string::String, + ) -> ::std::result::Result { + value.parse() + } + } + impl ::std::convert::TryFrom<::std::string::String> + for PostGetValidityProofV2BodyJsonrpc { + type Error = self::error::ConversionError; + fn try_from( + value: ::std::string::String, + ) -> ::std::result::Result { + value.parse() + } + } + ///The name of the method to invoke. + /// + ///
JSON schema + /// + /// ```json + ///{ + /// "description": "The name of the method to invoke.", + /// "type": "string", + /// "enum": [ + /// "getValidityProofV2" + /// ] + ///} + /// ``` + ///
+ #[derive( + ::serde::Deserialize, + ::serde::Serialize, + Clone, + Copy, + Debug, + Eq, + Hash, + Ord, + PartialEq, + PartialOrd + )] + pub enum PostGetValidityProofV2BodyMethod { + #[serde(rename = "getValidityProofV2")] + GetValidityProofV2, + } + impl ::std::fmt::Display for PostGetValidityProofV2BodyMethod { + fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result { + match *self { + Self::GetValidityProofV2 => f.write_str("getValidityProofV2"), + } + } + } + impl ::std::str::FromStr for PostGetValidityProofV2BodyMethod { + type Err = self::error::ConversionError; + fn from_str( + value: &str, + ) -> ::std::result::Result { + match value { + "getValidityProofV2" => Ok(Self::GetValidityProofV2), + _ => Err("invalid value".into()), + } + } + } + impl ::std::convert::TryFrom<&str> for PostGetValidityProofV2BodyMethod { + type Error = self::error::ConversionError; + fn try_from( + value: &str, + ) -> ::std::result::Result { + value.parse() + } + } + impl ::std::convert::TryFrom<&::std::string::String> + for PostGetValidityProofV2BodyMethod { + type Error = self::error::ConversionError; + fn try_from( + value: &::std::string::String, + ) -> ::std::result::Result { + value.parse() + } + } + impl ::std::convert::TryFrom<::std::string::String> + for PostGetValidityProofV2BodyMethod { + type Error = self::error::ConversionError; + fn try_from( + value: ::std::string::String, + ) -> ::std::result::Result { + value.parse() + } + } + ///`PostGetValidityProofV2BodyParams` + /// + ///
JSON schema + /// + /// ```json + ///{ + /// "type": "object", + /// "properties": { + /// "hashes": { + /// "type": "array", + /// "items": { + /// "$ref": "#/components/schemas/Hash" + /// } + /// }, + /// "newAddressesWithTrees": { + /// "type": "array", + /// "items": { + /// "$ref": "#/components/schemas/AddressWithTree" + /// } + /// } + /// }, + /// "additionalProperties": false + ///} + /// ``` + ///
+ #[derive(::serde::Deserialize, ::serde::Serialize, Clone, Debug)] + #[serde(deny_unknown_fields)] + pub struct PostGetValidityProofV2BodyParams { + #[serde(default, skip_serializing_if = "::std::vec::Vec::is_empty")] + pub hashes: ::std::vec::Vec, + #[serde( + rename = "newAddressesWithTrees", + default, + skip_serializing_if = "::std::vec::Vec::is_empty" + )] + pub new_addresses_with_trees: ::std::vec::Vec, + } + impl ::std::default::Default for PostGetValidityProofV2BodyParams { + fn default() -> Self { + Self { + hashes: Default::default(), + new_addresses_with_trees: Default::default(), + } + } + } + impl PostGetValidityProofV2BodyParams { + pub fn builder() -> builder::PostGetValidityProofV2BodyParams { + Default::default() + } + } + ///`PostGetValidityProofV2Response` /// ///
JSON schema /// @@ -27418,6 +28164,52 @@ All endpoints return AccountV2.*/ Default::default() } } + ///A lightweight queue leaf index entry + /// + ///
JSON schema + /// + /// ```json + ///{ + /// "description": "A lightweight queue leaf index entry", + /// "type": "object", + /// "required": [ + /// "hash", + /// "leafIndex", + /// "queueIndex" + /// ], + /// "properties": { + /// "hash": { + /// "$ref": "#/components/schemas/Hash" + /// }, + /// "leafIndex": { + /// "type": "integer", + /// "format": "uint64", + /// "minimum": 0.0 + /// }, + /// "queueIndex": { + /// "type": "integer", + /// "format": "uint64", + /// "minimum": 0.0 + /// } + /// }, + /// "additionalProperties": false + ///} + /// ``` + ///
+ #[derive(::serde::Deserialize, ::serde::Serialize, Clone, Debug)] + #[serde(deny_unknown_fields)] + pub struct QueueLeafIndex { + pub hash: Hash, + #[serde(rename = "leafIndex")] + pub leaf_index: u64, + #[serde(rename = "queueIndex")] + pub queue_index: u64, + } + impl QueueLeafIndex { + pub fn builder() -> builder::QueueLeafIndex { + Default::default() + } + } ///Parameters for requesting queue elements /// ///
JSON schema @@ -30890,6 +31682,148 @@ All endpoints return AccountV2.*/ } } #[derive(Clone, Debug)] + pub struct GetQueueLeafIndicesRequest { + limit: ::std::result::Result, + start_index: ::std::result::Result< + ::std::option::Option, + ::std::string::String, + >, + tree: ::std::result::Result, + } + impl ::std::default::Default for GetQueueLeafIndicesRequest { + fn default() -> Self { + Self { + limit: Err("no value supplied for limit".to_string()), + start_index: Ok(Default::default()), + tree: Err("no value supplied for tree".to_string()), + } + } + } + impl GetQueueLeafIndicesRequest { + pub fn limit(mut self, value: T) -> Self + where + T: ::std::convert::TryInto, + T::Error: ::std::fmt::Display, + { + self.limit = value + .try_into() + .map_err(|e| { + format!("error converting supplied value for limit: {e}") + }); + self + } + pub fn start_index(mut self, value: T) -> Self + where + T: ::std::convert::TryInto<::std::option::Option>, + T::Error: ::std::fmt::Display, + { + self.start_index = value + .try_into() + .map_err(|e| { + format!("error converting supplied value for start_index: {e}") + }); + self + } + pub fn tree(mut self, value: T) -> Self + where + T: ::std::convert::TryInto, + T::Error: ::std::fmt::Display, + { + self.tree = value + .try_into() + .map_err(|e| { + format!("error converting supplied value for tree: {e}") + }); + self + } + } + impl ::std::convert::TryFrom + for super::GetQueueLeafIndicesRequest { + type Error = super::error::ConversionError; + fn try_from( + value: GetQueueLeafIndicesRequest, + ) -> ::std::result::Result { + Ok(Self { + limit: value.limit?, + start_index: value.start_index?, + tree: value.tree?, + }) + } + } + impl ::std::convert::From + for GetQueueLeafIndicesRequest { + fn from(value: super::GetQueueLeafIndicesRequest) -> Self { + Self { + limit: Ok(value.limit), + start_index: Ok(value.start_index), + tree: Ok(value.tree), + } + } + } + #[derive(Clone, Debug)] + pub struct GetQueueLeafIndicesResponse { + context: ::std::result::Result, + value: ::std::result::Result< + ::std::vec::Vec, + ::std::string::String, + >, + } + impl ::std::default::Default for GetQueueLeafIndicesResponse { + fn default() -> Self { + Self { + context: Err("no value supplied for context".to_string()), + value: Err("no value supplied for value".to_string()), + } + } + } + impl GetQueueLeafIndicesResponse { + pub fn context(mut self, value: T) -> Self + where + T: ::std::convert::TryInto, + T::Error: ::std::fmt::Display, + { + self.context = value + .try_into() + .map_err(|e| { + format!("error converting supplied value for context: {e}") + }); + self + } + pub fn value(mut self, value: T) -> Self + where + T: ::std::convert::TryInto<::std::vec::Vec>, + T::Error: ::std::fmt::Display, + { + self.value = value + .try_into() + .map_err(|e| { + format!("error converting supplied value for value: {e}") + }); + self + } + } + impl ::std::convert::TryFrom + for super::GetQueueLeafIndicesResponse { + type Error = super::error::ConversionError; + fn try_from( + value: GetQueueLeafIndicesResponse, + ) -> ::std::result::Result { + Ok(Self { + context: value.context?, + value: value.value?, + }) + } + } + impl ::std::convert::From + for GetQueueLeafIndicesResponse { + fn from(value: super::GetQueueLeafIndicesResponse) -> Self { + Self { + context: Ok(value.context), + value: Ok(value.value), + } + } + } + #[derive(Clone, Debug)] pub struct InputQueueData { account_hashes: ::std::result::Result< ::std::vec::Vec, @@ -46275,6 +47209,424 @@ All endpoints return AccountV2.*/ } } #[derive(Clone, Debug)] + pub struct PostGetQueueLeafIndicesBody { + id: ::std::result::Result< + super::PostGetQueueLeafIndicesBodyId, + ::std::string::String, + >, + jsonrpc: ::std::result::Result< + super::PostGetQueueLeafIndicesBodyJsonrpc, + ::std::string::String, + >, + method: ::std::result::Result< + super::PostGetQueueLeafIndicesBodyMethod, + ::std::string::String, + >, + params: ::std::result::Result< + super::PostGetQueueLeafIndicesBodyParams, + ::std::string::String, + >, + } + impl ::std::default::Default for PostGetQueueLeafIndicesBody { + fn default() -> Self { + Self { + id: Err("no value supplied for id".to_string()), + jsonrpc: Err("no value supplied for jsonrpc".to_string()), + method: Err("no value supplied for method".to_string()), + params: Err("no value supplied for params".to_string()), + } + } + } + impl PostGetQueueLeafIndicesBody { + pub fn id(mut self, value: T) -> Self + where + T: ::std::convert::TryInto, + T::Error: ::std::fmt::Display, + { + self.id = value + .try_into() + .map_err(|e| format!("error converting supplied value for id: {e}")); + self + } + pub fn jsonrpc(mut self, value: T) -> Self + where + T: ::std::convert::TryInto, + T::Error: ::std::fmt::Display, + { + self.jsonrpc = value + .try_into() + .map_err(|e| { + format!("error converting supplied value for jsonrpc: {e}") + }); + self + } + pub fn method(mut self, value: T) -> Self + where + T: ::std::convert::TryInto, + T::Error: ::std::fmt::Display, + { + self.method = value + .try_into() + .map_err(|e| { + format!("error converting supplied value for method: {e}") + }); + self + } + pub fn params(mut self, value: T) -> Self + where + T: ::std::convert::TryInto, + T::Error: ::std::fmt::Display, + { + self.params = value + .try_into() + .map_err(|e| { + format!("error converting supplied value for params: {e}") + }); + self + } + } + impl ::std::convert::TryFrom + for super::PostGetQueueLeafIndicesBody { + type Error = super::error::ConversionError; + fn try_from( + value: PostGetQueueLeafIndicesBody, + ) -> ::std::result::Result { + Ok(Self { + id: value.id?, + jsonrpc: value.jsonrpc?, + method: value.method?, + params: value.params?, + }) + } + } + impl ::std::convert::From + for PostGetQueueLeafIndicesBody { + fn from(value: super::PostGetQueueLeafIndicesBody) -> Self { + Self { + id: Ok(value.id), + jsonrpc: Ok(value.jsonrpc), + method: Ok(value.method), + params: Ok(value.params), + } + } + } + #[derive(Clone, Debug)] + pub struct PostGetQueueLeafIndicesBodyParams { + limit: ::std::result::Result, + start_index: ::std::result::Result< + ::std::option::Option, + ::std::string::String, + >, + tree: ::std::result::Result, + } + impl ::std::default::Default for PostGetQueueLeafIndicesBodyParams { + fn default() -> Self { + Self { + limit: Err("no value supplied for limit".to_string()), + start_index: Ok(Default::default()), + tree: Err("no value supplied for tree".to_string()), + } + } + } + impl PostGetQueueLeafIndicesBodyParams { + pub fn limit(mut self, value: T) -> Self + where + T: ::std::convert::TryInto, + T::Error: ::std::fmt::Display, + { + self.limit = value + .try_into() + .map_err(|e| { + format!("error converting supplied value for limit: {e}") + }); + self + } + pub fn start_index(mut self, value: T) -> Self + where + T: ::std::convert::TryInto<::std::option::Option>, + T::Error: ::std::fmt::Display, + { + self.start_index = value + .try_into() + .map_err(|e| { + format!("error converting supplied value for start_index: {e}") + }); + self + } + pub fn tree(mut self, value: T) -> Self + where + T: ::std::convert::TryInto, + T::Error: ::std::fmt::Display, + { + self.tree = value + .try_into() + .map_err(|e| { + format!("error converting supplied value for tree: {e}") + }); + self + } + } + impl ::std::convert::TryFrom + for super::PostGetQueueLeafIndicesBodyParams { + type Error = super::error::ConversionError; + fn try_from( + value: PostGetQueueLeafIndicesBodyParams, + ) -> ::std::result::Result { + Ok(Self { + limit: value.limit?, + start_index: value.start_index?, + tree: value.tree?, + }) + } + } + impl ::std::convert::From + for PostGetQueueLeafIndicesBodyParams { + fn from(value: super::PostGetQueueLeafIndicesBodyParams) -> Self { + Self { + limit: Ok(value.limit), + start_index: Ok(value.start_index), + tree: Ok(value.tree), + } + } + } + #[derive(Clone, Debug)] + pub struct PostGetQueueLeafIndicesResponse { + error: ::std::result::Result< + ::std::option::Option, + ::std::string::String, + >, + id: ::std::result::Result< + super::PostGetQueueLeafIndicesResponseId, + ::std::string::String, + >, + jsonrpc: ::std::result::Result< + super::PostGetQueueLeafIndicesResponseJsonrpc, + ::std::string::String, + >, + result: ::std::result::Result< + ::std::option::Option, + ::std::string::String, + >, + } + impl ::std::default::Default for PostGetQueueLeafIndicesResponse { + fn default() -> Self { + Self { + error: Ok(Default::default()), + id: Err("no value supplied for id".to_string()), + jsonrpc: Err("no value supplied for jsonrpc".to_string()), + result: Ok(Default::default()), + } + } + } + impl PostGetQueueLeafIndicesResponse { + pub fn error(mut self, value: T) -> Self + where + T: ::std::convert::TryInto< + ::std::option::Option, + >, + T::Error: ::std::fmt::Display, + { + self.error = value + .try_into() + .map_err(|e| { + format!("error converting supplied value for error: {e}") + }); + self + } + pub fn id(mut self, value: T) -> Self + where + T: ::std::convert::TryInto, + T::Error: ::std::fmt::Display, + { + self.id = value + .try_into() + .map_err(|e| format!("error converting supplied value for id: {e}")); + self + } + pub fn jsonrpc(mut self, value: T) -> Self + where + T: ::std::convert::TryInto< + super::PostGetQueueLeafIndicesResponseJsonrpc, + >, + T::Error: ::std::fmt::Display, + { + self.jsonrpc = value + .try_into() + .map_err(|e| { + format!("error converting supplied value for jsonrpc: {e}") + }); + self + } + pub fn result(mut self, value: T) -> Self + where + T: ::std::convert::TryInto< + ::std::option::Option, + >, + T::Error: ::std::fmt::Display, + { + self.result = value + .try_into() + .map_err(|e| { + format!("error converting supplied value for result: {e}") + }); + self + } + } + impl ::std::convert::TryFrom + for super::PostGetQueueLeafIndicesResponse { + type Error = super::error::ConversionError; + fn try_from( + value: PostGetQueueLeafIndicesResponse, + ) -> ::std::result::Result { + Ok(Self { + error: value.error?, + id: value.id?, + jsonrpc: value.jsonrpc?, + result: value.result?, + }) + } + } + impl ::std::convert::From + for PostGetQueueLeafIndicesResponse { + fn from(value: super::PostGetQueueLeafIndicesResponse) -> Self { + Self { + error: Ok(value.error), + id: Ok(value.id), + jsonrpc: Ok(value.jsonrpc), + result: Ok(value.result), + } + } + } + #[derive(Clone, Debug)] + pub struct PostGetQueueLeafIndicesResponseError { + code: ::std::result::Result< + ::std::option::Option, + ::std::string::String, + >, + message: ::std::result::Result< + ::std::option::Option<::std::string::String>, + ::std::string::String, + >, + } + impl ::std::default::Default for PostGetQueueLeafIndicesResponseError { + fn default() -> Self { + Self { + code: Ok(Default::default()), + message: Ok(Default::default()), + } + } + } + impl PostGetQueueLeafIndicesResponseError { + pub fn code(mut self, value: T) -> Self + where + T: ::std::convert::TryInto<::std::option::Option>, + T::Error: ::std::fmt::Display, + { + self.code = value + .try_into() + .map_err(|e| { + format!("error converting supplied value for code: {e}") + }); + self + } + pub fn message(mut self, value: T) -> Self + where + T: ::std::convert::TryInto<::std::option::Option<::std::string::String>>, + T::Error: ::std::fmt::Display, + { + self.message = value + .try_into() + .map_err(|e| { + format!("error converting supplied value for message: {e}") + }); + self + } + } + impl ::std::convert::TryFrom + for super::PostGetQueueLeafIndicesResponseError { + type Error = super::error::ConversionError; + fn try_from( + value: PostGetQueueLeafIndicesResponseError, + ) -> ::std::result::Result { + Ok(Self { + code: value.code?, + message: value.message?, + }) + } + } + impl ::std::convert::From + for PostGetQueueLeafIndicesResponseError { + fn from(value: super::PostGetQueueLeafIndicesResponseError) -> Self { + Self { + code: Ok(value.code), + message: Ok(value.message), + } + } + } + #[derive(Clone, Debug)] + pub struct PostGetQueueLeafIndicesResponseResult { + context: ::std::result::Result, + value: ::std::result::Result< + ::std::vec::Vec, + ::std::string::String, + >, + } + impl ::std::default::Default for PostGetQueueLeafIndicesResponseResult { + fn default() -> Self { + Self { + context: Err("no value supplied for context".to_string()), + value: Err("no value supplied for value".to_string()), + } + } + } + impl PostGetQueueLeafIndicesResponseResult { + pub fn context(mut self, value: T) -> Self + where + T: ::std::convert::TryInto, + T::Error: ::std::fmt::Display, + { + self.context = value + .try_into() + .map_err(|e| { + format!("error converting supplied value for context: {e}") + }); + self + } + pub fn value(mut self, value: T) -> Self + where + T: ::std::convert::TryInto<::std::vec::Vec>, + T::Error: ::std::fmt::Display, + { + self.value = value + .try_into() + .map_err(|e| { + format!("error converting supplied value for value: {e}") + }); + self + } + } + impl ::std::convert::TryFrom + for super::PostGetQueueLeafIndicesResponseResult { + type Error = super::error::ConversionError; + fn try_from( + value: PostGetQueueLeafIndicesResponseResult, + ) -> ::std::result::Result { + Ok(Self { + context: value.context?, + value: value.value?, + }) + } + } + impl ::std::convert::From + for PostGetQueueLeafIndicesResponseResult { + fn from(value: super::PostGetQueueLeafIndicesResponseResult) -> Self { + Self { + context: Ok(value.context), + value: Ok(value.value), + } + } + } + #[derive(Clone, Debug)] pub struct PostGetTransactionWithCompressionInfoBody { id: ::std::result::Result< super::PostGetTransactionWithCompressionInfoBodyId, @@ -48206,6 +49558,80 @@ All endpoints return AccountV2.*/ } } #[derive(Clone, Debug)] + pub struct QueueLeafIndex { + hash: ::std::result::Result, + leaf_index: ::std::result::Result, + queue_index: ::std::result::Result, + } + impl ::std::default::Default for QueueLeafIndex { + fn default() -> Self { + Self { + hash: Err("no value supplied for hash".to_string()), + leaf_index: Err("no value supplied for leaf_index".to_string()), + queue_index: Err("no value supplied for queue_index".to_string()), + } + } + } + impl QueueLeafIndex { + pub fn hash(mut self, value: T) -> Self + where + T: ::std::convert::TryInto, + T::Error: ::std::fmt::Display, + { + self.hash = value + .try_into() + .map_err(|e| { + format!("error converting supplied value for hash: {e}") + }); + self + } + pub fn leaf_index(mut self, value: T) -> Self + where + T: ::std::convert::TryInto, + T::Error: ::std::fmt::Display, + { + self.leaf_index = value + .try_into() + .map_err(|e| { + format!("error converting supplied value for leaf_index: {e}") + }); + self + } + pub fn queue_index(mut self, value: T) -> Self + where + T: ::std::convert::TryInto, + T::Error: ::std::fmt::Display, + { + self.queue_index = value + .try_into() + .map_err(|e| { + format!("error converting supplied value for queue_index: {e}") + }); + self + } + } + impl ::std::convert::TryFrom for super::QueueLeafIndex { + type Error = super::error::ConversionError; + fn try_from( + value: QueueLeafIndex, + ) -> ::std::result::Result { + Ok(Self { + hash: value.hash?, + leaf_index: value.leaf_index?, + queue_index: value.queue_index?, + }) + } + } + impl ::std::convert::From for QueueLeafIndex { + fn from(value: super::QueueLeafIndex) -> Self { + Self { + hash: Ok(value.hash), + leaf_index: Ok(value.leaf_index), + queue_index: Ok(value.queue_index), + } + } + } + #[derive(Clone, Debug)] pub struct QueueRequest { limit: ::std::result::Result, start_index: ::std::result::Result< @@ -50080,6 +51506,17 @@ let response = client.post_get_queue_info() pub fn post_get_queue_info(&self) -> builder::PostGetQueueInfo<'_> { builder::PostGetQueueInfo::new(self) } + /**Sends a `POST` request to `/getQueueLeafIndices` + +```ignore +let response = client.post_get_queue_leaf_indices() + .body(body) + .send() + .await; +```*/ + pub fn post_get_queue_leaf_indices(&self) -> builder::PostGetQueueLeafIndices<'_> { + builder::PostGetQueueLeafIndices::new(self) + } /**Sends a `POST` request to `/getTransactionWithCompressionInfo` ```ignore @@ -50447,15 +51884,221 @@ pub mod builder { } } } - /**Builder for [`Client::post_get_compressed_account_proof`] + /**Builder for [`Client::post_get_compressed_account_proof`] + +[`Client::post_get_compressed_account_proof`]: super::Client::post_get_compressed_account_proof*/ + #[derive(Debug, Clone)] + pub struct PostGetCompressedAccountProof<'a> { + client: &'a super::Client, + body: Result, + } + impl<'a> PostGetCompressedAccountProof<'a> { + pub fn new(client: &'a super::Client) -> Self { + Self { + client: client, + body: Ok(::std::default::Default::default()), + } + } + pub fn body(mut self, value: V) -> Self + where + V: std::convert::TryInto, + >::Error: std::fmt::Display, + { + self.body = value + .try_into() + .map(From::from) + .map_err(|s| { + format!( + "conversion to `PostGetCompressedAccountProofBody` for body failed: {}", + s + ) + }); + self + } + pub fn body_map(mut self, f: F) -> Self + where + F: std::ops::FnOnce( + types::builder::PostGetCompressedAccountProofBody, + ) -> types::builder::PostGetCompressedAccountProofBody, + { + self.body = self.body.map(f); + self + } + ///Sends a `POST` request to `/getCompressedAccountProof` + pub async fn send( + self, + ) -> Result< + ResponseValue, + Error, + > { + let Self { client, body } = self; + let body = body + .and_then(|v| { + types::PostGetCompressedAccountProofBody::try_from(v) + .map_err(|e| e.to_string()) + }) + .map_err(Error::InvalidRequest)?; + let url = format!("{}/getCompressedAccountProof", client.baseurl,); + let mut header_map = ::reqwest::header::HeaderMap::with_capacity(1usize); + header_map + .append( + ::reqwest::header::HeaderName::from_static("api-version"), + ::reqwest::header::HeaderValue::from_static( + super::Client::api_version(), + ), + ); + #[allow(unused_mut)] + let mut request = client + .client + .post(url) + .header( + ::reqwest::header::ACCEPT, + ::reqwest::header::HeaderValue::from_static("application/json"), + ) + .json(&body) + .headers(header_map) + .build()?; + let info = OperationInfo { + operation_id: "post_get_compressed_account_proof", + }; + client.pre(&mut request, &info).await?; + let result = client.exec(request, &info).await; + client.post(&result, &info).await?; + let response = result?; + match response.status().as_u16() { + 200u16 => ResponseValue::from_response(response).await, + 429u16 => { + Err( + Error::ErrorResponse( + ResponseValue::from_response(response).await?, + ), + ) + } + 500u16 => { + Err( + Error::ErrorResponse( + ResponseValue::from_response(response).await?, + ), + ) + } + _ => Err(Error::UnexpectedResponse(response)), + } + } + } + /**Builder for [`Client::post_get_compressed_account_proof_v2`] + +[`Client::post_get_compressed_account_proof_v2`]: super::Client::post_get_compressed_account_proof_v2*/ + #[derive(Debug, Clone)] + pub struct PostGetCompressedAccountProofV2<'a> { + client: &'a super::Client, + body: Result, + } + impl<'a> PostGetCompressedAccountProofV2<'a> { + pub fn new(client: &'a super::Client) -> Self { + Self { + client: client, + body: Ok(::std::default::Default::default()), + } + } + pub fn body(mut self, value: V) -> Self + where + V: std::convert::TryInto, + >::Error: std::fmt::Display, + { + self.body = value + .try_into() + .map(From::from) + .map_err(|s| { + format!( + "conversion to `PostGetCompressedAccountProofV2Body` for body failed: {}", + s + ) + }); + self + } + pub fn body_map(mut self, f: F) -> Self + where + F: std::ops::FnOnce( + types::builder::PostGetCompressedAccountProofV2Body, + ) -> types::builder::PostGetCompressedAccountProofV2Body, + { + self.body = self.body.map(f); + self + } + ///Sends a `POST` request to `/getCompressedAccountProofV2` + pub async fn send( + self, + ) -> Result< + ResponseValue, + Error, + > { + let Self { client, body } = self; + let body = body + .and_then(|v| { + types::PostGetCompressedAccountProofV2Body::try_from(v) + .map_err(|e| e.to_string()) + }) + .map_err(Error::InvalidRequest)?; + let url = format!("{}/getCompressedAccountProofV2", client.baseurl,); + let mut header_map = ::reqwest::header::HeaderMap::with_capacity(1usize); + header_map + .append( + ::reqwest::header::HeaderName::from_static("api-version"), + ::reqwest::header::HeaderValue::from_static( + super::Client::api_version(), + ), + ); + #[allow(unused_mut)] + let mut request = client + .client + .post(url) + .header( + ::reqwest::header::ACCEPT, + ::reqwest::header::HeaderValue::from_static("application/json"), + ) + .json(&body) + .headers(header_map) + .build()?; + let info = OperationInfo { + operation_id: "post_get_compressed_account_proof_v2", + }; + client.pre(&mut request, &info).await?; + let result = client.exec(request, &info).await; + client.post(&result, &info).await?; + let response = result?; + match response.status().as_u16() { + 200u16 => ResponseValue::from_response(response).await, + 429u16 => { + Err( + Error::ErrorResponse( + ResponseValue::from_response(response).await?, + ), + ) + } + 500u16 => { + Err( + Error::ErrorResponse( + ResponseValue::from_response(response).await?, + ), + ) + } + _ => Err(Error::UnexpectedResponse(response)), + } + } + } + /**Builder for [`Client::post_get_compressed_account_v2`] -[`Client::post_get_compressed_account_proof`]: super::Client::post_get_compressed_account_proof*/ +[`Client::post_get_compressed_account_v2`]: super::Client::post_get_compressed_account_v2*/ #[derive(Debug, Clone)] - pub struct PostGetCompressedAccountProof<'a> { + pub struct PostGetCompressedAccountV2<'a> { client: &'a super::Client, - body: Result, + body: Result, } - impl<'a> PostGetCompressedAccountProof<'a> { + impl<'a> PostGetCompressedAccountV2<'a> { pub fn new(client: &'a super::Client) -> Self { Self { client: client, @@ -50464,9 +52107,9 @@ pub mod builder { } pub fn body(mut self, value: V) -> Self where - V: std::convert::TryInto, + V: std::convert::TryInto, >::Error: std::fmt::Display, { self.body = value @@ -50474,7 +52117,7 @@ pub mod builder { .map(From::from) .map_err(|s| { format!( - "conversion to `PostGetCompressedAccountProofBody` for body failed: {}", + "conversion to `PostGetCompressedAccountV2Body` for body failed: {}", s ) }); @@ -50483,27 +52126,27 @@ pub mod builder { pub fn body_map(mut self, f: F) -> Self where F: std::ops::FnOnce( - types::builder::PostGetCompressedAccountProofBody, - ) -> types::builder::PostGetCompressedAccountProofBody, + types::builder::PostGetCompressedAccountV2Body, + ) -> types::builder::PostGetCompressedAccountV2Body, { self.body = self.body.map(f); self } - ///Sends a `POST` request to `/getCompressedAccountProof` + ///Sends a `POST` request to `/getCompressedAccountV2` pub async fn send( self, ) -> Result< - ResponseValue, - Error, + ResponseValue, + Error, > { let Self { client, body } = self; let body = body .and_then(|v| { - types::PostGetCompressedAccountProofBody::try_from(v) + types::PostGetCompressedAccountV2Body::try_from(v) .map_err(|e| e.to_string()) }) .map_err(Error::InvalidRequest)?; - let url = format!("{}/getCompressedAccountProof", client.baseurl,); + let url = format!("{}/getCompressedAccountV2", client.baseurl,); let mut header_map = ::reqwest::header::HeaderMap::with_capacity(1usize); header_map .append( @@ -50524,7 +52167,7 @@ pub mod builder { .headers(header_map) .build()?; let info = OperationInfo { - operation_id: "post_get_compressed_account_proof", + operation_id: "post_get_compressed_account_v2", }; client.pre(&mut request, &info).await?; let result = client.exec(request, &info).await; @@ -50550,15 +52193,15 @@ pub mod builder { } } } - /**Builder for [`Client::post_get_compressed_account_proof_v2`] + /**Builder for [`Client::post_get_compressed_accounts_by_owner`] -[`Client::post_get_compressed_account_proof_v2`]: super::Client::post_get_compressed_account_proof_v2*/ +[`Client::post_get_compressed_accounts_by_owner`]: super::Client::post_get_compressed_accounts_by_owner*/ #[derive(Debug, Clone)] - pub struct PostGetCompressedAccountProofV2<'a> { + pub struct PostGetCompressedAccountsByOwner<'a> { client: &'a super::Client, - body: Result, + body: Result, } - impl<'a> PostGetCompressedAccountProofV2<'a> { + impl<'a> PostGetCompressedAccountsByOwner<'a> { pub fn new(client: &'a super::Client) -> Self { Self { client: client, @@ -50567,9 +52210,9 @@ pub mod builder { } pub fn body(mut self, value: V) -> Self where - V: std::convert::TryInto, + V: std::convert::TryInto, >::Error: std::fmt::Display, { self.body = value @@ -50577,7 +52220,7 @@ pub mod builder { .map(From::from) .map_err(|s| { format!( - "conversion to `PostGetCompressedAccountProofV2Body` for body failed: {}", + "conversion to `PostGetCompressedAccountsByOwnerBody` for body failed: {}", s ) }); @@ -50586,27 +52229,27 @@ pub mod builder { pub fn body_map(mut self, f: F) -> Self where F: std::ops::FnOnce( - types::builder::PostGetCompressedAccountProofV2Body, - ) -> types::builder::PostGetCompressedAccountProofV2Body, + types::builder::PostGetCompressedAccountsByOwnerBody, + ) -> types::builder::PostGetCompressedAccountsByOwnerBody, { self.body = self.body.map(f); self } - ///Sends a `POST` request to `/getCompressedAccountProofV2` + ///Sends a `POST` request to `/getCompressedAccountsByOwner` pub async fn send( self, ) -> Result< - ResponseValue, - Error, + ResponseValue, + Error, > { let Self { client, body } = self; let body = body .and_then(|v| { - types::PostGetCompressedAccountProofV2Body::try_from(v) + types::PostGetCompressedAccountsByOwnerBody::try_from(v) .map_err(|e| e.to_string()) }) .map_err(Error::InvalidRequest)?; - let url = format!("{}/getCompressedAccountProofV2", client.baseurl,); + let url = format!("{}/getCompressedAccountsByOwner", client.baseurl,); let mut header_map = ::reqwest::header::HeaderMap::with_capacity(1usize); header_map .append( @@ -50627,7 +52270,7 @@ pub mod builder { .headers(header_map) .build()?; let info = OperationInfo { - operation_id: "post_get_compressed_account_proof_v2", + operation_id: "post_get_compressed_accounts_by_owner", }; client.pre(&mut request, &info).await?; let result = client.exec(request, &info).await; @@ -50653,15 +52296,15 @@ pub mod builder { } } } - /**Builder for [`Client::post_get_compressed_account_v2`] + /**Builder for [`Client::post_get_compressed_accounts_by_owner_v2`] -[`Client::post_get_compressed_account_v2`]: super::Client::post_get_compressed_account_v2*/ +[`Client::post_get_compressed_accounts_by_owner_v2`]: super::Client::post_get_compressed_accounts_by_owner_v2*/ #[derive(Debug, Clone)] - pub struct PostGetCompressedAccountV2<'a> { + pub struct PostGetCompressedAccountsByOwnerV2<'a> { client: &'a super::Client, - body: Result, + body: Result, } - impl<'a> PostGetCompressedAccountV2<'a> { + impl<'a> PostGetCompressedAccountsByOwnerV2<'a> { pub fn new(client: &'a super::Client) -> Self { Self { client: client, @@ -50670,9 +52313,9 @@ pub mod builder { } pub fn body(mut self, value: V) -> Self where - V: std::convert::TryInto, + V: std::convert::TryInto, >::Error: std::fmt::Display, { self.body = value @@ -50680,7 +52323,7 @@ pub mod builder { .map(From::from) .map_err(|s| { format!( - "conversion to `PostGetCompressedAccountV2Body` for body failed: {}", + "conversion to `PostGetCompressedAccountsByOwnerV2Body` for body failed: {}", s ) }); @@ -50689,27 +52332,27 @@ pub mod builder { pub fn body_map(mut self, f: F) -> Self where F: std::ops::FnOnce( - types::builder::PostGetCompressedAccountV2Body, - ) -> types::builder::PostGetCompressedAccountV2Body, + types::builder::PostGetCompressedAccountsByOwnerV2Body, + ) -> types::builder::PostGetCompressedAccountsByOwnerV2Body, { self.body = self.body.map(f); self } - ///Sends a `POST` request to `/getCompressedAccountV2` + ///Sends a `POST` request to `/getCompressedAccountsByOwnerV2` pub async fn send( self, ) -> Result< - ResponseValue, - Error, + ResponseValue, + Error, > { let Self { client, body } = self; let body = body .and_then(|v| { - types::PostGetCompressedAccountV2Body::try_from(v) + types::PostGetCompressedAccountsByOwnerV2Body::try_from(v) .map_err(|e| e.to_string()) }) .map_err(Error::InvalidRequest)?; - let url = format!("{}/getCompressedAccountV2", client.baseurl,); + let url = format!("{}/getCompressedAccountsByOwnerV2", client.baseurl,); let mut header_map = ::reqwest::header::HeaderMap::with_capacity(1usize); header_map .append( @@ -50730,7 +52373,7 @@ pub mod builder { .headers(header_map) .build()?; let info = OperationInfo { - operation_id: "post_get_compressed_account_v2", + operation_id: "post_get_compressed_accounts_by_owner_v2", }; client.pre(&mut request, &info).await?; let result = client.exec(request, &info).await; @@ -50756,15 +52399,15 @@ pub mod builder { } } } - /**Builder for [`Client::post_get_compressed_accounts_by_owner`] + /**Builder for [`Client::post_get_compressed_balance_by_owner`] -[`Client::post_get_compressed_accounts_by_owner`]: super::Client::post_get_compressed_accounts_by_owner*/ +[`Client::post_get_compressed_balance_by_owner`]: super::Client::post_get_compressed_balance_by_owner*/ #[derive(Debug, Clone)] - pub struct PostGetCompressedAccountsByOwner<'a> { + pub struct PostGetCompressedBalanceByOwner<'a> { client: &'a super::Client, - body: Result, + body: Result, } - impl<'a> PostGetCompressedAccountsByOwner<'a> { + impl<'a> PostGetCompressedBalanceByOwner<'a> { pub fn new(client: &'a super::Client) -> Self { Self { client: client, @@ -50773,9 +52416,9 @@ pub mod builder { } pub fn body(mut self, value: V) -> Self where - V: std::convert::TryInto, + V: std::convert::TryInto, >::Error: std::fmt::Display, { self.body = value @@ -50783,7 +52426,7 @@ pub mod builder { .map(From::from) .map_err(|s| { format!( - "conversion to `PostGetCompressedAccountsByOwnerBody` for body failed: {}", + "conversion to `PostGetCompressedBalanceByOwnerBody` for body failed: {}", s ) }); @@ -50792,27 +52435,27 @@ pub mod builder { pub fn body_map(mut self, f: F) -> Self where F: std::ops::FnOnce( - types::builder::PostGetCompressedAccountsByOwnerBody, - ) -> types::builder::PostGetCompressedAccountsByOwnerBody, + types::builder::PostGetCompressedBalanceByOwnerBody, + ) -> types::builder::PostGetCompressedBalanceByOwnerBody, { self.body = self.body.map(f); self } - ///Sends a `POST` request to `/getCompressedAccountsByOwner` + ///Sends a `POST` request to `/getCompressedBalanceByOwner` pub async fn send( self, ) -> Result< - ResponseValue, - Error, + ResponseValue, + Error, > { let Self { client, body } = self; let body = body .and_then(|v| { - types::PostGetCompressedAccountsByOwnerBody::try_from(v) + types::PostGetCompressedBalanceByOwnerBody::try_from(v) .map_err(|e| e.to_string()) }) .map_err(Error::InvalidRequest)?; - let url = format!("{}/getCompressedAccountsByOwner", client.baseurl,); + let url = format!("{}/getCompressedBalanceByOwner", client.baseurl,); let mut header_map = ::reqwest::header::HeaderMap::with_capacity(1usize); header_map .append( @@ -50833,7 +52476,7 @@ pub mod builder { .headers(header_map) .build()?; let info = OperationInfo { - operation_id: "post_get_compressed_accounts_by_owner", + operation_id: "post_get_compressed_balance_by_owner", }; client.pre(&mut request, &info).await?; let result = client.exec(request, &info).await; @@ -50859,15 +52502,15 @@ pub mod builder { } } } - /**Builder for [`Client::post_get_compressed_accounts_by_owner_v2`] + /**Builder for [`Client::post_get_compressed_mint_token_holders`] -[`Client::post_get_compressed_accounts_by_owner_v2`]: super::Client::post_get_compressed_accounts_by_owner_v2*/ +[`Client::post_get_compressed_mint_token_holders`]: super::Client::post_get_compressed_mint_token_holders*/ #[derive(Debug, Clone)] - pub struct PostGetCompressedAccountsByOwnerV2<'a> { + pub struct PostGetCompressedMintTokenHolders<'a> { client: &'a super::Client, - body: Result, + body: Result, } - impl<'a> PostGetCompressedAccountsByOwnerV2<'a> { + impl<'a> PostGetCompressedMintTokenHolders<'a> { pub fn new(client: &'a super::Client) -> Self { Self { client: client, @@ -50876,9 +52519,9 @@ pub mod builder { } pub fn body(mut self, value: V) -> Self where - V: std::convert::TryInto, + V: std::convert::TryInto, >::Error: std::fmt::Display, { self.body = value @@ -50886,7 +52529,7 @@ pub mod builder { .map(From::from) .map_err(|s| { format!( - "conversion to `PostGetCompressedAccountsByOwnerV2Body` for body failed: {}", + "conversion to `PostGetCompressedMintTokenHoldersBody` for body failed: {}", s ) }); @@ -50895,27 +52538,27 @@ pub mod builder { pub fn body_map(mut self, f: F) -> Self where F: std::ops::FnOnce( - types::builder::PostGetCompressedAccountsByOwnerV2Body, - ) -> types::builder::PostGetCompressedAccountsByOwnerV2Body, + types::builder::PostGetCompressedMintTokenHoldersBody, + ) -> types::builder::PostGetCompressedMintTokenHoldersBody, { self.body = self.body.map(f); self } - ///Sends a `POST` request to `/getCompressedAccountsByOwnerV2` + ///Sends a `POST` request to `/getCompressedMintTokenHolders` pub async fn send( self, ) -> Result< - ResponseValue, - Error, + ResponseValue, + Error, > { let Self { client, body } = self; let body = body .and_then(|v| { - types::PostGetCompressedAccountsByOwnerV2Body::try_from(v) + types::PostGetCompressedMintTokenHoldersBody::try_from(v) .map_err(|e| e.to_string()) }) .map_err(Error::InvalidRequest)?; - let url = format!("{}/getCompressedAccountsByOwnerV2", client.baseurl,); + let url = format!("{}/getCompressedMintTokenHolders", client.baseurl,); let mut header_map = ::reqwest::header::HeaderMap::with_capacity(1usize); header_map .append( @@ -50936,7 +52579,7 @@ pub mod builder { .headers(header_map) .build()?; let info = OperationInfo { - operation_id: "post_get_compressed_accounts_by_owner_v2", + operation_id: "post_get_compressed_mint_token_holders", }; client.pre(&mut request, &info).await?; let result = client.exec(request, &info).await; @@ -50962,15 +52605,15 @@ pub mod builder { } } } - /**Builder for [`Client::post_get_compressed_balance_by_owner`] + /**Builder for [`Client::post_get_compressed_token_account_balance`] -[`Client::post_get_compressed_balance_by_owner`]: super::Client::post_get_compressed_balance_by_owner*/ +[`Client::post_get_compressed_token_account_balance`]: super::Client::post_get_compressed_token_account_balance*/ #[derive(Debug, Clone)] - pub struct PostGetCompressedBalanceByOwner<'a> { + pub struct PostGetCompressedTokenAccountBalance<'a> { client: &'a super::Client, - body: Result, + body: Result, } - impl<'a> PostGetCompressedBalanceByOwner<'a> { + impl<'a> PostGetCompressedTokenAccountBalance<'a> { pub fn new(client: &'a super::Client) -> Self { Self { client: client, @@ -50979,9 +52622,9 @@ pub mod builder { } pub fn body(mut self, value: V) -> Self where - V: std::convert::TryInto, + V: std::convert::TryInto, >::Error: std::fmt::Display, { self.body = value @@ -50989,7 +52632,7 @@ pub mod builder { .map(From::from) .map_err(|s| { format!( - "conversion to `PostGetCompressedBalanceByOwnerBody` for body failed: {}", + "conversion to `PostGetCompressedTokenAccountBalanceBody` for body failed: {}", s ) }); @@ -50998,27 +52641,27 @@ pub mod builder { pub fn body_map(mut self, f: F) -> Self where F: std::ops::FnOnce( - types::builder::PostGetCompressedBalanceByOwnerBody, - ) -> types::builder::PostGetCompressedBalanceByOwnerBody, + types::builder::PostGetCompressedTokenAccountBalanceBody, + ) -> types::builder::PostGetCompressedTokenAccountBalanceBody, { self.body = self.body.map(f); self } - ///Sends a `POST` request to `/getCompressedBalanceByOwner` + ///Sends a `POST` request to `/getCompressedTokenAccountBalance` pub async fn send( self, ) -> Result< - ResponseValue, - Error, + ResponseValue, + Error, > { let Self { client, body } = self; let body = body .and_then(|v| { - types::PostGetCompressedBalanceByOwnerBody::try_from(v) + types::PostGetCompressedTokenAccountBalanceBody::try_from(v) .map_err(|e| e.to_string()) }) .map_err(Error::InvalidRequest)?; - let url = format!("{}/getCompressedBalanceByOwner", client.baseurl,); + let url = format!("{}/getCompressedTokenAccountBalance", client.baseurl,); let mut header_map = ::reqwest::header::HeaderMap::with_capacity(1usize); header_map .append( @@ -51039,7 +52682,7 @@ pub mod builder { .headers(header_map) .build()?; let info = OperationInfo { - operation_id: "post_get_compressed_balance_by_owner", + operation_id: "post_get_compressed_token_account_balance", }; client.pre(&mut request, &info).await?; let result = client.exec(request, &info).await; @@ -51065,15 +52708,18 @@ pub mod builder { } } } - /**Builder for [`Client::post_get_compressed_mint_token_holders`] + /**Builder for [`Client::post_get_compressed_token_accounts_by_delegate`] -[`Client::post_get_compressed_mint_token_holders`]: super::Client::post_get_compressed_mint_token_holders*/ +[`Client::post_get_compressed_token_accounts_by_delegate`]: super::Client::post_get_compressed_token_accounts_by_delegate*/ #[derive(Debug, Clone)] - pub struct PostGetCompressedMintTokenHolders<'a> { + pub struct PostGetCompressedTokenAccountsByDelegate<'a> { client: &'a super::Client, - body: Result, + body: Result< + types::builder::PostGetCompressedTokenAccountsByDelegateBody, + String, + >, } - impl<'a> PostGetCompressedMintTokenHolders<'a> { + impl<'a> PostGetCompressedTokenAccountsByDelegate<'a> { pub fn new(client: &'a super::Client) -> Self { Self { client: client, @@ -51082,9 +52728,11 @@ pub mod builder { } pub fn body(mut self, value: V) -> Self where - V: std::convert::TryInto, + V: std::convert::TryInto< + types::PostGetCompressedTokenAccountsByDelegateBody, + >, >::Error: std::fmt::Display, { self.body = value @@ -51092,7 +52740,7 @@ pub mod builder { .map(From::from) .map_err(|s| { format!( - "conversion to `PostGetCompressedMintTokenHoldersBody` for body failed: {}", + "conversion to `PostGetCompressedTokenAccountsByDelegateBody` for body failed: {}", s ) }); @@ -51101,27 +52749,29 @@ pub mod builder { pub fn body_map(mut self, f: F) -> Self where F: std::ops::FnOnce( - types::builder::PostGetCompressedMintTokenHoldersBody, - ) -> types::builder::PostGetCompressedMintTokenHoldersBody, + types::builder::PostGetCompressedTokenAccountsByDelegateBody, + ) -> types::builder::PostGetCompressedTokenAccountsByDelegateBody, { self.body = self.body.map(f); self } - ///Sends a `POST` request to `/getCompressedMintTokenHolders` + ///Sends a `POST` request to `/getCompressedTokenAccountsByDelegate` pub async fn send( self, ) -> Result< - ResponseValue, - Error, + ResponseValue, + Error, > { let Self { client, body } = self; let body = body .and_then(|v| { - types::PostGetCompressedMintTokenHoldersBody::try_from(v) + types::PostGetCompressedTokenAccountsByDelegateBody::try_from(v) .map_err(|e| e.to_string()) }) .map_err(Error::InvalidRequest)?; - let url = format!("{}/getCompressedMintTokenHolders", client.baseurl,); + let url = format!( + "{}/getCompressedTokenAccountsByDelegate", client.baseurl, + ); let mut header_map = ::reqwest::header::HeaderMap::with_capacity(1usize); header_map .append( @@ -51142,7 +52792,7 @@ pub mod builder { .headers(header_map) .build()?; let info = OperationInfo { - operation_id: "post_get_compressed_mint_token_holders", + operation_id: "post_get_compressed_token_accounts_by_delegate", }; client.pre(&mut request, &info).await?; let result = client.exec(request, &info).await; @@ -51168,15 +52818,18 @@ pub mod builder { } } } - /**Builder for [`Client::post_get_compressed_token_account_balance`] + /**Builder for [`Client::post_get_compressed_token_accounts_by_delegate_v2`] -[`Client::post_get_compressed_token_account_balance`]: super::Client::post_get_compressed_token_account_balance*/ +[`Client::post_get_compressed_token_accounts_by_delegate_v2`]: super::Client::post_get_compressed_token_accounts_by_delegate_v2*/ #[derive(Debug, Clone)] - pub struct PostGetCompressedTokenAccountBalance<'a> { + pub struct PostGetCompressedTokenAccountsByDelegateV2<'a> { client: &'a super::Client, - body: Result, + body: Result< + types::builder::PostGetCompressedTokenAccountsByDelegateV2Body, + String, + >, } - impl<'a> PostGetCompressedTokenAccountBalance<'a> { + impl<'a> PostGetCompressedTokenAccountsByDelegateV2<'a> { pub fn new(client: &'a super::Client) -> Self { Self { client: client, @@ -51185,9 +52838,11 @@ pub mod builder { } pub fn body(mut self, value: V) -> Self where - V: std::convert::TryInto, + V: std::convert::TryInto< + types::PostGetCompressedTokenAccountsByDelegateV2Body, + >, >::Error: std::fmt::Display, { self.body = value @@ -51195,7 +52850,7 @@ pub mod builder { .map(From::from) .map_err(|s| { format!( - "conversion to `PostGetCompressedTokenAccountBalanceBody` for body failed: {}", + "conversion to `PostGetCompressedTokenAccountsByDelegateV2Body` for body failed: {}", s ) }); @@ -51204,27 +52859,29 @@ pub mod builder { pub fn body_map(mut self, f: F) -> Self where F: std::ops::FnOnce( - types::builder::PostGetCompressedTokenAccountBalanceBody, - ) -> types::builder::PostGetCompressedTokenAccountBalanceBody, + types::builder::PostGetCompressedTokenAccountsByDelegateV2Body, + ) -> types::builder::PostGetCompressedTokenAccountsByDelegateV2Body, { self.body = self.body.map(f); self } - ///Sends a `POST` request to `/getCompressedTokenAccountBalance` + ///Sends a `POST` request to `/getCompressedTokenAccountsByDelegateV2` pub async fn send( self, ) -> Result< - ResponseValue, - Error, + ResponseValue, + Error, > { let Self { client, body } = self; let body = body .and_then(|v| { - types::PostGetCompressedTokenAccountBalanceBody::try_from(v) + types::PostGetCompressedTokenAccountsByDelegateV2Body::try_from(v) .map_err(|e| e.to_string()) }) .map_err(Error::InvalidRequest)?; - let url = format!("{}/getCompressedTokenAccountBalance", client.baseurl,); + let url = format!( + "{}/getCompressedTokenAccountsByDelegateV2", client.baseurl, + ); let mut header_map = ::reqwest::header::HeaderMap::with_capacity(1usize); header_map .append( @@ -51245,7 +52902,7 @@ pub mod builder { .headers(header_map) .build()?; let info = OperationInfo { - operation_id: "post_get_compressed_token_account_balance", + operation_id: "post_get_compressed_token_accounts_by_delegate_v2", }; client.pre(&mut request, &info).await?; let result = client.exec(request, &info).await; @@ -51271,18 +52928,15 @@ pub mod builder { } } } - /**Builder for [`Client::post_get_compressed_token_accounts_by_delegate`] + /**Builder for [`Client::post_get_compressed_token_accounts_by_owner`] -[`Client::post_get_compressed_token_accounts_by_delegate`]: super::Client::post_get_compressed_token_accounts_by_delegate*/ +[`Client::post_get_compressed_token_accounts_by_owner`]: super::Client::post_get_compressed_token_accounts_by_owner*/ #[derive(Debug, Clone)] - pub struct PostGetCompressedTokenAccountsByDelegate<'a> { + pub struct PostGetCompressedTokenAccountsByOwner<'a> { client: &'a super::Client, - body: Result< - types::builder::PostGetCompressedTokenAccountsByDelegateBody, - String, - >, + body: Result, } - impl<'a> PostGetCompressedTokenAccountsByDelegate<'a> { + impl<'a> PostGetCompressedTokenAccountsByOwner<'a> { pub fn new(client: &'a super::Client) -> Self { Self { client: client, @@ -51291,11 +52945,9 @@ pub mod builder { } pub fn body(mut self, value: V) -> Self where - V: std::convert::TryInto< - types::PostGetCompressedTokenAccountsByDelegateBody, - >, + V: std::convert::TryInto, >::Error: std::fmt::Display, { self.body = value @@ -51303,7 +52955,7 @@ pub mod builder { .map(From::from) .map_err(|s| { format!( - "conversion to `PostGetCompressedTokenAccountsByDelegateBody` for body failed: {}", + "conversion to `PostGetCompressedTokenAccountsByOwnerBody` for body failed: {}", s ) }); @@ -51312,29 +52964,27 @@ pub mod builder { pub fn body_map(mut self, f: F) -> Self where F: std::ops::FnOnce( - types::builder::PostGetCompressedTokenAccountsByDelegateBody, - ) -> types::builder::PostGetCompressedTokenAccountsByDelegateBody, + types::builder::PostGetCompressedTokenAccountsByOwnerBody, + ) -> types::builder::PostGetCompressedTokenAccountsByOwnerBody, { self.body = self.body.map(f); self } - ///Sends a `POST` request to `/getCompressedTokenAccountsByDelegate` + ///Sends a `POST` request to `/getCompressedTokenAccountsByOwner` pub async fn send( self, ) -> Result< - ResponseValue, - Error, + ResponseValue, + Error, > { let Self { client, body } = self; let body = body .and_then(|v| { - types::PostGetCompressedTokenAccountsByDelegateBody::try_from(v) + types::PostGetCompressedTokenAccountsByOwnerBody::try_from(v) .map_err(|e| e.to_string()) }) .map_err(Error::InvalidRequest)?; - let url = format!( - "{}/getCompressedTokenAccountsByDelegate", client.baseurl, - ); + let url = format!("{}/getCompressedTokenAccountsByOwner", client.baseurl,); let mut header_map = ::reqwest::header::HeaderMap::with_capacity(1usize); header_map .append( @@ -51355,7 +53005,7 @@ pub mod builder { .headers(header_map) .build()?; let info = OperationInfo { - operation_id: "post_get_compressed_token_accounts_by_delegate", + operation_id: "post_get_compressed_token_accounts_by_owner", }; client.pre(&mut request, &info).await?; let result = client.exec(request, &info).await; @@ -51381,18 +53031,18 @@ pub mod builder { } } } - /**Builder for [`Client::post_get_compressed_token_accounts_by_delegate_v2`] + /**Builder for [`Client::post_get_compressed_token_accounts_by_owner_v2`] -[`Client::post_get_compressed_token_accounts_by_delegate_v2`]: super::Client::post_get_compressed_token_accounts_by_delegate_v2*/ +[`Client::post_get_compressed_token_accounts_by_owner_v2`]: super::Client::post_get_compressed_token_accounts_by_owner_v2*/ #[derive(Debug, Clone)] - pub struct PostGetCompressedTokenAccountsByDelegateV2<'a> { + pub struct PostGetCompressedTokenAccountsByOwnerV2<'a> { client: &'a super::Client, body: Result< - types::builder::PostGetCompressedTokenAccountsByDelegateV2Body, + types::builder::PostGetCompressedTokenAccountsByOwnerV2Body, String, >, } - impl<'a> PostGetCompressedTokenAccountsByDelegateV2<'a> { + impl<'a> PostGetCompressedTokenAccountsByOwnerV2<'a> { pub fn new(client: &'a super::Client) -> Self { Self { client: client, @@ -51401,11 +53051,9 @@ pub mod builder { } pub fn body(mut self, value: V) -> Self where - V: std::convert::TryInto< - types::PostGetCompressedTokenAccountsByDelegateV2Body, - >, + V: std::convert::TryInto, >::Error: std::fmt::Display, { self.body = value @@ -51413,7 +53061,7 @@ pub mod builder { .map(From::from) .map_err(|s| { format!( - "conversion to `PostGetCompressedTokenAccountsByDelegateV2Body` for body failed: {}", + "conversion to `PostGetCompressedTokenAccountsByOwnerV2Body` for body failed: {}", s ) }); @@ -51422,29 +53070,27 @@ pub mod builder { pub fn body_map(mut self, f: F) -> Self where F: std::ops::FnOnce( - types::builder::PostGetCompressedTokenAccountsByDelegateV2Body, - ) -> types::builder::PostGetCompressedTokenAccountsByDelegateV2Body, + types::builder::PostGetCompressedTokenAccountsByOwnerV2Body, + ) -> types::builder::PostGetCompressedTokenAccountsByOwnerV2Body, { self.body = self.body.map(f); self } - ///Sends a `POST` request to `/getCompressedTokenAccountsByDelegateV2` + ///Sends a `POST` request to `/getCompressedTokenAccountsByOwnerV2` pub async fn send( self, ) -> Result< - ResponseValue, - Error, + ResponseValue, + Error, > { let Self { client, body } = self; let body = body .and_then(|v| { - types::PostGetCompressedTokenAccountsByDelegateV2Body::try_from(v) + types::PostGetCompressedTokenAccountsByOwnerV2Body::try_from(v) .map_err(|e| e.to_string()) }) .map_err(Error::InvalidRequest)?; - let url = format!( - "{}/getCompressedTokenAccountsByDelegateV2", client.baseurl, - ); + let url = format!("{}/getCompressedTokenAccountsByOwnerV2", client.baseurl,); let mut header_map = ::reqwest::header::HeaderMap::with_capacity(1usize); header_map .append( @@ -51465,7 +53111,7 @@ pub mod builder { .headers(header_map) .build()?; let info = OperationInfo { - operation_id: "post_get_compressed_token_accounts_by_delegate_v2", + operation_id: "post_get_compressed_token_accounts_by_owner_v2", }; client.pre(&mut request, &info).await?; let result = client.exec(request, &info).await; @@ -51491,15 +53137,15 @@ pub mod builder { } } } - /**Builder for [`Client::post_get_compressed_token_accounts_by_owner`] + /**Builder for [`Client::post_get_compressed_token_balances_by_owner`] -[`Client::post_get_compressed_token_accounts_by_owner`]: super::Client::post_get_compressed_token_accounts_by_owner*/ +[`Client::post_get_compressed_token_balances_by_owner`]: super::Client::post_get_compressed_token_balances_by_owner*/ #[derive(Debug, Clone)] - pub struct PostGetCompressedTokenAccountsByOwner<'a> { + pub struct PostGetCompressedTokenBalancesByOwner<'a> { client: &'a super::Client, - body: Result, + body: Result, } - impl<'a> PostGetCompressedTokenAccountsByOwner<'a> { + impl<'a> PostGetCompressedTokenBalancesByOwner<'a> { pub fn new(client: &'a super::Client) -> Self { Self { client: client, @@ -51508,9 +53154,9 @@ pub mod builder { } pub fn body(mut self, value: V) -> Self where - V: std::convert::TryInto, + V: std::convert::TryInto, >::Error: std::fmt::Display, { self.body = value @@ -51518,7 +53164,7 @@ pub mod builder { .map(From::from) .map_err(|s| { format!( - "conversion to `PostGetCompressedTokenAccountsByOwnerBody` for body failed: {}", + "conversion to `PostGetCompressedTokenBalancesByOwnerBody` for body failed: {}", s ) }); @@ -51527,27 +53173,27 @@ pub mod builder { pub fn body_map(mut self, f: F) -> Self where F: std::ops::FnOnce( - types::builder::PostGetCompressedTokenAccountsByOwnerBody, - ) -> types::builder::PostGetCompressedTokenAccountsByOwnerBody, + types::builder::PostGetCompressedTokenBalancesByOwnerBody, + ) -> types::builder::PostGetCompressedTokenBalancesByOwnerBody, { self.body = self.body.map(f); self } - ///Sends a `POST` request to `/getCompressedTokenAccountsByOwner` + ///Sends a `POST` request to `/getCompressedTokenBalancesByOwner` pub async fn send( self, ) -> Result< - ResponseValue, - Error, + ResponseValue, + Error, > { let Self { client, body } = self; let body = body .and_then(|v| { - types::PostGetCompressedTokenAccountsByOwnerBody::try_from(v) + types::PostGetCompressedTokenBalancesByOwnerBody::try_from(v) .map_err(|e| e.to_string()) }) .map_err(Error::InvalidRequest)?; - let url = format!("{}/getCompressedTokenAccountsByOwner", client.baseurl,); + let url = format!("{}/getCompressedTokenBalancesByOwner", client.baseurl,); let mut header_map = ::reqwest::header::HeaderMap::with_capacity(1usize); header_map .append( @@ -51568,7 +53214,7 @@ pub mod builder { .headers(header_map) .build()?; let info = OperationInfo { - operation_id: "post_get_compressed_token_accounts_by_owner", + operation_id: "post_get_compressed_token_balances_by_owner", }; client.pre(&mut request, &info).await?; let result = client.exec(request, &info).await; @@ -51594,18 +53240,18 @@ pub mod builder { } } } - /**Builder for [`Client::post_get_compressed_token_accounts_by_owner_v2`] + /**Builder for [`Client::post_get_compressed_token_balances_by_owner_v2`] -[`Client::post_get_compressed_token_accounts_by_owner_v2`]: super::Client::post_get_compressed_token_accounts_by_owner_v2*/ +[`Client::post_get_compressed_token_balances_by_owner_v2`]: super::Client::post_get_compressed_token_balances_by_owner_v2*/ #[derive(Debug, Clone)] - pub struct PostGetCompressedTokenAccountsByOwnerV2<'a> { + pub struct PostGetCompressedTokenBalancesByOwnerV2<'a> { client: &'a super::Client, body: Result< - types::builder::PostGetCompressedTokenAccountsByOwnerV2Body, + types::builder::PostGetCompressedTokenBalancesByOwnerV2Body, String, >, } - impl<'a> PostGetCompressedTokenAccountsByOwnerV2<'a> { + impl<'a> PostGetCompressedTokenBalancesByOwnerV2<'a> { pub fn new(client: &'a super::Client) -> Self { Self { client: client, @@ -51614,9 +53260,9 @@ pub mod builder { } pub fn body(mut self, value: V) -> Self where - V: std::convert::TryInto, + V: std::convert::TryInto, >::Error: std::fmt::Display, { self.body = value @@ -51624,7 +53270,7 @@ pub mod builder { .map(From::from) .map_err(|s| { format!( - "conversion to `PostGetCompressedTokenAccountsByOwnerV2Body` for body failed: {}", + "conversion to `PostGetCompressedTokenBalancesByOwnerV2Body` for body failed: {}", s ) }); @@ -51633,27 +53279,27 @@ pub mod builder { pub fn body_map(mut self, f: F) -> Self where F: std::ops::FnOnce( - types::builder::PostGetCompressedTokenAccountsByOwnerV2Body, - ) -> types::builder::PostGetCompressedTokenAccountsByOwnerV2Body, + types::builder::PostGetCompressedTokenBalancesByOwnerV2Body, + ) -> types::builder::PostGetCompressedTokenBalancesByOwnerV2Body, { self.body = self.body.map(f); self } - ///Sends a `POST` request to `/getCompressedTokenAccountsByOwnerV2` + ///Sends a `POST` request to `/getCompressedTokenBalancesByOwnerV2` pub async fn send( self, ) -> Result< - ResponseValue, - Error, + ResponseValue, + Error, > { let Self { client, body } = self; let body = body .and_then(|v| { - types::PostGetCompressedTokenAccountsByOwnerV2Body::try_from(v) + types::PostGetCompressedTokenBalancesByOwnerV2Body::try_from(v) .map_err(|e| e.to_string()) }) .map_err(Error::InvalidRequest)?; - let url = format!("{}/getCompressedTokenAccountsByOwnerV2", client.baseurl,); + let url = format!("{}/getCompressedTokenBalancesByOwnerV2", client.baseurl,); let mut header_map = ::reqwest::header::HeaderMap::with_capacity(1usize); header_map .append( @@ -51674,7 +53320,7 @@ pub mod builder { .headers(header_map) .build()?; let info = OperationInfo { - operation_id: "post_get_compressed_token_accounts_by_owner_v2", + operation_id: "post_get_compressed_token_balances_by_owner_v2", }; client.pre(&mut request, &info).await?; let result = client.exec(request, &info).await; @@ -51700,15 +53346,15 @@ pub mod builder { } } } - /**Builder for [`Client::post_get_compressed_token_balances_by_owner`] + /**Builder for [`Client::post_get_compression_signatures_for_account`] -[`Client::post_get_compressed_token_balances_by_owner`]: super::Client::post_get_compressed_token_balances_by_owner*/ +[`Client::post_get_compression_signatures_for_account`]: super::Client::post_get_compression_signatures_for_account*/ #[derive(Debug, Clone)] - pub struct PostGetCompressedTokenBalancesByOwner<'a> { + pub struct PostGetCompressionSignaturesForAccount<'a> { client: &'a super::Client, - body: Result, + body: Result, } - impl<'a> PostGetCompressedTokenBalancesByOwner<'a> { + impl<'a> PostGetCompressionSignaturesForAccount<'a> { pub fn new(client: &'a super::Client) -> Self { Self { client: client, @@ -51717,9 +53363,9 @@ pub mod builder { } pub fn body(mut self, value: V) -> Self where - V: std::convert::TryInto, + V: std::convert::TryInto, >::Error: std::fmt::Display, { self.body = value @@ -51727,7 +53373,7 @@ pub mod builder { .map(From::from) .map_err(|s| { format!( - "conversion to `PostGetCompressedTokenBalancesByOwnerBody` for body failed: {}", + "conversion to `PostGetCompressionSignaturesForAccountBody` for body failed: {}", s ) }); @@ -51736,27 +53382,27 @@ pub mod builder { pub fn body_map(mut self, f: F) -> Self where F: std::ops::FnOnce( - types::builder::PostGetCompressedTokenBalancesByOwnerBody, - ) -> types::builder::PostGetCompressedTokenBalancesByOwnerBody, + types::builder::PostGetCompressionSignaturesForAccountBody, + ) -> types::builder::PostGetCompressionSignaturesForAccountBody, { self.body = self.body.map(f); self } - ///Sends a `POST` request to `/getCompressedTokenBalancesByOwner` + ///Sends a `POST` request to `/getCompressionSignaturesForAccount` pub async fn send( self, ) -> Result< - ResponseValue, - Error, + ResponseValue, + Error, > { let Self { client, body } = self; let body = body .and_then(|v| { - types::PostGetCompressedTokenBalancesByOwnerBody::try_from(v) + types::PostGetCompressionSignaturesForAccountBody::try_from(v) .map_err(|e| e.to_string()) }) .map_err(Error::InvalidRequest)?; - let url = format!("{}/getCompressedTokenBalancesByOwner", client.baseurl,); + let url = format!("{}/getCompressionSignaturesForAccount", client.baseurl,); let mut header_map = ::reqwest::header::HeaderMap::with_capacity(1usize); header_map .append( @@ -51777,7 +53423,7 @@ pub mod builder { .headers(header_map) .build()?; let info = OperationInfo { - operation_id: "post_get_compressed_token_balances_by_owner", + operation_id: "post_get_compression_signatures_for_account", }; client.pre(&mut request, &info).await?; let result = client.exec(request, &info).await; @@ -51803,18 +53449,15 @@ pub mod builder { } } } - /**Builder for [`Client::post_get_compressed_token_balances_by_owner_v2`] + /**Builder for [`Client::post_get_compression_signatures_for_address`] -[`Client::post_get_compressed_token_balances_by_owner_v2`]: super::Client::post_get_compressed_token_balances_by_owner_v2*/ +[`Client::post_get_compression_signatures_for_address`]: super::Client::post_get_compression_signatures_for_address*/ #[derive(Debug, Clone)] - pub struct PostGetCompressedTokenBalancesByOwnerV2<'a> { + pub struct PostGetCompressionSignaturesForAddress<'a> { client: &'a super::Client, - body: Result< - types::builder::PostGetCompressedTokenBalancesByOwnerV2Body, - String, - >, + body: Result, } - impl<'a> PostGetCompressedTokenBalancesByOwnerV2<'a> { + impl<'a> PostGetCompressionSignaturesForAddress<'a> { pub fn new(client: &'a super::Client) -> Self { Self { client: client, @@ -51823,9 +53466,9 @@ pub mod builder { } pub fn body(mut self, value: V) -> Self where - V: std::convert::TryInto, + V: std::convert::TryInto, >::Error: std::fmt::Display, { self.body = value @@ -51833,7 +53476,7 @@ pub mod builder { .map(From::from) .map_err(|s| { format!( - "conversion to `PostGetCompressedTokenBalancesByOwnerV2Body` for body failed: {}", + "conversion to `PostGetCompressionSignaturesForAddressBody` for body failed: {}", s ) }); @@ -51842,27 +53485,27 @@ pub mod builder { pub fn body_map(mut self, f: F) -> Self where F: std::ops::FnOnce( - types::builder::PostGetCompressedTokenBalancesByOwnerV2Body, - ) -> types::builder::PostGetCompressedTokenBalancesByOwnerV2Body, + types::builder::PostGetCompressionSignaturesForAddressBody, + ) -> types::builder::PostGetCompressionSignaturesForAddressBody, { self.body = self.body.map(f); self } - ///Sends a `POST` request to `/getCompressedTokenBalancesByOwnerV2` + ///Sends a `POST` request to `/getCompressionSignaturesForAddress` pub async fn send( self, ) -> Result< - ResponseValue, - Error, + ResponseValue, + Error, > { let Self { client, body } = self; let body = body .and_then(|v| { - types::PostGetCompressedTokenBalancesByOwnerV2Body::try_from(v) + types::PostGetCompressionSignaturesForAddressBody::try_from(v) .map_err(|e| e.to_string()) }) .map_err(Error::InvalidRequest)?; - let url = format!("{}/getCompressedTokenBalancesByOwnerV2", client.baseurl,); + let url = format!("{}/getCompressionSignaturesForAddress", client.baseurl,); let mut header_map = ::reqwest::header::HeaderMap::with_capacity(1usize); header_map .append( @@ -51883,7 +53526,7 @@ pub mod builder { .headers(header_map) .build()?; let info = OperationInfo { - operation_id: "post_get_compressed_token_balances_by_owner_v2", + operation_id: "post_get_compression_signatures_for_address", }; client.pre(&mut request, &info).await?; let result = client.exec(request, &info).await; @@ -51909,15 +53552,15 @@ pub mod builder { } } } - /**Builder for [`Client::post_get_compression_signatures_for_account`] + /**Builder for [`Client::post_get_compression_signatures_for_owner`] -[`Client::post_get_compression_signatures_for_account`]: super::Client::post_get_compression_signatures_for_account*/ +[`Client::post_get_compression_signatures_for_owner`]: super::Client::post_get_compression_signatures_for_owner*/ #[derive(Debug, Clone)] - pub struct PostGetCompressionSignaturesForAccount<'a> { + pub struct PostGetCompressionSignaturesForOwner<'a> { client: &'a super::Client, - body: Result, + body: Result, } - impl<'a> PostGetCompressionSignaturesForAccount<'a> { + impl<'a> PostGetCompressionSignaturesForOwner<'a> { pub fn new(client: &'a super::Client) -> Self { Self { client: client, @@ -51926,9 +53569,9 @@ pub mod builder { } pub fn body(mut self, value: V) -> Self where - V: std::convert::TryInto, + V: std::convert::TryInto, >::Error: std::fmt::Display, { self.body = value @@ -51936,7 +53579,7 @@ pub mod builder { .map(From::from) .map_err(|s| { format!( - "conversion to `PostGetCompressionSignaturesForAccountBody` for body failed: {}", + "conversion to `PostGetCompressionSignaturesForOwnerBody` for body failed: {}", s ) }); @@ -51945,27 +53588,27 @@ pub mod builder { pub fn body_map(mut self, f: F) -> Self where F: std::ops::FnOnce( - types::builder::PostGetCompressionSignaturesForAccountBody, - ) -> types::builder::PostGetCompressionSignaturesForAccountBody, + types::builder::PostGetCompressionSignaturesForOwnerBody, + ) -> types::builder::PostGetCompressionSignaturesForOwnerBody, { self.body = self.body.map(f); self } - ///Sends a `POST` request to `/getCompressionSignaturesForAccount` + ///Sends a `POST` request to `/getCompressionSignaturesForOwner` pub async fn send( self, ) -> Result< - ResponseValue, - Error, + ResponseValue, + Error, > { let Self { client, body } = self; let body = body .and_then(|v| { - types::PostGetCompressionSignaturesForAccountBody::try_from(v) + types::PostGetCompressionSignaturesForOwnerBody::try_from(v) .map_err(|e| e.to_string()) }) .map_err(Error::InvalidRequest)?; - let url = format!("{}/getCompressionSignaturesForAccount", client.baseurl,); + let url = format!("{}/getCompressionSignaturesForOwner", client.baseurl,); let mut header_map = ::reqwest::header::HeaderMap::with_capacity(1usize); header_map .append( @@ -51986,7 +53629,7 @@ pub mod builder { .headers(header_map) .build()?; let info = OperationInfo { - operation_id: "post_get_compression_signatures_for_account", + operation_id: "post_get_compression_signatures_for_owner", }; client.pre(&mut request, &info).await?; let result = client.exec(request, &info).await; @@ -52012,15 +53655,18 @@ pub mod builder { } } } - /**Builder for [`Client::post_get_compression_signatures_for_address`] + /**Builder for [`Client::post_get_compression_signatures_for_token_owner`] -[`Client::post_get_compression_signatures_for_address`]: super::Client::post_get_compression_signatures_for_address*/ +[`Client::post_get_compression_signatures_for_token_owner`]: super::Client::post_get_compression_signatures_for_token_owner*/ #[derive(Debug, Clone)] - pub struct PostGetCompressionSignaturesForAddress<'a> { + pub struct PostGetCompressionSignaturesForTokenOwner<'a> { client: &'a super::Client, - body: Result, + body: Result< + types::builder::PostGetCompressionSignaturesForTokenOwnerBody, + String, + >, } - impl<'a> PostGetCompressionSignaturesForAddress<'a> { + impl<'a> PostGetCompressionSignaturesForTokenOwner<'a> { pub fn new(client: &'a super::Client) -> Self { Self { client: client, @@ -52029,9 +53675,11 @@ pub mod builder { } pub fn body(mut self, value: V) -> Self where - V: std::convert::TryInto, + V: std::convert::TryInto< + types::PostGetCompressionSignaturesForTokenOwnerBody, + >, >::Error: std::fmt::Display, { self.body = value @@ -52039,7 +53687,7 @@ pub mod builder { .map(From::from) .map_err(|s| { format!( - "conversion to `PostGetCompressionSignaturesForAddressBody` for body failed: {}", + "conversion to `PostGetCompressionSignaturesForTokenOwnerBody` for body failed: {}", s ) }); @@ -52048,27 +53696,29 @@ pub mod builder { pub fn body_map(mut self, f: F) -> Self where F: std::ops::FnOnce( - types::builder::PostGetCompressionSignaturesForAddressBody, - ) -> types::builder::PostGetCompressionSignaturesForAddressBody, + types::builder::PostGetCompressionSignaturesForTokenOwnerBody, + ) -> types::builder::PostGetCompressionSignaturesForTokenOwnerBody, { self.body = self.body.map(f); self } - ///Sends a `POST` request to `/getCompressionSignaturesForAddress` + ///Sends a `POST` request to `/getCompressionSignaturesForTokenOwner` pub async fn send( self, ) -> Result< - ResponseValue, - Error, + ResponseValue, + Error, > { let Self { client, body } = self; let body = body .and_then(|v| { - types::PostGetCompressionSignaturesForAddressBody::try_from(v) + types::PostGetCompressionSignaturesForTokenOwnerBody::try_from(v) .map_err(|e| e.to_string()) }) .map_err(Error::InvalidRequest)?; - let url = format!("{}/getCompressionSignaturesForAddress", client.baseurl,); + let url = format!( + "{}/getCompressionSignaturesForTokenOwner", client.baseurl, + ); let mut header_map = ::reqwest::header::HeaderMap::with_capacity(1usize); header_map .append( @@ -52089,7 +53739,7 @@ pub mod builder { .headers(header_map) .build()?; let info = OperationInfo { - operation_id: "post_get_compression_signatures_for_address", + operation_id: "post_get_compression_signatures_for_token_owner", }; client.pre(&mut request, &info).await?; let result = client.exec(request, &info).await; @@ -52115,15 +53765,15 @@ pub mod builder { } } } - /**Builder for [`Client::post_get_compression_signatures_for_owner`] + /**Builder for [`Client::post_get_indexer_health`] -[`Client::post_get_compression_signatures_for_owner`]: super::Client::post_get_compression_signatures_for_owner*/ +[`Client::post_get_indexer_health`]: super::Client::post_get_indexer_health*/ #[derive(Debug, Clone)] - pub struct PostGetCompressionSignaturesForOwner<'a> { + pub struct PostGetIndexerHealth<'a> { client: &'a super::Client, - body: Result, + body: Result, } - impl<'a> PostGetCompressionSignaturesForOwner<'a> { + impl<'a> PostGetIndexerHealth<'a> { pub fn new(client: &'a super::Client) -> Self { Self { client: client, @@ -52132,9 +53782,9 @@ pub mod builder { } pub fn body(mut self, value: V) -> Self where - V: std::convert::TryInto, + V: std::convert::TryInto, >::Error: std::fmt::Display, { self.body = value @@ -52142,8 +53792,7 @@ pub mod builder { .map(From::from) .map_err(|s| { format!( - "conversion to `PostGetCompressionSignaturesForOwnerBody` for body failed: {}", - s + "conversion to `PostGetIndexerHealthBody` for body failed: {}", s ) }); self @@ -52151,27 +53800,27 @@ pub mod builder { pub fn body_map(mut self, f: F) -> Self where F: std::ops::FnOnce( - types::builder::PostGetCompressionSignaturesForOwnerBody, - ) -> types::builder::PostGetCompressionSignaturesForOwnerBody, + types::builder::PostGetIndexerHealthBody, + ) -> types::builder::PostGetIndexerHealthBody, { self.body = self.body.map(f); self } - ///Sends a `POST` request to `/getCompressionSignaturesForOwner` + ///Sends a `POST` request to `/getIndexerHealth` pub async fn send( self, ) -> Result< - ResponseValue, - Error, + ResponseValue, + Error, > { let Self { client, body } = self; let body = body .and_then(|v| { - types::PostGetCompressionSignaturesForOwnerBody::try_from(v) + types::PostGetIndexerHealthBody::try_from(v) .map_err(|e| e.to_string()) }) .map_err(Error::InvalidRequest)?; - let url = format!("{}/getCompressionSignaturesForOwner", client.baseurl,); + let url = format!("{}/getIndexerHealth", client.baseurl,); let mut header_map = ::reqwest::header::HeaderMap::with_capacity(1usize); header_map .append( @@ -52192,7 +53841,7 @@ pub mod builder { .headers(header_map) .build()?; let info = OperationInfo { - operation_id: "post_get_compression_signatures_for_owner", + operation_id: "post_get_indexer_health", }; client.pre(&mut request, &info).await?; let result = client.exec(request, &info).await; @@ -52218,18 +53867,15 @@ pub mod builder { } } } - /**Builder for [`Client::post_get_compression_signatures_for_token_owner`] + /**Builder for [`Client::post_get_indexer_slot`] -[`Client::post_get_compression_signatures_for_token_owner`]: super::Client::post_get_compression_signatures_for_token_owner*/ +[`Client::post_get_indexer_slot`]: super::Client::post_get_indexer_slot*/ #[derive(Debug, Clone)] - pub struct PostGetCompressionSignaturesForTokenOwner<'a> { + pub struct PostGetIndexerSlot<'a> { client: &'a super::Client, - body: Result< - types::builder::PostGetCompressionSignaturesForTokenOwnerBody, - String, - >, + body: Result, } - impl<'a> PostGetCompressionSignaturesForTokenOwner<'a> { + impl<'a> PostGetIndexerSlot<'a> { pub fn new(client: &'a super::Client) -> Self { Self { client: client, @@ -52238,11 +53884,9 @@ pub mod builder { } pub fn body(mut self, value: V) -> Self where - V: std::convert::TryInto< - types::PostGetCompressionSignaturesForTokenOwnerBody, - >, + V: std::convert::TryInto, >::Error: std::fmt::Display, { self.body = value @@ -52250,8 +53894,7 @@ pub mod builder { .map(From::from) .map_err(|s| { format!( - "conversion to `PostGetCompressionSignaturesForTokenOwnerBody` for body failed: {}", - s + "conversion to `PostGetIndexerSlotBody` for body failed: {}", s ) }); self @@ -52259,29 +53902,26 @@ pub mod builder { pub fn body_map(mut self, f: F) -> Self where F: std::ops::FnOnce( - types::builder::PostGetCompressionSignaturesForTokenOwnerBody, - ) -> types::builder::PostGetCompressionSignaturesForTokenOwnerBody, + types::builder::PostGetIndexerSlotBody, + ) -> types::builder::PostGetIndexerSlotBody, { self.body = self.body.map(f); self } - ///Sends a `POST` request to `/getCompressionSignaturesForTokenOwner` + ///Sends a `POST` request to `/getIndexerSlot` pub async fn send( self, ) -> Result< - ResponseValue, - Error, + ResponseValue, + Error, > { let Self { client, body } = self; let body = body .and_then(|v| { - types::PostGetCompressionSignaturesForTokenOwnerBody::try_from(v) - .map_err(|e| e.to_string()) + types::PostGetIndexerSlotBody::try_from(v).map_err(|e| e.to_string()) }) .map_err(Error::InvalidRequest)?; - let url = format!( - "{}/getCompressionSignaturesForTokenOwner", client.baseurl, - ); + let url = format!("{}/getIndexerSlot", client.baseurl,); let mut header_map = ::reqwest::header::HeaderMap::with_capacity(1usize); header_map .append( @@ -52302,7 +53942,7 @@ pub mod builder { .headers(header_map) .build()?; let info = OperationInfo { - operation_id: "post_get_compression_signatures_for_token_owner", + operation_id: "post_get_indexer_slot", }; client.pre(&mut request, &info).await?; let result = client.exec(request, &info).await; @@ -52328,15 +53968,15 @@ pub mod builder { } } } - /**Builder for [`Client::post_get_indexer_health`] + /**Builder for [`Client::post_get_latest_compression_signatures`] -[`Client::post_get_indexer_health`]: super::Client::post_get_indexer_health*/ +[`Client::post_get_latest_compression_signatures`]: super::Client::post_get_latest_compression_signatures*/ #[derive(Debug, Clone)] - pub struct PostGetIndexerHealth<'a> { + pub struct PostGetLatestCompressionSignatures<'a> { client: &'a super::Client, - body: Result, + body: Result, } - impl<'a> PostGetIndexerHealth<'a> { + impl<'a> PostGetLatestCompressionSignatures<'a> { pub fn new(client: &'a super::Client) -> Self { Self { client: client, @@ -52345,9 +53985,9 @@ pub mod builder { } pub fn body(mut self, value: V) -> Self where - V: std::convert::TryInto, + V: std::convert::TryInto, >::Error: std::fmt::Display, { self.body = value @@ -52355,7 +53995,8 @@ pub mod builder { .map(From::from) .map_err(|s| { format!( - "conversion to `PostGetIndexerHealthBody` for body failed: {}", s + "conversion to `PostGetLatestCompressionSignaturesBody` for body failed: {}", + s ) }); self @@ -52363,27 +54004,27 @@ pub mod builder { pub fn body_map(mut self, f: F) -> Self where F: std::ops::FnOnce( - types::builder::PostGetIndexerHealthBody, - ) -> types::builder::PostGetIndexerHealthBody, + types::builder::PostGetLatestCompressionSignaturesBody, + ) -> types::builder::PostGetLatestCompressionSignaturesBody, { self.body = self.body.map(f); self } - ///Sends a `POST` request to `/getIndexerHealth` + ///Sends a `POST` request to `/getLatestCompressionSignatures` pub async fn send( self, ) -> Result< - ResponseValue, - Error, + ResponseValue, + Error, > { let Self { client, body } = self; let body = body .and_then(|v| { - types::PostGetIndexerHealthBody::try_from(v) + types::PostGetLatestCompressionSignaturesBody::try_from(v) .map_err(|e| e.to_string()) }) .map_err(Error::InvalidRequest)?; - let url = format!("{}/getIndexerHealth", client.baseurl,); + let url = format!("{}/getLatestCompressionSignatures", client.baseurl,); let mut header_map = ::reqwest::header::HeaderMap::with_capacity(1usize); header_map .append( @@ -52404,7 +54045,7 @@ pub mod builder { .headers(header_map) .build()?; let info = OperationInfo { - operation_id: "post_get_indexer_health", + operation_id: "post_get_latest_compression_signatures", }; client.pre(&mut request, &info).await?; let result = client.exec(request, &info).await; @@ -52430,15 +54071,15 @@ pub mod builder { } } } - /**Builder for [`Client::post_get_indexer_slot`] + /**Builder for [`Client::post_get_latest_non_voting_signatures`] -[`Client::post_get_indexer_slot`]: super::Client::post_get_indexer_slot*/ +[`Client::post_get_latest_non_voting_signatures`]: super::Client::post_get_latest_non_voting_signatures*/ #[derive(Debug, Clone)] - pub struct PostGetIndexerSlot<'a> { + pub struct PostGetLatestNonVotingSignatures<'a> { client: &'a super::Client, - body: Result, + body: Result, } - impl<'a> PostGetIndexerSlot<'a> { + impl<'a> PostGetLatestNonVotingSignatures<'a> { pub fn new(client: &'a super::Client) -> Self { Self { client: client, @@ -52447,9 +54088,9 @@ pub mod builder { } pub fn body(mut self, value: V) -> Self where - V: std::convert::TryInto, + V: std::convert::TryInto, >::Error: std::fmt::Display, { self.body = value @@ -52457,7 +54098,8 @@ pub mod builder { .map(From::from) .map_err(|s| { format!( - "conversion to `PostGetIndexerSlotBody` for body failed: {}", s + "conversion to `PostGetLatestNonVotingSignaturesBody` for body failed: {}", + s ) }); self @@ -52465,26 +54107,27 @@ pub mod builder { pub fn body_map(mut self, f: F) -> Self where F: std::ops::FnOnce( - types::builder::PostGetIndexerSlotBody, - ) -> types::builder::PostGetIndexerSlotBody, + types::builder::PostGetLatestNonVotingSignaturesBody, + ) -> types::builder::PostGetLatestNonVotingSignaturesBody, { self.body = self.body.map(f); self } - ///Sends a `POST` request to `/getIndexerSlot` + ///Sends a `POST` request to `/getLatestNonVotingSignatures` pub async fn send( self, ) -> Result< - ResponseValue, - Error, + ResponseValue, + Error, > { let Self { client, body } = self; let body = body .and_then(|v| { - types::PostGetIndexerSlotBody::try_from(v).map_err(|e| e.to_string()) + types::PostGetLatestNonVotingSignaturesBody::try_from(v) + .map_err(|e| e.to_string()) }) .map_err(Error::InvalidRequest)?; - let url = format!("{}/getIndexerSlot", client.baseurl,); + let url = format!("{}/getLatestNonVotingSignatures", client.baseurl,); let mut header_map = ::reqwest::header::HeaderMap::with_capacity(1usize); header_map .append( @@ -52505,7 +54148,7 @@ pub mod builder { .headers(header_map) .build()?; let info = OperationInfo { - operation_id: "post_get_indexer_slot", + operation_id: "post_get_latest_non_voting_signatures", }; client.pre(&mut request, &info).await?; let result = client.exec(request, &info).await; @@ -52531,15 +54174,15 @@ pub mod builder { } } } - /**Builder for [`Client::post_get_latest_compression_signatures`] + /**Builder for [`Client::post_get_multiple_account_interfaces`] -[`Client::post_get_latest_compression_signatures`]: super::Client::post_get_latest_compression_signatures*/ +[`Client::post_get_multiple_account_interfaces`]: super::Client::post_get_multiple_account_interfaces*/ #[derive(Debug, Clone)] - pub struct PostGetLatestCompressionSignatures<'a> { + pub struct PostGetMultipleAccountInterfaces<'a> { client: &'a super::Client, - body: Result, + body: Result, } - impl<'a> PostGetLatestCompressionSignatures<'a> { + impl<'a> PostGetMultipleAccountInterfaces<'a> { pub fn new(client: &'a super::Client) -> Self { Self { client: client, @@ -52548,9 +54191,9 @@ pub mod builder { } pub fn body(mut self, value: V) -> Self where - V: std::convert::TryInto, + V: std::convert::TryInto, >::Error: std::fmt::Display, { self.body = value @@ -52558,7 +54201,7 @@ pub mod builder { .map(From::from) .map_err(|s| { format!( - "conversion to `PostGetLatestCompressionSignaturesBody` for body failed: {}", + "conversion to `PostGetMultipleAccountInterfacesBody` for body failed: {}", s ) }); @@ -52567,27 +54210,27 @@ pub mod builder { pub fn body_map(mut self, f: F) -> Self where F: std::ops::FnOnce( - types::builder::PostGetLatestCompressionSignaturesBody, - ) -> types::builder::PostGetLatestCompressionSignaturesBody, + types::builder::PostGetMultipleAccountInterfacesBody, + ) -> types::builder::PostGetMultipleAccountInterfacesBody, { self.body = self.body.map(f); self } - ///Sends a `POST` request to `/getLatestCompressionSignatures` + ///Sends a `POST` request to `/getMultipleAccountInterfaces` pub async fn send( self, ) -> Result< - ResponseValue, - Error, + ResponseValue, + Error, > { let Self { client, body } = self; let body = body .and_then(|v| { - types::PostGetLatestCompressionSignaturesBody::try_from(v) + types::PostGetMultipleAccountInterfacesBody::try_from(v) .map_err(|e| e.to_string()) }) .map_err(Error::InvalidRequest)?; - let url = format!("{}/getLatestCompressionSignatures", client.baseurl,); + let url = format!("{}/getMultipleAccountInterfaces", client.baseurl,); let mut header_map = ::reqwest::header::HeaderMap::with_capacity(1usize); header_map .append( @@ -52608,7 +54251,7 @@ pub mod builder { .headers(header_map) .build()?; let info = OperationInfo { - operation_id: "post_get_latest_compression_signatures", + operation_id: "post_get_multiple_account_interfaces", }; client.pre(&mut request, &info).await?; let result = client.exec(request, &info).await; @@ -52634,15 +54277,15 @@ pub mod builder { } } } - /**Builder for [`Client::post_get_latest_non_voting_signatures`] + /**Builder for [`Client::post_get_multiple_compressed_account_proofs`] -[`Client::post_get_latest_non_voting_signatures`]: super::Client::post_get_latest_non_voting_signatures*/ +[`Client::post_get_multiple_compressed_account_proofs`]: super::Client::post_get_multiple_compressed_account_proofs*/ #[derive(Debug, Clone)] - pub struct PostGetLatestNonVotingSignatures<'a> { + pub struct PostGetMultipleCompressedAccountProofs<'a> { client: &'a super::Client, - body: Result, + body: Result, } - impl<'a> PostGetLatestNonVotingSignatures<'a> { + impl<'a> PostGetMultipleCompressedAccountProofs<'a> { pub fn new(client: &'a super::Client) -> Self { Self { client: client, @@ -52651,9 +54294,9 @@ pub mod builder { } pub fn body(mut self, value: V) -> Self where - V: std::convert::TryInto, + V: std::convert::TryInto, >::Error: std::fmt::Display, { self.body = value @@ -52661,7 +54304,7 @@ pub mod builder { .map(From::from) .map_err(|s| { format!( - "conversion to `PostGetLatestNonVotingSignaturesBody` for body failed: {}", + "conversion to `PostGetMultipleCompressedAccountProofsBody` for body failed: {}", s ) }); @@ -52670,27 +54313,27 @@ pub mod builder { pub fn body_map(mut self, f: F) -> Self where F: std::ops::FnOnce( - types::builder::PostGetLatestNonVotingSignaturesBody, - ) -> types::builder::PostGetLatestNonVotingSignaturesBody, + types::builder::PostGetMultipleCompressedAccountProofsBody, + ) -> types::builder::PostGetMultipleCompressedAccountProofsBody, { self.body = self.body.map(f); self } - ///Sends a `POST` request to `/getLatestNonVotingSignatures` + ///Sends a `POST` request to `/getMultipleCompressedAccountProofs` pub async fn send( self, ) -> Result< - ResponseValue, - Error, + ResponseValue, + Error, > { let Self { client, body } = self; let body = body .and_then(|v| { - types::PostGetLatestNonVotingSignaturesBody::try_from(v) + types::PostGetMultipleCompressedAccountProofsBody::try_from(v) .map_err(|e| e.to_string()) }) .map_err(Error::InvalidRequest)?; - let url = format!("{}/getLatestNonVotingSignatures", client.baseurl,); + let url = format!("{}/getMultipleCompressedAccountProofs", client.baseurl,); let mut header_map = ::reqwest::header::HeaderMap::with_capacity(1usize); header_map .append( @@ -52711,7 +54354,7 @@ pub mod builder { .headers(header_map) .build()?; let info = OperationInfo { - operation_id: "post_get_latest_non_voting_signatures", + operation_id: "post_get_multiple_compressed_account_proofs", }; client.pre(&mut request, &info).await?; let result = client.exec(request, &info).await; @@ -52737,15 +54380,18 @@ pub mod builder { } } } - /**Builder for [`Client::post_get_multiple_account_interfaces`] + /**Builder for [`Client::post_get_multiple_compressed_account_proofs_v2`] -[`Client::post_get_multiple_account_interfaces`]: super::Client::post_get_multiple_account_interfaces*/ +[`Client::post_get_multiple_compressed_account_proofs_v2`]: super::Client::post_get_multiple_compressed_account_proofs_v2*/ #[derive(Debug, Clone)] - pub struct PostGetMultipleAccountInterfaces<'a> { + pub struct PostGetMultipleCompressedAccountProofsV2<'a> { client: &'a super::Client, - body: Result, + body: Result< + types::builder::PostGetMultipleCompressedAccountProofsV2Body, + String, + >, } - impl<'a> PostGetMultipleAccountInterfaces<'a> { + impl<'a> PostGetMultipleCompressedAccountProofsV2<'a> { pub fn new(client: &'a super::Client) -> Self { Self { client: client, @@ -52754,9 +54400,11 @@ pub mod builder { } pub fn body(mut self, value: V) -> Self where - V: std::convert::TryInto, + V: std::convert::TryInto< + types::PostGetMultipleCompressedAccountProofsV2Body, + >, >::Error: std::fmt::Display, { self.body = value @@ -52764,7 +54412,7 @@ pub mod builder { .map(From::from) .map_err(|s| { format!( - "conversion to `PostGetMultipleAccountInterfacesBody` for body failed: {}", + "conversion to `PostGetMultipleCompressedAccountProofsV2Body` for body failed: {}", s ) }); @@ -52773,27 +54421,29 @@ pub mod builder { pub fn body_map(mut self, f: F) -> Self where F: std::ops::FnOnce( - types::builder::PostGetMultipleAccountInterfacesBody, - ) -> types::builder::PostGetMultipleAccountInterfacesBody, + types::builder::PostGetMultipleCompressedAccountProofsV2Body, + ) -> types::builder::PostGetMultipleCompressedAccountProofsV2Body, { self.body = self.body.map(f); self } - ///Sends a `POST` request to `/getMultipleAccountInterfaces` + ///Sends a `POST` request to `/getMultipleCompressedAccountProofsV2` pub async fn send( self, ) -> Result< - ResponseValue, - Error, + ResponseValue, + Error, > { let Self { client, body } = self; let body = body .and_then(|v| { - types::PostGetMultipleAccountInterfacesBody::try_from(v) + types::PostGetMultipleCompressedAccountProofsV2Body::try_from(v) .map_err(|e| e.to_string()) }) .map_err(Error::InvalidRequest)?; - let url = format!("{}/getMultipleAccountInterfaces", client.baseurl,); + let url = format!( + "{}/getMultipleCompressedAccountProofsV2", client.baseurl, + ); let mut header_map = ::reqwest::header::HeaderMap::with_capacity(1usize); header_map .append( @@ -52814,7 +54464,7 @@ pub mod builder { .headers(header_map) .build()?; let info = OperationInfo { - operation_id: "post_get_multiple_account_interfaces", + operation_id: "post_get_multiple_compressed_account_proofs_v2", }; client.pre(&mut request, &info).await?; let result = client.exec(request, &info).await; @@ -52840,15 +54490,15 @@ pub mod builder { } } } - /**Builder for [`Client::post_get_multiple_compressed_account_proofs`] + /**Builder for [`Client::post_get_multiple_compressed_accounts`] -[`Client::post_get_multiple_compressed_account_proofs`]: super::Client::post_get_multiple_compressed_account_proofs*/ +[`Client::post_get_multiple_compressed_accounts`]: super::Client::post_get_multiple_compressed_accounts*/ #[derive(Debug, Clone)] - pub struct PostGetMultipleCompressedAccountProofs<'a> { + pub struct PostGetMultipleCompressedAccounts<'a> { client: &'a super::Client, - body: Result, + body: Result, } - impl<'a> PostGetMultipleCompressedAccountProofs<'a> { + impl<'a> PostGetMultipleCompressedAccounts<'a> { pub fn new(client: &'a super::Client) -> Self { Self { client: client, @@ -52857,9 +54507,9 @@ pub mod builder { } pub fn body(mut self, value: V) -> Self where - V: std::convert::TryInto, + V: std::convert::TryInto, >::Error: std::fmt::Display, { self.body = value @@ -52867,7 +54517,7 @@ pub mod builder { .map(From::from) .map_err(|s| { format!( - "conversion to `PostGetMultipleCompressedAccountProofsBody` for body failed: {}", + "conversion to `PostGetMultipleCompressedAccountsBody` for body failed: {}", s ) }); @@ -52876,27 +54526,27 @@ pub mod builder { pub fn body_map(mut self, f: F) -> Self where F: std::ops::FnOnce( - types::builder::PostGetMultipleCompressedAccountProofsBody, - ) -> types::builder::PostGetMultipleCompressedAccountProofsBody, + types::builder::PostGetMultipleCompressedAccountsBody, + ) -> types::builder::PostGetMultipleCompressedAccountsBody, { self.body = self.body.map(f); self } - ///Sends a `POST` request to `/getMultipleCompressedAccountProofs` + ///Sends a `POST` request to `/getMultipleCompressedAccounts` pub async fn send( self, ) -> Result< - ResponseValue, - Error, + ResponseValue, + Error, > { let Self { client, body } = self; let body = body .and_then(|v| { - types::PostGetMultipleCompressedAccountProofsBody::try_from(v) + types::PostGetMultipleCompressedAccountsBody::try_from(v) .map_err(|e| e.to_string()) }) .map_err(Error::InvalidRequest)?; - let url = format!("{}/getMultipleCompressedAccountProofs", client.baseurl,); + let url = format!("{}/getMultipleCompressedAccounts", client.baseurl,); let mut header_map = ::reqwest::header::HeaderMap::with_capacity(1usize); header_map .append( @@ -52917,7 +54567,7 @@ pub mod builder { .headers(header_map) .build()?; let info = OperationInfo { - operation_id: "post_get_multiple_compressed_account_proofs", + operation_id: "post_get_multiple_compressed_accounts", }; client.pre(&mut request, &info).await?; let result = client.exec(request, &info).await; @@ -52943,18 +54593,15 @@ pub mod builder { } } } - /**Builder for [`Client::post_get_multiple_compressed_account_proofs_v2`] + /**Builder for [`Client::post_get_multiple_compressed_accounts_v2`] -[`Client::post_get_multiple_compressed_account_proofs_v2`]: super::Client::post_get_multiple_compressed_account_proofs_v2*/ +[`Client::post_get_multiple_compressed_accounts_v2`]: super::Client::post_get_multiple_compressed_accounts_v2*/ #[derive(Debug, Clone)] - pub struct PostGetMultipleCompressedAccountProofsV2<'a> { + pub struct PostGetMultipleCompressedAccountsV2<'a> { client: &'a super::Client, - body: Result< - types::builder::PostGetMultipleCompressedAccountProofsV2Body, - String, - >, + body: Result, } - impl<'a> PostGetMultipleCompressedAccountProofsV2<'a> { + impl<'a> PostGetMultipleCompressedAccountsV2<'a> { pub fn new(client: &'a super::Client) -> Self { Self { client: client, @@ -52963,11 +54610,9 @@ pub mod builder { } pub fn body(mut self, value: V) -> Self where - V: std::convert::TryInto< - types::PostGetMultipleCompressedAccountProofsV2Body, - >, + V: std::convert::TryInto, >::Error: std::fmt::Display, { self.body = value @@ -52975,7 +54620,7 @@ pub mod builder { .map(From::from) .map_err(|s| { format!( - "conversion to `PostGetMultipleCompressedAccountProofsV2Body` for body failed: {}", + "conversion to `PostGetMultipleCompressedAccountsV2Body` for body failed: {}", s ) }); @@ -52984,29 +54629,27 @@ pub mod builder { pub fn body_map(mut self, f: F) -> Self where F: std::ops::FnOnce( - types::builder::PostGetMultipleCompressedAccountProofsV2Body, - ) -> types::builder::PostGetMultipleCompressedAccountProofsV2Body, + types::builder::PostGetMultipleCompressedAccountsV2Body, + ) -> types::builder::PostGetMultipleCompressedAccountsV2Body, { self.body = self.body.map(f); self } - ///Sends a `POST` request to `/getMultipleCompressedAccountProofsV2` + ///Sends a `POST` request to `/getMultipleCompressedAccountsV2` pub async fn send( self, ) -> Result< - ResponseValue, - Error, + ResponseValue, + Error, > { let Self { client, body } = self; let body = body .and_then(|v| { - types::PostGetMultipleCompressedAccountProofsV2Body::try_from(v) + types::PostGetMultipleCompressedAccountsV2Body::try_from(v) .map_err(|e| e.to_string()) }) .map_err(Error::InvalidRequest)?; - let url = format!( - "{}/getMultipleCompressedAccountProofsV2", client.baseurl, - ); + let url = format!("{}/getMultipleCompressedAccountsV2", client.baseurl,); let mut header_map = ::reqwest::header::HeaderMap::with_capacity(1usize); header_map .append( @@ -53027,7 +54670,7 @@ pub mod builder { .headers(header_map) .build()?; let info = OperationInfo { - operation_id: "post_get_multiple_compressed_account_proofs_v2", + operation_id: "post_get_multiple_compressed_accounts_v2", }; client.pre(&mut request, &info).await?; let result = client.exec(request, &info).await; @@ -53053,15 +54696,15 @@ pub mod builder { } } } - /**Builder for [`Client::post_get_multiple_compressed_accounts`] + /**Builder for [`Client::post_get_multiple_new_address_proofs`] -[`Client::post_get_multiple_compressed_accounts`]: super::Client::post_get_multiple_compressed_accounts*/ +[`Client::post_get_multiple_new_address_proofs`]: super::Client::post_get_multiple_new_address_proofs*/ #[derive(Debug, Clone)] - pub struct PostGetMultipleCompressedAccounts<'a> { + pub struct PostGetMultipleNewAddressProofs<'a> { client: &'a super::Client, - body: Result, + body: Result, } - impl<'a> PostGetMultipleCompressedAccounts<'a> { + impl<'a> PostGetMultipleNewAddressProofs<'a> { pub fn new(client: &'a super::Client) -> Self { Self { client: client, @@ -53070,9 +54713,9 @@ pub mod builder { } pub fn body(mut self, value: V) -> Self where - V: std::convert::TryInto, + V: std::convert::TryInto, >::Error: std::fmt::Display, { self.body = value @@ -53080,7 +54723,7 @@ pub mod builder { .map(From::from) .map_err(|s| { format!( - "conversion to `PostGetMultipleCompressedAccountsBody` for body failed: {}", + "conversion to `PostGetMultipleNewAddressProofsBody` for body failed: {}", s ) }); @@ -53089,27 +54732,27 @@ pub mod builder { pub fn body_map(mut self, f: F) -> Self where F: std::ops::FnOnce( - types::builder::PostGetMultipleCompressedAccountsBody, - ) -> types::builder::PostGetMultipleCompressedAccountsBody, + types::builder::PostGetMultipleNewAddressProofsBody, + ) -> types::builder::PostGetMultipleNewAddressProofsBody, { self.body = self.body.map(f); self } - ///Sends a `POST` request to `/getMultipleCompressedAccounts` + ///Sends a `POST` request to `/getMultipleNewAddressProofs` pub async fn send( self, ) -> Result< - ResponseValue, - Error, + ResponseValue, + Error, > { let Self { client, body } = self; let body = body .and_then(|v| { - types::PostGetMultipleCompressedAccountsBody::try_from(v) + types::PostGetMultipleNewAddressProofsBody::try_from(v) .map_err(|e| e.to_string()) }) .map_err(Error::InvalidRequest)?; - let url = format!("{}/getMultipleCompressedAccounts", client.baseurl,); + let url = format!("{}/getMultipleNewAddressProofs", client.baseurl,); let mut header_map = ::reqwest::header::HeaderMap::with_capacity(1usize); header_map .append( @@ -53130,7 +54773,7 @@ pub mod builder { .headers(header_map) .build()?; let info = OperationInfo { - operation_id: "post_get_multiple_compressed_accounts", + operation_id: "post_get_multiple_new_address_proofs", }; client.pre(&mut request, &info).await?; let result = client.exec(request, &info).await; @@ -53156,15 +54799,15 @@ pub mod builder { } } } - /**Builder for [`Client::post_get_multiple_compressed_accounts_v2`] + /**Builder for [`Client::post_get_multiple_new_address_proofs_v2`] -[`Client::post_get_multiple_compressed_accounts_v2`]: super::Client::post_get_multiple_compressed_accounts_v2*/ +[`Client::post_get_multiple_new_address_proofs_v2`]: super::Client::post_get_multiple_new_address_proofs_v2*/ #[derive(Debug, Clone)] - pub struct PostGetMultipleCompressedAccountsV2<'a> { + pub struct PostGetMultipleNewAddressProofsV2<'a> { client: &'a super::Client, - body: Result, + body: Result, } - impl<'a> PostGetMultipleCompressedAccountsV2<'a> { + impl<'a> PostGetMultipleNewAddressProofsV2<'a> { pub fn new(client: &'a super::Client) -> Self { Self { client: client, @@ -53173,9 +54816,9 @@ pub mod builder { } pub fn body(mut self, value: V) -> Self where - V: std::convert::TryInto, + V: std::convert::TryInto, >::Error: std::fmt::Display, { self.body = value @@ -53183,7 +54826,7 @@ pub mod builder { .map(From::from) .map_err(|s| { format!( - "conversion to `PostGetMultipleCompressedAccountsV2Body` for body failed: {}", + "conversion to `PostGetMultipleNewAddressProofsV2Body` for body failed: {}", s ) }); @@ -53192,27 +54835,27 @@ pub mod builder { pub fn body_map(mut self, f: F) -> Self where F: std::ops::FnOnce( - types::builder::PostGetMultipleCompressedAccountsV2Body, - ) -> types::builder::PostGetMultipleCompressedAccountsV2Body, + types::builder::PostGetMultipleNewAddressProofsV2Body, + ) -> types::builder::PostGetMultipleNewAddressProofsV2Body, { self.body = self.body.map(f); self } - ///Sends a `POST` request to `/getMultipleCompressedAccountsV2` + ///Sends a `POST` request to `/getMultipleNewAddressProofsV2` pub async fn send( self, ) -> Result< - ResponseValue, - Error, + ResponseValue, + Error, > { let Self { client, body } = self; let body = body .and_then(|v| { - types::PostGetMultipleCompressedAccountsV2Body::try_from(v) + types::PostGetMultipleNewAddressProofsV2Body::try_from(v) .map_err(|e| e.to_string()) }) .map_err(Error::InvalidRequest)?; - let url = format!("{}/getMultipleCompressedAccountsV2", client.baseurl,); + let url = format!("{}/getMultipleNewAddressProofsV2", client.baseurl,); let mut header_map = ::reqwest::header::HeaderMap::with_capacity(1usize); header_map .append( @@ -53233,7 +54876,7 @@ pub mod builder { .headers(header_map) .build()?; let info = OperationInfo { - operation_id: "post_get_multiple_compressed_accounts_v2", + operation_id: "post_get_multiple_new_address_proofs_v2", }; client.pre(&mut request, &info).await?; let result = client.exec(request, &info).await; @@ -53259,15 +54902,15 @@ pub mod builder { } } } - /**Builder for [`Client::post_get_multiple_new_address_proofs`] + /**Builder for [`Client::post_get_queue_elements`] -[`Client::post_get_multiple_new_address_proofs`]: super::Client::post_get_multiple_new_address_proofs*/ +[`Client::post_get_queue_elements`]: super::Client::post_get_queue_elements*/ #[derive(Debug, Clone)] - pub struct PostGetMultipleNewAddressProofs<'a> { + pub struct PostGetQueueElements<'a> { client: &'a super::Client, - body: Result, + body: Result, } - impl<'a> PostGetMultipleNewAddressProofs<'a> { + impl<'a> PostGetQueueElements<'a> { pub fn new(client: &'a super::Client) -> Self { Self { client: client, @@ -53276,9 +54919,9 @@ pub mod builder { } pub fn body(mut self, value: V) -> Self where - V: std::convert::TryInto, + V: std::convert::TryInto, >::Error: std::fmt::Display, { self.body = value @@ -53286,8 +54929,7 @@ pub mod builder { .map(From::from) .map_err(|s| { format!( - "conversion to `PostGetMultipleNewAddressProofsBody` for body failed: {}", - s + "conversion to `PostGetQueueElementsBody` for body failed: {}", s ) }); self @@ -53295,27 +54937,27 @@ pub mod builder { pub fn body_map(mut self, f: F) -> Self where F: std::ops::FnOnce( - types::builder::PostGetMultipleNewAddressProofsBody, - ) -> types::builder::PostGetMultipleNewAddressProofsBody, + types::builder::PostGetQueueElementsBody, + ) -> types::builder::PostGetQueueElementsBody, { self.body = self.body.map(f); self } - ///Sends a `POST` request to `/getMultipleNewAddressProofs` + ///Sends a `POST` request to `/getQueueElements` pub async fn send( self, ) -> Result< - ResponseValue, - Error, + ResponseValue, + Error, > { let Self { client, body } = self; let body = body .and_then(|v| { - types::PostGetMultipleNewAddressProofsBody::try_from(v) + types::PostGetQueueElementsBody::try_from(v) .map_err(|e| e.to_string()) }) .map_err(Error::InvalidRequest)?; - let url = format!("{}/getMultipleNewAddressProofs", client.baseurl,); + let url = format!("{}/getQueueElements", client.baseurl,); let mut header_map = ::reqwest::header::HeaderMap::with_capacity(1usize); header_map .append( @@ -53336,7 +54978,7 @@ pub mod builder { .headers(header_map) .build()?; let info = OperationInfo { - operation_id: "post_get_multiple_new_address_proofs", + operation_id: "post_get_queue_elements", }; client.pre(&mut request, &info).await?; let result = client.exec(request, &info).await; @@ -53362,15 +55004,15 @@ pub mod builder { } } } - /**Builder for [`Client::post_get_multiple_new_address_proofs_v2`] + /**Builder for [`Client::post_get_queue_info`] -[`Client::post_get_multiple_new_address_proofs_v2`]: super::Client::post_get_multiple_new_address_proofs_v2*/ +[`Client::post_get_queue_info`]: super::Client::post_get_queue_info*/ #[derive(Debug, Clone)] - pub struct PostGetMultipleNewAddressProofsV2<'a> { + pub struct PostGetQueueInfo<'a> { client: &'a super::Client, - body: Result, + body: Result, } - impl<'a> PostGetMultipleNewAddressProofsV2<'a> { + impl<'a> PostGetQueueInfo<'a> { pub fn new(client: &'a super::Client) -> Self { Self { client: client, @@ -53379,9 +55021,9 @@ pub mod builder { } pub fn body(mut self, value: V) -> Self where - V: std::convert::TryInto, + V: std::convert::TryInto, >::Error: std::fmt::Display, { self.body = value @@ -53389,8 +55031,7 @@ pub mod builder { .map(From::from) .map_err(|s| { format!( - "conversion to `PostGetMultipleNewAddressProofsV2Body` for body failed: {}", - s + "conversion to `PostGetQueueInfoBody` for body failed: {}", s ) }); self @@ -53398,27 +55039,26 @@ pub mod builder { pub fn body_map(mut self, f: F) -> Self where F: std::ops::FnOnce( - types::builder::PostGetMultipleNewAddressProofsV2Body, - ) -> types::builder::PostGetMultipleNewAddressProofsV2Body, + types::builder::PostGetQueueInfoBody, + ) -> types::builder::PostGetQueueInfoBody, { self.body = self.body.map(f); self } - ///Sends a `POST` request to `/getMultipleNewAddressProofsV2` + ///Sends a `POST` request to `/getQueueInfo` pub async fn send( self, ) -> Result< - ResponseValue, - Error, + ResponseValue, + Error, > { let Self { client, body } = self; let body = body .and_then(|v| { - types::PostGetMultipleNewAddressProofsV2Body::try_from(v) - .map_err(|e| e.to_string()) + types::PostGetQueueInfoBody::try_from(v).map_err(|e| e.to_string()) }) .map_err(Error::InvalidRequest)?; - let url = format!("{}/getMultipleNewAddressProofsV2", client.baseurl,); + let url = format!("{}/getQueueInfo", client.baseurl,); let mut header_map = ::reqwest::header::HeaderMap::with_capacity(1usize); header_map .append( @@ -53439,7 +55079,7 @@ pub mod builder { .headers(header_map) .build()?; let info = OperationInfo { - operation_id: "post_get_multiple_new_address_proofs_v2", + operation_id: "post_get_queue_info", }; client.pre(&mut request, &info).await?; let result = client.exec(request, &info).await; @@ -53465,15 +55105,15 @@ pub mod builder { } } } - /**Builder for [`Client::post_get_queue_elements`] + /**Builder for [`Client::post_get_queue_leaf_indices`] -[`Client::post_get_queue_elements`]: super::Client::post_get_queue_elements*/ +[`Client::post_get_queue_leaf_indices`]: super::Client::post_get_queue_leaf_indices*/ #[derive(Debug, Clone)] - pub struct PostGetQueueElements<'a> { + pub struct PostGetQueueLeafIndices<'a> { client: &'a super::Client, - body: Result, + body: Result, } - impl<'a> PostGetQueueElements<'a> { + impl<'a> PostGetQueueLeafIndices<'a> { pub fn new(client: &'a super::Client) -> Self { Self { client: client, @@ -53482,9 +55122,9 @@ pub mod builder { } pub fn body(mut self, value: V) -> Self where - V: std::convert::TryInto, + V: std::convert::TryInto, >::Error: std::fmt::Display, { self.body = value @@ -53492,7 +55132,8 @@ pub mod builder { .map(From::from) .map_err(|s| { format!( - "conversion to `PostGetQueueElementsBody` for body failed: {}", s + "conversion to `PostGetQueueLeafIndicesBody` for body failed: {}", + s ) }); self @@ -53500,128 +55141,27 @@ pub mod builder { pub fn body_map(mut self, f: F) -> Self where F: std::ops::FnOnce( - types::builder::PostGetQueueElementsBody, - ) -> types::builder::PostGetQueueElementsBody, + types::builder::PostGetQueueLeafIndicesBody, + ) -> types::builder::PostGetQueueLeafIndicesBody, { self.body = self.body.map(f); self } - ///Sends a `POST` request to `/getQueueElements` + ///Sends a `POST` request to `/getQueueLeafIndices` pub async fn send( self, ) -> Result< - ResponseValue, - Error, + ResponseValue, + Error, > { let Self { client, body } = self; let body = body .and_then(|v| { - types::PostGetQueueElementsBody::try_from(v) + types::PostGetQueueLeafIndicesBody::try_from(v) .map_err(|e| e.to_string()) }) .map_err(Error::InvalidRequest)?; - let url = format!("{}/getQueueElements", client.baseurl,); - let mut header_map = ::reqwest::header::HeaderMap::with_capacity(1usize); - header_map - .append( - ::reqwest::header::HeaderName::from_static("api-version"), - ::reqwest::header::HeaderValue::from_static( - super::Client::api_version(), - ), - ); - #[allow(unused_mut)] - let mut request = client - .client - .post(url) - .header( - ::reqwest::header::ACCEPT, - ::reqwest::header::HeaderValue::from_static("application/json"), - ) - .json(&body) - .headers(header_map) - .build()?; - let info = OperationInfo { - operation_id: "post_get_queue_elements", - }; - client.pre(&mut request, &info).await?; - let result = client.exec(request, &info).await; - client.post(&result, &info).await?; - let response = result?; - match response.status().as_u16() { - 200u16 => ResponseValue::from_response(response).await, - 429u16 => { - Err( - Error::ErrorResponse( - ResponseValue::from_response(response).await?, - ), - ) - } - 500u16 => { - Err( - Error::ErrorResponse( - ResponseValue::from_response(response).await?, - ), - ) - } - _ => Err(Error::UnexpectedResponse(response)), - } - } - } - /**Builder for [`Client::post_get_queue_info`] - -[`Client::post_get_queue_info`]: super::Client::post_get_queue_info*/ - #[derive(Debug, Clone)] - pub struct PostGetQueueInfo<'a> { - client: &'a super::Client, - body: Result, - } - impl<'a> PostGetQueueInfo<'a> { - pub fn new(client: &'a super::Client) -> Self { - Self { - client: client, - body: Ok(::std::default::Default::default()), - } - } - pub fn body(mut self, value: V) -> Self - where - V: std::convert::TryInto, - >::Error: std::fmt::Display, - { - self.body = value - .try_into() - .map(From::from) - .map_err(|s| { - format!( - "conversion to `PostGetQueueInfoBody` for body failed: {}", s - ) - }); - self - } - pub fn body_map(mut self, f: F) -> Self - where - F: std::ops::FnOnce( - types::builder::PostGetQueueInfoBody, - ) -> types::builder::PostGetQueueInfoBody, - { - self.body = self.body.map(f); - self - } - ///Sends a `POST` request to `/getQueueInfo` - pub async fn send( - self, - ) -> Result< - ResponseValue, - Error, - > { - let Self { client, body } = self; - let body = body - .and_then(|v| { - types::PostGetQueueInfoBody::try_from(v).map_err(|e| e.to_string()) - }) - .map_err(Error::InvalidRequest)?; - let url = format!("{}/getQueueInfo", client.baseurl,); + let url = format!("{}/getQueueLeafIndices", client.baseurl,); let mut header_map = ::reqwest::header::HeaderMap::with_capacity(1usize); header_map .append( @@ -53642,7 +55182,7 @@ pub mod builder { .headers(header_map) .build()?; let info = OperationInfo { - operation_id: "post_get_queue_info", + operation_id: "post_get_queue_leaf_indices", }; client.pre(&mut request, &info).await?; let result = client.exec(request, &info).await; From 97310df62f207db1d7729c5541d7158300a8fea9 Mon Sep 17 00:00:00 2001 From: Sergey Timoshin Date: Fri, 27 Mar 2026 10:38:53 +0000 Subject: [PATCH 12/23] refactor: simplify batch data length validation and remove redundant proof height checks --- forester/src/processor/v2/helpers.rs | 37 ++++++++++------------ sdk-libs/client/src/indexer/types/queue.rs | 2 -- 2 files changed, 16 insertions(+), 23 deletions(-) diff --git a/forester/src/processor/v2/helpers.rs b/forester/src/processor/v2/helpers.rs index e6cd8092ea..66b574dc4e 100644 --- a/forester/src/processor/v2/helpers.rs +++ b/forester/src/processor/v2/helpers.rs @@ -499,27 +499,22 @@ impl StreamingAddressQueue { let actual_end = end; let data = lock_recover(&self.data, "streaming_address_queue.data"); - for (name, len) in [ - ("addresses", data.addresses.len()), - ("low_element_values", data.low_element_values.len()), - ( - "low_element_next_values", - data.low_element_next_values.len(), - ), - ("low_element_indices", data.low_element_indices.len()), - ( - "low_element_next_indices", - data.low_element_next_indices.len(), - ), - ] { - if len < actual_end { - return Err(anyhow!( - "incomplete batch data: {} len {} < required end {}", - name, - len, - actual_end - )); - } + let min_len = [ + data.addresses.len(), + data.low_element_values.len(), + data.low_element_next_values.len(), + data.low_element_indices.len(), + data.low_element_next_indices.len(), + ] + .into_iter() + .min() + .unwrap_or(0); + if min_len < actual_end { + return Err(anyhow!( + "incomplete batch data: min field length {} < required end {}", + min_len, + actual_end + )); } let addresses = data.addresses[start..actual_end].to_vec(); diff --git a/sdk-libs/client/src/indexer/types/queue.rs b/sdk-libs/client/src/indexer/types/queue.rs index 8a9cd479a3..f64e200477 100644 --- a/sdk-libs/client/src/indexer/types/queue.rs +++ b/sdk-libs/client/src/indexer/types/queue.rs @@ -115,7 +115,6 @@ impl AddressQueueData { pub fn reconstruct_all_proofs( &self, ) -> Result, IndexerError> { - self.validate_proof_height::()?; self.reconstruct_proofs::(0..self.addresses.len()) } @@ -136,7 +135,6 @@ impl AddressQueueData { address_idx: usize, node_lookup: &HashMap, ) -> Result<[[u8; 32]; HEIGHT], IndexerError> { - self.validate_proof_height::()?; let leaf_index = *self.low_element_indices.get(address_idx).ok_or_else(|| { IndexerError::MissingResult { context: "reconstruct_proof".to_string(), From 275ec047800824d03a776a52614b284ac39e7d58 Mon Sep 17 00:00:00 2001 From: Sergey Timoshin Date: Sat, 14 Mar 2026 16:32:06 +0000 Subject: [PATCH 13/23] feat: optimize address batch pipeline --- .../utils/src/test_batch_forester.rs | 4 +++- prover/client/src/errors.rs | 1 + .../program-test/src/indexer/test_indexer.rs | 20 ++++++++++++------- 3 files changed, 17 insertions(+), 8 deletions(-) diff --git a/program-tests/utils/src/test_batch_forester.rs b/program-tests/utils/src/test_batch_forester.rs index e148e918d4..a004097cea 100644 --- a/program-tests/utils/src/test_batch_forester.rs +++ b/program-tests/utils/src/test_batch_forester.rs @@ -165,7 +165,9 @@ pub async fn create_append_batch_ix_data( bundle.merkle_tree.root() ); let proof_client = ProofClient::local(); - let inputs_json = BatchAppendInputsJson::from_inputs(&circuit_inputs).to_string(); + let inputs_json = BatchAppendInputsJson::from_inputs(&circuit_inputs) + .to_string() + ; match proof_client.generate_proof(inputs_json).await { Ok(compressed_proof) => ( diff --git a/prover/client/src/errors.rs b/prover/client/src/errors.rs index 859cae32b8..e095bf3579 100644 --- a/prover/client/src/errors.rs +++ b/prover/client/src/errors.rs @@ -39,6 +39,7 @@ pub enum ProverClientError { #[error("Integer conversion failed: {0}")] IntegerConversion(String), + #[error("Hashchain mismatch: computed {computed:?} != expected {expected:?} (batch_size={batch_size}, next_index={next_index})")] HashchainMismatch { computed: [u8; 32], diff --git a/sdk-libs/program-test/src/indexer/test_indexer.rs b/sdk-libs/program-test/src/indexer/test_indexer.rs index 584a684a59..07b1dbfd0e 100644 --- a/sdk-libs/program-test/src/indexer/test_indexer.rs +++ b/sdk-libs/program-test/src/indexer/test_indexer.rs @@ -2258,18 +2258,20 @@ impl TestIndexer { let inclusion_proof_inputs = InclusionProofInputs::new(inclusion_proofs.as_slice()).unwrap(); ( - Some(BatchInclusionJsonStruct::from_inclusion_proof_inputs( - &inclusion_proof_inputs, - )), + Some( + BatchInclusionJsonStruct::from_inclusion_proof_inputs(&inclusion_proof_inputs), + ), None, ) } else if height == STATE_MERKLE_TREE_HEIGHT as usize { let inclusion_proof_inputs = InclusionProofInputsLegacy(inclusion_proofs.as_slice()); ( None, - Some(BatchInclusionJsonStructLegacy::from_inclusion_proof_inputs( - &inclusion_proof_inputs, - )), + Some( + BatchInclusionJsonStructLegacy::from_inclusion_proof_inputs( + &inclusion_proof_inputs, + ), + ), ) } else { return Err(IndexerError::CustomError( @@ -2455,7 +2457,11 @@ impl TestIndexer { if let Some(payload) = payload { (indices, Vec::new(), payload.to_string()) } else { - (indices, Vec::new(), payload_legacy.unwrap().to_string()) + ( + indices, + Vec::new(), + payload_legacy.unwrap().to_string(), + ) } } (None, Some(addresses)) => { From 2c72d8400b37a9bdf0419d44aa150369c7340df0 Mon Sep 17 00:00:00 2001 From: Sergey Timoshin Date: Sat, 14 Mar 2026 19:30:35 +0000 Subject: [PATCH 14/23] format --- .../utils/src/test_batch_forester.rs | 4 +--- .../program-test/src/indexer/test_indexer.rs | 20 +++++++------------ .../tests/integration_tests.rs | 2 +- 3 files changed, 9 insertions(+), 17 deletions(-) diff --git a/program-tests/utils/src/test_batch_forester.rs b/program-tests/utils/src/test_batch_forester.rs index a004097cea..e148e918d4 100644 --- a/program-tests/utils/src/test_batch_forester.rs +++ b/program-tests/utils/src/test_batch_forester.rs @@ -165,9 +165,7 @@ pub async fn create_append_batch_ix_data( bundle.merkle_tree.root() ); let proof_client = ProofClient::local(); - let inputs_json = BatchAppendInputsJson::from_inputs(&circuit_inputs) - .to_string() - ; + let inputs_json = BatchAppendInputsJson::from_inputs(&circuit_inputs).to_string(); match proof_client.generate_proof(inputs_json).await { Ok(compressed_proof) => ( diff --git a/sdk-libs/program-test/src/indexer/test_indexer.rs b/sdk-libs/program-test/src/indexer/test_indexer.rs index 07b1dbfd0e..584a684a59 100644 --- a/sdk-libs/program-test/src/indexer/test_indexer.rs +++ b/sdk-libs/program-test/src/indexer/test_indexer.rs @@ -2258,20 +2258,18 @@ impl TestIndexer { let inclusion_proof_inputs = InclusionProofInputs::new(inclusion_proofs.as_slice()).unwrap(); ( - Some( - BatchInclusionJsonStruct::from_inclusion_proof_inputs(&inclusion_proof_inputs), - ), + Some(BatchInclusionJsonStruct::from_inclusion_proof_inputs( + &inclusion_proof_inputs, + )), None, ) } else if height == STATE_MERKLE_TREE_HEIGHT as usize { let inclusion_proof_inputs = InclusionProofInputsLegacy(inclusion_proofs.as_slice()); ( None, - Some( - BatchInclusionJsonStructLegacy::from_inclusion_proof_inputs( - &inclusion_proof_inputs, - ), - ), + Some(BatchInclusionJsonStructLegacy::from_inclusion_proof_inputs( + &inclusion_proof_inputs, + )), ) } else { return Err(IndexerError::CustomError( @@ -2457,11 +2455,7 @@ impl TestIndexer { if let Some(payload) = payload { (indices, Vec::new(), payload.to_string()) } else { - ( - indices, - Vec::new(), - payload_legacy.unwrap().to_string(), - ) + (indices, Vec::new(), payload_legacy.unwrap().to_string()) } } (None, Some(addresses)) => { diff --git a/sdk-tests/csdk-anchor-full-derived-test/tests/integration_tests.rs b/sdk-tests/csdk-anchor-full-derived-test/tests/integration_tests.rs index 9b40b900e5..2c3e82972a 100644 --- a/sdk-tests/csdk-anchor-full-derived-test/tests/integration_tests.rs +++ b/sdk-tests/csdk-anchor-full-derived-test/tests/integration_tests.rs @@ -3863,7 +3863,7 @@ async fn test_d9_edge_many_literals() { #[tokio::test] async fn test_d9_edge_mixed() { use csdk_anchor_full_derived_test::d9_seeds::{ - edge_cases::{AB, SEED_123, _UNDERSCORE_CONST}, + edge_cases::{_UNDERSCORE_CONST, AB, SEED_123}, D9EdgeMixedParams, }; From f7eec43e1ec706859be78da53978da3a70581408 Mon Sep 17 00:00:00 2001 From: Sergey Timoshin Date: Sat, 14 Mar 2026 19:42:28 +0000 Subject: [PATCH 15/23] feat: stabilize address batch pipeline --- .../csdk-anchor-full-derived-test/tests/integration_tests.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sdk-tests/csdk-anchor-full-derived-test/tests/integration_tests.rs b/sdk-tests/csdk-anchor-full-derived-test/tests/integration_tests.rs index 2c3e82972a..9b40b900e5 100644 --- a/sdk-tests/csdk-anchor-full-derived-test/tests/integration_tests.rs +++ b/sdk-tests/csdk-anchor-full-derived-test/tests/integration_tests.rs @@ -3863,7 +3863,7 @@ async fn test_d9_edge_many_literals() { #[tokio::test] async fn test_d9_edge_mixed() { use csdk_anchor_full_derived_test::d9_seeds::{ - edge_cases::{_UNDERSCORE_CONST, AB, SEED_123}, + edge_cases::{AB, SEED_123, _UNDERSCORE_CONST}, D9EdgeMixedParams, }; From 4535b49ca559566c6f871cc4dd06ba7916b22a0c Mon Sep 17 00:00:00 2001 From: Sergey Timoshin Date: Sat, 14 Mar 2026 16:32:39 +0000 Subject: [PATCH 16/23] feat: batch cold account loads in light client --- sdk-libs/client/src/indexer/types/queue.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/sdk-libs/client/src/indexer/types/queue.rs b/sdk-libs/client/src/indexer/types/queue.rs index f64e200477..8a9cd479a3 100644 --- a/sdk-libs/client/src/indexer/types/queue.rs +++ b/sdk-libs/client/src/indexer/types/queue.rs @@ -115,6 +115,7 @@ impl AddressQueueData { pub fn reconstruct_all_proofs( &self, ) -> Result, IndexerError> { + self.validate_proof_height::()?; self.reconstruct_proofs::(0..self.addresses.len()) } @@ -135,6 +136,7 @@ impl AddressQueueData { address_idx: usize, node_lookup: &HashMap, ) -> Result<[[u8; 32]; HEIGHT], IndexerError> { + self.validate_proof_height::()?; let leaf_index = *self.low_element_indices.get(address_idx).ok_or_else(|| { IndexerError::MissingResult { context: "reconstruct_proof".to_string(), From 3966959d8f2e824979a2e92872ce8ea0f589f013 Mon Sep 17 00:00:00 2001 From: Sergey Timoshin Date: Sun, 15 Mar 2026 14:42:54 +0000 Subject: [PATCH 17/23] fix: harden load batching and mixed decompression --- forester/src/processor/v2/processor.rs | 6 +++--- forester/src/processor/v2/proof_worker.rs | 18 +++++++++--------- program-tests/utils/src/test_batch_forester.rs | 6 +++--- prover/client/src/proof_client.rs | 8 ++++---- prover/client/src/prover.rs | 2 ++ .../src/interface/program/decompression/pda.rs | 2 +- 6 files changed, 22 insertions(+), 20 deletions(-) diff --git a/forester/src/processor/v2/processor.rs b/forester/src/processor/v2/processor.rs index 3de6dea860..372a800e0e 100644 --- a/forester/src/processor/v2/processor.rs +++ b/forester/src/processor/v2/processor.rs @@ -132,7 +132,7 @@ where } if self.worker_pool.is_none() { - let job_tx = spawn_proof_workers(&self.context.prover_config); + let job_tx = spawn_proof_workers(&self.context.prover_config)?; self.worker_pool = Some(WorkerPool { job_tx }); } @@ -532,7 +532,7 @@ where ((queue_size / self.zkp_batch_size) as usize).min(self.context.max_batches_per_tree); if self.worker_pool.is_none() { - let job_tx = spawn_proof_workers(&self.context.prover_config); + let job_tx = spawn_proof_workers(&self.context.prover_config)?; self.worker_pool = Some(WorkerPool { job_tx }); } @@ -561,7 +561,7 @@ where let max_batches = max_batches.min(self.context.max_batches_per_tree); if self.worker_pool.is_none() { - let job_tx = spawn_proof_workers(&self.context.prover_config); + let job_tx = spawn_proof_workers(&self.context.prover_config)?; self.worker_pool = Some(WorkerPool { job_tx }); } diff --git a/forester/src/processor/v2/proof_worker.rs b/forester/src/processor/v2/proof_worker.rs index b7afeacf0b..ded9fcedc8 100644 --- a/forester/src/processor/v2/proof_worker.rs +++ b/forester/src/processor/v2/proof_worker.rs @@ -132,27 +132,27 @@ struct ProofClients { } impl ProofClients { - fn new(config: &ProverConfig) -> Self { - Self { + fn new(config: &ProverConfig) -> crate::Result { + Ok(Self { append_client: ProofClient::with_config( config.append_url.clone(), config.polling_interval, config.max_wait_time, config.api_key.clone(), - ), + )?, nullify_client: ProofClient::with_config( config.update_url.clone(), config.polling_interval, config.max_wait_time, config.api_key.clone(), - ), + )?, address_append_client: ProofClient::with_config( config.address_append_url.clone(), config.polling_interval, config.max_wait_time, config.api_key.clone(), - ), - } + )?, + }) } fn get_client(&self, input: &ProofInput) -> &ProofClient { @@ -164,11 +164,11 @@ impl ProofClients { } } -pub fn spawn_proof_workers(config: &ProverConfig) -> async_channel::Sender { +pub fn spawn_proof_workers(config: &ProverConfig) -> crate::Result> { let (job_tx, job_rx) = async_channel::bounded::(256); - let clients = Arc::new(ProofClients::new(config)); + let clients = Arc::new(ProofClients::new(config)?); tokio::spawn(async move { run_proof_pipeline(job_rx, clients).await }); - job_tx + Ok(job_tx) } async fn run_proof_pipeline( diff --git a/program-tests/utils/src/test_batch_forester.rs b/program-tests/utils/src/test_batch_forester.rs index e148e918d4..8cec32757f 100644 --- a/program-tests/utils/src/test_batch_forester.rs +++ b/program-tests/utils/src/test_batch_forester.rs @@ -164,7 +164,7 @@ pub async fn create_append_batch_ix_data( bigint_to_be_bytes_array::<32>(&circuit_inputs.new_root.to_biguint().unwrap()).unwrap(), bundle.merkle_tree.root() ); - let proof_client = ProofClient::local(); + let proof_client = ProofClient::local().unwrap(); let inputs_json = BatchAppendInputsJson::from_inputs(&circuit_inputs).to_string(); match proof_client.generate_proof(inputs_json).await { @@ -293,7 +293,7 @@ pub async fn get_batched_nullify_ix_data( &[], ) .unwrap(); - let proof_client = ProofClient::local(); + let proof_client = ProofClient::local().unwrap(); let circuit_inputs_new_root = bigint_to_be_bytes_array::<32>(&inputs.new_root.to_biguint().unwrap()).unwrap(); let inputs_json = update_inputs_string(&inputs); @@ -715,7 +715,7 @@ pub async fn create_batch_update_address_tree_instruction_data_with_proof(&inputs.new_root).unwrap(); let inputs_json = to_json(&inputs); diff --git a/prover/client/src/proof_client.rs b/prover/client/src/proof_client.rs index 859ea4917f..9642cf1264 100644 --- a/prover/client/src/proof_client.rs +++ b/prover/client/src/proof_client.rs @@ -75,7 +75,7 @@ impl ProofClient { max_wait_time: Duration::from_secs(DEFAULT_MAX_WAIT_TIME_SECS), api_key: None, initial_poll_delay: Duration::from_millis(INITIAL_POLL_DELAY_SMALL_CIRCUIT_MS), - } + }) } #[allow(unused)] @@ -84,7 +84,7 @@ impl ProofClient { polling_interval: Duration, max_wait_time: Duration, api_key: Option, - ) -> Self { + ) -> Result { let initial_poll_delay = if api_key.is_some() { Duration::from_millis(INITIAL_POLL_DELAY_LARGE_CIRCUIT_MS) } else { @@ -98,7 +98,7 @@ impl ProofClient { max_wait_time, api_key, initial_poll_delay, - } + }) } #[allow(unused)] @@ -116,7 +116,7 @@ impl ProofClient { max_wait_time, api_key, initial_poll_delay, - } + }) } pub async fn submit_proof_async( diff --git a/prover/client/src/prover.rs b/prover/client/src/prover.rs index 5e8748299c..71fa37deae 100644 --- a/prover/client/src/prover.rs +++ b/prover/client/src/prover.rs @@ -6,9 +6,11 @@ use std::{ use tokio::time::sleep; use tracing::info; +use tokio::time::sleep; use crate::{ constants::{HEALTH_CHECK, SERVER_ADDRESS}, + errors::ProverClientError, helpers::get_project_root, }; diff --git a/sdk-libs/sdk-types/src/interface/program/decompression/pda.rs b/sdk-libs/sdk-types/src/interface/program/decompression/pda.rs index cc7aa4ba1f..926fe36e1d 100644 --- a/sdk-libs/sdk-types/src/interface/program/decompression/pda.rs +++ b/sdk-libs/sdk-types/src/interface/program/decompression/pda.rs @@ -151,7 +151,7 @@ where lamports: 0, merkle_context: PackedMerkleContext { merkle_tree_pubkey_index: tree_info.merkle_tree_pubkey_index, - queue_pubkey_index: tree_info.queue_pubkey_index, + queue_pubkey_index: input_queue_index, leaf_index: tree_info.leaf_index, prove_by_index: tree_info.prove_by_index, }, From 65481737a140ab8c2f00bd72bb2a04b01dd664b1 Mon Sep 17 00:00:00 2001 From: Sergey Timoshin Date: Mon, 16 Mar 2026 17:45:15 +0000 Subject: [PATCH 18/23] fix: harden test indexer proof parsing --- .../program-test/src/indexer/test_indexer.rs | 51 ++++++++++++++----- 1 file changed, 39 insertions(+), 12 deletions(-) diff --git a/sdk-libs/program-test/src/indexer/test_indexer.rs b/sdk-libs/program-test/src/indexer/test_indexer.rs index 584a684a59..f6507bbef6 100644 --- a/sdk-libs/program-test/src/indexer/test_indexer.rs +++ b/sdk-libs/program-test/src/indexer/test_indexer.rs @@ -1,4 +1,10 @@ -use std::{collections::HashMap, fmt::Debug, time::Duration}; +use std::{ + any::Any, + collections::HashMap, + fmt::Debug, + panic::{catch_unwind, AssertUnwindSafe}, + time::Duration, +}; #[cfg(feature = "devenv")] use account_compression::{ @@ -95,6 +101,37 @@ use crate::accounts::{ }; use crate::indexer::TestIndexerExtensions; +fn panic_payload_message(payload: &(dyn Any + Send)) -> String { + if let Some(message) = payload.downcast_ref::() { + message.clone() + } else if let Some(message) = payload.downcast_ref::<&str>() { + (*message).to_string() + } else { + "non-string panic payload".to_string() + } +} + +fn build_compressed_proof(body: &str) -> Result { + let proof_json = deserialize_gnark_proof_json(body) + .map_err(|error| IndexerError::CustomError(error.to_string()))?; + let (proof_a, proof_b, proof_c) = catch_unwind(AssertUnwindSafe(|| { + let (proof_a, proof_b, proof_c) = proof_from_json_struct(proof_json); + compress_proof(&proof_a, &proof_b, &proof_c) + })) + .map_err(|payload| { + IndexerError::CustomError(format!( + "failed to parse prover proof payload: {}", + panic_payload_message(payload.as_ref()) + )) + })?; + + Ok(CompressedProof { + a: proof_a, + b: proof_b, + c: proof_c, + }) +} + #[derive(Debug)] pub struct TestIndexer { pub state_merkle_trees: Vec, @@ -2585,20 +2622,10 @@ impl TestIndexer { })?; if status.is_success() { - let proof_json = deserialize_gnark_proof_json(&body) - .map_err(|error| IndexerError::CustomError(error.to_string()))?; - let (proof_a, proof_b, proof_c) = proof_from_json_struct(proof_json); - let (proof_a, proof_b, proof_c) = - compress_proof(&proof_a, &proof_b, &proof_c); return Ok(ValidityProofWithContext { accounts: account_proof_inputs, addresses: address_proof_inputs, - proof: CompressedProof { - a: proof_a, - b: proof_b, - c: proof_c, - } - .into(), + proof: build_compressed_proof(&body)?.into(), }); } From 98ed449019bd6f2b8f041fac6c102fb70c185472 Mon Sep 17 00:00:00 2001 From: Sergey Timoshin Date: Tue, 17 Mar 2026 08:32:34 +0000 Subject: [PATCH 19/23] fix: harden runtime safety edge cases --- forester/src/forester_status.rs | 32 ++--- forester/src/processor/v2/helpers.rs | 47 +++++++- .../actions/legacy/instructions/transfer2.rs | 4 +- program-tests/utils/src/e2e_test_env.rs | 4 +- prover/client/src/proof.rs | 111 +++++++++++++----- prover/client/src/proof_client.rs | 4 +- .../batch_address_append/proof_inputs.rs | 48 ++++---- .../proof_types/batch_update/proof_inputs.rs | 22 +++- sdk-libs/client/src/indexer/types/proof.rs | 42 +++++-- .../client/src/interface/initialize_config.rs | 12 +- sdk-libs/client/src/interface/instructions.rs | 4 +- .../client/src/interface/load_accounts.rs | 6 +- sdk-libs/client/src/interface/pack.rs | 7 +- sdk-libs/client/src/local_test_validator.rs | 37 +++--- sdk-libs/client/src/utils.rs | 27 +++-- .../program-test/src/indexer/test_indexer.rs | 32 +---- 16 files changed, 285 insertions(+), 154 deletions(-) diff --git a/forester/src/forester_status.rs b/forester/src/forester_status.rs index 80c4539075..038ac46ef4 100644 --- a/forester/src/forester_status.rs +++ b/forester/src/forester_status.rs @@ -671,19 +671,21 @@ fn parse_tree_status( let (queue_len, queue_cap) = queue_account .map(|acc| { - unsafe { parse_hash_set_from_bytes::(&acc.data) } - .ok() - .map(|hs| { + match unsafe { parse_hash_set_from_bytes::(&acc.data) } { + Ok(hs) => { let len = hs .iter() .filter(|(_, cell)| cell.sequence_number.is_none()) .count() as u64; let cap = hs.get_capacity() as u64; - (len, cap) - }) - .unwrap_or((0, 0)) + (Some(len), Some(cap)) + } + Err(error) => { + warn!(?error, "Failed to parse StateV1 queue hash set"); + (None, None) + } + } }) - .map(|(l, c)| (Some(l), Some(c))) .unwrap_or((None, None)); ( @@ -726,19 +728,21 @@ fn parse_tree_status( let (queue_len, queue_cap) = queue_account .map(|acc| { - unsafe { parse_hash_set_from_bytes::(&acc.data) } - .ok() - .map(|hs| { + match unsafe { parse_hash_set_from_bytes::(&acc.data) } { + Ok(hs) => { let len = hs .iter() .filter(|(_, cell)| cell.sequence_number.is_none()) .count() as u64; let cap = hs.get_capacity() as u64; - (len, cap) - }) - .unwrap_or((0, 0)) + (Some(len), Some(cap)) + } + Err(error) => { + warn!(?error, "Failed to parse AddressV1 queue hash set"); + (None, None) + } + } }) - .map(|(l, c)| (Some(l), Some(c))) .unwrap_or((None, None)); ( diff --git a/forester/src/processor/v2/helpers.rs b/forester/src/processor/v2/helpers.rs index 66b574dc4e..8f2fa209e3 100644 --- a/forester/src/processor/v2/helpers.rs +++ b/forester/src/processor/v2/helpers.rs @@ -496,7 +496,6 @@ impl StreamingAddressQueue { if available < end || start >= end { return Ok(None); } - let actual_end = end; let data = lock_recover(&self.data, "streaming_address_queue.data"); let min_len = [ @@ -519,8 +518,52 @@ impl StreamingAddressQueue { let addresses = data.addresses[start..actual_end].to_vec(); if addresses.is_empty() { - return Err(anyhow!("Empty batch at start={}", start)); + return Ok(None); } + let expected_len = addresses.len(); + let Some(low_element_values) = data + .low_element_values + .get(start..end) + .map(|slice| slice.to_vec()) + else { + return Ok(None); + }; + let Some(low_element_next_values) = data + .low_element_next_values + .get(start..end) + .map(|slice| slice.to_vec()) + else { + return Ok(None); + }; + let Some(low_element_indices) = data + .low_element_indices + .get(start..end) + .map(|slice| slice.to_vec()) + else { + return Ok(None); + }; + let Some(low_element_next_indices) = data + .low_element_next_indices + .get(start..end) + .map(|slice| slice.to_vec()) + else { + return Ok(None); + }; + if [ + low_element_values.len(), + low_element_next_values.len(), + low_element_indices.len(), + low_element_next_indices.len(), + ] + .iter() + .any(|&len| len != expected_len) + { + return Ok(None); + } + let low_element_proofs = match data.reconstruct_proofs::(start..end) { + Ok(proofs) if proofs.len() == expected_len => proofs, + Ok(_) | Err(_) => return Ok(None), + }; let leaves_hashchain = match data.leaves_hash_chains.get(hashchain_idx).copied() { Some(hashchain) => hashchain, diff --git a/program-tests/utils/src/actions/legacy/instructions/transfer2.rs b/program-tests/utils/src/actions/legacy/instructions/transfer2.rs index 1ff92eeda9..00a55f3ad8 100644 --- a/program-tests/utils/src/actions/legacy/instructions/transfer2.rs +++ b/program-tests/utils/src/actions/legacy/instructions/transfer2.rs @@ -211,7 +211,9 @@ pub async fn create_generic_transfer2_instruction( let mut packed_tree_accounts = PackedAccounts::default(); // tree infos must be packed before packing the token input accounts - let packed_tree_infos = rpc_proof_result.pack_tree_infos(&mut packed_tree_accounts); + let packed_tree_infos = rpc_proof_result + .pack_tree_infos(&mut packed_tree_accounts) + .unwrap(); // We use a single shared output queue for all compress/compress-and-close operations to avoid ordering failures. let shared_output_queue = if packed_tree_infos.address_trees.is_empty() { diff --git a/program-tests/utils/src/e2e_test_env.rs b/program-tests/utils/src/e2e_test_env.rs index edb94fdf48..c2c415ec9e 100644 --- a/program-tests/utils/src/e2e_test_env.rs +++ b/program-tests/utils/src/e2e_test_env.rs @@ -835,9 +835,9 @@ where .map_err(|error| RpcError::CustomError(error.to_string())) .unwrap(); let (proof_a, proof_b, proof_c) = - proof_from_json_struct(proof_json); + proof_from_json_struct(proof_json).unwrap(); let (proof_a, proof_b, proof_c) = - compress_proof(&proof_a, &proof_b, &proof_c); + compress_proof(&proof_a, &proof_b, &proof_c).unwrap(); let instruction_data = InstructionDataBatchNullifyInputs { new_root: circuit_inputs_new_root, compressed_proof: CompressedProof { diff --git a/prover/client/src/proof.rs b/prover/client/src/proof.rs index cc66f3aed6..e054f20855 100644 --- a/prover/client/src/proof.rs +++ b/prover/client/src/proof.rs @@ -66,16 +66,28 @@ pub fn deserialize_gnark_proof_json(json_data: &str) -> serde_json::Result [u8; 32] { - let trimmed_str = hex_str.trim_start_matches("0x"); - let big_int = num_bigint::BigInt::from_str_radix(trimmed_str, 16).unwrap(); - let big_int_bytes = big_int.to_bytes_be().1; - if big_int_bytes.len() < 32 { +pub fn deserialize_hex_string_to_be_bytes(hex_str: &str) -> Result<[u8; 32], ProverClientError> { + let trimmed_str = hex_str + .strip_prefix("0x") + .or_else(|| hex_str.strip_prefix("0X")) + .unwrap_or(hex_str); + let big_uint = num_bigint::BigUint::from_str_radix(trimmed_str, 16).map_err(|error| { + ProverClientError::InvalidHexString(format!("{hex_str}: {error}")) + })?; + let big_uint_bytes = big_uint.to_bytes_be(); + if big_uint_bytes.len() > 32 { + return Err(ProverClientError::InvalidHexString(format!( + "{hex_str}: exceeds 32 bytes" + ))); + } + if big_uint_bytes.len() < 32 { let mut result = [0u8; 32]; - result[32 - big_int_bytes.len()..].copy_from_slice(&big_int_bytes); - result + result[32 - big_uint_bytes.len()..].copy_from_slice(&big_uint_bytes); + Ok(result) } else { - big_int_bytes.try_into().unwrap() + big_uint_bytes.try_into().map_err(|_| { + ProverClientError::InvalidHexString(format!("{hex_str}: invalid 32-byte encoding")) + }) } } @@ -90,40 +102,85 @@ pub fn compress_proof( (proof_a, proof_b, proof_c) } -pub fn proof_from_json_struct(json: GnarkProofJson) -> ([u8; 64], [u8; 128], [u8; 64]) { - let proof_a_x = deserialize_hex_string_to_be_bytes(&json.ar[0]); - let proof_a_y = deserialize_hex_string_to_be_bytes(&json.ar[1]); - let proof_a: [u8; 64] = [proof_a_x, proof_a_y].concat().try_into().unwrap(); - let proof_a = negate_g1(&proof_a); - let proof_b_x_0 = deserialize_hex_string_to_be_bytes(&json.bs[0][0]); - let proof_b_x_1 = deserialize_hex_string_to_be_bytes(&json.bs[0][1]); - let proof_b_y_0 = deserialize_hex_string_to_be_bytes(&json.bs[1][0]); - let proof_b_y_1 = deserialize_hex_string_to_be_bytes(&json.bs[1][1]); +pub fn proof_from_json_struct( + json: GnarkProofJson, +) -> Result<([u8; 64], [u8; 128], [u8; 64]), ProverClientError> { + let proof_a_x = deserialize_hex_string_to_be_bytes(json.ar.first().ok_or_else(|| { + ProverClientError::InvalidProofData("missing proof A x coordinate".to_string()) + })?)?; + let proof_a_y = deserialize_hex_string_to_be_bytes(json.ar.get(1).ok_or_else(|| { + ProverClientError::InvalidProofData("missing proof A y coordinate".to_string()) + })?)?; + let proof_a: [u8; 64] = [proof_a_x, proof_a_y] + .concat() + .try_into() + .map_err(|_| ProverClientError::InvalidProofData("invalid proof A length".to_string()))?; + let proof_a = negate_g1(&proof_a)?; + let proof_b_x_0 = deserialize_hex_string_to_be_bytes( + json.bs + .first() + .and_then(|row| row.first()) + .ok_or_else(|| { + ProverClientError::InvalidProofData("missing proof B x0 coordinate".to_string()) + })?, + )?; + let proof_b_x_1 = deserialize_hex_string_to_be_bytes( + json.bs + .first() + .and_then(|row| row.get(1)) + .ok_or_else(|| { + ProverClientError::InvalidProofData("missing proof B x1 coordinate".to_string()) + })?, + )?; + let proof_b_y_0 = deserialize_hex_string_to_be_bytes( + json.bs + .get(1) + .and_then(|row| row.first()) + .ok_or_else(|| { + ProverClientError::InvalidProofData("missing proof B y0 coordinate".to_string()) + })?, + )?; + let proof_b_y_1 = deserialize_hex_string_to_be_bytes( + json.bs + .get(1) + .and_then(|row| row.get(1)) + .ok_or_else(|| { + ProverClientError::InvalidProofData("missing proof B y1 coordinate".to_string()) + })?, + )?; let proof_b: [u8; 128] = [proof_b_x_0, proof_b_x_1, proof_b_y_0, proof_b_y_1] .concat() .try_into() - .unwrap(); + .map_err(|_| ProverClientError::InvalidProofData("invalid proof B length".to_string()))?; - let proof_c_x = deserialize_hex_string_to_be_bytes(&json.krs[0]); - let proof_c_y = deserialize_hex_string_to_be_bytes(&json.krs[1]); - let proof_c: [u8; 64] = [proof_c_x, proof_c_y].concat().try_into().unwrap(); - (proof_a, proof_b, proof_c) + let proof_c_x = deserialize_hex_string_to_be_bytes(json.krs.first().ok_or_else(|| { + ProverClientError::InvalidProofData("missing proof C x coordinate".to_string()) + })?)?; + let proof_c_y = deserialize_hex_string_to_be_bytes(json.krs.get(1).ok_or_else(|| { + ProverClientError::InvalidProofData("missing proof C y coordinate".to_string()) + })?)?; + let proof_c: [u8; 64] = [proof_c_x, proof_c_y] + .concat() + .try_into() + .map_err(|_| ProverClientError::InvalidProofData("invalid proof C length".to_string()))?; + Ok((proof_a, proof_b, proof_c)) } -pub fn negate_g1(g1_be: &[u8; 64]) -> [u8; 64] { +pub fn negate_g1(g1_be: &[u8; 64]) -> Result<[u8; 64], ProverClientError> { let g1_le = convert_endianness::<32, 64>(g1_be); - let g1: G1 = G1::deserialize_with_mode(g1_le.as_slice(), Compress::No, Validate::No).unwrap(); + let g1: G1 = G1::deserialize_with_mode(g1_le.as_slice(), Compress::No, Validate::Yes) + .map_err(|error| ProverClientError::InvalidProofData(error.to_string()))?; let g1_neg = g1.neg(); let mut g1_neg_be = [0u8; 64]; g1_neg .x .serialize_with_mode(&mut g1_neg_be[..32], Compress::No) - .unwrap(); + .map_err(|error| ProverClientError::InvalidProofData(error.to_string()))?; g1_neg .y .serialize_with_mode(&mut g1_neg_be[32..], Compress::No) - .unwrap(); + .map_err(|error| ProverClientError::InvalidProofData(error.to_string()))?; let g1_neg_be: [u8; 64] = convert_endianness::<32, 64>(&g1_neg_be); - g1_neg_be + Ok(g1_neg_be) } diff --git a/prover/client/src/proof_client.rs b/prover/client/src/proof_client.rs index 9642cf1264..c2dcbcdd2f 100644 --- a/prover/client/src/proof_client.rs +++ b/prover/client/src/proof_client.rs @@ -654,8 +654,8 @@ impl ProofClient { ProverClientError::ProverServerError(format!("Failed to deserialize proof JSON: {}", e)) })?; - let (proof_a, proof_b, proof_c) = proof_from_json_struct(proof_json); - let (proof_a, proof_b, proof_c) = compress_proof(&proof_a, &proof_b, &proof_c); + let (proof_a, proof_b, proof_c) = proof_from_json_struct(proof_json)?; + let (proof_a, proof_b, proof_c) = compress_proof(&proof_a, &proof_b, &proof_c)?; Ok(ProofResult { proof: ProofCompressed { diff --git a/prover/client/src/proof_types/batch_address_append/proof_inputs.rs b/prover/client/src/proof_types/batch_address_append/proof_inputs.rs index fdc50621cc..96b8caa4a0 100644 --- a/prover/client/src/proof_types/batch_address_append/proof_inputs.rs +++ b/prover/client/src/proof_types/batch_address_append/proof_inputs.rs @@ -256,9 +256,9 @@ pub fn get_batch_address_append_circuit_inputs( next_index ); - let mut patcher = ChangelogProofPatcher::new::(changelog); + let mut patcher = ChangelogProofPatcher::new::(&staged_changelog); - let is_first_batch = indexed_changelog.is_empty(); + let is_first_batch = staged_indexed_changelog.is_empty(); let mut expected_root_for_low = current_root; for i in 0..zkp_batch_size { @@ -294,7 +294,7 @@ pub fn get_batch_address_append_circuit_inputs( patch_indexed_changelogs( 0, &mut changelog_index, - indexed_changelog, + &mut staged_indexed_changelog, &mut low_element, &mut new_element, &mut low_element_next_value, @@ -386,7 +386,7 @@ pub fn get_batch_address_append_circuit_inputs( new_low_element.index, )?; - patcher.push_changelog_entry::(changelog, changelog_entry); + patcher.push_changelog_entry::(&mut staged_changelog, changelog_entry); low_element_circuit_merkle_proofs.push( merkle_proof .iter() @@ -399,10 +399,10 @@ pub fn get_batch_address_append_circuit_inputs( let low_element_changelog_entry = IndexedChangelogEntry { element: new_low_element_raw, proof: low_element_changelog_proof, - changelog_index: indexed_changelog.len(), //change_log_index, + changelog_index: staged_indexed_changelog.len(), //change_log_index, }; - indexed_changelog.push(low_element_changelog_entry); + staged_indexed_changelog.push(low_element_changelog_entry); { let new_element_next_value = low_element_next_value; @@ -412,10 +412,10 @@ pub fn get_batch_address_append_circuit_inputs( ProverClientError::GenericError(format!("Failed to hash new element: {}", e)) })?; - let sparse_root_before = sparse_merkle_tree.root(); - let sparse_next_idx_before = sparse_merkle_tree.get_next_index(); + let sparse_root_before = staged_sparse_merkle_tree.root(); + let sparse_next_idx_before = staged_sparse_merkle_tree.get_next_index(); - let mut merkle_proof_array = sparse_merkle_tree.append(new_element_leaf_hash); + let mut merkle_proof_array = staged_sparse_merkle_tree.append(new_element_leaf_hash); let current_index = next_index + i; @@ -427,7 +427,7 @@ pub fn get_batch_address_append_circuit_inputs( current_index, )?; - if i == 0 && changelog.len() == 1 { + if i == 0 && staged_changelog.len() == initial_changelog_len + 1 { if sparse_next_idx_before != current_index { return Err(ProverClientError::GenericError(format!( "sparse index mismatch: sparse tree next_index={} but expected current_index={}", @@ -486,7 +486,7 @@ pub fn get_batch_address_append_circuit_inputs( new_root = updated_root; - patcher.push_changelog_entry::(changelog, changelog_entry); + patcher.push_changelog_entry::(&mut staged_changelog, changelog_entry); new_element_circuit_merkle_proofs.push( merkle_proof_array .iter() @@ -504,9 +504,9 @@ pub fn get_batch_address_append_circuit_inputs( let new_element_changelog_entry = IndexedChangelogEntry { element: new_element_raw, proof: merkle_proof_array, - changelog_index: indexed_changelog.len(), + changelog_index: staged_indexed_changelog.len(), }; - indexed_changelog.push(new_element_changelog_entry); + staged_indexed_changelog.push(new_element_changelog_entry); } } @@ -542,18 +542,18 @@ pub fn get_batch_address_append_circuit_inputs( patcher.hits, patcher.misses, patcher.overwrites, - changelog.len(), - indexed_changelog.len() + staged_changelog.len(), + staged_indexed_changelog.len() ); - if patcher.hits == 0 && !changelog.is_empty() { + if patcher.hits == 0 && !staged_changelog.is_empty() { tracing::warn!( "Address proof patcher had 0 cache hits despite non-empty changelog (changelog_len={}, indexed_changelog_len={})", - changelog.len(), - indexed_changelog.len() + staged_changelog.len(), + staged_indexed_changelog.len() ); } - Ok(BatchAddressAppendInputs { + let inputs = BatchAddressAppendInputs { batch_size: patched_low_element_values.len(), hashchain_hash: BigUint::from_bytes_be(&leaves_hashchain), low_element_values: patched_low_element_values @@ -573,7 +573,7 @@ pub fn get_batch_address_append_circuit_inputs( .map(|v| BigUint::from_bytes_be(v)) .collect(), low_element_proofs: low_element_circuit_merkle_proofs, - new_element_values: new_element_values[0..] + new_element_values: new_element_values .iter() .map(|v| BigUint::from_bytes_be(v)) .collect(), @@ -583,5 +583,11 @@ pub fn get_batch_address_append_circuit_inputs( public_input_hash: BigUint::from_bytes_be(&public_input_hash), start_index: next_index, tree_height: HEIGHT, - }) + }; + + *changelog = staged_changelog; + *indexed_changelog = staged_indexed_changelog; + *sparse_merkle_tree = staged_sparse_merkle_tree; + + Ok(inputs) } diff --git a/prover/client/src/proof_types/batch_update/proof_inputs.rs b/prover/client/src/proof_types/batch_update/proof_inputs.rs index 2ada02b92b..f5467184aa 100644 --- a/prover/client/src/proof_types/batch_update/proof_inputs.rs +++ b/prover/client/src/proof_types/batch_update/proof_inputs.rs @@ -31,8 +31,12 @@ pub struct BatchUpdateCircuitInputs { } impl BatchUpdateCircuitInputs { - pub fn public_inputs_arr(&self) -> [u8; 32] { - bigint_to_u8_32(&self.public_input_hash).unwrap() + pub fn public_inputs_arr(&self) -> Result<[u8; 32], ProverClientError> { + bigint_to_u8_32(&self.public_input_hash).map_err(|error| { + ProverClientError::GenericError(format!( + "failed to serialize batch update public input: {error}" + )) + }) } pub fn new( @@ -112,9 +116,17 @@ impl BatchUpdateCircuitInputs { pub struct BatchUpdateInputs<'a>(pub &'a [BatchUpdateCircuitInputs]); impl BatchUpdateInputs<'_> { - pub fn public_inputs(&self) -> Vec<[u8; 32]> { - // Concatenate all public inputs into a single flat vector - vec![self.0[0].public_inputs_arr()] + pub fn public_inputs(&self) -> Result, ProverClientError> { + if self.0.is_empty() { + return Err(ProverClientError::GenericError( + "batch update inputs cannot be empty".to_string(), + )); + } + + self.0 + .iter() + .map(BatchUpdateCircuitInputs::public_inputs_arr) + .collect() } } diff --git a/sdk-libs/client/src/indexer/types/proof.rs b/sdk-libs/client/src/indexer/types/proof.rs index 0b45e00986..1c858fd74d 100644 --- a/sdk-libs/client/src/indexer/types/proof.rs +++ b/sdk-libs/client/src/indexer/types/proof.rs @@ -189,7 +189,10 @@ pub struct PackedTreeInfos { } impl ValidityProofWithContext { - pub fn pack_tree_infos(&self, packed_accounts: &mut PackedAccounts) -> PackedTreeInfos { + pub fn pack_tree_infos( + &self, + packed_accounts: &mut PackedAccounts, + ) -> Result { let mut packed_tree_infos = Vec::new(); let mut address_trees = Vec::new(); let mut output_tree_index = None; @@ -211,19 +214,28 @@ impl ValidityProofWithContext { if let Some(next) = account.tree_info.next_tree_info { // SAFETY: account will always have a state Merkle tree context. // pack_output_tree_index only panics on an address Merkle tree context. - let index = next.pack_output_tree_index(packed_accounts).unwrap(); - if output_tree_index.is_none() { - output_tree_index = Some(index); + let index = next.pack_output_tree_index(packed_accounts)?; + match output_tree_index { + Some(existing) if existing != index => { + return Err(IndexerError::InvalidParameters(format!( + "mixed output tree indices in state proof: {existing} != {index}" + ))); + } + Some(_) => {} + None => output_tree_index = Some(index), } } else { // SAFETY: account will always have a state Merkle tree context. // pack_output_tree_index only panics on an address Merkle tree context. - let index = account - .tree_info - .pack_output_tree_index(packed_accounts) - .unwrap(); - if output_tree_index.is_none() { - output_tree_index = Some(index); + let index = account.tree_info.pack_output_tree_index(packed_accounts)?; + match output_tree_index { + Some(existing) if existing != index => { + return Err(IndexerError::InvalidParameters(format!( + "mixed output tree indices in state proof: {existing} != {index}" + ))); + } + Some(_) => {} + None => output_tree_index = Some(index), } } } @@ -244,13 +256,17 @@ impl ValidityProofWithContext { } else { Some(PackedStateTreeInfos { packed_tree_infos, - output_tree_index: output_tree_index.unwrap(), + output_tree_index: output_tree_index.ok_or_else(|| { + IndexerError::InvalidParameters( + "missing output tree index for non-empty state proof".to_string(), + ) + })?, }) }; - PackedTreeInfos { + Ok(PackedTreeInfos { state_trees: packed_tree_infos, address_trees, - } + }) } pub fn from_api_model( diff --git a/sdk-libs/client/src/interface/initialize_config.rs b/sdk-libs/client/src/interface/initialize_config.rs index 7b5919cdb1..9fbeacfe89 100644 --- a/sdk-libs/client/src/interface/initialize_config.rs +++ b/sdk-libs/client/src/interface/initialize_config.rs @@ -7,6 +7,8 @@ use borsh::{BorshDeserialize as AnchorDeserialize, BorshSerialize as AnchorSeria use solana_instruction::{AccountMeta, Instruction}; use solana_pubkey::Pubkey; +use crate::interface::instructions::INITIALIZE_COMPRESSION_CONFIG_DISCRIMINATOR; + /// Default address tree v2 pubkey. pub const ADDRESS_TREE_V2: Pubkey = solana_pubkey::pubkey!("amt2kaJA14v3urZbZvnc5v2np8jqvc4Z8zDep5wbtzx"); @@ -115,16 +117,14 @@ impl InitializeRentFreeConfig { address_space: self.address_space, }; - // Anchor discriminator for "initialize_compression_config" - // SHA256("global:initialize_compression_config")[..8] - const DISCRIMINATOR: [u8; 8] = [133, 228, 12, 169, 56, 76, 222, 61]; - let serialized_data = instruction_data .try_to_vec() .expect("Failed to serialize instruction data"); - let mut data = Vec::with_capacity(DISCRIMINATOR.len() + serialized_data.len()); - data.extend_from_slice(&DISCRIMINATOR); + let mut data = Vec::with_capacity( + INITIALIZE_COMPRESSION_CONFIG_DISCRIMINATOR.len() + serialized_data.len(), + ); + data.extend_from_slice(&INITIALIZE_COMPRESSION_CONFIG_DISCRIMINATOR); data.extend_from_slice(&serialized_data); let instruction = Instruction { diff --git a/sdk-libs/client/src/interface/instructions.rs b/sdk-libs/client/src/interface/instructions.rs index e80e7b72c1..41c06e637f 100644 --- a/sdk-libs/client/src/interface/instructions.rs +++ b/sdk-libs/client/src/interface/instructions.rs @@ -234,7 +234,7 @@ where let output_queue = get_output_queue(&cold_accounts[0].0.tree_info); let output_state_tree_index = remaining_accounts.insert_or_get(output_queue); - let packed_tree_infos = proof.pack_tree_infos(&mut remaining_accounts); + let packed_tree_infos = proof.pack_tree_infos(&mut remaining_accounts)?; let tree_infos = &packed_tree_infos .state_trees .as_ref() @@ -313,7 +313,7 @@ pub fn build_compress_accounts_idempotent( let output_queue = get_output_queue(&proof.accounts[0].tree_info); let output_state_tree_index = remaining_accounts.insert_or_get(output_queue); - let packed_tree_infos = proof.pack_tree_infos(&mut remaining_accounts); + let packed_tree_infos = proof.pack_tree_infos(&mut remaining_accounts)?; let tree_infos = packed_tree_infos .state_trees .as_ref() diff --git a/sdk-libs/client/src/interface/load_accounts.rs b/sdk-libs/client/src/interface/load_accounts.rs index 0d564734a2..4fccd73810 100644 --- a/sdk-libs/client/src/interface/load_accounts.rs +++ b/sdk-libs/client/src/interface/load_accounts.rs @@ -220,7 +220,7 @@ fn group_pda_specs<'a, V>( specs: &[&'a PdaSpec], max_per_group: usize, ) -> Vec>> { - assert!(max_per_group > 0, "max_per_group must be non-zero"); + debug_assert!(max_per_group > 0, "max_per_group must be non-zero"); if specs.is_empty() { return Vec::new(); } @@ -424,7 +424,9 @@ fn build_transfer2( fee_payer: Pubkey, ) -> Result { let mut packed = PackedAccounts::default(); - let packed_trees = proof.pack_tree_infos(&mut packed); + let packed_trees = proof + .pack_tree_infos(&mut packed) + .map_err(|error| LoadAccountsError::BuildInstruction(error.to_string()))?; let tree_infos = packed_trees .state_trees .as_ref() diff --git a/sdk-libs/client/src/interface/pack.rs b/sdk-libs/client/src/interface/pack.rs index 804a48751d..97505adabe 100644 --- a/sdk-libs/client/src/interface/pack.rs +++ b/sdk-libs/client/src/interface/pack.rs @@ -12,6 +12,9 @@ use crate::indexer::{TreeInfo, ValidityProofWithContext}; pub enum PackError { #[error("Failed to add system accounts: {0}")] SystemAccounts(#[from] light_sdk::error::LightSdkError), + + #[error("Failed to pack tree infos: {0}")] + Indexer(#[from] crate::indexer::IndexerError), } /// Packed state tree infos from validity proof. @@ -87,7 +90,7 @@ fn pack_proof_internal( // For mint creation: pack address tree first (index 1), then state tree. let (client_packed_tree_infos, state_tree_index) = if include_state_tree { // Pack tree infos first to ensure address tree is at index 1 - let tree_infos = proof.pack_tree_infos(&mut packed); + let tree_infos = proof.pack_tree_infos(&mut packed)?; // Then add state tree (will be after address tree) let state_tree = output_tree @@ -99,7 +102,7 @@ fn pack_proof_internal( (tree_infos, Some(state_idx)) } else { - let tree_infos = proof.pack_tree_infos(&mut packed); + let tree_infos = proof.pack_tree_infos(&mut packed)?; (tree_infos, None) }; let (remaining_accounts, system_offset, _) = packed.to_account_metas(); diff --git a/sdk-libs/client/src/local_test_validator.rs b/sdk-libs/client/src/local_test_validator.rs index 36ed7c04b3..4370f4911a 100644 --- a/sdk-libs/client/src/local_test_validator.rs +++ b/sdk-libs/client/src/local_test_validator.rs @@ -1,6 +1,7 @@ -use std::process::{Command, Stdio}; +use std::process::Stdio; use light_prover_client::helpers::get_project_root; +use tokio::process::Command; /// Configuration for an upgradeable program to deploy to the validator. #[derive(Debug, Clone)] @@ -57,25 +58,25 @@ impl Default for LightValidatorConfig { pub async fn spawn_validator(config: LightValidatorConfig) { if let Some(project_root) = get_project_root() { - let path = "cli/test_bin/run test-validator"; - let mut path = format!("{}/{}", project_root.trim(), path); + let command = "cli/test_bin/run test-validator"; + let mut command = format!("{}/{}", project_root.trim(), command); if !config.enable_indexer { - path.push_str(" --skip-indexer"); + command.push_str(" --skip-indexer"); } if let Some(limit_ledger_size) = config.limit_ledger_size { - path.push_str(&format!(" --limit-ledger-size {}", limit_ledger_size)); + command.push_str(&format!(" --limit-ledger-size {}", limit_ledger_size)); } for sbf_program in config.sbf_programs.iter() { - path.push_str(&format!( + command.push_str(&format!( " --sbf-program {} {}", sbf_program.0, sbf_program.1 )); } for upgradeable_program in config.upgradeable_programs.iter() { - path.push_str(&format!( + command.push_str(&format!( " --upgradeable-program {} {} {}", upgradeable_program.program_id, upgradeable_program.program_path, @@ -84,18 +85,18 @@ pub async fn spawn_validator(config: LightValidatorConfig) { } if !config.enable_prover { - path.push_str(" --skip-prover"); + command.push_str(" --skip-prover"); } if config.use_surfpool { - path.push_str(" --use-surfpool"); + command.push_str(" --use-surfpool"); } for arg in config.validator_args.iter() { - path.push_str(&format!(" {}", arg)); + command.push_str(&format!(" {}", arg)); } - println!("Starting validator with command: {}", path); + println!("Starting validator with command: {}", command); if config.use_surfpool { // The CLI starts surfpool, prover, and photon, then exits once all @@ -103,24 +104,28 @@ pub async fn spawn_validator(config: LightValidatorConfig) { // is up before the test proceeds. let mut child = Command::new("sh") .arg("-c") - .arg(path) + .arg(command) .stdin(Stdio::null()) .stdout(Stdio::inherit()) .stderr(Stdio::inherit()) .spawn() .expect("Failed to start server process"); - let status = child.wait().expect("Failed to wait for CLI process"); + let status = child + .wait() + .await + .expect("Failed to wait for CLI process"); assert!(status.success(), "CLI exited with error: {}", status); } else { - let child = Command::new("sh") + let _child = Command::new("sh") .arg("-c") - .arg(path) + .arg(command) .stdin(Stdio::null()) .stdout(Stdio::null()) .stderr(Stdio::null()) .spawn() .expect("Failed to start server process"); - std::mem::drop(child); + // Intentionally detaching the spawned child; the caller only waits + // for the validator services to become available. tokio::time::sleep(tokio::time::Duration::from_secs(config.wait_time)).await; } } diff --git a/sdk-libs/client/src/utils.rs b/sdk-libs/client/src/utils.rs index b8f2e05ecb..0055f8dbea 100644 --- a/sdk-libs/client/src/utils.rs +++ b/sdk-libs/client/src/utils.rs @@ -15,8 +15,11 @@ pub fn find_light_bin() -> Option { if !output.status.success() { return None; } - // Convert the output into a string (removing any trailing newline) - let light_path = String::from_utf8_lossy(&output.stdout).trim().to_string(); + let light_path = std::str::from_utf8(&output.stdout) + .ok()? + .trim_end_matches("\r\n") + .trim_end_matches('\n') + .to_string(); // Get the parent directory of the 'light' binary let mut light_bin_path = PathBuf::from(light_path); light_bin_path.pop(); // Remove the 'light' binary itself @@ -30,16 +33,16 @@ pub fn find_light_bin() -> Option { #[cfg(feature = "devenv")] { println!("Use only in light protocol monorepo. Using 'git rev-parse --show-toplevel' to find the location of 'light' binary"); - let light_protocol_toplevel = String::from_utf8_lossy( - &std::process::Command::new("git") - .arg("rev-parse") - .arg("--show-toplevel") - .output() - .expect("Failed to get top-level directory") - .stdout, - ) - .trim() - .to_string(); + let output = std::process::Command::new("git") + .arg("rev-parse") + .arg("--show-toplevel") + .output() + .expect("Failed to get top-level directory"); + let light_protocol_toplevel = std::str::from_utf8(&output.stdout) + .ok()? + .trim_end_matches("\r\n") + .trim_end_matches('\n') + .to_string(); let light_path = PathBuf::from(format!("{}/target/deploy/", light_protocol_toplevel)); Some(light_path) } diff --git a/sdk-libs/program-test/src/indexer/test_indexer.rs b/sdk-libs/program-test/src/indexer/test_indexer.rs index f6507bbef6..7618e045f3 100644 --- a/sdk-libs/program-test/src/indexer/test_indexer.rs +++ b/sdk-libs/program-test/src/indexer/test_indexer.rs @@ -1,10 +1,4 @@ -use std::{ - any::Any, - collections::HashMap, - fmt::Debug, - panic::{catch_unwind, AssertUnwindSafe}, - time::Duration, -}; +use std::{collections::HashMap, fmt::Debug, time::Duration}; #[cfg(feature = "devenv")] use account_compression::{ @@ -101,29 +95,13 @@ use crate::accounts::{ }; use crate::indexer::TestIndexerExtensions; -fn panic_payload_message(payload: &(dyn Any + Send)) -> String { - if let Some(message) = payload.downcast_ref::() { - message.clone() - } else if let Some(message) = payload.downcast_ref::<&str>() { - (*message).to_string() - } else { - "non-string panic payload".to_string() - } -} - fn build_compressed_proof(body: &str) -> Result { let proof_json = deserialize_gnark_proof_json(body) .map_err(|error| IndexerError::CustomError(error.to_string()))?; - let (proof_a, proof_b, proof_c) = catch_unwind(AssertUnwindSafe(|| { - let (proof_a, proof_b, proof_c) = proof_from_json_struct(proof_json); - compress_proof(&proof_a, &proof_b, &proof_c) - })) - .map_err(|payload| { - IndexerError::CustomError(format!( - "failed to parse prover proof payload: {}", - panic_payload_message(payload.as_ref()) - )) - })?; + let (proof_a, proof_b, proof_c) = proof_from_json_struct(proof_json) + .map_err(|error| IndexerError::CustomError(error.to_string()))?; + let (proof_a, proof_b, proof_c) = compress_proof(&proof_a, &proof_b, &proof_c) + .map_err(|error| IndexerError::CustomError(error.to_string()))?; Ok(CompressedProof { a: proof_a, From 338b4ac4566fa689a84bd3b13ce8ae4c08c3e523 Mon Sep 17 00:00:00 2001 From: Sergey Timoshin Date: Tue, 17 Mar 2026 08:34:12 +0000 Subject: [PATCH 20/23] fix: harden runtime safety fallout --- forester/src/forester_status.rs | 16 +-- forester/src/processor/v2/proof_worker.rs | 4 +- prover/client/src/proof.rs | 49 ++++----- sdk-libs/client/src/indexer/types/proof.rs | 30 +++--- sdk-libs/client/src/interface/instructions.rs | 19 +--- .../client/src/interface/load_accounts.rs | 18 +--- sdk-libs/client/src/local_test_validator.rs | 5 +- .../sdk-anchor-test/tests/read_only.rs | 12 ++- .../programs/sdk-anchor-test/tests/test.rs | 8 +- sdk-tests/sdk-native-test/tests/test.rs | 6 +- sdk-tests/sdk-pinocchio-v1-test/tests/test.rs | 6 +- sdk-tests/sdk-token-test/tests/ctoken_pda.rs | 4 +- .../tests/decompress_full_cpi.rs | 37 ++++--- sdk-tests/sdk-token-test/tests/pda_ctoken.rs | 4 +- sdk-tests/sdk-token-test/tests/test.rs | 8 +- .../tests/test_4_invocations.rs | 64 ++++++----- .../sdk-token-test/tests/test_4_transfer2.rs | 62 ++++++----- .../sdk-token-test/tests/test_deposit.rs | 101 ++++++++++++------ sdk-tests/sdk-v1-native-test/tests/test.rs | 5 +- 19 files changed, 261 insertions(+), 197 deletions(-) diff --git a/forester/src/forester_status.rs b/forester/src/forester_status.rs index 038ac46ef4..d8f958134d 100644 --- a/forester/src/forester_status.rs +++ b/forester/src/forester_status.rs @@ -670,8 +670,8 @@ fn parse_tree_status( let fullness = next_index as f64 / capacity as f64 * 100.0; let (queue_len, queue_cap) = queue_account - .map(|acc| { - match unsafe { parse_hash_set_from_bytes::(&acc.data) } { + .map( + |acc| match unsafe { parse_hash_set_from_bytes::(&acc.data) } { Ok(hs) => { let len = hs .iter() @@ -684,8 +684,8 @@ fn parse_tree_status( warn!(?error, "Failed to parse StateV1 queue hash set"); (None, None) } - } - }) + }, + ) .unwrap_or((None, None)); ( @@ -727,8 +727,8 @@ fn parse_tree_status( let fullness = next_index as f64 / capacity as f64 * 100.0; let (queue_len, queue_cap) = queue_account - .map(|acc| { - match unsafe { parse_hash_set_from_bytes::(&acc.data) } { + .map( + |acc| match unsafe { parse_hash_set_from_bytes::(&acc.data) } { Ok(hs) => { let len = hs .iter() @@ -741,8 +741,8 @@ fn parse_tree_status( warn!(?error, "Failed to parse AddressV1 queue hash set"); (None, None) } - } - }) + }, + ) .unwrap_or((None, None)); ( diff --git a/forester/src/processor/v2/proof_worker.rs b/forester/src/processor/v2/proof_worker.rs index ded9fcedc8..603fa3f19b 100644 --- a/forester/src/processor/v2/proof_worker.rs +++ b/forester/src/processor/v2/proof_worker.rs @@ -164,7 +164,9 @@ impl ProofClients { } } -pub fn spawn_proof_workers(config: &ProverConfig) -> crate::Result> { +pub fn spawn_proof_workers( + config: &ProverConfig, +) -> crate::Result> { let (job_tx, job_rx) = async_channel::bounded::(256); let clients = Arc::new(ProofClients::new(config)?); tokio::spawn(async move { run_proof_pipeline(job_rx, clients).await }); diff --git a/prover/client/src/proof.rs b/prover/client/src/proof.rs index e054f20855..da9b913830 100644 --- a/prover/client/src/proof.rs +++ b/prover/client/src/proof.rs @@ -12,6 +12,9 @@ use solana_bn254::compression::prelude::{ alt_bn128_g2_decompress_be, convert_endianness, }; +pub type CompressedProofBytes = ([u8; 32], [u8; 64], [u8; 32]); +pub type UncompressedProofBytes = ([u8; 64], [u8; 128], [u8; 64]); + #[derive(Debug, Clone, Copy)] pub struct ProofCompressed { pub a: [u8; 32], @@ -71,9 +74,8 @@ pub fn deserialize_hex_string_to_be_bytes(hex_str: &str) -> Result<[u8; 32], Pro .strip_prefix("0x") .or_else(|| hex_str.strip_prefix("0X")) .unwrap_or(hex_str); - let big_uint = num_bigint::BigUint::from_str_radix(trimmed_str, 16).map_err(|error| { - ProverClientError::InvalidHexString(format!("{hex_str}: {error}")) - })?; + let big_uint = num_bigint::BigUint::from_str_radix(trimmed_str, 16) + .map_err(|error| ProverClientError::InvalidHexString(format!("{hex_str}: {error}")))?; let big_uint_bytes = big_uint.to_bytes_be(); if big_uint_bytes.len() > 32 { return Err(ProverClientError::InvalidHexString(format!( @@ -104,7 +106,7 @@ pub fn compress_proof( pub fn proof_from_json_struct( json: GnarkProofJson, -) -> Result<([u8; 64], [u8; 128], [u8; 64]), ProverClientError> { +) -> Result { let proof_a_x = deserialize_hex_string_to_be_bytes(json.ar.first().ok_or_else(|| { ProverClientError::InvalidProofData("missing proof A x coordinate".to_string()) })?)?; @@ -117,37 +119,24 @@ pub fn proof_from_json_struct( .map_err(|_| ProverClientError::InvalidProofData("invalid proof A length".to_string()))?; let proof_a = negate_g1(&proof_a)?; let proof_b_x_0 = deserialize_hex_string_to_be_bytes( - json.bs - .first() - .and_then(|row| row.first()) - .ok_or_else(|| { - ProverClientError::InvalidProofData("missing proof B x0 coordinate".to_string()) - })?, + json.bs.first().and_then(|row| row.first()).ok_or_else(|| { + ProverClientError::InvalidProofData("missing proof B x0 coordinate".to_string()) + })?, )?; let proof_b_x_1 = deserialize_hex_string_to_be_bytes( - json.bs - .first() - .and_then(|row| row.get(1)) - .ok_or_else(|| { - ProverClientError::InvalidProofData("missing proof B x1 coordinate".to_string()) - })?, + json.bs.first().and_then(|row| row.get(1)).ok_or_else(|| { + ProverClientError::InvalidProofData("missing proof B x1 coordinate".to_string()) + })?, )?; let proof_b_y_0 = deserialize_hex_string_to_be_bytes( - json.bs - .get(1) - .and_then(|row| row.first()) - .ok_or_else(|| { - ProverClientError::InvalidProofData("missing proof B y0 coordinate".to_string()) - })?, - )?; - let proof_b_y_1 = deserialize_hex_string_to_be_bytes( - json.bs - .get(1) - .and_then(|row| row.get(1)) - .ok_or_else(|| { - ProverClientError::InvalidProofData("missing proof B y1 coordinate".to_string()) - })?, + json.bs.get(1).and_then(|row| row.first()).ok_or_else(|| { + ProverClientError::InvalidProofData("missing proof B y0 coordinate".to_string()) + })?, )?; + let proof_b_y_1 = + deserialize_hex_string_to_be_bytes(json.bs.get(1).and_then(|row| row.get(1)).ok_or_else( + || ProverClientError::InvalidProofData("missing proof B y1 coordinate".to_string()), + )?)?; let proof_b: [u8; 128] = [proof_b_x_0, proof_b_x_1, proof_b_y_0, proof_b_y_1] .concat() .try_into() diff --git a/sdk-libs/client/src/indexer/types/proof.rs b/sdk-libs/client/src/indexer/types/proof.rs index 1c858fd74d..4a9f396732 100644 --- a/sdk-libs/client/src/indexer/types/proof.rs +++ b/sdk-libs/client/src/indexer/types/proof.rs @@ -189,26 +189,30 @@ pub struct PackedTreeInfos { } impl ValidityProofWithContext { + pub fn pack_state_tree_infos( + &self, + packed_accounts: &mut PackedAccounts, + ) -> Vec { + self.accounts + .iter() + .map(|account| PackedStateTreeInfo { + root_index: account.root_index.root_index().unwrap_or_default(), + merkle_tree_pubkey_index: packed_accounts.insert_or_get(account.tree_info.tree), + queue_pubkey_index: packed_accounts.insert_or_get(account.tree_info.queue), + leaf_index: account.leaf_index as u32, + prove_by_index: account.root_index.proof_by_index(), + }) + .collect() + } + pub fn pack_tree_infos( &self, packed_accounts: &mut PackedAccounts, ) -> Result { - let mut packed_tree_infos = Vec::new(); + let packed_tree_infos = self.pack_state_tree_infos(packed_accounts); let mut address_trees = Vec::new(); let mut output_tree_index = None; for account in self.accounts.iter() { - // Pack TreeInfo - let merkle_tree_pubkey_index = packed_accounts.insert_or_get(account.tree_info.tree); - let queue_pubkey_index = packed_accounts.insert_or_get(account.tree_info.queue); - let tree_info_packed = PackedStateTreeInfo { - root_index: account.root_index.root_index, - merkle_tree_pubkey_index, - queue_pubkey_index, - leaf_index: account.leaf_index as u32, - prove_by_index: account.root_index.proof_by_index(), - }; - packed_tree_infos.push(tree_info_packed); - // If a next Merkle tree exists the Merkle tree is full -> use the next Merkle tree for new state. // Else use the current Merkle tree for new state. if let Some(next) = account.tree_info.next_tree_info { diff --git a/sdk-libs/client/src/interface/instructions.rs b/sdk-libs/client/src/interface/instructions.rs index 41c06e637f..026667d536 100644 --- a/sdk-libs/client/src/interface/instructions.rs +++ b/sdk-libs/client/src/interface/instructions.rs @@ -234,12 +234,7 @@ where let output_queue = get_output_queue(&cold_accounts[0].0.tree_info); let output_state_tree_index = remaining_accounts.insert_or_get(output_queue); - let packed_tree_infos = proof.pack_tree_infos(&mut remaining_accounts)?; - let tree_infos = &packed_tree_infos - .state_trees - .as_ref() - .ok_or("missing state_trees in packed_tree_infos")? - .packed_tree_infos; + let tree_infos = proof.pack_state_tree_infos(&mut remaining_accounts); let mut accounts = program_account_metas.to_vec(); let mut typed_accounts = Vec::with_capacity(cold_accounts.len()); @@ -247,10 +242,7 @@ where // Process PDAs first, then tokens, to match on-chain split_at(token_accounts_offset). for &i in pda_indices.iter().chain(token_indices.iter()) { let (acc, data) = &cold_accounts[i]; - let proof_tree_info = tree_infos - .get(i) - .copied() - .ok_or("tree info index out of bounds")?; + let proof_tree_info = tree_infos.get(i).copied().ok_or("tree info index out of bounds")?; let queue_index = remaining_accounts.insert_or_get(acc.tree_info.queue); let tree_info = PackedStateTreeInfo { queue_pubkey_index: queue_index, @@ -313,14 +305,9 @@ pub fn build_compress_accounts_idempotent( let output_queue = get_output_queue(&proof.accounts[0].tree_info); let output_state_tree_index = remaining_accounts.insert_or_get(output_queue); - let packed_tree_infos = proof.pack_tree_infos(&mut remaining_accounts)?; - let tree_infos = packed_tree_infos - .state_trees - .as_ref() - .ok_or("missing state_trees in packed_tree_infos")?; + let tree_infos = proof.pack_state_tree_infos(&mut remaining_accounts); let cold_metas: Vec<_> = tree_infos - .packed_tree_infos .iter() .map(|tree_info| CompressedAccountMetaNoLamportsNoAddress { tree_info: *tree_info, diff --git a/sdk-libs/client/src/interface/load_accounts.rs b/sdk-libs/client/src/interface/load_accounts.rs index 4fccd73810..40d1a5ac82 100644 --- a/sdk-libs/client/src/interface/load_accounts.rs +++ b/sdk-libs/client/src/interface/load_accounts.rs @@ -424,13 +424,7 @@ fn build_transfer2( fee_payer: Pubkey, ) -> Result { let mut packed = PackedAccounts::default(); - let packed_trees = proof - .pack_tree_infos(&mut packed) - .map_err(|error| LoadAccountsError::BuildInstruction(error.to_string()))?; - let tree_infos = packed_trees - .state_trees - .as_ref() - .ok_or_else(|| LoadAccountsError::BuildInstruction("no state trees".into()))?; + let tree_infos = proof.pack_state_tree_infos(&mut packed); let mut token_accounts = Vec::with_capacity(contexts.len()); let mut tlv_data: Vec> = Vec::with_capacity(contexts.len()); @@ -438,12 +432,10 @@ fn build_transfer2( for (i, ctx) in contexts.iter().enumerate() { let token = &ctx.compressed.token; - let tree = tree_infos.packed_tree_infos.get(i).ok_or( - LoadAccountsError::TreeInfoIndexOutOfBounds { - index: i, - len: tree_infos.packed_tree_infos.len(), - }, - )?; + let tree = tree_infos.get(i).ok_or(LoadAccountsError::TreeInfoIndexOutOfBounds { + index: i, + len: tree_infos.len(), + })?; let owner_idx = packed.insert_or_get_config(ctx.wallet_owner, true, false); let ata_idx = packed.insert_or_get(derive_token_ata(&ctx.wallet_owner, &ctx.mint)); diff --git a/sdk-libs/client/src/local_test_validator.rs b/sdk-libs/client/src/local_test_validator.rs index 4370f4911a..b27daa6a25 100644 --- a/sdk-libs/client/src/local_test_validator.rs +++ b/sdk-libs/client/src/local_test_validator.rs @@ -110,10 +110,7 @@ pub async fn spawn_validator(config: LightValidatorConfig) { .stderr(Stdio::inherit()) .spawn() .expect("Failed to start server process"); - let status = child - .wait() - .await - .expect("Failed to wait for CLI process"); + let status = child.wait().await.expect("Failed to wait for CLI process"); assert!(status.success(), "CLI exited with error: {}", status); } else { let _child = Command::new("sh") diff --git a/sdk-tests/sdk-anchor-test/programs/sdk-anchor-test/tests/read_only.rs b/sdk-tests/sdk-anchor-test/programs/sdk-anchor-test/tests/read_only.rs index 154f4e2045..3e3fb4934d 100644 --- a/sdk-tests/sdk-anchor-test/programs/sdk-anchor-test/tests/read_only.rs +++ b/sdk-tests/sdk-anchor-test/programs/sdk-anchor-test/tests/read_only.rs @@ -127,7 +127,9 @@ async fn create_compressed_account( ) .await? .value; - let packed_accounts = rpc_result.pack_tree_infos(&mut remaining_accounts); + let packed_accounts = rpc_result + .pack_tree_infos(&mut remaining_accounts) + .map_err(|error| RpcError::CustomError(format!("Failed to pack tree infos: {error}")))?; let output_tree_index = rpc .get_random_state_tree_info() @@ -178,6 +180,7 @@ async fn read_sha256_light_system_cpi( let packed_tree_accounts = rpc_result .pack_tree_infos(&mut remaining_accounts) + .map_err(|error| RpcError::CustomError(format!("Failed to pack tree infos: {error}")))? .state_trees .unwrap(); @@ -231,6 +234,7 @@ async fn read_sha256_lowlevel( let packed_tree_accounts = rpc_result .pack_tree_infos(&mut remaining_accounts) + .map_err(|error| RpcError::CustomError(format!("Failed to pack tree infos: {error}")))? .state_trees .unwrap(); @@ -289,7 +293,9 @@ async fn create_compressed_account_poseidon( ) .await? .value; - let packed_accounts = rpc_result.pack_tree_infos(&mut remaining_accounts); + let packed_accounts = rpc_result + .pack_tree_infos(&mut remaining_accounts) + .map_err(|error| RpcError::CustomError(format!("Failed to pack tree infos: {error}")))?; let output_tree_index = rpc .get_random_state_tree_info() @@ -340,6 +346,7 @@ async fn read_poseidon_light_system_cpi( let packed_tree_accounts = rpc_result .pack_tree_infos(&mut remaining_accounts) + .map_err(|error| RpcError::CustomError(format!("Failed to pack tree infos: {error}")))? .state_trees .unwrap(); @@ -393,6 +400,7 @@ async fn read_poseidon_lowlevel( let packed_tree_accounts = rpc_result .pack_tree_infos(&mut remaining_accounts) + .map_err(|error| RpcError::CustomError(format!("Failed to pack tree infos: {error}")))? .state_trees .unwrap(); 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 index e19d0742de..e5cde869bd 100644 --- 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 @@ -171,7 +171,9 @@ async fn create_compressed_account( ) .await? .value; - let packed_accounts = rpc_result.pack_tree_infos(&mut remaining_accounts); + let packed_accounts = rpc_result + .pack_tree_infos(&mut remaining_accounts) + .map_err(|error| RpcError::CustomError(format!("Failed to pack tree infos: {error}")))?; let output_tree_index = rpc .get_random_state_tree_info() @@ -223,6 +225,7 @@ async fn update_compressed_account( let packed_tree_accounts = rpc_result .pack_tree_infos(&mut remaining_accounts) + .map_err(|error| RpcError::CustomError(format!("Failed to pack tree infos: {error}")))? .state_trees .unwrap(); @@ -277,6 +280,7 @@ async fn close_compressed_account( let packed_tree_accounts = rpc_result .pack_tree_infos(&mut remaining_accounts) + .map_err(|error| RpcError::CustomError(format!("Failed to pack tree infos: {error}")))? .state_trees .unwrap(); @@ -340,6 +344,7 @@ async fn reinit_closed_account( let packed_tree_accounts = rpc_result .pack_tree_infos(&mut remaining_accounts) + .map_err(|error| RpcError::CustomError(format!("Failed to pack tree infos: {error}")))? .state_trees .unwrap(); @@ -388,6 +393,7 @@ async fn close_compressed_account_permanent( let packed_tree_accounts = rpc_result .pack_tree_infos(&mut remaining_accounts) + .map_err(|error| RpcError::CustomError(format!("Failed to pack tree infos: {error}")))? .state_trees .unwrap(); diff --git a/sdk-tests/sdk-native-test/tests/test.rs b/sdk-tests/sdk-native-test/tests/test.rs index 30d792487f..eb81e8cf47 100644 --- a/sdk-tests/sdk-native-test/tests/test.rs +++ b/sdk-tests/sdk-native-test/tests/test.rs @@ -103,7 +103,10 @@ pub async fn create_pda( .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 packed_address_tree_info = rpc_result + .pack_tree_infos(&mut accounts) + .map_err(|error| RpcError::CustomError(format!("Failed to pack tree infos: {error}")))? + .address_trees[0]; let (accounts, system_accounts_offset, tree_accounts_offset) = accounts.to_account_metas(); let instruction_data = CreatePdaInstructionData { @@ -147,6 +150,7 @@ pub async fn update_pda( let packed_accounts = rpc_result .pack_tree_infos(&mut accounts) + .map_err(|error| RpcError::CustomError(format!("Failed to pack tree infos: {error}")))? .state_trees .unwrap(); diff --git a/sdk-tests/sdk-pinocchio-v1-test/tests/test.rs b/sdk-tests/sdk-pinocchio-v1-test/tests/test.rs index 0ae7f5c029..83e205bbf4 100644 --- a/sdk-tests/sdk-pinocchio-v1-test/tests/test.rs +++ b/sdk-tests/sdk-pinocchio-v1-test/tests/test.rs @@ -101,7 +101,10 @@ pub async fn create_pda( .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 packed_address_tree_info = rpc_result + .pack_tree_infos(&mut accounts) + .map_err(|error| RpcError::CustomError(format!("Failed to pack tree infos: {error}")))? + .address_trees[0]; let (accounts, system_accounts_offset, tree_accounts_offset) = accounts.to_account_metas(); let instruction_data = CreatePdaInstructionData { proof: rpc_result.proof, @@ -145,6 +148,7 @@ pub async fn update_pda( let packed_accounts = rpc_result .pack_tree_infos(&mut accounts) + .map_err(|error| RpcError::CustomError(format!("Failed to pack tree infos: {error}")))? .state_trees .unwrap(); diff --git a/sdk-tests/sdk-token-test/tests/ctoken_pda.rs b/sdk-tests/sdk-token-test/tests/ctoken_pda.rs index 8e2b595285..10a4cc4680 100644 --- a/sdk-tests/sdk-token-test/tests/ctoken_pda.rs +++ b/sdk-tests/sdk-token-test/tests/ctoken_pda.rs @@ -156,7 +156,9 @@ pub async fn create_mint( let config = SystemAccountMetaConfig::new_with_cpi_context(ID, tree_info.cpi_context.unwrap()); packed_accounts.add_system_accounts_v2(config).unwrap(); // packed_accounts.insert_or_get(tree_info.get_output_pubkey()?); - rpc_result.pack_tree_infos(&mut packed_accounts); + rpc_result + .pack_tree_infos(&mut packed_accounts) + .map_err(|error| RpcError::CustomError(format!("Failed to pack tree infos: {error}")))?; // Create PDA parameters let pda_amount = 100u64; diff --git a/sdk-tests/sdk-token-test/tests/decompress_full_cpi.rs b/sdk-tests/sdk-token-test/tests/decompress_full_cpi.rs index 5f096af560..04cef5e47a 100644 --- a/sdk-tests/sdk-token-test/tests/decompress_full_cpi.rs +++ b/sdk-tests/sdk-token-test/tests/decompress_full_cpi.rs @@ -8,7 +8,7 @@ use light_compressed_token_sdk::compressed_token::{ create_compressed_mint::find_mint_address, decompress_full::DecompressFullAccounts, }; use light_program_test::{Indexer, LightProgramTest, ProgramTestConfig, Rpc}; -use light_sdk::instruction::PackedAccounts; +use light_sdk::instruction::{PackedAccounts, PackedStateTreeInfo}; use light_test_utils::{ actions::{legacy::instructions::mint_action::NewMint, mint_action_comprehensive}, airdrop_lamports, @@ -34,6 +34,23 @@ struct TestContext { total_compressed_amount: u64, } +fn pack_input_state_tree_infos( + rpc_result: &light_client::indexer::ValidityProofWithContext, + remaining_accounts: &mut PackedAccounts, +) -> Vec { + rpc_result + .accounts + .iter() + .map(|account| PackedStateTreeInfo { + root_index: account.root_index.root_index().unwrap_or_default(), + merkle_tree_pubkey_index: remaining_accounts.insert_or_get(account.tree_info.tree), + queue_pubkey_index: remaining_accounts.insert_or_get(account.tree_info.queue), + leaf_index: account.leaf_index as u32, + prove_by_index: account.root_index.proof_by_index(), + }) + .collect() +} + /// Setup function for decompress_full tests /// Creates compressed tokens (source) and empty decompressed accounts (destination) async fn setup_decompress_full_test(num_inputs: usize) -> (LightProgramTest, TestContext) { @@ -213,7 +230,7 @@ async fn test_decompress_full_cpi() { .unwrap() .value; - let packed_tree_info = rpc_result.pack_tree_infos(&mut remaining_accounts); + let packed_tree_infos = pack_input_state_tree_infos(&rpc_result, &mut remaining_accounts); let config = DecompressFullAccounts::new(None); remaining_accounts .add_custom_system_accounts(config) @@ -236,12 +253,7 @@ async fn test_decompress_full_cpi() { let indices: Vec<_> = token_data .iter() .zip( - packed_tree_info - .state_trees - .as_ref() - .unwrap() - .packed_tree_infos - .iter(), + packed_tree_infos.iter(), ) .zip(ctx.destination_accounts.iter()) .zip(versions.iter()) @@ -370,7 +382,7 @@ async fn test_decompress_full_cpi_with_context() { .value; // Add tree accounts first, then custom system accounts (no CPI context since params is None) - let packed_tree_info = rpc_result.pack_tree_infos(&mut remaining_accounts); + let packed_tree_infos = pack_input_state_tree_infos(&rpc_result, &mut remaining_accounts); let config = DecompressFullAccounts::new(None); remaining_accounts .add_custom_system_accounts(config) @@ -393,12 +405,7 @@ async fn test_decompress_full_cpi_with_context() { let indices: Vec<_> = token_data .iter() .zip( - packed_tree_info - .state_trees - .as_ref() - .unwrap() - .packed_tree_infos - .iter(), + packed_tree_infos.iter(), ) .zip(ctx.destination_accounts.iter()) .zip(versions.iter()) diff --git a/sdk-tests/sdk-token-test/tests/pda_ctoken.rs b/sdk-tests/sdk-token-test/tests/pda_ctoken.rs index 91e0f2db9e..0d38a38a21 100644 --- a/sdk-tests/sdk-token-test/tests/pda_ctoken.rs +++ b/sdk-tests/sdk-token-test/tests/pda_ctoken.rs @@ -214,7 +214,9 @@ pub async fn create_mint( let mut packed_accounts = PackedAccounts::default(); let config = SystemAccountMetaConfig::new_with_cpi_context(ID, tree_info.cpi_context.unwrap()); packed_accounts.add_system_accounts_v2(config).unwrap(); - rpc_result.pack_tree_infos(&mut packed_accounts); + rpc_result + .pack_tree_infos(&mut packed_accounts) + .map_err(|error| RpcError::CustomError(format!("Failed to pack tree infos: {error}")))?; // Create PDA parameters let pda_amount = 100u64; diff --git a/sdk-tests/sdk-token-test/tests/test.rs b/sdk-tests/sdk-token-test/tests/test.rs index 3c6941881d..26646657ce 100644 --- a/sdk-tests/sdk-token-test/tests/test.rs +++ b/sdk-tests/sdk-token-test/tests/test.rs @@ -367,7 +367,9 @@ async fn transfer_compressed_tokens( .await? .value; - let packed_tree_info = rpc_result.pack_tree_infos(&mut remaining_accounts); + let packed_tree_info = rpc_result + .pack_tree_infos(&mut remaining_accounts) + .map_err(|error| RpcError::CustomError(format!("Failed to pack tree infos: {error}")))?; let output_tree_index = packed_tree_info .state_trees .as_ref() @@ -433,7 +435,9 @@ async fn decompress_compressed_tokens( .await? .value; - let packed_tree_info = rpc_result.pack_tree_infos(&mut remaining_accounts); + let packed_tree_info = rpc_result + .pack_tree_infos(&mut remaining_accounts) + .map_err(|error| RpcError::CustomError(format!("Failed to pack tree infos: {error}")))?; let output_tree_index = packed_tree_info .state_trees .as_ref() diff --git a/sdk-tests/sdk-token-test/tests/test_4_invocations.rs b/sdk-tests/sdk-token-test/tests/test_4_invocations.rs index 9e70170056..507e3eea29 100644 --- a/sdk-tests/sdk-token-test/tests/test_4_invocations.rs +++ b/sdk-tests/sdk-token-test/tests/test_4_invocations.rs @@ -9,7 +9,7 @@ use light_compressed_token_sdk::{ use light_program_test::{AddressWithTree, Indexer, LightProgramTest, ProgramTestConfig, Rpc}; use light_sdk::{ address::v1::derive_address, - instruction::{PackedAccounts, SystemAccountMetaConfig}, + instruction::{PackedAccounts, PackedStateTreeInfo, SystemAccountMetaConfig}, }; use light_test_utils::{ spl::{create_mint_helper, create_token_account, mint_spl_tokens}, @@ -22,6 +22,34 @@ use solana_sdk::{ signature::{Keypair, Signature, Signer}, }; +fn pack_input_state_tree_infos( + rpc_result: &light_client::indexer::ValidityProofWithContext, + remaining_accounts: &mut PackedAccounts, +) -> Vec { + rpc_result + .accounts + .iter() + .map(|account| PackedStateTreeInfo { + root_index: account.root_index.root_index().unwrap_or_default(), + merkle_tree_pubkey_index: remaining_accounts.insert_or_get(account.tree_info.tree), + queue_pubkey_index: remaining_accounts.insert_or_get(account.tree_info.queue), + leaf_index: account.leaf_index as u32, + prove_by_index: account.root_index.proof_by_index(), + }) + .collect() +} + +fn pack_selected_output_tree_index( + tree_info: light_client::indexer::TreeInfo, + remaining_accounts: &mut PackedAccounts, +) -> Result { + tree_info + .next_tree_info + .map(|next| next.pack_output_tree_index(remaining_accounts)) + .unwrap_or_else(|| tree_info.pack_output_tree_index(remaining_accounts)) + .map_err(|error| RpcError::CustomError(format!("Failed to pack output tree index: {error}"))) +} + #[ignore = "fix cpi context usage"] #[tokio::test] async fn test_4_invocations() { @@ -389,7 +417,9 @@ async fn create_compressed_escrow_pda( .await? .value; - let packed_tree_info = rpc_result.pack_tree_infos(&mut remaining_accounts); + let packed_tree_info = rpc_result + .pack_tree_infos(&mut remaining_accounts) + .map_err(|error| RpcError::CustomError(format!("Failed to pack tree infos: {error}")))?; let new_address_params = packed_tree_info.address_trees[0] .into_new_address_params_assigned_packed(address_seed, Some(0)); @@ -495,29 +525,15 @@ async fn test_four_invokes_instruction( ) .await? .value; - // We need to pack the tree after the cpi context. - remaining_accounts.insert_or_get(rpc_result.accounts[0].tree_info.tree); - - let packed_tree_info = rpc_result.pack_tree_infos(&mut remaining_accounts); - let output_tree_index = packed_tree_info - .state_trees - .as_ref() - .unwrap() - .output_tree_index; + let output_tree_index = + pack_selected_output_tree_index(mint2_token_account.account.tree_info, &mut remaining_accounts)?; + let packed_tree_infos = pack_input_state_tree_infos(&rpc_result, &mut remaining_accounts); // Create token metas from compressed accounts - each uses its respective tree info index // Index 0: escrow PDA, Index 1: mint2 token account, Index 2: mint3 token account - let mint2_tree_info = packed_tree_info - .state_trees - .as_ref() - .unwrap() - .packed_tree_infos[1]; + let mint2_tree_info = packed_tree_infos[1]; - let mint3_tree_info = packed_tree_info - .state_trees - .as_ref() - .unwrap() - .packed_tree_infos[2]; + let mint3_tree_info = packed_tree_infos[2]; // Create FourInvokesParams let four_invokes_params = sdk_token_test::FourInvokesParams { @@ -557,11 +573,7 @@ async fn test_four_invokes_instruction( }; // Create PdaParams - escrow PDA uses tree info index 0 - let escrow_tree_info = packed_tree_info - .state_trees - .as_ref() - .unwrap() - .packed_tree_infos[0]; + let escrow_tree_info = packed_tree_infos[0]; let pda_params = sdk_token_test::PdaParams { account_meta: light_sdk::instruction::account_meta::CompressedAccountMeta { diff --git a/sdk-tests/sdk-token-test/tests/test_4_transfer2.rs b/sdk-tests/sdk-token-test/tests/test_4_transfer2.rs index d7ef38a08c..bb06681f16 100644 --- a/sdk-tests/sdk-token-test/tests/test_4_transfer2.rs +++ b/sdk-tests/sdk-token-test/tests/test_4_transfer2.rs @@ -27,6 +27,34 @@ use solana_sdk::{ signature::{Keypair, Signer}, }; +fn pack_input_state_tree_infos( + rpc_result: &light_client::indexer::ValidityProofWithContext, + remaining_accounts: &mut PackedAccounts, +) -> Vec { + rpc_result + .accounts + .iter() + .map(|account| PackedStateTreeInfo { + root_index: account.root_index.root_index().unwrap_or_default(), + merkle_tree_pubkey_index: remaining_accounts.insert_or_get(account.tree_info.tree), + queue_pubkey_index: remaining_accounts.insert_or_get(account.tree_info.queue), + leaf_index: account.leaf_index as u32, + prove_by_index: account.root_index.proof_by_index(), + }) + .collect() +} + +fn pack_selected_output_tree_index( + tree_info: light_client::indexer::TreeInfo, + remaining_accounts: &mut PackedAccounts, +) -> Result { + tree_info + .next_tree_info + .map(|next| next.pack_output_tree_index(remaining_accounts)) + .unwrap_or_else(|| tree_info.pack_output_tree_index(remaining_accounts)) + .map_err(|error| RpcError::CustomError(format!("Failed to pack output tree index: {error}"))) +} + #[tokio::test] async fn test_4_transfer2() { // Initialize the test environment @@ -339,7 +367,9 @@ async fn create_compressed_escrow_pda( .await? .value; - let packed_tree_info = rpc_result.pack_tree_infos(&mut remaining_accounts); + let packed_tree_info = rpc_result + .pack_tree_infos(&mut remaining_accounts) + .map_err(|error| RpcError::CustomError(format!("Failed to pack tree infos: {error}")))?; let new_address_params = packed_tree_info.address_trees[0] .into_new_address_params_assigned_packed(address_seed, Some(0)); @@ -435,29 +465,15 @@ async fn test_four_transfer2_instruction( ) .await? .value; - // We need to pack the tree after the cpi context. - remaining_accounts.insert_or_get(rpc_result.accounts[0].tree_info.tree); - - let packed_tree_info = rpc_result.pack_tree_infos(&mut remaining_accounts); - let output_tree_index = packed_tree_info - .state_trees - .as_ref() - .unwrap() - .output_tree_index; + let output_tree_index = + pack_selected_output_tree_index(mint2_token_account.account.tree_info, &mut remaining_accounts)?; + let packed_tree_infos = pack_input_state_tree_infos(&rpc_result, &mut remaining_accounts); // Create token metas from compressed accounts - each uses its respective tree info index // Index 0: escrow PDA, Index 1: mint2 token account, Index 2: mint3 token account - let mint2_tree_info = packed_tree_info - .state_trees - .as_ref() - .unwrap() - .packed_tree_infos[1]; + let mint2_tree_info = packed_tree_infos[1]; - let mint3_tree_info = packed_tree_info - .state_trees - .as_ref() - .unwrap() - .packed_tree_infos[2]; + let mint3_tree_info = packed_tree_infos[2]; // Create FourTransfer2Params let four_transfer2_params = sdk_token_test::process_four_transfer2::FourTransfer2Params { @@ -491,11 +507,7 @@ async fn test_four_transfer2_instruction( }; // Create PdaParams - escrow PDA uses tree info index 0 - let escrow_tree_info = packed_tree_info - .state_trees - .as_ref() - .unwrap() - .packed_tree_infos[0]; + let escrow_tree_info = packed_tree_infos[0]; let pda_params = sdk_token_test::PdaParams { account_meta: light_sdk::instruction::account_meta::CompressedAccountMeta { diff --git a/sdk-tests/sdk-token-test/tests/test_deposit.rs b/sdk-tests/sdk-token-test/tests/test_deposit.rs index 9ebcbd8549..1e78e5c19f 100644 --- a/sdk-tests/sdk-token-test/tests/test_deposit.rs +++ b/sdk-tests/sdk-token-test/tests/test_deposit.rs @@ -10,7 +10,10 @@ use light_compressed_token_sdk::{ use light_program_test::{AddressWithTree, Indexer, LightProgramTest, ProgramTestConfig, Rpc}; use light_sdk::{ address::v1::derive_address, - instruction::{account_meta::CompressedAccountMeta, PackedAccounts, SystemAccountMetaConfig}, + instruction::{ + account_meta::CompressedAccountMeta, PackedAccounts, PackedStateTreeInfo, + SystemAccountMetaConfig, + }, }; use light_test_utils::{ spl::{create_mint_helper, create_token_account, mint_spl_tokens}, @@ -23,6 +26,52 @@ use solana_sdk::{ signature::{Keypair, Signature, Signer}, }; +fn pack_input_state_tree_infos( + rpc_result: &light_client::indexer::ValidityProofWithContext, + remaining_accounts: &mut PackedAccounts, +) -> Vec { + rpc_result + .accounts + .iter() + .map(|account| PackedStateTreeInfo { + root_index: account.root_index.root_index().unwrap_or_default(), + merkle_tree_pubkey_index: remaining_accounts.insert_or_get(account.tree_info.tree), + queue_pubkey_index: remaining_accounts.insert_or_get(account.tree_info.queue), + leaf_index: account.leaf_index as u32, + prove_by_index: account.root_index.proof_by_index(), + }) + .collect() +} + +fn pack_selected_output_tree_context( + tree_info: light_client::indexer::TreeInfo, + remaining_accounts: &mut PackedAccounts, +) -> Result<(u8, u8, u8), RpcError> { + let (tree, queue, output_state_tree_index) = if let Some(next) = tree_info.next_tree_info { + ( + next.tree, + next.queue, + next.pack_output_tree_index(remaining_accounts).map_err(|error| { + RpcError::CustomError(format!("Failed to pack output tree index: {error}")) + })?, + ) + } else { + ( + tree_info.tree, + tree_info.queue, + tree_info.pack_output_tree_index(remaining_accounts).map_err(|error| { + RpcError::CustomError(format!("Failed to pack output tree index: {error}")) + })?, + ) + }; + + Ok(( + remaining_accounts.insert_or_get(tree), + remaining_accounts.insert_or_get(queue), + output_state_tree_index, + )) +} + #[ignore = "fix cpi context usage"] #[tokio::test] async fn test_deposit_compressed_account() { @@ -206,7 +255,9 @@ async fn create_deposit_compressed_account( ) .await? .value; - let packed_accounts = rpc_result.pack_tree_infos(&mut remaining_accounts); + let packed_accounts = rpc_result + .pack_tree_infos(&mut remaining_accounts) + .map_err(|error| RpcError::CustomError(format!("Failed to pack tree infos: {error}")))?; println!("packed_accounts {:?}", packed_accounts.state_trees); // Create token meta from compressed account @@ -302,9 +353,11 @@ async fn update_deposit_compressed_account( "rpc_result.accounts[0].tree_info.queue {:?}", rpc_result.accounts[0].tree_info.queue.to_bytes() ); - // We need to pack the tree after the cpi context. - let index = remaining_accounts.insert_or_get(rpc_result.accounts[0].tree_info.tree); - println!("index {}", index); + let (output_tree_index, output_tree_queue_index, output_state_tree_index) = + pack_selected_output_tree_context(rpc_result.accounts[0].tree_info, &mut remaining_accounts)?; + println!("output_tree_index {}", output_tree_index); + println!("output_tree_queue_index {}", output_tree_queue_index); + println!("output_state_tree_index {}", output_state_tree_index); // Get mint from the compressed token account let mint = deposit_ctoken_account.token.mint; println!( @@ -318,15 +371,11 @@ async fn update_deposit_compressed_account( // Get validity proof for the compressed token account and new address println!("rpc_result {:?}", rpc_result); - let packed_accounts = rpc_result.pack_tree_infos(&mut remaining_accounts); - println!("packed_accounts {:?}", packed_accounts.state_trees); + let packed_tree_infos = pack_input_state_tree_infos(&rpc_result, &mut remaining_accounts); + println!("packed_tree_infos {:?}", packed_tree_infos); // TODO: investigate why packed_tree_infos seem to be out of order // Create token meta from compressed account - let tree_info = packed_accounts - .state_trees - .as_ref() - .unwrap() - .packed_tree_infos[1]; + let tree_info = packed_tree_infos[1]; let depositing_token_metas = vec![TokenAccountMeta { amount: deposit_ctoken_account.token.amount, delegate_index: None, @@ -335,11 +384,7 @@ async fn update_deposit_compressed_account( tlv: None, }]; println!("depositing_token_metas {:?}", depositing_token_metas); - let tree_info = packed_accounts - .state_trees - .as_ref() - .unwrap() - .packed_tree_infos[2]; + let tree_info = packed_tree_infos[2]; let escrowed_token_meta = TokenAccountMeta { amount: escrow_ctoken_account.token.amount, delegate_index: None, @@ -354,19 +399,11 @@ async fn update_deposit_compressed_account( let system_accounts_start_offset = system_accounts_start_offset as u8; println!("remaining_accounts {:?}", remaining_accounts); - let tree_info = packed_accounts - .state_trees - .as_ref() - .unwrap() - .packed_tree_infos[0]; + let tree_info = packed_tree_infos[0]; let account_meta = CompressedAccountMeta { tree_info, address: escrow_pda.address.unwrap(), - output_state_tree_index: packed_accounts - .state_trees - .as_ref() - .unwrap() - .output_tree_index, + output_state_tree_index, }; let instruction = Instruction { @@ -381,14 +418,8 @@ async fn update_deposit_compressed_account( .concat(), data: sdk_token_test::instruction::UpdateDeposit { proof: rpc_result.proof, - output_tree_index: packed_accounts - .state_trees - .as_ref() - .unwrap() - .packed_tree_infos[0] - .merkle_tree_pubkey_index, - output_tree_queue_index: packed_accounts.state_trees.unwrap().packed_tree_infos[0] - .queue_pubkey_index, + output_tree_index, + output_tree_queue_index, system_accounts_start_offset, token_params: sdk_token_test::TokenParams { deposit_amount: amount, diff --git a/sdk-tests/sdk-v1-native-test/tests/test.rs b/sdk-tests/sdk-v1-native-test/tests/test.rs index a93beab599..2e10e61e14 100644 --- a/sdk-tests/sdk-v1-native-test/tests/test.rs +++ b/sdk-tests/sdk-v1-native-test/tests/test.rs @@ -94,7 +94,8 @@ pub async fn create_pda( .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 packed_tree_infos = rpc_result.pack_tree_infos(&mut accounts)?; + let packed_address_tree_info = packed_tree_infos.address_trees[0]; let (accounts, system_accounts_offset, tree_accounts_offset) = accounts.to_account_metas(); let instruction_data = CreatePdaInstructionData { @@ -137,7 +138,7 @@ pub async fn update_pda( .value; let packed_accounts = rpc_result - .pack_tree_infos(&mut accounts) + .pack_tree_infos(&mut accounts)? .state_trees .unwrap(); From 62dc3968b4eab5873b268dda7178ae037c337a8c Mon Sep 17 00:00:00 2001 From: Sergey Timoshin Date: Tue, 17 Mar 2026 14:56:14 +0000 Subject: [PATCH 21/23] format --- .../actions/legacy/instructions/transfer2.rs | 82 +++++++------------ sdk-libs/client/src/interface/instructions.rs | 5 +- .../client/src/interface/load_accounts.rs | 10 ++- sdk-tests/sdk-pinocchio-v2-test/tests/test.rs | 5 +- .../tests/test_4_invocations.rs | 10 ++- .../sdk-token-test/tests/test_4_transfer2.rs | 10 ++- .../sdk-token-test/tests/test_deposit.rs | 20 +++-- 7 files changed, 68 insertions(+), 74 deletions(-) diff --git a/program-tests/utils/src/actions/legacy/instructions/transfer2.rs b/program-tests/utils/src/actions/legacy/instructions/transfer2.rs index 00a55f3ad8..1a68be1293 100644 --- a/program-tests/utils/src/actions/legacy/instructions/transfer2.rs +++ b/program-tests/utils/src/actions/legacy/instructions/transfer2.rs @@ -169,13 +169,23 @@ pub async fn create_generic_transfer2_instruction( payer: Pubkey, should_filter_zero_outputs: bool, ) -> Result { - // // Get a single shared output queue for ALL compress/compress-and-close operations - // // This prevents reordering issues caused by the sort_by_key at the end - // let shared_output_queue = rpc - // .get_random_state_tree_info() - // .unwrap() - // .get_output_pubkey() - // .unwrap(); + // Transfer2 supports a single output queue per instruction. Legacy helpers accept + // per-action queues, but normalize them down to one shared queue for the IX. + let mut explicit_output_queue = None; + for action in &actions { + let candidate = match action { + Transfer2InstructionType::Compress(input) => Some(input.output_queue), + Transfer2InstructionType::CompressAndClose(input) => Some(input.output_queue), + Transfer2InstructionType::Decompress(_) + | Transfer2InstructionType::Transfer(_) + | Transfer2InstructionType::Approve(_) => None, + }; + if let Some(candidate) = candidate { + if explicit_output_queue.is_none() { + explicit_output_queue = Some(candidate); + } + } + } let mut hashes = Vec::new(); actions.iter().for_each(|account| match account { @@ -210,26 +220,16 @@ pub async fn create_generic_transfer2_instruction( .value; let mut packed_tree_accounts = PackedAccounts::default(); - // tree infos must be packed before packing the token input accounts - let packed_tree_infos = rpc_proof_result - .pack_tree_infos(&mut packed_tree_accounts) - .unwrap(); - - // We use a single shared output queue for all compress/compress-and-close operations to avoid ordering failures. - let shared_output_queue = if packed_tree_infos.address_trees.is_empty() { - let shared_output_queue = rpc - .get_random_state_tree_info() + // Pack only input state tree infos. Grouped transfer2 proofs can span multiple output trees. + let packed_tree_infos = rpc_proof_result.pack_state_tree_infos(&mut packed_tree_accounts); + + let shared_output_queue = explicit_output_queue.unwrap_or_else(|| { + rpc.get_random_state_tree_info() .unwrap() .get_output_pubkey() - .unwrap(); - packed_tree_accounts.insert_or_get(shared_output_queue) - } else { - packed_tree_infos - .state_trees - .as_ref() .unwrap() - .output_tree_index - }; + }); + let shared_output_queue = packed_tree_accounts.insert_or_get(shared_output_queue); let mut inputs_offset = 0; let mut in_lamports = Vec::new(); @@ -245,12 +245,7 @@ pub async fn create_generic_transfer2_instruction( let token_data = input_token_account .iter() .zip( - packed_tree_infos - .state_trees - .as_ref() - .unwrap() - .packed_tree_infos[inputs_offset..] - .iter(), + packed_tree_infos[inputs_offset..].iter(), ) .map(|(account, rpc_account)| { if input.to != account.token.owner { @@ -393,14 +388,7 @@ pub async fn create_generic_transfer2_instruction( let token_data = input .compressed_token_account .iter() - .zip( - packed_tree_infos - .state_trees - .as_ref() - .unwrap() - .packed_tree_infos[inputs_offset..] - .iter(), - ) + .zip(packed_tree_infos[inputs_offset..].iter()) .map(|(account, rpc_account)| { pack_input_token_account( account, @@ -462,14 +450,7 @@ pub async fn create_generic_transfer2_instruction( let token_data = input .compressed_token_account .iter() - .zip( - packed_tree_infos - .state_trees - .as_ref() - .unwrap() - .packed_tree_infos[inputs_offset..] - .iter(), - ) + .zip(packed_tree_infos[inputs_offset..].iter()) .map(|(account, rpc_account)| { pack_input_token_account( account, @@ -544,14 +525,7 @@ pub async fn create_generic_transfer2_instruction( let token_data = input .compressed_token_account .iter() - .zip( - packed_tree_infos - .state_trees - .as_ref() - .unwrap() - .packed_tree_infos[inputs_offset..] - .iter(), - ) + .zip(packed_tree_infos[inputs_offset..].iter()) .map(|(account, rpc_account)| { pack_input_token_account( account, diff --git a/sdk-libs/client/src/interface/instructions.rs b/sdk-libs/client/src/interface/instructions.rs index 026667d536..bb4056ceae 100644 --- a/sdk-libs/client/src/interface/instructions.rs +++ b/sdk-libs/client/src/interface/instructions.rs @@ -242,7 +242,10 @@ where // Process PDAs first, then tokens, to match on-chain split_at(token_accounts_offset). for &i in pda_indices.iter().chain(token_indices.iter()) { let (acc, data) = &cold_accounts[i]; - let proof_tree_info = tree_infos.get(i).copied().ok_or("tree info index out of bounds")?; + let proof_tree_info = tree_infos + .get(i) + .copied() + .ok_or("tree info index out of bounds")?; let queue_index = remaining_accounts.insert_or_get(acc.tree_info.queue); let tree_info = PackedStateTreeInfo { queue_pubkey_index: queue_index, diff --git a/sdk-libs/client/src/interface/load_accounts.rs b/sdk-libs/client/src/interface/load_accounts.rs index 40d1a5ac82..01d91364c1 100644 --- a/sdk-libs/client/src/interface/load_accounts.rs +++ b/sdk-libs/client/src/interface/load_accounts.rs @@ -432,10 +432,12 @@ fn build_transfer2( for (i, ctx) in contexts.iter().enumerate() { let token = &ctx.compressed.token; - let tree = tree_infos.get(i).ok_or(LoadAccountsError::TreeInfoIndexOutOfBounds { - index: i, - len: tree_infos.len(), - })?; + let tree = tree_infos + .get(i) + .ok_or(LoadAccountsError::TreeInfoIndexOutOfBounds { + index: i, + len: tree_infos.len(), + })?; let owner_idx = packed.insert_or_get_config(ctx.wallet_owner, true, false); let ata_idx = packed.insert_or_get(derive_token_ata(&ctx.wallet_owner, &ctx.mint)); diff --git a/sdk-tests/sdk-pinocchio-v2-test/tests/test.rs b/sdk-tests/sdk-pinocchio-v2-test/tests/test.rs index 59a0562c63..510c98b2b5 100644 --- a/sdk-tests/sdk-pinocchio-v2-test/tests/test.rs +++ b/sdk-tests/sdk-pinocchio-v2-test/tests/test.rs @@ -111,7 +111,8 @@ pub async fn create_pda( .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 packed_tree_infos = rpc_result.pack_tree_infos(&mut accounts)?; + let packed_address_tree_info = packed_tree_infos.address_trees[0]; let (accounts, system_accounts_offset, tree_accounts_offset) = accounts.to_account_metas(); let instruction_data = CreatePdaInstructionData { proof: rpc_result.proof, @@ -154,7 +155,7 @@ pub async fn update_pda( .value; let packed_accounts = rpc_result - .pack_tree_infos(&mut accounts) + .pack_tree_infos(&mut accounts)? .state_trees .unwrap(); diff --git a/sdk-tests/sdk-token-test/tests/test_4_invocations.rs b/sdk-tests/sdk-token-test/tests/test_4_invocations.rs index 507e3eea29..75f1a18c28 100644 --- a/sdk-tests/sdk-token-test/tests/test_4_invocations.rs +++ b/sdk-tests/sdk-token-test/tests/test_4_invocations.rs @@ -47,7 +47,9 @@ fn pack_selected_output_tree_index( .next_tree_info .map(|next| next.pack_output_tree_index(remaining_accounts)) .unwrap_or_else(|| tree_info.pack_output_tree_index(remaining_accounts)) - .map_err(|error| RpcError::CustomError(format!("Failed to pack output tree index: {error}"))) + .map_err(|error| { + RpcError::CustomError(format!("Failed to pack output tree index: {error}")) + }) } #[ignore = "fix cpi context usage"] @@ -525,8 +527,10 @@ async fn test_four_invokes_instruction( ) .await? .value; - let output_tree_index = - pack_selected_output_tree_index(mint2_token_account.account.tree_info, &mut remaining_accounts)?; + let output_tree_index = pack_selected_output_tree_index( + mint2_token_account.account.tree_info, + &mut remaining_accounts, + )?; let packed_tree_infos = pack_input_state_tree_infos(&rpc_result, &mut remaining_accounts); // Create token metas from compressed accounts - each uses its respective tree info index diff --git a/sdk-tests/sdk-token-test/tests/test_4_transfer2.rs b/sdk-tests/sdk-token-test/tests/test_4_transfer2.rs index bb06681f16..8c7b8d422c 100644 --- a/sdk-tests/sdk-token-test/tests/test_4_transfer2.rs +++ b/sdk-tests/sdk-token-test/tests/test_4_transfer2.rs @@ -52,7 +52,9 @@ fn pack_selected_output_tree_index( .next_tree_info .map(|next| next.pack_output_tree_index(remaining_accounts)) .unwrap_or_else(|| tree_info.pack_output_tree_index(remaining_accounts)) - .map_err(|error| RpcError::CustomError(format!("Failed to pack output tree index: {error}"))) + .map_err(|error| { + RpcError::CustomError(format!("Failed to pack output tree index: {error}")) + }) } #[tokio::test] @@ -465,8 +467,10 @@ async fn test_four_transfer2_instruction( ) .await? .value; - let output_tree_index = - pack_selected_output_tree_index(mint2_token_account.account.tree_info, &mut remaining_accounts)?; + let output_tree_index = pack_selected_output_tree_index( + mint2_token_account.account.tree_info, + &mut remaining_accounts, + )?; let packed_tree_infos = pack_input_state_tree_infos(&rpc_result, &mut remaining_accounts); // Create token metas from compressed accounts - each uses its respective tree info index diff --git a/sdk-tests/sdk-token-test/tests/test_deposit.rs b/sdk-tests/sdk-token-test/tests/test_deposit.rs index 1e78e5c19f..dd962abeec 100644 --- a/sdk-tests/sdk-token-test/tests/test_deposit.rs +++ b/sdk-tests/sdk-token-test/tests/test_deposit.rs @@ -51,17 +51,20 @@ fn pack_selected_output_tree_context( ( next.tree, next.queue, - next.pack_output_tree_index(remaining_accounts).map_err(|error| { - RpcError::CustomError(format!("Failed to pack output tree index: {error}")) - })?, + next.pack_output_tree_index(remaining_accounts) + .map_err(|error| { + RpcError::CustomError(format!("Failed to pack output tree index: {error}")) + })?, ) } else { ( tree_info.tree, tree_info.queue, - tree_info.pack_output_tree_index(remaining_accounts).map_err(|error| { - RpcError::CustomError(format!("Failed to pack output tree index: {error}")) - })?, + tree_info + .pack_output_tree_index(remaining_accounts) + .map_err(|error| { + RpcError::CustomError(format!("Failed to pack output tree index: {error}")) + })?, ) }; @@ -354,7 +357,10 @@ async fn update_deposit_compressed_account( rpc_result.accounts[0].tree_info.queue.to_bytes() ); let (output_tree_index, output_tree_queue_index, output_state_tree_index) = - pack_selected_output_tree_context(rpc_result.accounts[0].tree_info, &mut remaining_accounts)?; + pack_selected_output_tree_context( + rpc_result.accounts[0].tree_info, + &mut remaining_accounts, + )?; println!("output_tree_index {}", output_tree_index); println!("output_tree_queue_index {}", output_tree_queue_index); println!("output_state_tree_index {}", output_state_tree_index); From ffda165caba442c9ccb7485b56ae9b22f24d7af4 Mon Sep 17 00:00:00 2001 From: Sergey Timoshin Date: Tue, 17 Mar 2026 17:40:09 +0000 Subject: [PATCH 22/23] format --- .../utils/src/actions/legacy/instructions/transfer2.rs | 4 +--- sdk-tests/sdk-token-test/tests/test_4_invocations.rs | 9 +++++---- 2 files changed, 6 insertions(+), 7 deletions(-) diff --git a/program-tests/utils/src/actions/legacy/instructions/transfer2.rs b/program-tests/utils/src/actions/legacy/instructions/transfer2.rs index 1a68be1293..b006824302 100644 --- a/program-tests/utils/src/actions/legacy/instructions/transfer2.rs +++ b/program-tests/utils/src/actions/legacy/instructions/transfer2.rs @@ -244,9 +244,7 @@ pub async fn create_generic_transfer2_instruction( if let Some(ref input_token_account) = input.compressed_token_account { let token_data = input_token_account .iter() - .zip( - packed_tree_infos[inputs_offset..].iter(), - ) + .zip(packed_tree_infos[inputs_offset..].iter()) .map(|(account, rpc_account)| { if input.to != account.token.owner { return Err(TokenSdkError::InvalidCompressInputOwner); diff --git a/sdk-tests/sdk-token-test/tests/test_4_invocations.rs b/sdk-tests/sdk-token-test/tests/test_4_invocations.rs index 75f1a18c28..913bdf39a9 100644 --- a/sdk-tests/sdk-token-test/tests/test_4_invocations.rs +++ b/sdk-tests/sdk-token-test/tests/test_4_invocations.rs @@ -42,14 +42,14 @@ fn pack_input_state_tree_infos( fn pack_selected_output_tree_index( tree_info: light_client::indexer::TreeInfo, remaining_accounts: &mut PackedAccounts, -) -> Result { +) -> Result> { tree_info .next_tree_info .map(|next| next.pack_output_tree_index(remaining_accounts)) .unwrap_or_else(|| tree_info.pack_output_tree_index(remaining_accounts)) - .map_err(|error| { + .map_err(|error| Box::new( RpcError::CustomError(format!("Failed to pack output tree index: {error}")) - }) + )) } #[ignore = "fix cpi context usage"] @@ -530,7 +530,8 @@ async fn test_four_invokes_instruction( let output_tree_index = pack_selected_output_tree_index( mint2_token_account.account.tree_info, &mut remaining_accounts, - )?; + ) + .map_err(|error| *error)?; let packed_tree_infos = pack_input_state_tree_infos(&rpc_result, &mut remaining_accounts); // Create token metas from compressed accounts - each uses its respective tree info index From bd856c3fb117ff60b35eb5b19b73f70145e7dedf Mon Sep 17 00:00:00 2001 From: Sergey Timoshin Date: Fri, 27 Mar 2026 13:11:03 +0000 Subject: [PATCH 23/23] cleanup --- prover/client/src/proof_client.rs | 6 +++--- prover/client/src/prover.rs | 1 - .../sdk-types/src/interface/program/decompression/pda.rs | 2 +- sdk-tests/sdk-token-test/tests/test_4_invocations.rs | 8 +++++--- 4 files changed, 9 insertions(+), 8 deletions(-) diff --git a/prover/client/src/proof_client.rs b/prover/client/src/proof_client.rs index c2dcbcdd2f..8a7c5b8ff9 100644 --- a/prover/client/src/proof_client.rs +++ b/prover/client/src/proof_client.rs @@ -75,7 +75,7 @@ impl ProofClient { max_wait_time: Duration::from_secs(DEFAULT_MAX_WAIT_TIME_SECS), api_key: None, initial_poll_delay: Duration::from_millis(INITIAL_POLL_DELAY_SMALL_CIRCUIT_MS), - }) + } } #[allow(unused)] @@ -91,7 +91,7 @@ impl ProofClient { Duration::from_millis(INITIAL_POLL_DELAY_SMALL_CIRCUIT_MS) }; - Self { + Ok(Self { client: build_http_client(), server_address, polling_interval, @@ -116,7 +116,7 @@ impl ProofClient { max_wait_time, api_key, initial_poll_delay, - }) + } } pub async fn submit_proof_async( diff --git a/prover/client/src/prover.rs b/prover/client/src/prover.rs index 71fa37deae..e390e1c54b 100644 --- a/prover/client/src/prover.rs +++ b/prover/client/src/prover.rs @@ -6,7 +6,6 @@ use std::{ use tokio::time::sleep; use tracing::info; -use tokio::time::sleep; use crate::{ constants::{HEALTH_CHECK, SERVER_ADDRESS}, diff --git a/sdk-libs/sdk-types/src/interface/program/decompression/pda.rs b/sdk-libs/sdk-types/src/interface/program/decompression/pda.rs index 926fe36e1d..cc7aa4ba1f 100644 --- a/sdk-libs/sdk-types/src/interface/program/decompression/pda.rs +++ b/sdk-libs/sdk-types/src/interface/program/decompression/pda.rs @@ -151,7 +151,7 @@ where lamports: 0, merkle_context: PackedMerkleContext { merkle_tree_pubkey_index: tree_info.merkle_tree_pubkey_index, - queue_pubkey_index: input_queue_index, + queue_pubkey_index: tree_info.queue_pubkey_index, leaf_index: tree_info.leaf_index, prove_by_index: tree_info.prove_by_index, }, diff --git a/sdk-tests/sdk-token-test/tests/test_4_invocations.rs b/sdk-tests/sdk-token-test/tests/test_4_invocations.rs index 913bdf39a9..3ab40a9043 100644 --- a/sdk-tests/sdk-token-test/tests/test_4_invocations.rs +++ b/sdk-tests/sdk-token-test/tests/test_4_invocations.rs @@ -47,9 +47,11 @@ fn pack_selected_output_tree_index( .next_tree_info .map(|next| next.pack_output_tree_index(remaining_accounts)) .unwrap_or_else(|| tree_info.pack_output_tree_index(remaining_accounts)) - .map_err(|error| Box::new( - RpcError::CustomError(format!("Failed to pack output tree index: {error}")) - )) + .map_err(|error| { + Box::new(RpcError::CustomError(format!( + "Failed to pack output tree index: {error}" + ))) + }) } #[ignore = "fix cpi context usage"]