Get Index Key Size RPC Support (#28383)
Co-authored-by: K-anon <IntokuSatori@users.noreply.github.com>
This commit is contained in:
parent
83a7b2ca6c
commit
e8c8235474
|
@ -137,6 +137,14 @@ pub struct RpcEpochConfig {
|
|||
pub min_context_slot: Option<Slot>,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq, Hash)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub enum RpcAccountIndex {
|
||||
ProgramId,
|
||||
SplTokenMint,
|
||||
SplTokenOwner,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Default, PartialEq, Eq, Serialize, Deserialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct RpcAccountInfoConfig {
|
||||
|
|
424
rpc/src/rpc.rs
424
rpc/src/rpc.rs
|
@ -114,6 +114,14 @@ 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()),
|
||||
|
@ -496,6 +504,51 @@ 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>,
|
||||
|
@ -2970,6 +3023,14 @@ pub mod rpc_accounts {
|
|||
config: Option<RpcProgramAccountsConfig>,
|
||||
) -> Result<OptionalContext<Vec<RpcKeyedAccount>>>;
|
||||
|
||||
#[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 = "getBlockCommitment")]
|
||||
fn get_block_commitment(
|
||||
&self,
|
||||
|
@ -3121,6 +3182,20 @@ pub mod rpc_accounts {
|
|||
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_block_commitment(
|
||||
&self,
|
||||
meta: Self::Metadata,
|
||||
|
@ -4589,6 +4664,7 @@ 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},
|
||||
|
@ -4606,8 +4682,9 @@ pub mod tests {
|
|||
filter::{Memcmp, MemcmpEncodedBytes},
|
||||
},
|
||||
solana_runtime::{
|
||||
accounts_background_service::AbsRequestSender, commitment::BlockCommitment,
|
||||
inline_spl_token, non_circulating_supply::non_circulating_accounts,
|
||||
accounts_background_service::AbsRequestSender, bank::BankTestConfig,
|
||||
commitment::BlockCommitment, inline_spl_token,
|
||||
non_circulating_supply::non_circulating_accounts,
|
||||
},
|
||||
solana_sdk::{
|
||||
account::{Account, WritableAccount},
|
||||
|
@ -4704,7 +4781,18 @@ pub mod tests {
|
|||
|
||||
impl RpcHandler {
|
||||
fn start() -> Self {
|
||||
let (bank_forks, mint_keypair, leader_vote_keypair) = new_bank_forks();
|
||||
Self::start_with_config(JsonRpcConfig {
|
||||
enable_rpc_transaction_history: true,
|
||||
..JsonRpcConfig::default()
|
||||
})
|
||||
}
|
||||
|
||||
fn start_with_config(config: JsonRpcConfig) -> Self {
|
||||
let (bank_forks, mint_keypair, leader_vote_keypair) =
|
||||
new_bank_forks_with_config(BankTestConfig {
|
||||
secondary_indexes: config.account_indexes.clone(),
|
||||
});
|
||||
|
||||
let ledger_path = get_tmp_ledger_path!();
|
||||
let blockstore = Arc::new(Blockstore::open(&ledger_path).unwrap());
|
||||
let bank = bank_forks.read().unwrap().working_bank();
|
||||
|
@ -4731,10 +4819,7 @@ pub mod tests {
|
|||
let max_complete_transaction_status_slot = Arc::new(AtomicU64::new(0));
|
||||
|
||||
let meta = JsonRpcRequestProcessor::new(
|
||||
JsonRpcConfig {
|
||||
enable_rpc_transaction_history: true,
|
||||
..JsonRpcConfig::default()
|
||||
},
|
||||
config,
|
||||
None,
|
||||
bank_forks.clone(),
|
||||
block_commitment_cache.clone(),
|
||||
|
@ -6535,6 +6620,12 @@ pub mod tests {
|
|||
}
|
||||
|
||||
fn new_bank_forks() -> (Arc<RwLock<BankForks>>, Keypair, Arc<Keypair>) {
|
||||
new_bank_forks_with_config(BankTestConfig::default())
|
||||
}
|
||||
|
||||
fn new_bank_forks_with_config(
|
||||
config: BankTestConfig,
|
||||
) -> (Arc<RwLock<BankForks>>, Keypair, Arc<Keypair>) {
|
||||
let GenesisConfigInfo {
|
||||
mut genesis_config,
|
||||
mint_keypair,
|
||||
|
@ -6548,7 +6639,7 @@ pub mod tests {
|
|||
EpochSchedule::custom(TEST_SLOTS_PER_EPOCH, TEST_SLOTS_PER_EPOCH, false);
|
||||
genesis_config.fee_rate_governor = FeeRateGovernor::new(TEST_SIGNATURE_FEE, 0);
|
||||
|
||||
let bank = Bank::new_for_tests(&genesis_config);
|
||||
let bank = Bank::new_for_tests_with_config(&genesis_config, config);
|
||||
(
|
||||
Arc::new(RwLock::new(BankForks::new(bank))),
|
||||
mint_keypair,
|
||||
|
@ -7343,6 +7434,323 @@ 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() {
|
||||
|
|
|
@ -1472,6 +1472,22 @@ impl<T: IndexValue> AccountsIndex<T> {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn get_index_key_size(&self, index: &AccountIndex, index_key: &Pubkey) -> Option<usize> {
|
||||
match index {
|
||||
AccountIndex::ProgramId => self.program_id_index.index.get(index_key).map(|x| x.len()),
|
||||
AccountIndex::SplTokenOwner => self
|
||||
.spl_token_owner_index
|
||||
.index
|
||||
.get(index_key)
|
||||
.map(|x| x.len()),
|
||||
AccountIndex::SplTokenMint => self
|
||||
.spl_token_mint_index
|
||||
.index
|
||||
.get(index_key)
|
||||
.map(|x| x.len()),
|
||||
}
|
||||
}
|
||||
|
||||
/// log any secondary index counts, if non-zero
|
||||
pub(crate) fn log_secondary_indexes(&self) {
|
||||
if !self.program_id_index.index.is_empty() {
|
||||
|
|
|
@ -1147,6 +1147,11 @@ pub struct NewBankOptions {
|
|||
pub vote_only_bank: bool,
|
||||
}
|
||||
|
||||
#[derive(Debug, Default)]
|
||||
pub struct BankTestConfig {
|
||||
pub secondary_indexes: AccountSecondaryIndexes,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
struct PrevEpochInflationRewards {
|
||||
validator_rewards: u64,
|
||||
|
@ -1209,9 +1214,16 @@ impl Bank {
|
|||
}
|
||||
|
||||
pub fn new_for_tests(genesis_config: &GenesisConfig) -> Self {
|
||||
Self::new_for_tests_with_config(genesis_config, BankTestConfig::default())
|
||||
}
|
||||
|
||||
pub fn new_for_tests_with_config(
|
||||
genesis_config: &GenesisConfig,
|
||||
test_config: BankTestConfig,
|
||||
) -> Self {
|
||||
Self::new_with_config_for_tests(
|
||||
genesis_config,
|
||||
AccountSecondaryIndexes::default(),
|
||||
test_config.secondary_indexes,
|
||||
false,
|
||||
AccountShrinkThreshold::default(),
|
||||
)
|
||||
|
|
|
@ -823,6 +823,7 @@ impl TestValidator {
|
|||
staked_nodes_overrides: config.staked_nodes_overrides.clone(),
|
||||
accounts_db_config,
|
||||
runtime_config,
|
||||
account_indexes: config.rpc_config.account_indexes.clone(),
|
||||
..ValidatorConfig::default_for_test()
|
||||
};
|
||||
if let Some(ref tower_storage) = config.tower_storage {
|
||||
|
|
|
@ -16,6 +16,7 @@ use {
|
|||
rpc_pubsub_service::PubSubConfig,
|
||||
},
|
||||
solana_rpc_client::rpc_client::RpcClient,
|
||||
solana_runtime::accounts_index::{AccountIndex, AccountSecondaryIndexes},
|
||||
solana_sdk::{
|
||||
account::AccountSharedData,
|
||||
clock::Slot,
|
||||
|
@ -140,6 +141,15 @@ fn main() {
|
|||
.conflicts_with("quiet")
|
||||
.help("Log mode: stream the validator log"),
|
||||
)
|
||||
.arg(
|
||||
Arg::with_name("account_indexes")
|
||||
.long("account-index")
|
||||
.takes_value(true)
|
||||
.multiple(true)
|
||||
.possible_values(&["program-id", "spl-token-owner", "spl-token-mint"])
|
||||
.value_name("INDEX")
|
||||
.help("Enable an accounts index, indexed by the selected account field"),
|
||||
)
|
||||
.arg(
|
||||
Arg::with_name("faucet_port")
|
||||
.long("faucet-port")
|
||||
|
@ -441,6 +451,22 @@ fn main() {
|
|||
let ledger_path = value_t_or_exit!(matches, "ledger_path", PathBuf);
|
||||
let reset_ledger = matches.is_present("reset");
|
||||
|
||||
let indexes: HashSet<AccountIndex> = matches
|
||||
.values_of("account_indexes")
|
||||
.unwrap_or_default()
|
||||
.map(|value| match value {
|
||||
"program-id" => AccountIndex::ProgramId,
|
||||
"spl-token-mint" => AccountIndex::SplTokenMint,
|
||||
"spl-token-owner" => AccountIndex::SplTokenOwner,
|
||||
_ => unreachable!(),
|
||||
})
|
||||
.collect();
|
||||
|
||||
let account_indexes = AccountSecondaryIndexes {
|
||||
keys: None,
|
||||
indexes,
|
||||
};
|
||||
|
||||
if !ledger_path.exists() {
|
||||
fs::create_dir(&ledger_path).unwrap_or_else(|err| {
|
||||
println!(
|
||||
|
@ -752,13 +778,6 @@ fn main() {
|
|||
faucet_pubkey,
|
||||
AccountSharedData::new(faucet_lamports, 0, &system_program::id()),
|
||||
)
|
||||
.rpc_config(JsonRpcConfig {
|
||||
enable_rpc_transaction_history: true,
|
||||
enable_extended_tx_metadata_storage: true,
|
||||
rpc_bigtable_config,
|
||||
faucet_addr,
|
||||
..JsonRpcConfig::default_for_test()
|
||||
})
|
||||
.pubsub_config(PubSubConfig {
|
||||
enable_vote_subscription,
|
||||
..PubSubConfig::default()
|
||||
|
@ -778,6 +797,15 @@ fn main() {
|
|||
})
|
||||
.deactivate_features(&features_to_deactivate);
|
||||
|
||||
genesis.rpc_config(JsonRpcConfig {
|
||||
enable_rpc_transaction_history: true,
|
||||
enable_extended_tx_metadata_storage: true,
|
||||
rpc_bigtable_config,
|
||||
faucet_addr,
|
||||
account_indexes,
|
||||
..JsonRpcConfig::default_for_test()
|
||||
});
|
||||
|
||||
if !accounts_to_clone.is_empty() {
|
||||
if let Err(e) = genesis.clone_accounts(
|
||||
accounts_to_clone,
|
||||
|
|
Loading…
Reference in New Issue