diff --git a/book/src/jsonrpc-api.md b/book/src/jsonrpc-api.md index 1e855c96a9..19d93aeba0 100644 --- a/book/src/jsonrpc-api.md +++ b/book/src/jsonrpc-api.md @@ -30,6 +30,7 @@ Methods * [getSlotLeader](#getslotleader) * [getNumBlocksSinceSignatureConfirmation](#getnumblockssincesignatureconfirmation) * [getTransactionCount](#gettransactioncount) +* [getTotalSupply](#gettotalsupply) * [getEpochVoteAccounts](#getepochvoteaccounts) * [requestAirdrop](#requestairdrop) * [sendTransaction](#sendtransaction) @@ -275,6 +276,26 @@ curl -X POST -H "Content-Type: application/json" -d '{"jsonrpc":"2.0","id":1, "m --- +### getTotalSupply +Returns the current total supply in Lamports + +##### Parameters: +None + +##### Results: +* `integer` - Total supply, as unsigned 64-bit integer + +##### Example: +```bash +// Request +curl -X POST -H "Content-Type: application/json" -d '{"jsonrpc":"2.0","id":1, "method":"getTotalSupply"}' http://localhost:8899 + +// Result +{"jsonrpc":"2.0","result":10126,"id":1} +``` + +--- + ### getEpochVoteAccounts Returns the account info and associated stake for all the voting accounts in the current epoch. diff --git a/core/src/rpc.rs b/core/src/rpc.rs index 1f02110520..d4f60b54b8 100644 --- a/core/src/rpc.rs +++ b/core/src/rpc.rs @@ -104,6 +104,10 @@ impl JsonRpcRequestProcessor { Ok(self.bank().transaction_count() as u64) } + fn get_total_supply(&self) -> Result { + Ok(self.bank().capitalization()) + } + fn get_epoch_vote_accounts(&self) -> Result> { let bank = self.bank(); Ok(bank @@ -228,6 +232,9 @@ pub trait RpcSol { #[rpc(meta, name = "getTransactionCount")] fn get_transaction_count(&self, _: Self::Metadata) -> Result; + #[rpc(meta, name = "getTotalSupply")] + fn get_total_supply(&self, _: Self::Metadata) -> Result; + #[rpc(meta, name = "requestAirdrop")] fn request_airdrop(&self, _: Self::Metadata, _: String, _: u64) -> Result; @@ -376,6 +383,11 @@ impl RpcSol for RpcSolImpl { .get_transaction_count() } + fn get_total_supply(&self, meta: Self::Metadata) -> Result { + debug!("get_total_supply rpc request received"); + meta.request_processor.read().unwrap().get_total_supply() + } + fn request_airdrop(&self, meta: Self::Metadata, id: String, lamports: u64) -> Result { trace!("request_airdrop id={} lamports={}", id, lamports); @@ -511,7 +523,7 @@ mod tests { use super::*; use crate::contact_info::ContactInfo; use crate::genesis_utils::{create_genesis_block, GenesisBlockInfo}; - use jsonrpc_core::{MetaIoHandler, Response}; + use jsonrpc_core::{MetaIoHandler, Output, Response, Value}; use solana_sdk::hash::{hash, Hash}; use solana_sdk::instruction::InstructionError; use solana_sdk::signature::{Keypair, KeypairUtil}; @@ -519,6 +531,8 @@ mod tests { use solana_sdk::transaction::TransactionError; use std::thread; + const TEST_MINT_LAMPORTS: u64 = 10_000; + fn start_rpc_handler_with_tx( pubkey: &Pubkey, ) -> (MetaIoHandler, Meta, Hash, Keypair, Pubkey) { @@ -647,6 +661,31 @@ mod tests { assert_eq!(expected, result); } + #[test] + fn test_rpc_get_total_supply() { + let bob_pubkey = Pubkey::new_rand(); + let (io, meta, _blockhash, _alice, _leader_pubkey) = start_rpc_handler_with_tx(&bob_pubkey); + + let req = format!(r#"{{"jsonrpc":"2.0","id":1,"method":"getTotalSupply"}}"#); + let rep = io.handle_request_sync(&req, meta); + let res: Response = serde_json::from_str(&rep.expect("actual response")) + .expect("actual response deserialization"); + let supply: u64 = if let Response::Single(res) = res { + if let Output::Success(res) = res { + if let Value::Number(num) = res.result { + num.as_u64().unwrap() + } else { + panic!("Expected number"); + } + } else { + panic!("Expected success"); + } + } else { + panic!("Expected single response"); + }; + assert!(supply >= TEST_MINT_LAMPORTS); + } + #[test] fn test_rpc_get_account_info() { let bob_pubkey = Pubkey::new_rand(); @@ -877,7 +916,7 @@ mod tests { genesis_block, mint_keypair, .. - } = create_genesis_block(10_000); + } = create_genesis_block(TEST_MINT_LAMPORTS); let bank = Bank::new(&genesis_block); ( Arc::new(RwLock::new(BankForks::new(bank.slot(), bank))),