Add config param to specify offset/length for single and program account info (#11515)
* Add config param to specify dataSlice for account info and program accounts * Use match instead of if
This commit is contained in:
137
core/src/rpc.rs
137
core/src/rpc.rs
@ -244,6 +244,7 @@ impl JsonRpcRequestProcessor {
|
||||
let config = config.unwrap_or_default();
|
||||
let bank = self.bank(config.commitment);
|
||||
let encoding = config.encoding.unwrap_or(UiAccountEncoding::Binary);
|
||||
check_slice_and_encoding(&encoding, config.data_slice.is_some())?;
|
||||
let mut response = None;
|
||||
if let Some(account) = bank.get_account(pubkey) {
|
||||
if account.owner == spl_token_id_v1_0() && encoding == UiAccountEncoding::JsonParsed {
|
||||
@ -256,7 +257,13 @@ impl JsonRpcRequestProcessor {
|
||||
data: None,
|
||||
});
|
||||
} else {
|
||||
response = Some(UiAccount::encode(pubkey, account, encoding, None));
|
||||
response = Some(UiAccount::encode(
|
||||
pubkey,
|
||||
account,
|
||||
encoding,
|
||||
None,
|
||||
config.data_slice,
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
@ -277,21 +284,31 @@ impl JsonRpcRequestProcessor {
|
||||
program_id: &Pubkey,
|
||||
config: Option<RpcAccountInfoConfig>,
|
||||
filters: Vec<RpcFilterType>,
|
||||
) -> Vec<RpcKeyedAccount> {
|
||||
) -> Result<Vec<RpcKeyedAccount>> {
|
||||
let config = config.unwrap_or_default();
|
||||
let bank = self.bank(config.commitment);
|
||||
let encoding = config.encoding.unwrap_or(UiAccountEncoding::Binary);
|
||||
let data_slice_config = config.data_slice;
|
||||
check_slice_and_encoding(&encoding, data_slice_config.is_some())?;
|
||||
let keyed_accounts = get_filtered_program_accounts(&bank, program_id, filters);
|
||||
if program_id == &spl_token_id_v1_0() && encoding == UiAccountEncoding::JsonParsed {
|
||||
get_parsed_token_accounts(bank, keyed_accounts).collect()
|
||||
} else {
|
||||
keyed_accounts
|
||||
.map(|(pubkey, account)| RpcKeyedAccount {
|
||||
pubkey: pubkey.to_string(),
|
||||
account: UiAccount::encode(&pubkey, account, encoding.clone(), None),
|
||||
})
|
||||
.collect()
|
||||
}
|
||||
let result =
|
||||
if program_id == &spl_token_id_v1_0() && encoding == UiAccountEncoding::JsonParsed {
|
||||
get_parsed_token_accounts(bank, keyed_accounts).collect()
|
||||
} else {
|
||||
keyed_accounts
|
||||
.map(|(pubkey, account)| RpcKeyedAccount {
|
||||
pubkey: pubkey.to_string(),
|
||||
account: UiAccount::encode(
|
||||
&pubkey,
|
||||
account,
|
||||
encoding.clone(),
|
||||
None,
|
||||
data_slice_config,
|
||||
),
|
||||
})
|
||||
.collect()
|
||||
};
|
||||
Ok(result)
|
||||
}
|
||||
|
||||
pub fn get_inflation_governor(
|
||||
@ -1107,6 +1124,8 @@ impl JsonRpcRequestProcessor {
|
||||
let config = config.unwrap_or_default();
|
||||
let bank = self.bank(config.commitment);
|
||||
let encoding = config.encoding.unwrap_or(UiAccountEncoding::Binary);
|
||||
let data_slice_config = config.data_slice;
|
||||
check_slice_and_encoding(&encoding, data_slice_config.is_some())?;
|
||||
let (token_program_id, mint) = get_token_program_id_and_mint(&bank, token_account_filter)?;
|
||||
|
||||
let mut filters = vec![
|
||||
@ -1134,7 +1153,13 @@ impl JsonRpcRequestProcessor {
|
||||
keyed_accounts
|
||||
.map(|(pubkey, account)| RpcKeyedAccount {
|
||||
pubkey: pubkey.to_string(),
|
||||
account: UiAccount::encode(&pubkey, account, encoding.clone(), None),
|
||||
account: UiAccount::encode(
|
||||
&pubkey,
|
||||
account,
|
||||
encoding.clone(),
|
||||
None,
|
||||
data_slice_config,
|
||||
),
|
||||
})
|
||||
.collect()
|
||||
};
|
||||
@ -1150,6 +1175,8 @@ impl JsonRpcRequestProcessor {
|
||||
let config = config.unwrap_or_default();
|
||||
let bank = self.bank(config.commitment);
|
||||
let encoding = config.encoding.unwrap_or(UiAccountEncoding::Binary);
|
||||
let data_slice_config = config.data_slice;
|
||||
check_slice_and_encoding(&encoding, data_slice_config.is_some())?;
|
||||
let (token_program_id, mint) = get_token_program_id_and_mint(&bank, token_account_filter)?;
|
||||
|
||||
let mut filters = vec![
|
||||
@ -1185,7 +1212,13 @@ impl JsonRpcRequestProcessor {
|
||||
keyed_accounts
|
||||
.map(|(pubkey, account)| RpcKeyedAccount {
|
||||
pubkey: pubkey.to_string(),
|
||||
account: UiAccount::encode(&pubkey, account, encoding.clone(), None),
|
||||
account: UiAccount::encode(
|
||||
&pubkey,
|
||||
account,
|
||||
encoding.clone(),
|
||||
None,
|
||||
data_slice_config,
|
||||
),
|
||||
})
|
||||
.collect()
|
||||
};
|
||||
@ -1226,6 +1259,26 @@ fn verify_token_account_filter(
|
||||
}
|
||||
}
|
||||
|
||||
fn check_slice_and_encoding(encoding: &UiAccountEncoding, data_slice_is_some: bool) -> Result<()> {
|
||||
match encoding {
|
||||
UiAccountEncoding::JsonParsed => {
|
||||
if data_slice_is_some {
|
||||
let message =
|
||||
"Sliced account data can only be encoded using binary (base 58) or binary64 encoding."
|
||||
.to_string();
|
||||
Err(error::Error {
|
||||
code: error::ErrorCode::InvalidRequest,
|
||||
message,
|
||||
data: None,
|
||||
})
|
||||
} else {
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
UiAccountEncoding::Binary | UiAccountEncoding::Binary64 => Ok(()),
|
||||
}
|
||||
}
|
||||
|
||||
/// Use a set of filters to get an iterator of keyed program accounts from a bank
|
||||
fn get_filtered_program_accounts(
|
||||
bank: &Arc<Bank>,
|
||||
@ -1258,6 +1311,7 @@ pub(crate) fn get_parsed_token_account(
|
||||
account,
|
||||
UiAccountEncoding::JsonParsed,
|
||||
additional_data,
|
||||
None,
|
||||
)
|
||||
}
|
||||
|
||||
@ -1286,6 +1340,7 @@ where
|
||||
account,
|
||||
UiAccountEncoding::JsonParsed,
|
||||
additional_data,
|
||||
None,
|
||||
),
|
||||
}
|
||||
})
|
||||
@ -1753,7 +1808,7 @@ impl RpcSol for RpcSolImpl {
|
||||
for filter in &filters {
|
||||
verify_filter(filter)?;
|
||||
}
|
||||
Ok(meta.get_program_accounts(&program_id, config, filters))
|
||||
meta.get_program_accounts(&program_id, config, filters)
|
||||
}
|
||||
|
||||
fn get_inflation_governor(
|
||||
@ -3028,13 +3083,13 @@ pub mod tests {
|
||||
#[test]
|
||||
fn test_rpc_get_account_info() {
|
||||
let bob_pubkey = Pubkey::new_rand();
|
||||
let RpcHandler { io, meta, .. } = start_rpc_handler_with_tx(&bob_pubkey);
|
||||
let RpcHandler { io, meta, bank, .. } = start_rpc_handler_with_tx(&bob_pubkey);
|
||||
|
||||
let req = format!(
|
||||
r#"{{"jsonrpc":"2.0","id":1,"method":"getAccountInfo","params":["{}"]}}"#,
|
||||
bob_pubkey
|
||||
);
|
||||
let res = io.handle_request_sync(&req, meta);
|
||||
let res = io.handle_request_sync(&req, meta.clone());
|
||||
let expected = json!({
|
||||
"jsonrpc": "2.0",
|
||||
"result": {
|
||||
@ -3054,6 +3109,54 @@ pub mod tests {
|
||||
let result: Response = serde_json::from_str(&res.expect("actual response"))
|
||||
.expect("actual response deserialization");
|
||||
assert_eq!(expected, result);
|
||||
|
||||
let address = Pubkey::new_rand();
|
||||
let data = vec![1, 2, 3, 4, 5];
|
||||
let mut account = Account::new(42, 5, &Pubkey::default());
|
||||
account.data = data.clone();
|
||||
bank.store_account(&address, &account);
|
||||
|
||||
let req = format!(
|
||||
r#"{{"jsonrpc":"2.0","id":1,"method":"getAccountInfo","params":["{}", {{"encoding":"binary64"}}]}}"#,
|
||||
address
|
||||
);
|
||||
let res = io.handle_request_sync(&req, meta.clone());
|
||||
let result: Value = serde_json::from_str(&res.expect("actual response"))
|
||||
.expect("actual response deserialization");
|
||||
assert_eq!(result["result"]["value"]["data"], base64::encode(&data));
|
||||
|
||||
let req = format!(
|
||||
r#"{{"jsonrpc":"2.0","id":1,"method":"getAccountInfo","params":["{}", {{"encoding":"binary64", "dataSlice": {{"length": 2, "offset": 1}}}}]}}"#,
|
||||
address
|
||||
);
|
||||
let res = io.handle_request_sync(&req, meta.clone());
|
||||
let result: Value = serde_json::from_str(&res.expect("actual response"))
|
||||
.expect("actual response deserialization");
|
||||
assert_eq!(
|
||||
result["result"]["value"]["data"],
|
||||
base64::encode(&data[1..3]),
|
||||
);
|
||||
|
||||
let req = format!(
|
||||
r#"{{"jsonrpc":"2.0","id":1,"method":"getAccountInfo","params":["{}", {{"encoding":"binary", "dataSlice": {{"length": 2, "offset": 1}}}}]}}"#,
|
||||
address
|
||||
);
|
||||
let res = io.handle_request_sync(&req, meta.clone());
|
||||
let result: Value = serde_json::from_str(&res.expect("actual response"))
|
||||
.expect("actual response deserialization");
|
||||
assert_eq!(
|
||||
result["result"]["value"]["data"],
|
||||
bs58::encode(&data[1..3]).into_string(),
|
||||
);
|
||||
|
||||
let req = format!(
|
||||
r#"{{"jsonrpc":"2.0","id":1,"method":"getAccountInfo","params":["{}", {{"encoding":"jsonParsed", "dataSlice": {{"length": 2, "offset": 1}}}}]}}"#,
|
||||
address
|
||||
);
|
||||
let res = io.handle_request_sync(&req, meta);
|
||||
let result: Value = serde_json::from_str(&res.expect("actual response"))
|
||||
.expect("actual response deserialization");
|
||||
result["error"].as_object().unwrap();
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
@ -542,6 +542,7 @@ mod tests {
|
||||
Some(RpcAccountInfoConfig {
|
||||
commitment: Some(CommitmentConfig::recent()),
|
||||
encoding: None,
|
||||
data_slice: None,
|
||||
}),
|
||||
);
|
||||
|
||||
@ -649,6 +650,7 @@ mod tests {
|
||||
Some(RpcAccountInfoConfig {
|
||||
commitment: Some(CommitmentConfig::recent()),
|
||||
encoding: Some(UiAccountEncoding::JsonParsed),
|
||||
data_slice: None,
|
||||
}),
|
||||
);
|
||||
|
||||
@ -769,6 +771,7 @@ mod tests {
|
||||
Some(RpcAccountInfoConfig {
|
||||
commitment: Some(CommitmentConfig::root()),
|
||||
encoding: None,
|
||||
data_slice: None,
|
||||
}),
|
||||
);
|
||||
|
||||
@ -818,6 +821,7 @@ mod tests {
|
||||
Some(RpcAccountInfoConfig {
|
||||
commitment: Some(CommitmentConfig::root()),
|
||||
encoding: None,
|
||||
data_slice: None,
|
||||
}),
|
||||
);
|
||||
|
||||
|
@ -265,7 +265,7 @@ fn filter_account_result(
|
||||
} else {
|
||||
return (
|
||||
Box::new(iter::once(UiAccount::encode(
|
||||
pubkey, account, encoding, None,
|
||||
pubkey, account, encoding, None, None,
|
||||
))),
|
||||
fork,
|
||||
);
|
||||
@ -316,7 +316,7 @@ fn filter_program_results(
|
||||
Box::new(
|
||||
keyed_accounts.map(move |(pubkey, account)| RpcKeyedAccount {
|
||||
pubkey: pubkey.to_string(),
|
||||
account: UiAccount::encode(&pubkey, account, encoding.clone(), None),
|
||||
account: UiAccount::encode(&pubkey, account, encoding.clone(), None, None),
|
||||
}),
|
||||
)
|
||||
};
|
||||
@ -1033,6 +1033,7 @@ pub(crate) mod tests {
|
||||
Some(RpcAccountInfoConfig {
|
||||
commitment: Some(CommitmentConfig::recent()),
|
||||
encoding: None,
|
||||
data_slice: None,
|
||||
}),
|
||||
sub_id.clone(),
|
||||
subscriber,
|
||||
@ -1517,6 +1518,7 @@ pub(crate) mod tests {
|
||||
Some(RpcAccountInfoConfig {
|
||||
commitment: Some(CommitmentConfig::single_gossip()),
|
||||
encoding: None,
|
||||
data_slice: None,
|
||||
}),
|
||||
sub_id0.clone(),
|
||||
subscriber0,
|
||||
@ -1585,6 +1587,7 @@ pub(crate) mod tests {
|
||||
Some(RpcAccountInfoConfig {
|
||||
commitment: Some(CommitmentConfig::single_gossip()),
|
||||
encoding: None,
|
||||
data_slice: None,
|
||||
}),
|
||||
sub_id1.clone(),
|
||||
subscriber1,
|
||||
|
Reference in New Issue
Block a user