From 4334fef9552f95982e0da1e9181850da7580cf3a Mon Sep 17 00:00:00 2001 From: "mergify[bot]" <37929162+mergify[bot]@users.noreply.github.com> Date: Wed, 20 May 2020 22:14:59 -0700 Subject: [PATCH] Add v0 REST APIs for circulating and total supply (#10102) (#10159) automerge --- core/src/non_circulating_supply.rs | 8 +-- core/src/rpc.rs | 2 +- core/src/rpc_service.rs | 112 +++++++++++++++++++++++------ ledger/src/bank_forks.rs | 4 ++ 4 files changed, 101 insertions(+), 25 deletions(-) diff --git a/core/src/non_circulating_supply.rs b/core/src/non_circulating_supply.rs index e137ffe50b..69740ca266 100644 --- a/core/src/non_circulating_supply.rs +++ b/core/src/non_circulating_supply.rs @@ -8,7 +8,7 @@ pub struct NonCirculatingSupply { pub accounts: Vec, } -pub fn calculate_non_circulating_supply(bank: Arc) -> NonCirculatingSupply { +pub fn calculate_non_circulating_supply(bank: &Arc) -> NonCirculatingSupply { debug!("Updating Bank supply, epoch: {}", bank.epoch()); let mut non_circulating_accounts_set: HashSet = HashSet::new(); @@ -149,7 +149,7 @@ mod tests { (num_genesis_accounts + num_non_circulating_accounts + num_stake_accounts) * balance ); - let non_circulating_supply = calculate_non_circulating_supply(bank.clone()); + let non_circulating_supply = calculate_non_circulating_supply(&bank); assert_eq!( non_circulating_supply.lamports, (num_non_circulating_accounts + num_stake_accounts) * balance @@ -164,7 +164,7 @@ mod tests { for key in non_circulating_accounts { bank.store_account(&key, &Account::new(new_balance, 0, &Pubkey::default())); } - let non_circulating_supply = calculate_non_circulating_supply(bank.clone()); + let non_circulating_supply = calculate_non_circulating_supply(&bank); assert_eq!( non_circulating_supply.lamports, (num_non_circulating_accounts * new_balance) + (num_stake_accounts * balance) @@ -179,7 +179,7 @@ mod tests { bank = Arc::new(new_from_parent(&bank)); } assert_eq!(bank.epoch(), 1); - let non_circulating_supply = calculate_non_circulating_supply(bank.clone()); + let non_circulating_supply = calculate_non_circulating_supply(&bank); assert_eq!( non_circulating_supply.lamports, num_non_circulating_accounts * new_balance diff --git a/core/src/rpc.rs b/core/src/rpc.rs index 31fa9a2198..e0a11dc2de 100644 --- a/core/src/rpc.rs +++ b/core/src/rpc.rs @@ -308,7 +308,7 @@ impl JsonRpcRequestProcessor { fn get_supply(&self, commitment: Option) -> RpcResponse { let bank = self.bank(commitment)?; - let non_circulating_supply = calculate_non_circulating_supply(bank.clone()); + let non_circulating_supply = calculate_non_circulating_supply(&bank); let total_supply = bank.capitalization(); new_response( &bank, diff --git a/core/src/rpc_service.rs b/core/src/rpc_service.rs index c114a96b78..3b648d6216 100644 --- a/core/src/rpc_service.rs +++ b/core/src/rpc_service.rs @@ -44,6 +44,7 @@ struct RpcRequestMiddleware { snapshot_config: Option, cluster_info: Arc>, trusted_validators: Option>, + bank_forks: Arc>, } impl RpcRequestMiddleware { @@ -52,6 +53,7 @@ impl RpcRequestMiddleware { snapshot_config: Option, cluster_info: Arc>, trusted_validators: Option>, + bank_forks: Arc>, ) -> Self { Self { ledger_path, @@ -60,6 +62,7 @@ impl RpcRequestMiddleware { snapshot_config, cluster_info, trusted_validators, + bank_forks, } } @@ -85,7 +88,7 @@ impl RpcRequestMiddleware { .unwrap() } - fn is_get_path(&self, path: &str) -> bool { + fn is_file_get_path(&self, path: &str) -> bool { match path { "/genesis.tar.bz2" => true, _ => { @@ -98,7 +101,7 @@ impl RpcRequestMiddleware { } } - fn get(&self, path: &str) -> RequestMiddlewareAction { + fn process_file_get(&self, path: &str) -> RequestMiddlewareAction { let filename = self.ledger_path.join( path.split_at(1).1, // Drop leading '/' from path ); @@ -202,8 +205,19 @@ impl RequestMiddleware for RpcRequestMiddleware { }; } } - if self.is_get_path(request.uri().path()) { - self.get(request.uri().path()) + + if let Some(result) = process_rest(&self.bank_forks, request.uri().path()) { + RequestMiddlewareAction::Respond { + should_validate_hosts: true, + response: Box::new(jsonrpc_core::futures::future::ok( + hyper::Response::builder() + .status(hyper::StatusCode::OK) + .body(hyper::Body::from(result)) + .unwrap(), + )), + } + } else if self.is_file_get_path(request.uri().path()) { + self.process_file_get(request.uri().path()) } else if request.uri().path() == "/health" { RequestMiddlewareAction::Respond { should_validate_hosts: true, @@ -223,6 +237,26 @@ impl RequestMiddleware for RpcRequestMiddleware { } } +fn process_rest(bank_forks: &Arc>, path: &str) -> Option { + match path { + "/v0/circulating-supply" => { + let r_bank_forks = bank_forks.read().unwrap(); + let bank = r_bank_forks.root_bank(); + let total_supply = bank.capitalization(); + let non_circulating_supply = + crate::non_circulating_supply::calculate_non_circulating_supply(&bank).lamports; + Some(format!("{}", total_supply - non_circulating_supply)) + } + "/v0/total-supply" => { + let r_bank_forks = bank_forks.read().unwrap(); + let bank = r_bank_forks.root_bank(); + let total_supply = bank.capitalization(); + Some(format!("{}", total_supply)) + } + _ => None, + } +} + impl JsonRpcService { #[allow(clippy::too_many_arguments)] pub fn new( @@ -243,7 +277,7 @@ impl JsonRpcService { info!("rpc configuration: {:?}", config); let request_processor = Arc::new(RwLock::new(JsonRpcRequestProcessor::new( config, - bank_forks, + bank_forks.clone(), block_commitment_cache, blockstore, storage_state, @@ -268,6 +302,7 @@ impl JsonRpcService { snapshot_config, cluster_info.clone(), trusted_validators, + bank_forks.clone(), ); let server = ServerBuilder::with_meta_extractor( io, @@ -397,13 +432,41 @@ mod tests { rpc_service.join().unwrap(); } + fn create_bank_forks() -> Arc> { + let GenesisConfigInfo { genesis_config, .. } = create_genesis_config(10_000); + let bank = Bank::new(&genesis_config); + Arc::new(RwLock::new(BankForks::new(bank.slot(), bank))) + } + #[test] - fn test_is_get_path() { + fn test_process_rest_api() { + let bank_forks = create_bank_forks(); + + assert_eq!(None, process_rest(&bank_forks, "not-a-supported-rest-api")); + assert_eq!( + Some("10127".to_string()), + process_rest(&bank_forks, "/v0/circulating-supply") + ); + assert_eq!( + Some("10127".to_string()), + process_rest(&bank_forks, "/v0/total-supply") + ); + } + + #[test] + fn test_is_file_get_path() { let cluster_info = Arc::new(RwLock::new(ClusterInfo::new_with_invalid_keypair( ContactInfo::default(), ))); + let bank_forks = create_bank_forks(); - let rrm = RpcRequestMiddleware::new(PathBuf::from("/"), None, cluster_info.clone(), None); + let rrm = RpcRequestMiddleware::new( + PathBuf::from("/"), + None, + cluster_info.clone(), + None, + bank_forks.clone(), + ); let rrm_with_snapshot_config = RpcRequestMiddleware::new( PathBuf::from("/"), Some(SnapshotConfig { @@ -413,26 +476,28 @@ mod tests { }), cluster_info, None, + bank_forks, ); - assert!(rrm.is_get_path("/genesis.tar.bz2")); - assert!(!rrm.is_get_path("genesis.tar.bz2")); + assert!(rrm.is_file_get_path("/genesis.tar.bz2")); + assert!(!rrm.is_file_get_path("genesis.tar.bz2")); - assert!(!rrm.is_get_path("/snapshot.tar.bz2")); // This is a redirect + assert!(!rrm.is_file_get_path("/snapshot.tar.bz2")); // This is a redirect - assert!( - !rrm.is_get_path("/snapshot-100-AvFf9oS8A8U78HdjT9YG2sTTThLHJZmhaMn2g8vkWYnr.tar.bz2") - ); - assert!(rrm_with_snapshot_config - .is_get_path("/snapshot-100-AvFf9oS8A8U78HdjT9YG2sTTThLHJZmhaMn2g8vkWYnr.tar.bz2")); + assert!(!rrm.is_file_get_path( + "/snapshot-100-AvFf9oS8A8U78HdjT9YG2sTTThLHJZmhaMn2g8vkWYnr.tar.bz2" + )); + assert!(rrm_with_snapshot_config.is_file_get_path( + "/snapshot-100-AvFf9oS8A8U78HdjT9YG2sTTThLHJZmhaMn2g8vkWYnr.tar.bz2" + )); - assert!(!rrm.is_get_path( + assert!(!rrm.is_file_get_path( "/snapshot-notaslotnumber-AvFf9oS8A8U78HdjT9YG2sTTThLHJZmhaMn2g8vkWYnr.tar.bz2" )); - assert!(!rrm.is_get_path("/")); - assert!(!rrm.is_get_path("..")); - assert!(!rrm.is_get_path("🎣")); + assert!(!rrm.is_file_get_path("/")); + assert!(!rrm.is_file_get_path("..")); + assert!(!rrm.is_file_get_path("🎣")); } #[test] @@ -441,7 +506,13 @@ mod tests { ContactInfo::default(), ))); - let rm = RpcRequestMiddleware::new(PathBuf::from("/"), None, cluster_info.clone(), None); + let rm = RpcRequestMiddleware::new( + PathBuf::from("/"), + None, + cluster_info.clone(), + None, + create_bank_forks(), + ); assert_eq!(rm.health_check(), "ok"); } @@ -457,6 +528,7 @@ mod tests { None, cluster_info.clone(), Some(trusted_validators.clone().into_iter().collect()), + create_bank_forks(), ); // No account hashes for this node or any trusted validators == "behind" diff --git a/ledger/src/bank_forks.rs b/ledger/src/bank_forks.rs index 58e18f2d3f..e75cd27e92 100644 --- a/ledger/src/bank_forks.rs +++ b/ledger/src/bank_forks.rs @@ -222,6 +222,10 @@ impl BankForks { self.root } + pub fn root_bank(&self) -> &Arc { + self.banks.get(&self.root()).expect("Root bank must exist") + } + pub fn purge_old_snapshots(&self) { // Remove outdated snapshots let config = self.snapshot_config.as_ref().unwrap();