From de0beec96af0ef0a97c3b483f3d6f9741a3f1800 Mon Sep 17 00:00:00 2001 From: Swenschaeferjohann Date: Fri, 6 Feb 2026 04:13:09 +0000 Subject: [PATCH 1/2] fix light-client tree infos v2 --- sdk-libs/client/src/rpc/client.rs | 213 ++++++++++++++++-------------- 1 file changed, 114 insertions(+), 99 deletions(-) diff --git a/sdk-libs/client/src/rpc/client.rs b/sdk-libs/client/src/rpc/client.rs index d87d8d728d..6f27075187 100644 --- a/sdk-libs/client/src/rpc/client.rs +++ b/sdk-libs/client/src/rpc/client.rs @@ -37,16 +37,55 @@ use crate::{ TreeInfo, }, interface::{AccountInterface, MintInterface, MintState, TokenAccountInterface}, - rpc::{ - errors::RpcError, - get_light_state_tree_infos::{ - default_state_tree_lookup_tables, get_light_state_tree_infos, - }, - merkle_tree::MerkleTreeExt, - Rpc, - }, + rpc::{errors::RpcError, merkle_tree::MerkleTreeExt, Rpc}, +}; +#[cfg(not(feature = "v2"))] +use crate::rpc::get_light_state_tree_infos::{ + default_state_tree_lookup_tables, get_light_state_tree_infos, }; +/// V2 batched state trees. +#[cfg(feature = "v2")] +pub(crate) fn default_v2_state_trees() -> [TreeInfo; 5] { + [ + TreeInfo { + tree: pubkey!("bmt1LryLZUMmF7ZtqESaw7wifBXLfXHQYoE4GAmrahU"), + queue: pubkey!("oq1na8gojfdUhsfCpyjNt6h4JaDWtHf1yQj4koBWfto"), + cpi_context: Some(pubkey!("cpi15BoVPKgEPw5o8wc2T816GE7b378nMXnhH3Xbq4y")), + next_tree_info: None, + tree_type: TreeType::StateV2, + }, + TreeInfo { + tree: pubkey!("bmt2UxoBxB9xWev4BkLvkGdapsz6sZGkzViPNph7VFi"), + queue: pubkey!("oq2UkeMsJLfXt2QHzim242SUi3nvjJs8Pn7Eac9H9vg"), + cpi_context: Some(pubkey!("cpi2yGapXUR3As5SjnHBAVvmApNiLsbeZpF3euWnW6B")), + next_tree_info: None, + tree_type: TreeType::StateV2, + }, + TreeInfo { + tree: pubkey!("bmt3ccLd4bqSVZVeCJnH1F6C8jNygAhaDfxDwePyyGb"), + queue: pubkey!("oq3AxjekBWgo64gpauB6QtuZNesuv19xrhaC1ZM1THQ"), + cpi_context: Some(pubkey!("cpi3mbwMpSX8FAGMZVP85AwxqCaQMfEk9Em1v8QK9Rf")), + next_tree_info: None, + tree_type: TreeType::StateV2, + }, + TreeInfo { + tree: pubkey!("bmt4d3p1a4YQgk9PeZv5s4DBUmbF5NxqYpk9HGjQsd8"), + queue: pubkey!("oq4ypwvVGzCUMoiKKHWh4S1SgZJ9vCvKpcz6RT6A8dq"), + cpi_context: Some(pubkey!("cpi4yyPDc4bCgHAnsenunGA8Y77j3XEDyjgfyCKgcoc")), + next_tree_info: None, + tree_type: TreeType::StateV2, + }, + TreeInfo { + tree: pubkey!("bmt5yU97jC88YXTuSukYHa8Z5Bi2ZDUtmzfkDTA2mG2"), + queue: pubkey!("oq5oh5ZR3yGomuQgFduNDzjtGvVWfDRGLuDVjv9a96P"), + cpi_context: Some(pubkey!("cpi5ZTjdgYpZ1Xr7B1cMLLUE81oTtJbNNAyKary2nV6")), + next_tree_info: None, + tree_type: TreeType::StateV2, + }, + ] +} + pub enum RpcUrl { Testnet, Devnet, @@ -135,7 +174,8 @@ impl LightClient { self.indexer = Some(PhotonIndexer::new(path, api_key)); } - /// Detects the network type based on the RPC URL + /// Detects the network type based on the RPC URL. V1 only. + #[cfg(not(feature = "v2"))] fn detect_network(&self) -> RpcUrl { let url = self.client.url(); @@ -963,113 +1003,88 @@ impl Rpc for LightClient { } /// Fetch the latest state tree addresses from the cluster. + /// + /// When the `v2` feature is enabled, returns the default V2 + /// batched state trees. + /// When `v2` is disabled, uses V1 lookup-table resolution or + /// localnet defaults. async fn get_latest_active_state_trees(&mut self) -> Result, RpcError> { - let network = self.detect_network(); - - // Return default test values for localnet - if matches!(network, RpcUrl::Localnet) { - use light_compressed_account::TreeType; - use solana_pubkey::pubkey; + // V2: the default batched state trees are the same on every network. + #[cfg(feature = "v2")] + { + let trees = default_v2_state_trees().to_vec(); + self.state_merkle_trees = trees.clone(); + return Ok(trees); + } - use crate::indexer::TreeInfo; + // V1 path: network-dependent resolution. + #[cfg(not(feature = "v2"))] + { + let network = self.detect_network(); - #[cfg(feature = "v2")] - let default_trees = vec![ - TreeInfo { - tree: pubkey!("bmt1LryLZUMmF7ZtqESaw7wifBXLfXHQYoE4GAmrahU"), - queue: pubkey!("oq1na8gojfdUhsfCpyjNt6h4JaDWtHf1yQj4koBWfto"), - cpi_context: Some(pubkey!("cpi15BoVPKgEPw5o8wc2T816GE7b378nMXnhH3Xbq4y")), - next_tree_info: None, - tree_type: TreeType::StateV2, - }, - TreeInfo { - tree: pubkey!("bmt2UxoBxB9xWev4BkLvkGdapsz6sZGkzViPNph7VFi"), - queue: pubkey!("oq2UkeMsJLfXt2QHzim242SUi3nvjJs8Pn7Eac9H9vg"), - cpi_context: Some(pubkey!("cpi2yGapXUR3As5SjnHBAVvmApNiLsbeZpF3euWnW6B")), - next_tree_info: None, - tree_type: TreeType::StateV2, - }, - TreeInfo { - tree: pubkey!("bmt3ccLd4bqSVZVeCJnH1F6C8jNygAhaDfxDwePyyGb"), - queue: pubkey!("oq3AxjekBWgo64gpauB6QtuZNesuv19xrhaC1ZM1THQ"), - cpi_context: Some(pubkey!("cpi3mbwMpSX8FAGMZVP85AwxqCaQMfEk9Em1v8QK9Rf")), - next_tree_info: None, - tree_type: TreeType::StateV2, - }, - TreeInfo { - tree: pubkey!("bmt4d3p1a4YQgk9PeZv5s4DBUmbF5NxqYpk9HGjQsd8"), - queue: pubkey!("oq4ypwvVGzCUMoiKKHWh4S1SgZJ9vCvKpcz6RT6A8dq"), - cpi_context: Some(pubkey!("cpi4yyPDc4bCgHAnsenunGA8Y77j3XEDyjgfyCKgcoc")), + if matches!(network, RpcUrl::Localnet) { + let default_trees = vec![TreeInfo { + tree: pubkey!("smt1NamzXdq4AMqS2fS2F1i5KTYPZRhoHgWx38d8WsT"), + queue: pubkey!("nfq1NvQDJ2GEgnS8zt9prAe8rjjpAW1zFkrvZoBR148"), + cpi_context: Some(pubkey!("cpi1uHzrEhBG733DoEJNgHCyRS3XmmyVNZx5fonubE4")), next_tree_info: None, - tree_type: TreeType::StateV2, - }, - TreeInfo { - tree: pubkey!("bmt5yU97jC88YXTuSukYHa8Z5Bi2ZDUtmzfkDTA2mG2"), - queue: pubkey!("oq5oh5ZR3yGomuQgFduNDzjtGvVWfDRGLuDVjv9a96P"), - cpi_context: Some(pubkey!("cpi5ZTjdgYpZ1Xr7B1cMLLUE81oTtJbNNAyKary2nV6")), - next_tree_info: None, - tree_type: TreeType::StateV2, - }, - ]; - - #[cfg(not(feature = "v2"))] - let default_trees = vec![TreeInfo { - tree: pubkey!("smt1NamzXdq4AMqS2fS2F1i5KTYPZRhoHgWx38d8WsT"), - queue: pubkey!("nfq1NvQDJ2GEgnS8zt9prAe8rjjpAW1zFkrvZoBR148"), - cpi_context: Some(pubkey!("cpi1uHzrEhBG733DoEJNgHCyRS3XmmyVNZx5fonubE4")), - next_tree_info: None, - tree_type: TreeType::StateV1, - }]; - - self.state_merkle_trees = default_trees.clone(); - return Ok(default_trees); - } + tree_type: TreeType::StateV1, + }]; + self.state_merkle_trees = default_trees.clone(); + return Ok(default_trees); + } - let (mainnet_tables, devnet_tables) = default_state_tree_lookup_tables(); + let (mainnet_tables, devnet_tables) = default_state_tree_lookup_tables(); - let lookup_tables = match network { - RpcUrl::Devnet | RpcUrl::Testnet | RpcUrl::ZKTestnet => &devnet_tables, - _ => &mainnet_tables, // Default to mainnet for production and custom URLs - }; + let lookup_tables = match network { + RpcUrl::Devnet | RpcUrl::Testnet | RpcUrl::ZKTestnet => &devnet_tables, + _ => &mainnet_tables, + }; - let res = get_light_state_tree_infos( - self, - &lookup_tables[0].state_tree_lookup_table, - &lookup_tables[0].nullify_table, - ) - .await?; - self.state_merkle_trees = res.clone(); - Ok(res) + let res = get_light_state_tree_infos( + self, + &lookup_tables[0].state_tree_lookup_table, + &lookup_tables[0].nullify_table, + ) + .await?; + self.state_merkle_trees = res.clone(); + Ok(res) + } } - /// Fetch the latest state tree addresses from the cluster. + /// Returns list of state tree infos. fn get_state_tree_infos(&self) -> Vec { - self.state_merkle_trees.to_vec() + #[cfg(feature = "v2")] + { + default_v2_state_trees().to_vec() + } + #[cfg(not(feature = "v2"))] + { + self.state_merkle_trees.to_vec() + } } /// Gets a random active state tree. - /// State trees are cached and have to be fetched or set. - /// Returns v1 state trees by default, v2 state trees when v2 feature is enabled. fn get_random_state_tree_info(&self) -> Result { - let mut rng = rand::thread_rng(); - #[cfg(feature = "v2")] - let filtered_trees: Vec = self - .state_merkle_trees - .iter() - .filter(|tree| tree.tree_type == TreeType::StateV2) - .copied() - .collect(); + { + use rand::Rng; + let mut rng = rand::thread_rng(); + let trees = default_v2_state_trees(); + Ok(trees[rng.gen_range(0..trees.len())]) + } #[cfg(not(feature = "v2"))] - let filtered_trees: Vec = self - .state_merkle_trees - .iter() - .filter(|tree| tree.tree_type == TreeType::StateV1) - .copied() - .collect(); - - select_state_tree_info(&mut rng, &filtered_trees) + { + let mut rng = rand::thread_rng(); + let filtered_trees: Vec = self + .state_merkle_trees + .iter() + .filter(|tree| tree.tree_type == TreeType::StateV1) + .copied() + .collect(); + select_state_tree_info(&mut rng, &filtered_trees) + } } /// Gets a random v1 state tree. From 7dde10a9620e2de8efbc2f86eec0912379e480c6 Mon Sep 17 00:00:00 2001 From: Swenschaeferjohann Date: Fri, 6 Feb 2026 04:46:33 +0000 Subject: [PATCH 2/2] format --- sdk-libs/client/src/rpc/client.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/sdk-libs/client/src/rpc/client.rs b/sdk-libs/client/src/rpc/client.rs index 6f27075187..5fd58211d8 100644 --- a/sdk-libs/client/src/rpc/client.rs +++ b/sdk-libs/client/src/rpc/client.rs @@ -30,6 +30,10 @@ use tokio::time::{sleep, Instant}; use tracing::warn; use super::LightClientConfig; +#[cfg(not(feature = "v2"))] +use crate::rpc::get_light_state_tree_infos::{ + default_state_tree_lookup_tables, get_light_state_tree_infos, +}; use crate::{ indexer::{ photon_indexer::PhotonIndexer, AccountInterface as IndexerAccountInterface, Indexer, @@ -39,10 +43,6 @@ use crate::{ interface::{AccountInterface, MintInterface, MintState, TokenAccountInterface}, rpc::{errors::RpcError, merkle_tree::MerkleTreeExt, Rpc}, }; -#[cfg(not(feature = "v2"))] -use crate::rpc::get_light_state_tree_infos::{ - default_state_tree_lookup_tables, get_light_state_tree_infos, -}; /// V2 batched state trees. #[cfg(feature = "v2")]