light_client/rpc/
get_light_state_tree_infos.rs

1use light_compressed_account::TreeType;
2use solana_address_lookup_table_interface::state::AddressLookupTable;
3use solana_pubkey::Pubkey;
4
5use crate::{
6    constants::{
7        NULLIFIED_STATE_TREE_LOOKUP_TABLE_DEVNET, NULLIFIED_STATE_TREE_LOOKUP_TABLE_MAINNET,
8        STATE_TREE_LOOKUP_TABLE_DEVNET, STATE_TREE_LOOKUP_TABLE_MAINNET,
9    },
10    indexer::TreeInfo,
11    rpc::{errors::RpcError, LightClient, Rpc},
12};
13
14/// Represents a pair of state tree lookup tables
15pub struct StateTreeLUTPair {
16    pub state_tree_lookup_table: Pubkey,
17    pub nullify_table: Pubkey,
18}
19
20/// Returns the Default Public State Tree LUTs for Devnet and Mainnet-Beta.
21pub fn default_state_tree_lookup_tables() -> (Vec<StateTreeLUTPair>, Vec<StateTreeLUTPair>) {
22    let mainnet = vec![StateTreeLUTPair {
23        state_tree_lookup_table: STATE_TREE_LOOKUP_TABLE_MAINNET,
24        nullify_table: NULLIFIED_STATE_TREE_LOOKUP_TABLE_MAINNET,
25    }];
26
27    let devnet = vec![StateTreeLUTPair {
28        state_tree_lookup_table: STATE_TREE_LOOKUP_TABLE_DEVNET,
29        nullify_table: NULLIFIED_STATE_TREE_LOOKUP_TABLE_DEVNET,
30    }];
31
32    (mainnet, devnet)
33}
34
35/// Get a random tree and queue from the active state tree addresses.
36///
37/// Prevents write lock contention on state trees.
38///
39/// # Arguments
40/// * `info` - The active state tree addresses
41///
42/// # Returns
43/// A random tree and queue
44pub fn pick_random_tree_and_queue(info: &[TreeInfo]) -> Result<(Pubkey, Pubkey), RpcError> {
45    let length = info.len();
46    if length == 0 {
47        return Err(RpcError::StateTreeLookupTableNotFound);
48    }
49
50    let index = rand::random::<usize>() % length;
51
52    let tree = info[index].tree;
53    let queue = info[index].queue;
54
55    Ok((tree, queue))
56}
57
58pub async fn get_light_state_tree_infos(
59    rpc_client: &LightClient,
60    state_tree_lookup_table_address: &Pubkey,
61    nullify_table_address: &Pubkey,
62) -> Result<Vec<TreeInfo>, RpcError> {
63    let account = rpc_client
64        .get_account(*state_tree_lookup_table_address)
65        .await
66        .map_err(|_| RpcError::StateTreeLookupTableNotFound)?
67        .ok_or(RpcError::StateTreeLookupTableNotFound)?;
68
69    let state_tree_lookup_table = AddressLookupTable::deserialize(&account.data)
70        .map_err(|_| RpcError::StateTreeLookupTableNotFound)?;
71    let state_tree_pubkeys = state_tree_lookup_table.addresses.to_vec();
72
73    if state_tree_pubkeys.len() % 3 != 0 {
74        return Err(RpcError::InvalidStateTreeLookupTable);
75    }
76
77    let account = rpc_client
78        .get_account(*nullify_table_address)
79        .await
80        .map_err(|_| RpcError::StateTreeLookupTableNotFound)?
81        .ok_or(RpcError::StateTreeLookupTableNotFound)?;
82
83    let nullify_table = AddressLookupTable::deserialize(&account.data)
84        .map_err(|_| RpcError::StateTreeLookupTableNotFound)?;
85
86    let nullify_table_pubkeys = nullify_table.addresses.to_vec();
87
88    let mut bundles = Vec::new();
89
90    for chunk in state_tree_pubkeys.chunks(3) {
91        if let [tree, queue, cpi_context] = chunk {
92            if !nullify_table_pubkeys.contains(tree) {
93                bundles.push(TreeInfo {
94                    tree: *tree,
95                    queue: *queue,
96                    cpi_context: Some(*cpi_context),
97                    next_tree_info: None,
98                    tree_type: TreeType::StateV1,
99                });
100            }
101        }
102    }
103
104    Ok(bundles)
105}