Add v0 REST APIs for circulating and total supply (#10102)
This commit is contained in:
parent
64cec764b9
commit
324cfd40f0
|
@ -8,7 +8,7 @@ pub struct NonCirculatingSupply {
|
||||||
pub accounts: Vec<Pubkey>,
|
pub accounts: Vec<Pubkey>,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn calculate_non_circulating_supply(bank: Arc<Bank>) -> NonCirculatingSupply {
|
pub fn calculate_non_circulating_supply(bank: &Arc<Bank>) -> NonCirculatingSupply {
|
||||||
debug!("Updating Bank supply, epoch: {}", bank.epoch());
|
debug!("Updating Bank supply, epoch: {}", bank.epoch());
|
||||||
let mut non_circulating_accounts_set: HashSet<Pubkey> = HashSet::new();
|
let mut non_circulating_accounts_set: HashSet<Pubkey> = HashSet::new();
|
||||||
|
|
||||||
|
@ -150,7 +150,7 @@ mod tests {
|
||||||
(num_genesis_accounts + num_non_circulating_accounts + num_stake_accounts) * balance
|
(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!(
|
assert_eq!(
|
||||||
non_circulating_supply.lamports,
|
non_circulating_supply.lamports,
|
||||||
(num_non_circulating_accounts + num_stake_accounts) * balance
|
(num_non_circulating_accounts + num_stake_accounts) * balance
|
||||||
|
@ -165,7 +165,7 @@ mod tests {
|
||||||
for key in non_circulating_accounts {
|
for key in non_circulating_accounts {
|
||||||
bank.store_account(&key, &Account::new(new_balance, 0, &Pubkey::default()));
|
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!(
|
assert_eq!(
|
||||||
non_circulating_supply.lamports,
|
non_circulating_supply.lamports,
|
||||||
(num_non_circulating_accounts * new_balance) + (num_stake_accounts * balance)
|
(num_non_circulating_accounts * new_balance) + (num_stake_accounts * balance)
|
||||||
|
@ -180,7 +180,7 @@ mod tests {
|
||||||
bank = Arc::new(new_from_parent(&bank));
|
bank = Arc::new(new_from_parent(&bank));
|
||||||
}
|
}
|
||||||
assert_eq!(bank.epoch(), 1);
|
assert_eq!(bank.epoch(), 1);
|
||||||
let non_circulating_supply = calculate_non_circulating_supply(bank);
|
let non_circulating_supply = calculate_non_circulating_supply(&bank);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
non_circulating_supply.lamports,
|
non_circulating_supply.lamports,
|
||||||
num_non_circulating_accounts * new_balance
|
num_non_circulating_accounts * new_balance
|
||||||
|
|
|
@ -291,7 +291,7 @@ impl JsonRpcRequestProcessor {
|
||||||
let config = config.unwrap_or_default();
|
let config = config.unwrap_or_default();
|
||||||
let bank = self.bank(config.commitment)?;
|
let bank = self.bank(config.commitment)?;
|
||||||
let (addresses, address_filter) = if let Some(filter) = config.filter {
|
let (addresses, address_filter) = if let Some(filter) = config.filter {
|
||||||
let non_circulating_supply = calculate_non_circulating_supply(bank.clone());
|
let non_circulating_supply = calculate_non_circulating_supply(&bank);
|
||||||
let addresses = non_circulating_supply.accounts.into_iter().collect();
|
let addresses = non_circulating_supply.accounts.into_iter().collect();
|
||||||
let address_filter = match filter {
|
let address_filter = match filter {
|
||||||
RpcLargestAccountsFilter::Circulating => AccountAddressFilter::Exclude,
|
RpcLargestAccountsFilter::Circulating => AccountAddressFilter::Exclude,
|
||||||
|
@ -315,7 +315,7 @@ impl JsonRpcRequestProcessor {
|
||||||
|
|
||||||
fn get_supply(&self, commitment: Option<CommitmentConfig>) -> RpcResponse<RpcSupply> {
|
fn get_supply(&self, commitment: Option<CommitmentConfig>) -> RpcResponse<RpcSupply> {
|
||||||
let bank = self.bank(commitment)?;
|
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();
|
let total_supply = bank.capitalization();
|
||||||
new_response(
|
new_response(
|
||||||
&bank,
|
&bank,
|
||||||
|
|
|
@ -43,6 +43,7 @@ struct RpcRequestMiddleware {
|
||||||
snapshot_config: Option<SnapshotConfig>,
|
snapshot_config: Option<SnapshotConfig>,
|
||||||
cluster_info: Arc<ClusterInfo>,
|
cluster_info: Arc<ClusterInfo>,
|
||||||
trusted_validators: Option<HashSet<Pubkey>>,
|
trusted_validators: Option<HashSet<Pubkey>>,
|
||||||
|
bank_forks: Arc<RwLock<BankForks>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl RpcRequestMiddleware {
|
impl RpcRequestMiddleware {
|
||||||
|
@ -51,6 +52,7 @@ impl RpcRequestMiddleware {
|
||||||
snapshot_config: Option<SnapshotConfig>,
|
snapshot_config: Option<SnapshotConfig>,
|
||||||
cluster_info: Arc<ClusterInfo>,
|
cluster_info: Arc<ClusterInfo>,
|
||||||
trusted_validators: Option<HashSet<Pubkey>>,
|
trusted_validators: Option<HashSet<Pubkey>>,
|
||||||
|
bank_forks: Arc<RwLock<BankForks>>,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
Self {
|
Self {
|
||||||
ledger_path,
|
ledger_path,
|
||||||
|
@ -61,6 +63,7 @@ impl RpcRequestMiddleware {
|
||||||
snapshot_config,
|
snapshot_config,
|
||||||
cluster_info,
|
cluster_info,
|
||||||
trusted_validators,
|
trusted_validators,
|
||||||
|
bank_forks,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -86,7 +89,7 @@ impl RpcRequestMiddleware {
|
||||||
.unwrap()
|
.unwrap()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn is_get_path(&self, path: &str) -> bool {
|
fn is_file_get_path(&self, path: &str) -> bool {
|
||||||
match path {
|
match path {
|
||||||
"/genesis.tar.bz2" => true,
|
"/genesis.tar.bz2" => true,
|
||||||
_ => {
|
_ => {
|
||||||
|
@ -99,7 +102,7 @@ impl RpcRequestMiddleware {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get(&self, path: &str) -> RequestMiddlewareAction {
|
fn process_file_get(&self, path: &str) -> RequestMiddlewareAction {
|
||||||
let stem = path.split_at(1).1; // Drop leading '/' from path
|
let stem = path.split_at(1).1; // Drop leading '/' from path
|
||||||
let filename = {
|
let filename = {
|
||||||
match path {
|
match path {
|
||||||
|
@ -218,8 +221,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" {
|
} else if request.uri().path() == "/health" {
|
||||||
RequestMiddlewareAction::Respond {
|
RequestMiddlewareAction::Respond {
|
||||||
should_validate_hosts: true,
|
should_validate_hosts: true,
|
||||||
|
@ -239,6 +253,26 @@ impl RequestMiddleware for RpcRequestMiddleware {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn process_rest(bank_forks: &Arc<RwLock<BankForks>>, path: &str) -> Option<String> {
|
||||||
|
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 {
|
impl JsonRpcService {
|
||||||
#[allow(clippy::too_many_arguments)]
|
#[allow(clippy::too_many_arguments)]
|
||||||
pub fn new(
|
pub fn new(
|
||||||
|
@ -258,7 +292,7 @@ impl JsonRpcService {
|
||||||
info!("rpc configuration: {:?}", config);
|
info!("rpc configuration: {:?}", config);
|
||||||
let request_processor = Arc::new(RwLock::new(JsonRpcRequestProcessor::new(
|
let request_processor = Arc::new(RwLock::new(JsonRpcRequestProcessor::new(
|
||||||
config,
|
config,
|
||||||
bank_forks,
|
bank_forks.clone(),
|
||||||
block_commitment_cache,
|
block_commitment_cache,
|
||||||
blockstore,
|
blockstore,
|
||||||
validator_exit.clone(),
|
validator_exit.clone(),
|
||||||
|
@ -282,6 +316,7 @@ impl JsonRpcService {
|
||||||
snapshot_config,
|
snapshot_config,
|
||||||
cluster_info.clone(),
|
cluster_info.clone(),
|
||||||
trusted_validators,
|
trusted_validators,
|
||||||
|
bank_forks.clone(),
|
||||||
);
|
);
|
||||||
let server = ServerBuilder::with_meta_extractor(
|
let server = ServerBuilder::with_meta_extractor(
|
||||||
io,
|
io,
|
||||||
|
@ -411,11 +446,39 @@ mod tests {
|
||||||
rpc_service.join().unwrap();
|
rpc_service.join().unwrap();
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
fn create_bank_forks() -> Arc<RwLock<BankForks>> {
|
||||||
fn test_is_get_path() {
|
let GenesisConfigInfo { genesis_config, .. } = create_genesis_config(10_000);
|
||||||
let cluster_info = Arc::new(ClusterInfo::new_with_invalid_keypair(ContactInfo::default()));
|
let bank = Bank::new(&genesis_config);
|
||||||
|
Arc::new(RwLock::new(BankForks::new(bank.slot(), bank)))
|
||||||
|
}
|
||||||
|
|
||||||
let rrm = RpcRequestMiddleware::new(PathBuf::from("/"), None, cluster_info.clone(), None);
|
#[test]
|
||||||
|
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(ClusterInfo::new_with_invalid_keypair(ContactInfo::default()));
|
||||||
|
let bank_forks = create_bank_forks();
|
||||||
|
|
||||||
|
let rrm = RpcRequestMiddleware::new(
|
||||||
|
PathBuf::from("/"),
|
||||||
|
None,
|
||||||
|
cluster_info.clone(),
|
||||||
|
None,
|
||||||
|
bank_forks.clone(),
|
||||||
|
);
|
||||||
let rrm_with_snapshot_config = RpcRequestMiddleware::new(
|
let rrm_with_snapshot_config = RpcRequestMiddleware::new(
|
||||||
PathBuf::from("/"),
|
PathBuf::from("/"),
|
||||||
Some(SnapshotConfig {
|
Some(SnapshotConfig {
|
||||||
|
@ -426,33 +489,41 @@ mod tests {
|
||||||
}),
|
}),
|
||||||
cluster_info,
|
cluster_info,
|
||||||
None,
|
None,
|
||||||
|
bank_forks,
|
||||||
);
|
);
|
||||||
|
|
||||||
assert!(rrm.is_get_path("/genesis.tar.bz2"));
|
assert!(rrm.is_file_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_get_path("/snapshot.tar.bz2")); // This is a redirect
|
assert!(!rrm.is_file_get_path("/snapshot.tar.bz2")); // This is a redirect
|
||||||
|
|
||||||
assert!(
|
assert!(!rrm.is_file_get_path(
|
||||||
!rrm.is_get_path("/snapshot-100-AvFf9oS8A8U78HdjT9YG2sTTThLHJZmhaMn2g8vkWYnr.tar.bz2")
|
"/snapshot-100-AvFf9oS8A8U78HdjT9YG2sTTThLHJZmhaMn2g8vkWYnr.tar.bz2"
|
||||||
);
|
));
|
||||||
assert!(rrm_with_snapshot_config
|
assert!(rrm_with_snapshot_config.is_file_get_path(
|
||||||
.is_get_path("/snapshot-100-AvFf9oS8A8U78HdjT9YG2sTTThLHJZmhaMn2g8vkWYnr.tar.bz2"));
|
"/snapshot-100-AvFf9oS8A8U78HdjT9YG2sTTThLHJZmhaMn2g8vkWYnr.tar.bz2"
|
||||||
|
));
|
||||||
|
|
||||||
assert!(!rrm.is_get_path(
|
assert!(!rrm.is_file_get_path(
|
||||||
"/snapshot-notaslotnumber-AvFf9oS8A8U78HdjT9YG2sTTThLHJZmhaMn2g8vkWYnr.tar.bz2"
|
"/snapshot-notaslotnumber-AvFf9oS8A8U78HdjT9YG2sTTThLHJZmhaMn2g8vkWYnr.tar.bz2"
|
||||||
));
|
));
|
||||||
|
|
||||||
assert!(!rrm.is_get_path("/"));
|
assert!(!rrm.is_file_get_path("/"));
|
||||||
assert!(!rrm.is_get_path(".."));
|
assert!(!rrm.is_file_get_path(".."));
|
||||||
assert!(!rrm.is_get_path("🎣"));
|
assert!(!rrm.is_file_get_path("🎣"));
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_health_check_with_no_trusted_validators() {
|
fn test_health_check_with_no_trusted_validators() {
|
||||||
let cluster_info = Arc::new(ClusterInfo::new_with_invalid_keypair(ContactInfo::default()));
|
let cluster_info = Arc::new(ClusterInfo::new_with_invalid_keypair(ContactInfo::default()));
|
||||||
|
|
||||||
let rm = RpcRequestMiddleware::new(PathBuf::from("/"), None, cluster_info, None);
|
let rm = RpcRequestMiddleware::new(
|
||||||
|
PathBuf::from("/"),
|
||||||
|
None,
|
||||||
|
cluster_info,
|
||||||
|
None,
|
||||||
|
create_bank_forks(),
|
||||||
|
);
|
||||||
assert_eq!(rm.health_check(), "ok");
|
assert_eq!(rm.health_check(), "ok");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -466,6 +537,7 @@ mod tests {
|
||||||
None,
|
None,
|
||||||
cluster_info.clone(),
|
cluster_info.clone(),
|
||||||
Some(trusted_validators.clone().into_iter().collect()),
|
Some(trusted_validators.clone().into_iter().collect()),
|
||||||
|
create_bank_forks(),
|
||||||
);
|
);
|
||||||
|
|
||||||
// No account hashes for this node or any trusted validators == "behind"
|
// No account hashes for this node or any trusted validators == "behind"
|
||||||
|
|
Loading…
Reference in New Issue