Move getSecondaryIndexKeySize RPC to admin_rpc_service (#29003)
* Move getSecondaryIndexKeySize to admin_rpc_service * Add AdminRpc test framework * Move test to admin_rpc_service * Update test * Remove full-api infra
This commit is contained in:
parent
6ebbaf30c9
commit
c8dd5bbd48
|
@ -6833,6 +6833,7 @@ dependencies = [
|
|||
"serde_json",
|
||||
"serde_yaml 0.9.13",
|
||||
"signal-hook",
|
||||
"solana-account-decoder",
|
||||
"solana-clap-utils",
|
||||
"solana-cli-config",
|
||||
"solana-core",
|
||||
|
@ -6859,6 +6860,7 @@ dependencies = [
|
|||
"solana-tpu-client",
|
||||
"solana-version",
|
||||
"solana-vote-program",
|
||||
"spl-token-2022",
|
||||
"symlink",
|
||||
"tikv-jemallocator",
|
||||
]
|
||||
|
|
392
rpc/src/rpc.rs
392
rpc/src/rpc.rs
|
@ -114,14 +114,6 @@ type RpcCustomResult<T> = std::result::Result<T, RpcCustomError>;
|
|||
pub const MAX_REQUEST_BODY_SIZE: usize = 50 * (1 << 10); // 50kB
|
||||
pub const PERFORMANCE_SAMPLES_LIMIT: usize = 720;
|
||||
|
||||
fn rpc_account_index_from_account_index(account_index: &AccountIndex) -> RpcAccountIndex {
|
||||
match account_index {
|
||||
AccountIndex::ProgramId => RpcAccountIndex::ProgramId,
|
||||
AccountIndex::SplTokenOwner => RpcAccountIndex::SplTokenOwner,
|
||||
AccountIndex::SplTokenMint => RpcAccountIndex::SplTokenMint,
|
||||
}
|
||||
}
|
||||
|
||||
fn new_response<T>(bank: &Bank, value: T) -> RpcResponse<T> {
|
||||
RpcResponse {
|
||||
context: RpcResponseContext::new(bank.slot()),
|
||||
|
@ -504,51 +496,6 @@ impl JsonRpcRequestProcessor {
|
|||
})
|
||||
}
|
||||
|
||||
pub fn get_secondary_index_key_size(
|
||||
&self,
|
||||
index_key: &Pubkey,
|
||||
config: Option<RpcContextConfig>,
|
||||
) -> Result<RpcResponse<HashMap<RpcAccountIndex, usize>>> {
|
||||
// Acquire the bank
|
||||
let bank = self.get_bank_with_config(config.unwrap_or_default())?;
|
||||
|
||||
// Exit if secondary indexes are not enabled
|
||||
if self.config.account_indexes.is_empty() {
|
||||
debug!("get_secondary_index_key_size: secondary index not enabled.");
|
||||
return Ok(new_response(&bank, HashMap::new()));
|
||||
};
|
||||
|
||||
// Make sure the requested key is not explicitly excluded
|
||||
if !self.config.account_indexes.include_key(index_key) {
|
||||
return Err(RpcCustomError::KeyExcludedFromSecondaryIndex {
|
||||
index_key: index_key.to_string(),
|
||||
}
|
||||
.into());
|
||||
}
|
||||
|
||||
// Grab a ref to the AccountsIndex for this Bank
|
||||
let accounts_index = &bank.accounts().accounts_db.accounts_index;
|
||||
|
||||
// Find the size of the key in every index where it exists
|
||||
let found_sizes = self
|
||||
.config
|
||||
.account_indexes
|
||||
.indexes
|
||||
.iter()
|
||||
.filter_map(|index| {
|
||||
accounts_index
|
||||
.get_index_key_size(index, index_key)
|
||||
.map(|size| (rpc_account_index_from_account_index(index), size))
|
||||
})
|
||||
.collect::<HashMap<_, _>>();
|
||||
|
||||
// Note: Will return an empty HashMap if no keys are found.
|
||||
if found_sizes.is_empty() {
|
||||
debug!("get_secondary_index_key_size: key not found in the secondary index.");
|
||||
}
|
||||
Ok(new_response(&bank, found_sizes))
|
||||
}
|
||||
|
||||
pub async fn get_inflation_reward(
|
||||
&self,
|
||||
addresses: Vec<Pubkey>,
|
||||
|
@ -2262,7 +2209,7 @@ fn verify_filter(input: &RpcFilterType) -> Result<()> {
|
|||
.map_err(|e| Error::invalid_params(format!("Invalid param: {e:?}")))
|
||||
}
|
||||
|
||||
fn verify_pubkey(input: &str) -> Result<Pubkey> {
|
||||
pub fn verify_pubkey(input: &str) -> Result<Pubkey> {
|
||||
input
|
||||
.parse()
|
||||
.map_err(|e| Error::invalid_params(format!("Invalid param: {e:?}")))
|
||||
|
@ -3155,16 +3102,6 @@ pub mod rpc_accounts_scan {
|
|||
config: Option<RpcProgramAccountsConfig>,
|
||||
) -> Result<OptionalContext<Vec<RpcKeyedAccount>>>;
|
||||
|
||||
// This method does not itself do an accounts scan, but returns data only relevant to nodes
|
||||
// that do support accounts-scan RPC apis
|
||||
#[rpc(meta, name = "getSecondaryIndexKeySize")]
|
||||
fn get_secondary_index_key_size(
|
||||
&self,
|
||||
meta: Self::Metadata,
|
||||
pubkey_str: String,
|
||||
config: Option<RpcContextConfig>,
|
||||
) -> Result<RpcResponse<HashMap<RpcAccountIndex, usize>>>;
|
||||
|
||||
#[rpc(meta, name = "getLargestAccounts")]
|
||||
fn get_largest_accounts(
|
||||
&self,
|
||||
|
@ -3245,20 +3182,6 @@ pub mod rpc_accounts_scan {
|
|||
meta.get_program_accounts(&program_id, config, filters, with_context)
|
||||
}
|
||||
|
||||
fn get_secondary_index_key_size(
|
||||
&self,
|
||||
meta: Self::Metadata,
|
||||
pubkey_str: String,
|
||||
config: Option<RpcContextConfig>,
|
||||
) -> Result<RpcResponse<HashMap<RpcAccountIndex, usize>>> {
|
||||
debug!(
|
||||
"get_secondary_index_key_size rpc request received: {:?}",
|
||||
pubkey_str
|
||||
);
|
||||
let index_key = verify_pubkey(&pubkey_str)?;
|
||||
meta.get_secondary_index_key_size(&index_key, config)
|
||||
}
|
||||
|
||||
fn get_largest_accounts(
|
||||
&self,
|
||||
meta: Self::Metadata,
|
||||
|
@ -4562,7 +4485,7 @@ fn sanitize_transaction(
|
|||
.map_err(|err| Error::invalid_params(format!("invalid transaction: {err}")))
|
||||
}
|
||||
|
||||
pub(crate) fn create_validator_exit(exit: &Arc<AtomicBool>) -> Arc<RwLock<Exit>> {
|
||||
pub fn create_validator_exit(exit: &Arc<AtomicBool>) -> Arc<RwLock<Exit>> {
|
||||
let mut validator_exit = Exit::default();
|
||||
let exit_ = exit.clone();
|
||||
validator_exit.register_exit(Box::new(move || exit_.store(true, Ordering::Relaxed)));
|
||||
|
@ -4672,7 +4595,6 @@ pub mod tests {
|
|||
jsonrpc_core::{futures, ErrorCode, MetaIoHandler, Output, Response, Value},
|
||||
jsonrpc_core_client::transports::local,
|
||||
serde::de::DeserializeOwned,
|
||||
solana_account_decoder::parse_token::spl_token_pubkey,
|
||||
solana_address_lookup_table_program::state::{AddressLookupTable, LookupTableMeta},
|
||||
solana_entry::entry::next_versioned_entry,
|
||||
solana_gossip::{contact_info::ContactInfo, socketaddr},
|
||||
|
@ -7433,316 +7355,6 @@ pub mod tests {
|
|||
));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_secondary_index_key_sizes() {
|
||||
for secondary_index_enabled in [true, false] {
|
||||
let account_indexes = if secondary_index_enabled {
|
||||
AccountSecondaryIndexes {
|
||||
keys: None,
|
||||
indexes: HashSet::from([
|
||||
AccountIndex::ProgramId,
|
||||
AccountIndex::SplTokenMint,
|
||||
AccountIndex::SplTokenOwner,
|
||||
]),
|
||||
}
|
||||
} else {
|
||||
AccountSecondaryIndexes::default()
|
||||
};
|
||||
|
||||
// RPC & Bank Setup
|
||||
let rpc = RpcHandler::start_with_config(JsonRpcConfig {
|
||||
enable_rpc_transaction_history: true,
|
||||
account_indexes,
|
||||
..JsonRpcConfig::default()
|
||||
});
|
||||
|
||||
let bank = rpc.working_bank();
|
||||
let RpcHandler { io, meta, .. } = rpc;
|
||||
|
||||
// Pubkeys
|
||||
let token_account1_pubkey = Pubkey::new_unique();
|
||||
let token_account2_pubkey = Pubkey::new_unique();
|
||||
let token_account3_pubkey = Pubkey::new_unique();
|
||||
let mint1_pubkey = Pubkey::new_unique();
|
||||
let mint2_pubkey = Pubkey::new_unique();
|
||||
let wallet1_pubkey = Pubkey::new_unique();
|
||||
let wallet2_pubkey = Pubkey::new_unique();
|
||||
let non_existent_pubkey = Pubkey::new_unique();
|
||||
let delegate = spl_token_pubkey(&Pubkey::new_unique());
|
||||
|
||||
let mut num_default_spl_token_program_accounts = 0;
|
||||
let mut num_default_system_program_accounts = 0;
|
||||
|
||||
if !secondary_index_enabled {
|
||||
// Test first with no accounts added & no secondary indexes enabled:
|
||||
let req = format!(
|
||||
r#"{{"jsonrpc":"2.0","id":1,"method":"getSecondaryIndexKeySize","params":["{token_account1_pubkey}"]}}"#,
|
||||
);
|
||||
let res = io.handle_request_sync(&req, meta.clone());
|
||||
let result: Value = serde_json::from_str(&res.expect("actual response"))
|
||||
.expect("actual response deserialization");
|
||||
let sizes: HashMap<RpcAccountIndex, usize> =
|
||||
serde_json::from_value(result["result"]["value"].clone()).unwrap();
|
||||
assert!(sizes.is_empty());
|
||||
} else {
|
||||
// Count SPL Token Program Default Accounts
|
||||
let req = format!(
|
||||
r#"{{"jsonrpc":"2.0","id":1,"method":"getSecondaryIndexKeySize","params":["{}"]}}"#,
|
||||
inline_spl_token::id(),
|
||||
);
|
||||
let res = io.handle_request_sync(&req, meta.clone());
|
||||
let result: Value = serde_json::from_str(&res.expect("actual response"))
|
||||
.expect("actual response deserialization");
|
||||
let sizes: HashMap<RpcAccountIndex, usize> =
|
||||
serde_json::from_value(result["result"]["value"].clone()).unwrap();
|
||||
assert_eq!(sizes.len(), 1);
|
||||
num_default_spl_token_program_accounts =
|
||||
*sizes.get(&RpcAccountIndex::ProgramId).unwrap();
|
||||
// Count System Program Default Accounts
|
||||
let req = format!(
|
||||
r#"{{"jsonrpc":"2.0","id":1,"method":"getSecondaryIndexKeySize","params":["{}"]}}"#,
|
||||
system_program::id(),
|
||||
);
|
||||
let res = io.handle_request_sync(&req, meta.clone());
|
||||
let result: Value = serde_json::from_str(&res.expect("actual response"))
|
||||
.expect("actual response deserialization");
|
||||
let sizes: HashMap<RpcAccountIndex, usize> =
|
||||
serde_json::from_value(result["result"]["value"].clone()).unwrap();
|
||||
assert_eq!(sizes.len(), 1);
|
||||
num_default_system_program_accounts =
|
||||
*sizes.get(&RpcAccountIndex::ProgramId).unwrap();
|
||||
}
|
||||
|
||||
// Add 2 basic wallet accounts
|
||||
let wallet1_account = AccountSharedData::from(Account {
|
||||
lamports: 11111111,
|
||||
owner: system_program::id(),
|
||||
..Account::default()
|
||||
});
|
||||
bank.store_account(&wallet1_pubkey, &wallet1_account);
|
||||
let wallet2_account = AccountSharedData::from(Account {
|
||||
lamports: 11111111,
|
||||
owner: system_program::id(),
|
||||
..Account::default()
|
||||
});
|
||||
bank.store_account(&wallet2_pubkey, &wallet2_account);
|
||||
|
||||
// Add a token account
|
||||
let mut account1_data = vec![0; TokenAccount::get_packed_len()];
|
||||
let token_account1 = TokenAccount {
|
||||
mint: spl_token_pubkey(&mint1_pubkey),
|
||||
owner: spl_token_pubkey(&wallet1_pubkey),
|
||||
delegate: COption::Some(delegate),
|
||||
amount: 420,
|
||||
state: TokenAccountState::Initialized,
|
||||
is_native: COption::None,
|
||||
delegated_amount: 30,
|
||||
close_authority: COption::Some(spl_token_pubkey(&wallet1_pubkey)),
|
||||
};
|
||||
TokenAccount::pack(token_account1, &mut account1_data).unwrap();
|
||||
let token_account1 = AccountSharedData::from(Account {
|
||||
lamports: 111,
|
||||
data: account1_data.to_vec(),
|
||||
owner: inline_spl_token::id(),
|
||||
..Account::default()
|
||||
});
|
||||
bank.store_account(&token_account1_pubkey, &token_account1);
|
||||
|
||||
// Add the mint
|
||||
let mut mint1_data = vec![0; Mint::get_packed_len()];
|
||||
let mint1_state = Mint {
|
||||
mint_authority: COption::Some(spl_token_pubkey(&wallet1_pubkey)),
|
||||
supply: 500,
|
||||
decimals: 2,
|
||||
is_initialized: true,
|
||||
freeze_authority: COption::Some(spl_token_pubkey(&wallet1_pubkey)),
|
||||
};
|
||||
Mint::pack(mint1_state, &mut mint1_data).unwrap();
|
||||
let mint_account1 = AccountSharedData::from(Account {
|
||||
lamports: 222,
|
||||
data: mint1_data.to_vec(),
|
||||
owner: inline_spl_token::id(),
|
||||
..Account::default()
|
||||
});
|
||||
bank.store_account(&mint1_pubkey, &mint_account1);
|
||||
|
||||
// Add another token account with the different owner, but same delegate, and mint
|
||||
let mut account2_data = vec![0; TokenAccount::get_packed_len()];
|
||||
let token_account2 = TokenAccount {
|
||||
mint: spl_token_pubkey(&mint1_pubkey),
|
||||
owner: spl_token_pubkey(&wallet2_pubkey),
|
||||
delegate: COption::Some(delegate),
|
||||
amount: 420,
|
||||
state: TokenAccountState::Initialized,
|
||||
is_native: COption::None,
|
||||
delegated_amount: 30,
|
||||
close_authority: COption::Some(spl_token_pubkey(&wallet2_pubkey)),
|
||||
};
|
||||
TokenAccount::pack(token_account2, &mut account2_data).unwrap();
|
||||
let token_account2 = AccountSharedData::from(Account {
|
||||
lamports: 333,
|
||||
data: account2_data.to_vec(),
|
||||
owner: inline_spl_token::id(),
|
||||
..Account::default()
|
||||
});
|
||||
bank.store_account(&token_account2_pubkey, &token_account2);
|
||||
|
||||
// Add another token account with the same owner and delegate but different mint
|
||||
let mut account3_data = vec![0; TokenAccount::get_packed_len()];
|
||||
let token_account3 = TokenAccount {
|
||||
mint: spl_token_pubkey(&mint2_pubkey),
|
||||
owner: spl_token_pubkey(&wallet2_pubkey),
|
||||
delegate: COption::Some(delegate),
|
||||
amount: 42,
|
||||
state: TokenAccountState::Initialized,
|
||||
is_native: COption::None,
|
||||
delegated_amount: 30,
|
||||
close_authority: COption::Some(spl_token_pubkey(&wallet2_pubkey)),
|
||||
};
|
||||
TokenAccount::pack(token_account3, &mut account3_data).unwrap();
|
||||
let token_account3 = AccountSharedData::from(Account {
|
||||
lamports: 444,
|
||||
data: account3_data.to_vec(),
|
||||
owner: inline_spl_token::id(),
|
||||
..Account::default()
|
||||
});
|
||||
bank.store_account(&token_account3_pubkey, &token_account3);
|
||||
|
||||
// Add the new mint
|
||||
let mut mint2_data = vec![0; Mint::get_packed_len()];
|
||||
let mint2_state = Mint {
|
||||
mint_authority: COption::Some(spl_token_pubkey(&wallet2_pubkey)),
|
||||
supply: 200,
|
||||
decimals: 3,
|
||||
is_initialized: true,
|
||||
freeze_authority: COption::Some(spl_token_pubkey(&wallet2_pubkey)),
|
||||
};
|
||||
Mint::pack(mint2_state, &mut mint2_data).unwrap();
|
||||
let mint_account2 = AccountSharedData::from(Account {
|
||||
lamports: 555,
|
||||
data: mint2_data.to_vec(),
|
||||
owner: inline_spl_token::id(),
|
||||
..Account::default()
|
||||
});
|
||||
bank.store_account(&mint2_pubkey, &mint_account2);
|
||||
|
||||
// Accounts should now look like the following:
|
||||
//
|
||||
// -----system_program------
|
||||
// / \
|
||||
// /-(owns) \-(owns)
|
||||
// / \
|
||||
// wallet1 ---wallet2---
|
||||
// / / \
|
||||
// /-(SPL::owns) /-(SPL::owns) \-(SPL::owns)
|
||||
// / / \
|
||||
// token_account1 token_account2 token_account3
|
||||
// \ / /
|
||||
// \-(SPL::mint) /-(SPL::mint) /-(SPL::mint)
|
||||
// \ / /
|
||||
// --mint_account1-- mint_account2
|
||||
|
||||
if secondary_index_enabled {
|
||||
// ----------- Test for a non-existant key -----------
|
||||
let req = format!(
|
||||
r#"{{"jsonrpc":"2.0","id":1,"method":"getSecondaryIndexKeySize","params":["{non_existent_pubkey}"]}}"#,
|
||||
);
|
||||
let res = io.handle_request_sync(&req, meta.clone());
|
||||
let result: Value = serde_json::from_str(&res.expect("actual response"))
|
||||
.expect("actual response deserialization");
|
||||
let sizes: HashMap<RpcAccountIndex, usize> =
|
||||
serde_json::from_value(result["result"]["value"].clone()).unwrap();
|
||||
assert!(sizes.is_empty());
|
||||
// --------------- Test Queries ---------------
|
||||
// 1) Wallet1 - Owns 1 SPL Token
|
||||
let req = format!(
|
||||
r#"{{"jsonrpc":"2.0","id":1,"method":"getSecondaryIndexKeySize","params":["{wallet1_pubkey}"]}}"#,
|
||||
);
|
||||
let res = io.handle_request_sync(&req, meta.clone());
|
||||
let result: Value = serde_json::from_str(&res.expect("actual response"))
|
||||
.expect("actual response deserialization");
|
||||
let sizes: HashMap<RpcAccountIndex, usize> =
|
||||
serde_json::from_value(result["result"]["value"].clone()).unwrap();
|
||||
assert_eq!(sizes.len(), 1);
|
||||
assert_eq!(*sizes.get(&RpcAccountIndex::SplTokenOwner).unwrap(), 1);
|
||||
// 2) Wallet2 - Owns 2 SPL Tokens
|
||||
let req = format!(
|
||||
r#"{{"jsonrpc":"2.0","id":1,"method":"getSecondaryIndexKeySize","params":["{wallet2_pubkey}"]}}"#,
|
||||
);
|
||||
let res = io.handle_request_sync(&req, meta.clone());
|
||||
let result: Value = serde_json::from_str(&res.expect("actual response"))
|
||||
.expect("actual response deserialization");
|
||||
let sizes: HashMap<RpcAccountIndex, usize> =
|
||||
serde_json::from_value(result["result"]["value"].clone()).unwrap();
|
||||
assert_eq!(sizes.len(), 1);
|
||||
assert_eq!(*sizes.get(&RpcAccountIndex::SplTokenOwner).unwrap(), 2);
|
||||
// 3) Mint1 - Is in 2 SPL Accounts
|
||||
let req = format!(
|
||||
r#"{{"jsonrpc":"2.0","id":1,"method":"getSecondaryIndexKeySize","params":["{mint1_pubkey}"]}}"#,
|
||||
);
|
||||
let res = io.handle_request_sync(&req, meta.clone());
|
||||
let result: Value = serde_json::from_str(&res.expect("actual response"))
|
||||
.expect("actual response deserialization");
|
||||
let sizes: HashMap<RpcAccountIndex, usize> =
|
||||
serde_json::from_value(result["result"]["value"].clone()).unwrap();
|
||||
assert_eq!(sizes.len(), 1);
|
||||
assert_eq!(*sizes.get(&RpcAccountIndex::SplTokenMint).unwrap(), 2);
|
||||
// 4) Mint2 - Is in 1 SPL Account
|
||||
let req = format!(
|
||||
r#"{{"jsonrpc":"2.0","id":1,"method":"getSecondaryIndexKeySize","params":["{mint2_pubkey}"]}}"#,
|
||||
);
|
||||
let res = io.handle_request_sync(&req, meta.clone());
|
||||
let result: Value = serde_json::from_str(&res.expect("actual response"))
|
||||
.expect("actual response deserialization");
|
||||
let sizes: HashMap<RpcAccountIndex, usize> =
|
||||
serde_json::from_value(result["result"]["value"].clone()).unwrap();
|
||||
assert_eq!(sizes.len(), 1);
|
||||
assert_eq!(*sizes.get(&RpcAccountIndex::SplTokenMint).unwrap(), 1);
|
||||
// 5) SPL Token Program Owns 6 Accounts - 1 Default, 5 created above.
|
||||
let req = format!(
|
||||
r#"{{"jsonrpc":"2.0","id":1,"method":"getSecondaryIndexKeySize","params":["{}"]}}"#,
|
||||
inline_spl_token::id(),
|
||||
);
|
||||
let res = io.handle_request_sync(&req, meta.clone());
|
||||
let result: Value = serde_json::from_str(&res.expect("actual response"))
|
||||
.expect("actual response deserialization");
|
||||
let sizes: HashMap<RpcAccountIndex, usize> =
|
||||
serde_json::from_value(result["result"]["value"].clone()).unwrap();
|
||||
assert_eq!(sizes.len(), 1);
|
||||
assert_eq!(
|
||||
*sizes.get(&RpcAccountIndex::ProgramId).unwrap(),
|
||||
(num_default_spl_token_program_accounts + 5)
|
||||
);
|
||||
// 5) System Program Owns 4 Accounts + 2 Default, 2 created above.
|
||||
let req = format!(
|
||||
r#"{{"jsonrpc":"2.0","id":1,"method":"getSecondaryIndexKeySize","params":["{}"]}}"#,
|
||||
system_program::id(),
|
||||
);
|
||||
let res = io.handle_request_sync(&req, meta.clone());
|
||||
let result: Value = serde_json::from_str(&res.expect("actual response"))
|
||||
.expect("actual response deserialization");
|
||||
let sizes: HashMap<RpcAccountIndex, usize> =
|
||||
serde_json::from_value(result["result"]["value"].clone()).unwrap();
|
||||
assert_eq!(sizes.len(), 1);
|
||||
assert_eq!(
|
||||
*sizes.get(&RpcAccountIndex::ProgramId).unwrap(),
|
||||
(num_default_system_program_accounts + 2)
|
||||
);
|
||||
} else {
|
||||
// ------------ Secondary Indexes Disabled ------------
|
||||
let req = format!(
|
||||
r#"{{"jsonrpc":"2.0","id":1,"method":"getSecondaryIndexKeySize","params":["{token_account2_pubkey}"]}}"#,
|
||||
);
|
||||
let res = io.handle_request_sync(&req, meta.clone());
|
||||
let result: Value = serde_json::from_str(&res.expect("actual response"))
|
||||
.expect("actual response deserialization");
|
||||
let sizes: HashMap<RpcAccountIndex, usize> =
|
||||
serde_json::from_value(result["result"]["value"].clone()).unwrap();
|
||||
assert!(sizes.is_empty());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_token_rpcs() {
|
||||
for program_id in solana_account_decoder::parse_token::spl_token_ids() {
|
||||
|
|
|
@ -59,6 +59,10 @@ solana-version = { path = "../version", version = "=1.15.0" }
|
|||
solana-vote-program = { path = "../programs/vote", version = "=1.15.0" }
|
||||
symlink = "0.1.0"
|
||||
|
||||
[dev-dependencies]
|
||||
solana-account-decoder = { path = "../account-decoder", version = "=1.15.0" }
|
||||
spl-token-2022 = { version = "=0.5.0", features = ["no-entrypoint"] }
|
||||
|
||||
[target.'cfg(not(target_env = "msvc"))'.dependencies]
|
||||
jemallocator = { package = "tikv-jemallocator", version = "0.4.1", features = ["unprefixed_malloc_on_supported_platforms"] }
|
||||
|
||||
|
|
|
@ -10,7 +10,9 @@ use {
|
|||
consensus::Tower, tower_storage::TowerStorage, validator::ValidatorStartProgress,
|
||||
},
|
||||
solana_gossip::{cluster_info::ClusterInfo, contact_info::ContactInfo},
|
||||
solana_runtime::bank_forks::BankForks,
|
||||
solana_rpc::rpc::verify_pubkey,
|
||||
solana_rpc_client_api::{config::RpcAccountIndex, custom_error::RpcCustomError},
|
||||
solana_runtime::{accounts_index::AccountIndex, bank_forks::BankForks},
|
||||
solana_sdk::{
|
||||
exit::Exit,
|
||||
pubkey::Pubkey,
|
||||
|
@ -201,6 +203,13 @@ pub trait AdminRpc {
|
|||
|
||||
#[rpc(meta, name = "setRepairWhitelist")]
|
||||
fn set_repair_whitelist(&self, meta: Self::Metadata, whitelist: Vec<Pubkey>) -> Result<()>;
|
||||
|
||||
#[rpc(meta, name = "getSecondaryIndexKeySize")]
|
||||
fn get_secondary_index_key_size(
|
||||
&self,
|
||||
meta: Self::Metadata,
|
||||
pubkey_str: String,
|
||||
) -> Result<HashMap<RpcAccountIndex, usize>>;
|
||||
}
|
||||
|
||||
pub struct AdminRpcImpl;
|
||||
|
@ -368,6 +377,58 @@ impl AdminRpc for AdminRpcImpl {
|
|||
Ok(())
|
||||
})
|
||||
}
|
||||
|
||||
fn get_secondary_index_key_size(
|
||||
&self,
|
||||
meta: Self::Metadata,
|
||||
pubkey_str: String,
|
||||
) -> Result<HashMap<RpcAccountIndex, usize>> {
|
||||
debug!(
|
||||
"get_secondary_index_key_size rpc request received: {:?}",
|
||||
pubkey_str
|
||||
);
|
||||
let index_key = verify_pubkey(&pubkey_str)?;
|
||||
meta.with_post_init(|post_init| {
|
||||
let bank = post_init.bank_forks.read().unwrap().root_bank();
|
||||
|
||||
// Take ref to enabled AccountSecondaryIndexes
|
||||
let enabled_account_indexes = &bank.accounts().accounts_db.account_indexes;
|
||||
|
||||
// Exit if secondary indexes are not enabled
|
||||
if enabled_account_indexes.is_empty() {
|
||||
debug!("get_secondary_index_key_size: secondary index not enabled.");
|
||||
return Ok(HashMap::new());
|
||||
};
|
||||
|
||||
// Make sure the requested key is not explicitly excluded
|
||||
if !enabled_account_indexes.include_key(&index_key) {
|
||||
return Err(RpcCustomError::KeyExcludedFromSecondaryIndex {
|
||||
index_key: index_key.to_string(),
|
||||
}
|
||||
.into());
|
||||
}
|
||||
|
||||
// Grab a ref to the AccountsDbfor this Bank
|
||||
let accounts_index = &bank.accounts().accounts_db.accounts_index;
|
||||
|
||||
// Find the size of the key in every index where it exists
|
||||
let found_sizes = enabled_account_indexes
|
||||
.indexes
|
||||
.iter()
|
||||
.filter_map(|index| {
|
||||
accounts_index
|
||||
.get_index_key_size(index, &index_key)
|
||||
.map(|size| (rpc_account_index_from_account_index(index), size))
|
||||
})
|
||||
.collect::<HashMap<_, _>>();
|
||||
|
||||
// Note: Will return an empty HashMap if no keys are found.
|
||||
if found_sizes.is_empty() {
|
||||
debug!("get_secondary_index_key_size: key not found in the secondary index.");
|
||||
}
|
||||
Ok(found_sizes)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl AdminRpcImpl {
|
||||
|
@ -417,6 +478,14 @@ impl AdminRpcImpl {
|
|||
}
|
||||
}
|
||||
|
||||
fn rpc_account_index_from_account_index(account_index: &AccountIndex) -> RpcAccountIndex {
|
||||
match account_index {
|
||||
AccountIndex::ProgramId => RpcAccountIndex::ProgramId,
|
||||
AccountIndex::SplTokenOwner => RpcAccountIndex::SplTokenOwner,
|
||||
AccountIndex::SplTokenMint => RpcAccountIndex::SplTokenMint,
|
||||
}
|
||||
}
|
||||
|
||||
// Start the Admin RPC interface
|
||||
pub fn run(ledger_path: &Path, metadata: AdminRpcRequestMetadata) {
|
||||
let admin_rpc_path = admin_rpc_path(ledger_path);
|
||||
|
@ -529,3 +598,417 @@ pub fn load_staked_nodes_overrides(
|
|||
Err(format!("Staked nodes overrides provided '{path}' a non-existing file path.").into())
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use {
|
||||
super::*,
|
||||
serde_json::Value,
|
||||
solana_account_decoder::parse_token::spl_token_pubkey,
|
||||
solana_core::tower_storage::NullTowerStorage,
|
||||
solana_ledger::genesis_utils::{create_genesis_config, GenesisConfigInfo},
|
||||
solana_rpc::rpc::create_validator_exit,
|
||||
solana_runtime::{
|
||||
accounts_index::AccountSecondaryIndexes,
|
||||
bank::{Bank, BankTestConfig},
|
||||
inline_spl_token,
|
||||
},
|
||||
solana_sdk::{
|
||||
account::{Account, AccountSharedData},
|
||||
system_program,
|
||||
},
|
||||
solana_streamer::socket::SocketAddrSpace,
|
||||
spl_token_2022::{
|
||||
solana_program::{program_option::COption, program_pack::Pack},
|
||||
state::{Account as TokenAccount, AccountState as TokenAccountState, Mint},
|
||||
},
|
||||
std::{collections::HashSet, sync::atomic::AtomicBool},
|
||||
};
|
||||
|
||||
#[derive(Default)]
|
||||
struct TestConfig {
|
||||
account_indexes: AccountSecondaryIndexes,
|
||||
}
|
||||
|
||||
struct RpcHandler {
|
||||
io: MetaIoHandler<AdminRpcRequestMetadata>,
|
||||
meta: AdminRpcRequestMetadata,
|
||||
bank_forks: Arc<RwLock<BankForks>>,
|
||||
}
|
||||
|
||||
impl RpcHandler {
|
||||
fn _start() -> Self {
|
||||
Self::start_with_config(TestConfig::default())
|
||||
}
|
||||
|
||||
fn start_with_config(config: TestConfig) -> Self {
|
||||
let identity = Pubkey::new_unique();
|
||||
let cluster_info = Arc::new(ClusterInfo::new(
|
||||
ContactInfo {
|
||||
id: identity,
|
||||
..ContactInfo::default()
|
||||
},
|
||||
Arc::new(Keypair::new()),
|
||||
SocketAddrSpace::Unspecified,
|
||||
));
|
||||
let exit = Arc::new(AtomicBool::new(false));
|
||||
let validator_exit = create_validator_exit(&exit);
|
||||
let (bank_forks, vote_keypair) = new_bank_forks_with_config(BankTestConfig {
|
||||
secondary_indexes: config.account_indexes,
|
||||
});
|
||||
let vote_account = vote_keypair.pubkey();
|
||||
let start_progress = Arc::new(RwLock::new(ValidatorStartProgress::default()));
|
||||
let repair_whitelist = Arc::new(RwLock::new(HashSet::new()));
|
||||
let meta = AdminRpcRequestMetadata {
|
||||
rpc_addr: None,
|
||||
start_time: SystemTime::now(),
|
||||
start_progress,
|
||||
validator_exit,
|
||||
authorized_voter_keypairs: Arc::new(RwLock::new(vec![vote_keypair])),
|
||||
tower_storage: Arc::new(NullTowerStorage {}),
|
||||
post_init: Arc::new(RwLock::new(Some(AdminRpcRequestMetadataPostInit {
|
||||
cluster_info,
|
||||
bank_forks: bank_forks.clone(),
|
||||
vote_account,
|
||||
repair_whitelist,
|
||||
}))),
|
||||
staked_nodes_overrides: Arc::new(RwLock::new(HashMap::new())),
|
||||
};
|
||||
let mut io = MetaIoHandler::default();
|
||||
io.extend_with(AdminRpcImpl.to_delegate());
|
||||
|
||||
Self {
|
||||
io,
|
||||
meta,
|
||||
bank_forks,
|
||||
}
|
||||
}
|
||||
|
||||
fn root_bank(&self) -> Arc<Bank> {
|
||||
self.bank_forks.read().unwrap().root_bank()
|
||||
}
|
||||
}
|
||||
|
||||
fn new_bank_forks_with_config(
|
||||
config: BankTestConfig,
|
||||
) -> (Arc<RwLock<BankForks>>, Arc<Keypair>) {
|
||||
let GenesisConfigInfo {
|
||||
genesis_config,
|
||||
voting_keypair,
|
||||
..
|
||||
} = create_genesis_config(1_000_000_000);
|
||||
|
||||
let bank = Bank::new_for_tests_with_config(&genesis_config, config);
|
||||
(
|
||||
Arc::new(RwLock::new(BankForks::new(bank))),
|
||||
Arc::new(voting_keypair),
|
||||
)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_secondary_index_key_sizes() {
|
||||
for secondary_index_enabled in [true, false] {
|
||||
let account_indexes = if secondary_index_enabled {
|
||||
AccountSecondaryIndexes {
|
||||
keys: None,
|
||||
indexes: HashSet::from([
|
||||
AccountIndex::ProgramId,
|
||||
AccountIndex::SplTokenMint,
|
||||
AccountIndex::SplTokenOwner,
|
||||
]),
|
||||
}
|
||||
} else {
|
||||
AccountSecondaryIndexes::default()
|
||||
};
|
||||
|
||||
// RPC & Bank Setup
|
||||
let rpc = RpcHandler::start_with_config(TestConfig { account_indexes });
|
||||
|
||||
let bank = rpc.root_bank();
|
||||
let RpcHandler { io, meta, .. } = rpc;
|
||||
|
||||
// Pubkeys
|
||||
let token_account1_pubkey = Pubkey::new_unique();
|
||||
let token_account2_pubkey = Pubkey::new_unique();
|
||||
let token_account3_pubkey = Pubkey::new_unique();
|
||||
let mint1_pubkey = Pubkey::new_unique();
|
||||
let mint2_pubkey = Pubkey::new_unique();
|
||||
let wallet1_pubkey = Pubkey::new_unique();
|
||||
let wallet2_pubkey = Pubkey::new_unique();
|
||||
let non_existent_pubkey = Pubkey::new_unique();
|
||||
let delegate = spl_token_pubkey(&Pubkey::new_unique());
|
||||
|
||||
let mut num_default_spl_token_program_accounts = 0;
|
||||
let mut num_default_system_program_accounts = 0;
|
||||
|
||||
if !secondary_index_enabled {
|
||||
// Test first with no accounts added & no secondary indexes enabled:
|
||||
let req = format!(
|
||||
r#"{{"jsonrpc":"2.0","id":1,"method":"getSecondaryIndexKeySize","params":["{token_account1_pubkey}"]}}"#,
|
||||
);
|
||||
let res = io.handle_request_sync(&req, meta.clone());
|
||||
let result: Value = serde_json::from_str(&res.expect("actual response"))
|
||||
.expect("actual response deserialization");
|
||||
let sizes: HashMap<RpcAccountIndex, usize> =
|
||||
serde_json::from_value(result["result"].clone()).unwrap();
|
||||
assert!(sizes.is_empty());
|
||||
} else {
|
||||
// Count SPL Token Program Default Accounts
|
||||
let req = format!(
|
||||
r#"{{"jsonrpc":"2.0","id":1,"method":"getSecondaryIndexKeySize","params":["{}"]}}"#,
|
||||
inline_spl_token::id(),
|
||||
);
|
||||
let res = io.handle_request_sync(&req, meta.clone());
|
||||
let result: Value = serde_json::from_str(&res.expect("actual response"))
|
||||
.expect("actual response deserialization");
|
||||
println!("{:?}", result);
|
||||
let sizes: HashMap<RpcAccountIndex, usize> =
|
||||
serde_json::from_value(result["result"].clone()).unwrap();
|
||||
assert_eq!(sizes.len(), 1);
|
||||
num_default_spl_token_program_accounts =
|
||||
*sizes.get(&RpcAccountIndex::ProgramId).unwrap();
|
||||
// Count System Program Default Accounts
|
||||
let req = format!(
|
||||
r#"{{"jsonrpc":"2.0","id":1,"method":"getSecondaryIndexKeySize","params":["{}"]}}"#,
|
||||
system_program::id(),
|
||||
);
|
||||
let res = io.handle_request_sync(&req, meta.clone());
|
||||
let result: Value = serde_json::from_str(&res.expect("actual response"))
|
||||
.expect("actual response deserialization");
|
||||
let sizes: HashMap<RpcAccountIndex, usize> =
|
||||
serde_json::from_value(result["result"].clone()).unwrap();
|
||||
assert_eq!(sizes.len(), 1);
|
||||
num_default_system_program_accounts =
|
||||
*sizes.get(&RpcAccountIndex::ProgramId).unwrap();
|
||||
}
|
||||
|
||||
// Add 2 basic wallet accounts
|
||||
let wallet1_account = AccountSharedData::from(Account {
|
||||
lamports: 11111111,
|
||||
owner: system_program::id(),
|
||||
..Account::default()
|
||||
});
|
||||
bank.store_account(&wallet1_pubkey, &wallet1_account);
|
||||
let wallet2_account = AccountSharedData::from(Account {
|
||||
lamports: 11111111,
|
||||
owner: system_program::id(),
|
||||
..Account::default()
|
||||
});
|
||||
bank.store_account(&wallet2_pubkey, &wallet2_account);
|
||||
|
||||
// Add a token account
|
||||
let mut account1_data = vec![0; TokenAccount::get_packed_len()];
|
||||
let token_account1 = TokenAccount {
|
||||
mint: spl_token_pubkey(&mint1_pubkey),
|
||||
owner: spl_token_pubkey(&wallet1_pubkey),
|
||||
delegate: COption::Some(delegate),
|
||||
amount: 420,
|
||||
state: TokenAccountState::Initialized,
|
||||
is_native: COption::None,
|
||||
delegated_amount: 30,
|
||||
close_authority: COption::Some(spl_token_pubkey(&wallet1_pubkey)),
|
||||
};
|
||||
TokenAccount::pack(token_account1, &mut account1_data).unwrap();
|
||||
let token_account1 = AccountSharedData::from(Account {
|
||||
lamports: 111,
|
||||
data: account1_data.to_vec(),
|
||||
owner: inline_spl_token::id(),
|
||||
..Account::default()
|
||||
});
|
||||
bank.store_account(&token_account1_pubkey, &token_account1);
|
||||
|
||||
// Add the mint
|
||||
let mut mint1_data = vec![0; Mint::get_packed_len()];
|
||||
let mint1_state = Mint {
|
||||
mint_authority: COption::Some(spl_token_pubkey(&wallet1_pubkey)),
|
||||
supply: 500,
|
||||
decimals: 2,
|
||||
is_initialized: true,
|
||||
freeze_authority: COption::Some(spl_token_pubkey(&wallet1_pubkey)),
|
||||
};
|
||||
Mint::pack(mint1_state, &mut mint1_data).unwrap();
|
||||
let mint_account1 = AccountSharedData::from(Account {
|
||||
lamports: 222,
|
||||
data: mint1_data.to_vec(),
|
||||
owner: inline_spl_token::id(),
|
||||
..Account::default()
|
||||
});
|
||||
bank.store_account(&mint1_pubkey, &mint_account1);
|
||||
|
||||
// Add another token account with the different owner, but same delegate, and mint
|
||||
let mut account2_data = vec![0; TokenAccount::get_packed_len()];
|
||||
let token_account2 = TokenAccount {
|
||||
mint: spl_token_pubkey(&mint1_pubkey),
|
||||
owner: spl_token_pubkey(&wallet2_pubkey),
|
||||
delegate: COption::Some(delegate),
|
||||
amount: 420,
|
||||
state: TokenAccountState::Initialized,
|
||||
is_native: COption::None,
|
||||
delegated_amount: 30,
|
||||
close_authority: COption::Some(spl_token_pubkey(&wallet2_pubkey)),
|
||||
};
|
||||
TokenAccount::pack(token_account2, &mut account2_data).unwrap();
|
||||
let token_account2 = AccountSharedData::from(Account {
|
||||
lamports: 333,
|
||||
data: account2_data.to_vec(),
|
||||
owner: inline_spl_token::id(),
|
||||
..Account::default()
|
||||
});
|
||||
bank.store_account(&token_account2_pubkey, &token_account2);
|
||||
|
||||
// Add another token account with the same owner and delegate but different mint
|
||||
let mut account3_data = vec![0; TokenAccount::get_packed_len()];
|
||||
let token_account3 = TokenAccount {
|
||||
mint: spl_token_pubkey(&mint2_pubkey),
|
||||
owner: spl_token_pubkey(&wallet2_pubkey),
|
||||
delegate: COption::Some(delegate),
|
||||
amount: 42,
|
||||
state: TokenAccountState::Initialized,
|
||||
is_native: COption::None,
|
||||
delegated_amount: 30,
|
||||
close_authority: COption::Some(spl_token_pubkey(&wallet2_pubkey)),
|
||||
};
|
||||
TokenAccount::pack(token_account3, &mut account3_data).unwrap();
|
||||
let token_account3 = AccountSharedData::from(Account {
|
||||
lamports: 444,
|
||||
data: account3_data.to_vec(),
|
||||
owner: inline_spl_token::id(),
|
||||
..Account::default()
|
||||
});
|
||||
bank.store_account(&token_account3_pubkey, &token_account3);
|
||||
|
||||
// Add the new mint
|
||||
let mut mint2_data = vec![0; Mint::get_packed_len()];
|
||||
let mint2_state = Mint {
|
||||
mint_authority: COption::Some(spl_token_pubkey(&wallet2_pubkey)),
|
||||
supply: 200,
|
||||
decimals: 3,
|
||||
is_initialized: true,
|
||||
freeze_authority: COption::Some(spl_token_pubkey(&wallet2_pubkey)),
|
||||
};
|
||||
Mint::pack(mint2_state, &mut mint2_data).unwrap();
|
||||
let mint_account2 = AccountSharedData::from(Account {
|
||||
lamports: 555,
|
||||
data: mint2_data.to_vec(),
|
||||
owner: inline_spl_token::id(),
|
||||
..Account::default()
|
||||
});
|
||||
bank.store_account(&mint2_pubkey, &mint_account2);
|
||||
|
||||
// Accounts should now look like the following:
|
||||
//
|
||||
// -----system_program------
|
||||
// / \
|
||||
// /-(owns) \-(owns)
|
||||
// / \
|
||||
// wallet1 ---wallet2---
|
||||
// / / \
|
||||
// /-(SPL::owns) /-(SPL::owns) \-(SPL::owns)
|
||||
// / / \
|
||||
// token_account1 token_account2 token_account3
|
||||
// \ / /
|
||||
// \-(SPL::mint) /-(SPL::mint) /-(SPL::mint)
|
||||
// \ / /
|
||||
// --mint_account1-- mint_account2
|
||||
|
||||
if secondary_index_enabled {
|
||||
// ----------- Test for a non-existant key -----------
|
||||
let req = format!(
|
||||
r#"{{"jsonrpc":"2.0","id":1,"method":"getSecondaryIndexKeySize","params":["{non_existent_pubkey}"]}}"#,
|
||||
);
|
||||
let res = io.handle_request_sync(&req, meta.clone());
|
||||
let result: Value = serde_json::from_str(&res.expect("actual response"))
|
||||
.expect("actual response deserialization");
|
||||
let sizes: HashMap<RpcAccountIndex, usize> =
|
||||
serde_json::from_value(result["result"].clone()).unwrap();
|
||||
assert!(sizes.is_empty());
|
||||
// --------------- Test Queries ---------------
|
||||
// 1) Wallet1 - Owns 1 SPL Token
|
||||
let req = format!(
|
||||
r#"{{"jsonrpc":"2.0","id":1,"method":"getSecondaryIndexKeySize","params":["{wallet1_pubkey}"]}}"#,
|
||||
);
|
||||
let res = io.handle_request_sync(&req, meta.clone());
|
||||
let result: Value = serde_json::from_str(&res.expect("actual response"))
|
||||
.expect("actual response deserialization");
|
||||
let sizes: HashMap<RpcAccountIndex, usize> =
|
||||
serde_json::from_value(result["result"].clone()).unwrap();
|
||||
assert_eq!(sizes.len(), 1);
|
||||
assert_eq!(*sizes.get(&RpcAccountIndex::SplTokenOwner).unwrap(), 1);
|
||||
// 2) Wallet2 - Owns 2 SPL Tokens
|
||||
let req = format!(
|
||||
r#"{{"jsonrpc":"2.0","id":1,"method":"getSecondaryIndexKeySize","params":["{wallet2_pubkey}"]}}"#,
|
||||
);
|
||||
let res = io.handle_request_sync(&req, meta.clone());
|
||||
let result: Value = serde_json::from_str(&res.expect("actual response"))
|
||||
.expect("actual response deserialization");
|
||||
let sizes: HashMap<RpcAccountIndex, usize> =
|
||||
serde_json::from_value(result["result"].clone()).unwrap();
|
||||
assert_eq!(sizes.len(), 1);
|
||||
assert_eq!(*sizes.get(&RpcAccountIndex::SplTokenOwner).unwrap(), 2);
|
||||
// 3) Mint1 - Is in 2 SPL Accounts
|
||||
let req = format!(
|
||||
r#"{{"jsonrpc":"2.0","id":1,"method":"getSecondaryIndexKeySize","params":["{mint1_pubkey}"]}}"#,
|
||||
);
|
||||
let res = io.handle_request_sync(&req, meta.clone());
|
||||
let result: Value = serde_json::from_str(&res.expect("actual response"))
|
||||
.expect("actual response deserialization");
|
||||
let sizes: HashMap<RpcAccountIndex, usize> =
|
||||
serde_json::from_value(result["result"].clone()).unwrap();
|
||||
assert_eq!(sizes.len(), 1);
|
||||
assert_eq!(*sizes.get(&RpcAccountIndex::SplTokenMint).unwrap(), 2);
|
||||
// 4) Mint2 - Is in 1 SPL Account
|
||||
let req = format!(
|
||||
r#"{{"jsonrpc":"2.0","id":1,"method":"getSecondaryIndexKeySize","params":["{mint2_pubkey}"]}}"#,
|
||||
);
|
||||
let res = io.handle_request_sync(&req, meta.clone());
|
||||
let result: Value = serde_json::from_str(&res.expect("actual response"))
|
||||
.expect("actual response deserialization");
|
||||
let sizes: HashMap<RpcAccountIndex, usize> =
|
||||
serde_json::from_value(result["result"].clone()).unwrap();
|
||||
assert_eq!(sizes.len(), 1);
|
||||
assert_eq!(*sizes.get(&RpcAccountIndex::SplTokenMint).unwrap(), 1);
|
||||
// 5) SPL Token Program Owns 6 Accounts - 1 Default, 5 created above.
|
||||
let req = format!(
|
||||
r#"{{"jsonrpc":"2.0","id":1,"method":"getSecondaryIndexKeySize","params":["{}"]}}"#,
|
||||
inline_spl_token::id(),
|
||||
);
|
||||
let res = io.handle_request_sync(&req, meta.clone());
|
||||
let result: Value = serde_json::from_str(&res.expect("actual response"))
|
||||
.expect("actual response deserialization");
|
||||
let sizes: HashMap<RpcAccountIndex, usize> =
|
||||
serde_json::from_value(result["result"].clone()).unwrap();
|
||||
assert_eq!(sizes.len(), 1);
|
||||
assert_eq!(
|
||||
*sizes.get(&RpcAccountIndex::ProgramId).unwrap(),
|
||||
(num_default_spl_token_program_accounts + 5)
|
||||
);
|
||||
// 5) System Program Owns 4 Accounts + 2 Default, 2 created above.
|
||||
let req = format!(
|
||||
r#"{{"jsonrpc":"2.0","id":1,"method":"getSecondaryIndexKeySize","params":["{}"]}}"#,
|
||||
system_program::id(),
|
||||
);
|
||||
let res = io.handle_request_sync(&req, meta.clone());
|
||||
let result: Value = serde_json::from_str(&res.expect("actual response"))
|
||||
.expect("actual response deserialization");
|
||||
let sizes: HashMap<RpcAccountIndex, usize> =
|
||||
serde_json::from_value(result["result"].clone()).unwrap();
|
||||
assert_eq!(sizes.len(), 1);
|
||||
assert_eq!(
|
||||
*sizes.get(&RpcAccountIndex::ProgramId).unwrap(),
|
||||
(num_default_system_program_accounts + 2)
|
||||
);
|
||||
} else {
|
||||
// ------------ Secondary Indexes Disabled ------------
|
||||
let req = format!(
|
||||
r#"{{"jsonrpc":"2.0","id":1,"method":"getSecondaryIndexKeySize","params":["{token_account2_pubkey}"]}}"#,
|
||||
);
|
||||
let res = io.handle_request_sync(&req, meta.clone());
|
||||
let result: Value = serde_json::from_str(&res.expect("actual response"))
|
||||
.expect("actual response deserialization");
|
||||
let sizes: HashMap<RpcAccountIndex, usize> =
|
||||
serde_json::from_value(result["result"].clone()).unwrap();
|
||||
assert!(sizes.is_empty());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue