From 33322d9501d9903228abc8b28b5c6f6d6aea6a13 Mon Sep 17 00:00:00 2001 From: Tyera Eulberg Date: Fri, 22 May 2020 15:14:18 -0600 Subject: [PATCH] Add circ/non-circ filter to getLargestAccounts (#10188) --- client/src/lib.rs | 1 + client/src/rpc_config.rs | 5 +- client/src/rpc_request.rs | 2 + core/src/rpc.rs | 112 ++++++++++++++++++++++++++------------ 4 files changed, 84 insertions(+), 36 deletions(-) diff --git a/client/src/lib.rs b/client/src/lib.rs index dd4d3183b0..90a4839c1c 100644 --- a/client/src/lib.rs +++ b/client/src/lib.rs @@ -8,6 +8,7 @@ pub mod perf_utils; pub mod pubsub_client; pub mod rpc_client; pub mod rpc_client_request; +pub mod rpc_config; pub mod rpc_request; pub mod rpc_response; pub mod thin_client; diff --git a/client/src/rpc_config.rs b/client/src/rpc_config.rs index e31bdd9e49..98d39d657b 100644 --- a/client/src/rpc_config.rs +++ b/client/src/rpc_config.rs @@ -3,7 +3,10 @@ use solana_sdk::commitment_config::CommitmentConfig; #[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] #[serde(rename_all = "camelCase")] pub struct RpcSignatureStatusConfig { - pub search_transaction_history: bool, + pub search_transaction_history: Option, + // DEPRECATED + #[serde(flatten)] + pub commitment: Option, } #[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] diff --git a/client/src/rpc_request.rs b/client/src/rpc_request.rs index bf5cc29d80..1ae2002b82 100644 --- a/client/src/rpc_request.rs +++ b/client/src/rpc_request.rs @@ -18,6 +18,7 @@ pub enum RpcRequest { GetGenesisHash, GetIdentity, GetInflation, + GetLargestAccounts, GetLeaderSchedule, GetProgramAccounts, GetRecentBlockhash, @@ -61,6 +62,7 @@ impl RpcRequest { RpcRequest::GetGenesisHash => "getGenesisHash", RpcRequest::GetIdentity => "getIdentity", RpcRequest::GetInflation => "getInflation", + RpcRequest::GetLargestAccounts => "getLargestAccounts", RpcRequest::GetLeaderSchedule => "getLeaderSchedule", RpcRequest::GetProgramAccounts => "getProgramAccounts", RpcRequest::GetRecentBlockhash => "getRecentBlockhash", diff --git a/core/src/rpc.rs b/core/src/rpc.rs index 890b65d85a..1d42eb3444 100644 --- a/core/src/rpc.rs +++ b/core/src/rpc.rs @@ -13,7 +13,7 @@ use crate::{ use bincode::serialize; use jsonrpc_core::{Error, Metadata, Result}; use jsonrpc_derive::rpc; -use solana_client::rpc_response::*; +use solana_client::{rpc_config::*, rpc_response::*}; use solana_faucet::faucet::request_airdrop_transaction; use solana_ledger::{ bank_forks::BankForks, blockstore::Blockstore, blockstore_db::BlockstoreError, @@ -64,21 +64,6 @@ pub struct JsonRpcConfig { pub faucet_addr: Option, } -#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] -#[serde(rename_all = "camelCase")] -pub struct RpcSignatureStatusConfig { - pub search_transaction_history: Option, - // DEPRECATED - #[serde(flatten)] - pub commitment: Option, -} - -#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] -#[serde(rename_all = "camelCase")] -pub struct RpcSimulateTransactionConfig { - pub sig_verify: bool, -} - #[derive(Clone)] pub struct JsonRpcRequestProcessor { bank_forks: Arc>, @@ -287,22 +272,30 @@ impl JsonRpcRequestProcessor { fn get_largest_accounts( &self, - commitment: Option, + config: Option, ) -> RpcResponse> { - let bank = self.bank(commitment)?; + let config = config.unwrap_or_default(); + let bank = self.bank(config.commitment)?; + let (addresses, address_filter) = if let Some(filter) = config.filter { + let non_circulating_supply = calculate_non_circulating_supply(&bank); + let addresses = non_circulating_supply.accounts.into_iter().collect(); + let address_filter = match filter { + RpcLargestAccountsFilter::Circulating => AccountAddressFilter::Exclude, + RpcLargestAccountsFilter::NonCirculating => AccountAddressFilter::Include, + }; + (addresses, address_filter) + } else { + (HashSet::new(), AccountAddressFilter::Exclude) + }; new_response( &bank, - bank.get_largest_accounts( - NUM_LARGEST_ACCOUNTS, - &HashSet::new(), - AccountAddressFilter::Exclude, - ) - .into_iter() - .map(|(address, lamports)| RpcAccountBalance { - address: address.to_string(), - lamports, - }) - .collect(), + bank.get_largest_accounts(NUM_LARGEST_ACCOUNTS, &addresses, address_filter) + .into_iter() + .map(|(address, lamports)| RpcAccountBalance { + address: address.to_string(), + lamports, + }) + .collect(), ) } @@ -851,7 +844,7 @@ pub trait RpcSol { fn get_largest_accounts( &self, meta: Self::Metadata, - commitment: Option, + config: Option, ) -> RpcResponse>; #[rpc(meta, name = "getSupply")] @@ -1276,13 +1269,13 @@ impl RpcSol for RpcSolImpl { fn get_largest_accounts( &self, meta: Self::Metadata, - commitment: Option, + config: Option, ) -> RpcResponse> { debug!("get_largest_accounts rpc request received"); meta.request_processor .read() .unwrap() - .get_largest_accounts(commitment) + .get_largest_accounts(config) } fn get_supply( @@ -1637,6 +1630,7 @@ pub mod tests { commitment::BlockCommitment, contact_info::ContactInfo, genesis_utils::{create_genesis_config, GenesisConfigInfo}, + non_circulating_supply::non_circulating_accounts, replay_stage::tests::create_test_transactions_and_populate_blockstore, }; use bincode::deserialize; @@ -1786,6 +1780,9 @@ pub mod tests { let blockhash = bank.confirmed_last_blockhash().0; let tx = system_transaction::transfer(&alice, pubkey, 20, blockhash); bank.process_transaction(&tx).expect("process transaction"); + let tx = + system_transaction::transfer(&alice, &non_circulating_accounts()[0], 20, blockhash); + bank.process_transaction(&tx).expect("process transaction"); let tx = system_transaction::transfer(&alice, pubkey, std::u64::MAX, blockhash); let _ = bank.process_transaction(&tx); @@ -1942,7 +1939,7 @@ pub mod tests { let req = format!(r#"{{"jsonrpc":"2.0","id":1,"method":"getTransactionCount"}}"#); let res = io.handle_request_sync(&req, meta); - let expected = format!(r#"{{"jsonrpc":"2.0","result":3,"id":1}}"#); + let expected = format!(r#"{{"jsonrpc":"2.0","result":4,"id":1}}"#); let expected: Response = serde_json::from_str(&expected).expect("expected response deserialization"); let result: Response = serde_json::from_str(&res.expect("actual response")) @@ -1990,6 +1987,31 @@ pub mod tests { assert!(supply >= TEST_MINT_LAMPORTS); } + #[test] + fn test_get_supply() { + let bob_pubkey = Pubkey::new_rand(); + let RpcHandler { io, meta, .. } = start_rpc_handler_with_tx(&bob_pubkey); + let req = format!(r#"{{"jsonrpc":"2.0","id":1,"method":"getSupply"}}"#); + let res = io.handle_request_sync(&req, meta.clone()); + let json: Value = serde_json::from_str(&res.unwrap()).unwrap(); + let supply: RpcSupply = serde_json::from_value(json["result"]["value"].clone()) + .expect("actual response deserialization"); + assert_eq!(supply.non_circulating, 20); + assert!(supply.circulating >= TEST_MINT_LAMPORTS); + assert!(supply.total >= TEST_MINT_LAMPORTS + 20); + let expected_accounts: Vec = non_circulating_accounts() + .iter() + .map(|pubkey| pubkey.to_string()) + .collect(); + assert_eq!( + supply.non_circulating_accounts.len(), + expected_accounts.len() + ); + for address in supply.non_circulating_accounts { + assert!(expected_accounts.contains(&address)); + } + } + #[test] fn test_get_largest_accounts() { let bob_pubkey = Pubkey::new_rand(); @@ -2002,7 +2024,7 @@ pub mod tests { let largest_accounts: Vec = serde_json::from_value(json["result"]["value"].clone()) .expect("actual response deserialization"); - assert_eq!(largest_accounts.len(), 18); + assert_eq!(largest_accounts.len(), 19); // Get Alice balance let req = format!( @@ -2023,7 +2045,7 @@ pub mod tests { r#"{{"jsonrpc":"2.0","id":1,"method":"getBalance","params":["{}"]}}"#, bob_pubkey ); - let res = io.handle_request_sync(&req, meta); + let res = io.handle_request_sync(&req, meta.clone()); let json: Value = serde_json::from_str(&res.unwrap()).unwrap(); let bob_balance: u64 = serde_json::from_value(json["result"]["value"].clone()) .expect("actual response deserialization"); @@ -2031,6 +2053,26 @@ pub mod tests { address: bob_pubkey.to_string(), lamports: bob_balance, })); + + // Test Circulating/NonCirculating Filter + let req = format!( + r#"{{"jsonrpc":"2.0","id":1,"method":"getLargestAccounts","params":[{{"filter":"circulating"}}]}}"# + ); + let res = io.handle_request_sync(&req, meta.clone()); + let json: Value = serde_json::from_str(&res.unwrap()).unwrap(); + let largest_accounts: Vec = + serde_json::from_value(json["result"]["value"].clone()) + .expect("actual response deserialization"); + assert_eq!(largest_accounts.len(), 18); + let req = format!( + r#"{{"jsonrpc":"2.0","id":1,"method":"getLargestAccounts","params":[{{"filter":"nonCirculating"}}]}}"# + ); + let res = io.handle_request_sync(&req, meta.clone()); + let json: Value = serde_json::from_str(&res.unwrap()).unwrap(); + let largest_accounts: Vec = + serde_json::from_value(json["result"]["value"].clone()) + .expect("actual response deserialization"); + assert_eq!(largest_accounts.len(), 1); } #[test]