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:
parent
74a648accb
commit
67d07254c2
|
@ -30,6 +30,7 @@ To interact with a Solana node inside a JavaScript application, use the [solana-
|
||||||
* [getStorageTurn](jsonrpc-api.md#getstorageturn)
|
* [getStorageTurn](jsonrpc-api.md#getstorageturn)
|
||||||
* [getStorageTurnRate](jsonrpc-api.md#getstorageturnrate)
|
* [getStorageTurnRate](jsonrpc-api.md#getstorageturnrate)
|
||||||
* [getNumBlocksSinceSignatureConfirmation](jsonrpc-api.md#getnumblockssincesignatureconfirmation)
|
* [getNumBlocksSinceSignatureConfirmation](jsonrpc-api.md#getnumblockssincesignatureconfirmation)
|
||||||
|
* [getMinimumBalanceForRentExemption](jsonrpc-api.md#getminimumbalanceforrentexemption)
|
||||||
* [getTransactionCount](jsonrpc-api.md#gettransactioncount)
|
* [getTransactionCount](jsonrpc-api.md#gettransactioncount)
|
||||||
* [getTotalSupply](jsonrpc-api.md#gettotalsupply)
|
* [getTotalSupply](jsonrpc-api.md#gettotalsupply)
|
||||||
* [getVersion](jsonrpc-api.md#getversion)
|
* [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}
|
{"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
|
### getTransactionCount
|
||||||
|
|
||||||
Returns the current Transaction count from the ledger
|
Returns the current Transaction count from the ledger
|
||||||
|
|
|
@ -306,6 +306,35 @@ impl RpcClient {
|
||||||
self.get_account(pubkey).map(|account| account.data)
|
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
|
/// Request the balance of the user holding `pubkey`. This method blocks
|
||||||
/// until the server sends a response. If the response packet is dropped
|
/// until the server sends a response. If the response packet is dropped
|
||||||
/// by the network, this method will hang indefinitely.
|
/// by the network, this method will hang indefinitely.
|
||||||
|
|
|
@ -28,6 +28,7 @@ pub enum RpcRequest {
|
||||||
RequestAirdrop,
|
RequestAirdrop,
|
||||||
SendTransaction,
|
SendTransaction,
|
||||||
SignVote,
|
SignVote,
|
||||||
|
GetMinimumBalanceForRentExemption,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl RpcRequest {
|
impl RpcRequest {
|
||||||
|
@ -61,6 +62,7 @@ impl RpcRequest {
|
||||||
RpcRequest::RequestAirdrop => "requestAirdrop",
|
RpcRequest::RequestAirdrop => "requestAirdrop",
|
||||||
RpcRequest::SendTransaction => "sendTransaction",
|
RpcRequest::SendTransaction => "sendTransaction",
|
||||||
RpcRequest::SignVote => "signVote",
|
RpcRequest::SignVote => "signVote",
|
||||||
|
RpcRequest::GetMinimumBalanceForRentExemption => "getMinimumBalanceForRentExemption",
|
||||||
};
|
};
|
||||||
let mut request = json!({
|
let mut request = json!({
|
||||||
"jsonrpc": jsonrpc,
|
"jsonrpc": jsonrpc,
|
||||||
|
|
|
@ -73,6 +73,10 @@ impl JsonRpcRequestProcessor {
|
||||||
.ok_or_else(Error::invalid_request)
|
.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)>> {
|
pub fn get_program_accounts(&self, program_id: &Pubkey) -> Result<Vec<(String, Account)>> {
|
||||||
Ok(self
|
Ok(self
|
||||||
.bank()
|
.bank()
|
||||||
|
@ -299,6 +303,9 @@ pub trait RpcSol {
|
||||||
#[rpc(meta, name = "getProgramAccounts")]
|
#[rpc(meta, name = "getProgramAccounts")]
|
||||||
fn get_program_accounts(&self, _: Self::Metadata, _: String) -> Result<Vec<(String, Account)>>;
|
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")]
|
#[rpc(meta, name = "getInflation")]
|
||||||
fn get_inflation(&self, _: Self::Metadata) -> Result<Inflation>;
|
fn get_inflation(&self, _: Self::Metadata) -> Result<Inflation>;
|
||||||
|
|
||||||
|
@ -407,6 +414,21 @@ impl RpcSol for RpcSolImpl {
|
||||||
.get_account_info(&pubkey)
|
.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(
|
fn get_program_accounts(
|
||||||
&self,
|
&self,
|
||||||
meta: Self::Metadata,
|
meta: Self::Metadata,
|
||||||
|
@ -877,6 +899,39 @@ pub mod tests {
|
||||||
assert!(supply >= TEST_MINT_LAMPORTS);
|
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]
|
#[test]
|
||||||
fn test_rpc_get_inflation() {
|
fn test_rpc_get_inflation() {
|
||||||
let bob_pubkey = Pubkey::new_rand();
|
let bob_pubkey = Pubkey::new_rand();
|
||||||
|
@ -1171,10 +1226,14 @@ pub mod tests {
|
||||||
|
|
||||||
fn new_bank_forks() -> (Arc<RwLock<BankForks>>, Keypair) {
|
fn new_bank_forks() -> (Arc<RwLock<BankForks>>, Keypair) {
|
||||||
let GenesisBlockInfo {
|
let GenesisBlockInfo {
|
||||||
genesis_block,
|
mut genesis_block,
|
||||||
mint_keypair,
|
mint_keypair,
|
||||||
..
|
..
|
||||||
} = create_genesis_block(TEST_MINT_LAMPORTS);
|
} = 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);
|
let bank = Bank::new(&genesis_block);
|
||||||
(
|
(
|
||||||
Arc::new(RwLock::new(BankForks::new(bank.slot(), bank))),
|
Arc::new(RwLock::new(BankForks::new(bank.slot(), bank))),
|
||||||
|
|
|
@ -679,6 +679,12 @@ impl Bank {
|
||||||
self.blockhash_queue.read().unwrap().last_hash()
|
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) {
|
pub fn last_blockhash_with_fee_calculator(&self) -> (Hash, FeeCalculator) {
|
||||||
let blockhash_queue = self.blockhash_queue.read().unwrap();
|
let blockhash_queue = self.blockhash_queue.read().unwrap();
|
||||||
let last_hash = blockhash_queue.last_hash();
|
let last_hash = blockhash_queue.last_hash();
|
||||||
|
|
Loading…
Reference in New Issue