Add rent estimation rpc (#6109)

* server side new rpc endpoint

* client side rpc

* take data_len as usize

Co-Authored-By: Tyera Eulberg <teulberg@gmail.com>

* add test and documentation
This commit is contained in:
Parth 2019-09-26 23:27:13 +05:30 committed by GitHub
parent 74a648accb
commit 67d07254c2
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 120 additions and 1 deletions

View File

@ -30,6 +30,7 @@ To interact with a Solana node inside a JavaScript application, use the [solana-
* [getStorageTurn](jsonrpc-api.md#getstorageturn)
* [getStorageTurnRate](jsonrpc-api.md#getstorageturnrate)
* [getNumBlocksSinceSignatureConfirmation](jsonrpc-api.md#getnumblockssincesignatureconfirmation)
* [getMinimumBalanceForRentExemption](jsonrpc-api.md#getminimumbalanceforrentexemption)
* [getTransactionCount](jsonrpc-api.md#gettransactioncount)
* [getTotalSupply](jsonrpc-api.md#gettotalsupply)
* [getVersion](jsonrpc-api.md#getversion)
@ -455,6 +456,28 @@ curl -X POST -H "Content-Type: application/json" -d '{"jsonrpc":"2.0", "id":1, "
{"jsonrpc":"2.0","result":8,"id":1}
```
### getMinimumBalanceForRentExemption
Returns minimum balance required to make account rent exempt.
#### Parameters:
* `integer` - account data length, as unsigned integer
#### Results:
* `integer` - minimum lamports required in account, as unsigned 64-bit integer
#### Example:
```bash
// Request
curl -X POST -H "Content-Type: application/json" -d '{"jsonrpc":"2.0", "id":1, "method":"getMinimumBalanceForRentExemption", "params":[50]}' http://localhost:8899
// Result
{"jsonrpc":"2.0","result":500,"id":1}
```
### getTransactionCount
Returns the current Transaction count from the ledger

View File

@ -306,6 +306,35 @@ impl RpcClient {
self.get_account(pubkey).map(|account| account.data)
}
pub fn get_minimum_balance_for_rent_exemption(&self, data_len: usize) -> io::Result<u64> {
let params = json!([data_len]);
let minimum_balance_json = self
.client
.send(
&RpcRequest::GetMinimumBalanceForRentExemption,
Some(params),
0,
)
.map_err(|err| {
io::Error::new(
io::ErrorKind::Other,
format!(
"GetMinimumBalanceForRentExemption request failure: {:?}",
err
),
)
})?;
let minimum_balance: u64 =
serde_json::from_value(minimum_balance_json).expect("deserialize minimum_balance");
trace!(
"Response minimum balance {:?} {:?}",
data_len,
minimum_balance
);
Ok(minimum_balance)
}
/// Request the balance of the user holding `pubkey`. This method blocks
/// until the server sends a response. If the response packet is dropped
/// by the network, this method will hang indefinitely.

View File

@ -28,6 +28,7 @@ pub enum RpcRequest {
RequestAirdrop,
SendTransaction,
SignVote,
GetMinimumBalanceForRentExemption,
}
impl RpcRequest {
@ -61,6 +62,7 @@ impl RpcRequest {
RpcRequest::RequestAirdrop => "requestAirdrop",
RpcRequest::SendTransaction => "sendTransaction",
RpcRequest::SignVote => "signVote",
RpcRequest::GetMinimumBalanceForRentExemption => "getMinimumBalanceForRentExemption",
};
let mut request = json!({
"jsonrpc": jsonrpc,

View File

@ -73,6 +73,10 @@ impl JsonRpcRequestProcessor {
.ok_or_else(Error::invalid_request)
}
pub fn get_minimum_balance_for_rent_exemption(&self, data_len: usize) -> Result<u64> {
Ok(self.bank().get_minimum_balance_for_rent_exemption(data_len))
}
pub fn get_program_accounts(&self, program_id: &Pubkey) -> Result<Vec<(String, Account)>> {
Ok(self
.bank()
@ -299,6 +303,9 @@ pub trait RpcSol {
#[rpc(meta, name = "getProgramAccounts")]
fn get_program_accounts(&self, _: Self::Metadata, _: String) -> Result<Vec<(String, Account)>>;
#[rpc(meta, name = "getMinimumBalanceForRentExemption")]
fn get_minimum_balance_for_rent_exemption(&self, _: Self::Metadata, _: usize) -> Result<u64>;
#[rpc(meta, name = "getInflation")]
fn get_inflation(&self, _: Self::Metadata) -> Result<Inflation>;
@ -407,6 +414,21 @@ impl RpcSol for RpcSolImpl {
.get_account_info(&pubkey)
}
fn get_minimum_balance_for_rent_exemption(
&self,
meta: Self::Metadata,
data_len: usize,
) -> Result<u64> {
debug!(
"get_minimum_balance_for_rent_exemption rpc request received: {:?}",
data_len
);
meta.request_processor
.read()
.unwrap()
.get_minimum_balance_for_rent_exemption(data_len)
}
fn get_program_accounts(
&self,
meta: Self::Metadata,
@ -877,6 +899,39 @@ pub mod tests {
assert!(supply >= TEST_MINT_LAMPORTS);
}
#[test]
fn test_rpc_get_minimum_balance_for_rent_exemption() {
let bob_pubkey = Pubkey::new_rand();
let data_len = 50;
let (io, meta, bank, _blockhash, _alice, _leader_pubkey) =
start_rpc_handler_with_tx(&bob_pubkey);
let req = format!(
r#"{{"jsonrpc":"2.0","id":1,"method":"getMinimumBalanceForRentExemption","params":[{}]}}"#,
data_len
);
let rep = io.handle_request_sync(&req, meta);
let res: Response = serde_json::from_str(&rep.expect("actual response"))
.expect("actual response deserialization");
let minimum_balance: 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_eq!(
minimum_balance,
bank.get_minimum_balance_for_rent_exemption(data_len)
);
}
#[test]
fn test_rpc_get_inflation() {
let bob_pubkey = Pubkey::new_rand();
@ -1171,10 +1226,14 @@ pub mod tests {
fn new_bank_forks() -> (Arc<RwLock<BankForks>>, Keypair) {
let GenesisBlockInfo {
genesis_block,
mut genesis_block,
mint_keypair,
..
} = create_genesis_block(TEST_MINT_LAMPORTS);
genesis_block.rent_calculator.lamports_per_byte_year = 50;
genesis_block.rent_calculator.exemption_threshold = 2.0;
let bank = Bank::new(&genesis_block);
(
Arc::new(RwLock::new(BankForks::new(bank.slot(), bank))),

View File

@ -679,6 +679,12 @@ impl Bank {
self.blockhash_queue.read().unwrap().last_hash()
}
pub fn get_minimum_balance_for_rent_exemption(&self, data_len: usize) -> u64 {
self.rent_collector
.rent_calculator
.minimum_balance(data_len)
}
pub fn last_blockhash_with_fee_calculator(&self) -> (Hash, FeeCalculator) {
let blockhash_queue = self.blockhash_queue.read().unwrap();
let last_hash = blockhash_queue.last_hash();