feat: return bank/block info with block-related results (#6716)

This commit is contained in:
Sunny Gleason
2019-11-12 14:49:41 -05:00
committed by GitHub
parent 2688ae614c
commit 5903339c17
10 changed files with 262 additions and 134 deletions

View File

@ -96,6 +96,13 @@ If commitment configuration is not provided, the node will default to `"commitme
Only methods that query bank state accept the commitment parameter. They are indicated in the API Reference below. Only methods that query bank state accept the commitment parameter. They are indicated in the API Reference below.
#### RpcResponse Structure
Many methods that take a commitment parameter return an RpcResponse JSON object comprised of two parts:
* `context` : An RpcResponseContext JSON structure including a `slot` field at which the operation was evaluated.
* `value` : The value returned by the operation itself.
## JSON RPC API Reference ## JSON RPC API Reference
### confirmTransaction ### confirmTransaction
@ -109,7 +116,7 @@ Returns a transaction receipt
#### Results: #### Results:
* `boolean` - Transaction status, true if Transaction is confirmed * `RpcResponse<boolean>` - RpcResponse JSON object with `value` field set to Transaction status, boolean true if Transaction is confirmed
#### Example: #### Example:
@ -118,7 +125,7 @@ Returns a transaction receipt
curl -X POST -H "Content-Type: application/json" -d '{"jsonrpc":"2.0", "id":1, "method":"confirmTransaction", "params":["5VERv8NMvzbJMEkV8xnrLkEaWRtSz9CosKDYjCJjBRnbJLgp8uirBgmQpjKhoR4tjF3ZpRzrFmBV6UjKdiSZkQUW"]}' http://localhost:8899 curl -X POST -H "Content-Type: application/json" -d '{"jsonrpc":"2.0", "id":1, "method":"confirmTransaction", "params":["5VERv8NMvzbJMEkV8xnrLkEaWRtSz9CosKDYjCJjBRnbJLgp8uirBgmQpjKhoR4tjF3ZpRzrFmBV6UjKdiSZkQUW"]}' http://localhost:8899
// Result // Result
{"jsonrpc":"2.0","result":true,"id":1} {"jsonrpc":"2.0","result":{"context":{"slot":1},"value":true},"id":1}
``` ```
### getAccountInfo ### getAccountInfo
@ -132,8 +139,9 @@ Returns all information associated with the account of provided Pubkey
#### Results: #### Results:
The result field will be a JSON object with the following sub fields: The result value will be an RpcResponse JSON object containing an AccountInfo JSON object.
* `RpcResponse<AccountInfo>`, RpcResponse JSON object with `value` field set to AccountInfo, a JSON object containing:
* `lamports`, number of lamports assigned to this account, as a signed 64-bit integer * `lamports`, number of lamports assigned to this account, as a signed 64-bit integer
* `owner`, array of 32 bytes representing the program this account has been assigned to * `owner`, array of 32 bytes representing the program this account has been assigned to
* `data`, array of bytes representing any data associated with the account * `data`, array of bytes representing any data associated with the account
@ -146,7 +154,7 @@ The result field will be a JSON object with the following sub fields:
curl -X POST -H "Content-Type: application/json" -d '{"jsonrpc":"2.0", "id":1, "method":"getAccountInfo", "params":["2gVkYWexTHR5Hb2aLeQN3tnngvWzisFKXDUPrgMHpdST"]}' http://localhost:8899 curl -X POST -H "Content-Type: application/json" -d '{"jsonrpc":"2.0", "id":1, "method":"getAccountInfo", "params":["2gVkYWexTHR5Hb2aLeQN3tnngvWzisFKXDUPrgMHpdST"]}' http://localhost:8899
// Result // Result
{"jsonrpc":"2.0","result":{"executable":false,"owner":[1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],"lamports":1,"data":[3,0,0,0,0,0,0,0,1,0,0,0,0,0,1,0,0,0,0,0,0,0.21.0,0,0,0,0,0,0,50,48,53,48,45,48,49,45,48,49,84,48,48,58,48,48,58,48,48,90,252,10,7,28,246,140,88,177,98,82,10,227,89,81,18,30,194,101,199,16,11,73,133,20,246,62,114,39,20,113,189,32,50,0,0,0,0,0,0,0,247,15,36,102,167,83,225,42,133,127,82,34,36,224,207,130,109,230,224,188,163,33,213,13,5,117,211,251,65,159,197,51,0,0,0,0,0,0]},"id":1} {"jsonrpc":"2.0","result":{"context":{"slot":1},"value":{"executable":false,"owner":[1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],"lamports":1,"data":[3,0,0,0,0,0,0,0,1,0,0,0,0,0,1,0,0,0,0,0,0,0.21.0,0,0,0,0,0,0,50,48,53,48,45,48,49,45,48,49,84,48,48,58,48,48,58,48,48,90,252,10,7,28,246,140,88,177,98,82,10,227,89,81,18,30,194,101,199,16,11,73,133,20,246,62,114,39,20,113,189,32,50,0,0,0,0,0,0,0,247,15,36,102,167,83,225,42,133,127,82,34,36,224,207,130,109,230,224,188,163,33,213,13,5,117,211,251,65,159,197,51,0,0,0,0,0,0]}},"id":1}
``` ```
### getBalance ### getBalance
@ -160,7 +168,7 @@ Returns the balance of the account of provided Pubkey
#### Results: #### Results:
* `integer` - quantity, as a signed 64-bit integer * `RpcResponse<integer>` - RpcResponse JSON object with `value` field set to quantity, as a signed 64-bit integer
#### Example: #### Example:
@ -169,7 +177,7 @@ Returns the balance of the account of provided Pubkey
curl -X POST -H "Content-Type: application/json" -d '{"jsonrpc":"2.0", "id":1, "method":"getBalance", "params":["83astBRguLMdt2h5U1Tpdq5tjFoJ6noeGwaY3mDLVcri"]}' http://localhost:8899 curl -X POST -H "Content-Type: application/json" -d '{"jsonrpc":"2.0", "id":1, "method":"getBalance", "params":["83astBRguLMdt2h5U1Tpdq5tjFoJ6noeGwaY3mDLVcri"]}' http://localhost:8899
// Result // Result
{"jsonrpc":"2.0","result":0,"id":1} {"jsonrpc":"2.0","result":{"context":{"slot":1},"value":0},"id":1}
``` ```
### getBlockCommitment ### getBlockCommitment
@ -410,8 +418,9 @@ Returns a recent block hash from the ledger, and a fee schedule that can be used
#### Results: #### Results:
An array consisting of An RpcResponse containing an array consisting of a string blockhash and FeeCalculator JSON object.
* `RpcResponse<array>` - RpcResponse JSON object with `value` field set to an array including:
* `string` - a Hash as base-58 encoded string * `string` - a Hash as base-58 encoded string
* `FeeCalculator object` - the fee schedule for this block hash * `FeeCalculator object` - the fee schedule for this block hash
@ -422,7 +431,7 @@ An array consisting of
curl -X POST -H "Content-Type: application/json" -d '{"jsonrpc":"2.0","id":1, "method":"getRecentBlockhash"}' http://localhost:8899 curl -X POST -H "Content-Type: application/json" -d '{"jsonrpc":"2.0","id":1, "method":"getRecentBlockhash"}' http://localhost:8899
// Result // Result
{"jsonrpc":"2.0","result":["GH7ome3EiwEr7tu9JuTh2dpYWBJK3z69Xm1ZE3MEE6JC",{"lamportsPerSignature": 0}],"id":1} {"jsonrpc":"2.0","result":{"context":{"slot":1},"value":["GH7ome3EiwEr7tu9JuTh2dpYWBJK3z69Xm1ZE3MEE6JC",{"lamportsPerSignature": 0}]},"id":1}
``` ```
### getSignatureStatus ### getSignatureStatus

View File

@ -3,7 +3,7 @@ use solana_cli::cli::{process_command, CliCommand, CliConfig};
use solana_client::rpc_client::RpcClient; use solana_client::rpc_client::RpcClient;
use solana_core::validator::new_validator_for_tests; use solana_core::validator::new_validator_for_tests;
use solana_drone::drone::run_local_drone; use solana_drone::drone::run_local_drone;
use solana_sdk::{bpf_loader, commitment_config::CommitmentConfig, pubkey::Pubkey}; use solana_sdk::{bpf_loader, pubkey::Pubkey};
use std::{ use std::{
fs::{remove_dir_all, File}, fs::{remove_dir_all, File},
io::Read, io::Read,
@ -59,10 +59,7 @@ fn test_cli_deploy_program() {
.as_str() .as_str()
.unwrap(); .unwrap();
let program_id = Pubkey::from_str(&program_id_str).unwrap(); let program_id = Pubkey::from_str(&program_id_str).unwrap();
let account = rpc_client.get_account(&program_id).unwrap();
let account = rpc_client
.get_account_with_commitment(&program_id, CommitmentConfig::recent())
.unwrap();
assert_eq!(account.lamports, minimum_balance_for_rent_exemption); assert_eq!(account.lamports, minimum_balance_for_rent_exemption);
assert_eq!(account.owner, bpf_loader::id()); assert_eq!(account.owner, bpf_loader::id());
assert_eq!(account.executable, true); assert_eq!(account.executable, true);

View File

@ -1,3 +1,4 @@
use crate::rpc_request::{Response, RpcResponseContext};
use crate::{ use crate::{
client_error::ClientError, generic_rpc_client_request::GenericRpcClientRequest, client_error::ClientError, generic_rpc_client_request::GenericRpcClientRequest,
rpc_request::RpcRequest, rpc_request::RpcRequest,
@ -48,12 +49,18 @@ impl GenericRpcClientRequest for MockRpcClientRequest {
} }
RpcRequest::GetBalance => { RpcRequest::GetBalance => {
let n = if self.url == "airdrop" { 0 } else { 50 }; let n = if self.url == "airdrop" { 0 } else { 50 };
Value::Number(Number::from(n)) serde_json::to_value(Response {
context: RpcResponseContext { slot: 1 },
value: Value::Number(Number::from(n)),
})?
} }
RpcRequest::GetRecentBlockhash => Value::Array(vec![ RpcRequest::GetRecentBlockhash => serde_json::to_value(Response {
Value::String(PUBKEY.to_string()), context: RpcResponseContext { slot: 1 },
serde_json::to_value(FeeCalculator::default()).unwrap(), value: (
]), Value::String(PUBKEY.to_string()),
serde_json::to_value(FeeCalculator::default()).unwrap(),
),
})?,
RpcRequest::GetSignatureStatus => { RpcRequest::GetSignatureStatus => {
let response: Option<transaction::Result<()>> = if self.url == "account_in_use" { let response: Option<transaction::Result<()>> = if self.url == "account_in_use" {
Some(Err(TransactionError::AccountInUse)) Some(Err(TransactionError::AccountInUse))

View File

@ -1,3 +1,4 @@
use crate::rpc_request::{Response, RpcResponse};
use crate::{ use crate::{
client_error::ClientError, client_error::ClientError,
generic_rpc_client_request::GenericRpcClientRequest, generic_rpc_client_request::GenericRpcClientRequest,
@ -55,31 +56,39 @@ impl RpcClient {
} }
} }
pub fn confirm_transaction(&self, signature: &str) -> Result<bool, ClientError> { pub fn confirm_transaction(&self, signature: &str) -> io::Result<bool> {
self.confirm_transaction_with_commitment(signature, CommitmentConfig::default()) Ok(self
.confirm_transaction_with_commitment(signature, CommitmentConfig::default())?
.value)
} }
pub fn confirm_transaction_with_commitment( pub fn confirm_transaction_with_commitment(
&self, &self,
signature: &str, signature: &str,
commitment_config: CommitmentConfig, commitment_config: CommitmentConfig,
) -> Result<bool, ClientError> { ) -> RpcResponse<bool> {
let params = json!(signature); let params = json!(signature);
let response = self.client.send( let response = self
&RpcRequest::ConfirmTransaction, .client
Some(params), .send(
0, &RpcRequest::ConfirmTransaction,
Some(commitment_config), Some(params),
)?; 0,
if response.as_bool().is_none() { Some(commitment_config),
Err(io::Error::new(
io::ErrorKind::Other,
"Received result of an unexpected type",
) )
.into()) .map_err(|err| {
} else { io::Error::new(
Ok(response.as_bool().unwrap()) io::ErrorKind::Other,
} format!("ConfirmTransaction request failure {:?}", err),
)
})?;
serde_json::from_value::<Response<bool>>(response).map_err(|err| {
io::Error::new(
io::ErrorKind::Other,
format!("Received result of an unexpected type {:?}", err),
)
})
} }
pub fn send_transaction(&self, transaction: &Transaction) -> Result<String, ClientError> { pub fn send_transaction(&self, transaction: &Transaction) -> Result<String, ClientError> {
@ -378,46 +387,69 @@ impl RpcClient {
retries: usize, retries: usize,
) -> Result<Option<u64>, Box<dyn error::Error>> { ) -> Result<Option<u64>, Box<dyn error::Error>> {
let params = json!(format!("{}", pubkey)); let params = json!(format!("{}", pubkey));
let res = self let balance_json = self
.client .client
.send(&RpcRequest::GetBalance, Some(params), retries, None)? .send(&RpcRequest::GetBalance, Some(params), retries, None)
.as_u64(); .map_err(|err| {
Ok(res) io::Error::new(
io::ErrorKind::Other,
format!("RetryGetBalance request failure: {:?}", err),
)
})?;
Ok(Some(
serde_json::from_value::<Response<u64>>(balance_json)
.map_err(|err| {
io::Error::new(
io::ErrorKind::Other,
format!("RetryGetBalance parse failure: {:?}", err),
)
})?
.value,
))
} }
pub fn get_account(&self, pubkey: &Pubkey) -> io::Result<Account> { pub fn get_account(&self, pubkey: &Pubkey) -> io::Result<Account> {
self.get_account_with_commitment(pubkey, CommitmentConfig::default()) Ok(self
.get_account_with_commitment(pubkey, CommitmentConfig::default())
.map(|x| x.value.unwrap())?)
} }
pub fn get_account_with_commitment( pub fn get_account_with_commitment(
&self, &self,
pubkey: &Pubkey, pubkey: &Pubkey,
commitment_config: CommitmentConfig, commitment_config: CommitmentConfig,
) -> io::Result<Account> { ) -> RpcResponse<Option<Account>> {
let params = json!(format!("{}", pubkey)); let params = json!(format!("{}", pubkey));
let response = self.client.send( let response = self.client.send(
&RpcRequest::GetAccountInfo, &RpcRequest::GetAccountInfo,
Some(params), Some(params),
0, 0,
commitment_config.ok(), Some(commitment_config),
); );
response response
.and_then(|account_json| { .map(|result_json| {
let account: Account = serde_json::from_value(account_json)?; if result_json.is_null() {
trace!("Response account {:?} {:?}", pubkey, account); return Err(io::Error::new(
Ok(account) io::ErrorKind::Other,
format!("AccountNotFound: pubkey={}", pubkey),
));
}
let result = serde_json::from_value::<Response<Option<Account>>>(result_json)?;
trace!("Response account {:?} {:?}", pubkey, result);
Ok(result)
}) })
.map_err(|err| { .map_err(|err| {
io::Error::new( io::Error::new(
io::ErrorKind::Other, io::ErrorKind::Other,
format!("AccountNotFound: pubkey={}: {}", pubkey, err), format!("AccountNotFound: pubkey={}: {}", pubkey, err),
) )
}) })?
} }
pub fn get_account_data(&self, pubkey: &Pubkey) -> io::Result<Vec<u8>> { pub fn get_account_data(&self, pubkey: &Pubkey) -> io::Result<Vec<u8>> {
self.get_account(pubkey).map(|account| account.data) Ok(self.get_account(pubkey).unwrap().data)
} }
pub fn get_minimum_balance_for_rent_exemption(&self, data_len: usize) -> io::Result<u64> { pub fn get_minimum_balance_for_rent_exemption(&self, data_len: usize) -> io::Result<u64> {
@ -456,14 +488,16 @@ impl RpcClient {
/// Request the balance of the account `pubkey`. /// Request the balance of the account `pubkey`.
pub fn get_balance(&self, pubkey: &Pubkey) -> io::Result<u64> { pub fn get_balance(&self, pubkey: &Pubkey) -> io::Result<u64> {
self.get_balance_with_commitment(pubkey, CommitmentConfig::default()) Ok(self
.get_balance_with_commitment(pubkey, CommitmentConfig::default())?
.value)
} }
pub fn get_balance_with_commitment( pub fn get_balance_with_commitment(
&self, &self,
pubkey: &Pubkey, pubkey: &Pubkey,
commitment_config: CommitmentConfig, commitment_config: CommitmentConfig,
) -> io::Result<u64> { ) -> RpcResponse<u64> {
let params = json!(pubkey.to_string()); let params = json!(pubkey.to_string());
let balance_json = self let balance_json = self
.client .client
@ -479,7 +513,8 @@ impl RpcClient {
format!("GetBalance request failure: {:?}", err), format!("GetBalance request failure: {:?}", err),
) )
})?; })?;
serde_json::from_value(balance_json).map_err(|err| {
serde_json::from_value::<Response<u64>>(balance_json).map_err(|err| {
io::Error::new( io::Error::new(
io::ErrorKind::Other, io::ErrorKind::Other,
format!("GetBalance parse failure: {:?}", err), format!("GetBalance parse failure: {:?}", err),
@ -553,13 +588,15 @@ impl RpcClient {
} }
pub fn get_recent_blockhash(&self) -> io::Result<(Hash, FeeCalculator)> { pub fn get_recent_blockhash(&self) -> io::Result<(Hash, FeeCalculator)> {
self.get_recent_blockhash_with_commitment(CommitmentConfig::default()) Ok(self
.get_recent_blockhash_with_commitment(CommitmentConfig::default())?
.value)
} }
pub fn get_recent_blockhash_with_commitment( pub fn get_recent_blockhash_with_commitment(
&self, &self,
commitment_config: CommitmentConfig, commitment_config: CommitmentConfig,
) -> io::Result<(Hash, FeeCalculator)> { ) -> RpcResponse<(Hash, FeeCalculator)> {
let response = self let response = self
.client .client
.send( .send(
@ -575,21 +612,27 @@ impl RpcClient {
) )
})?; })?;
let (blockhash, fee_calculator) = let Response {
serde_json::from_value::<(String, FeeCalculator)>(response).map_err(|err| { context,
value: (blockhash_str, fee_calculator),
} = serde_json::from_value::<Response<(String, FeeCalculator)>>(response).map_err(
|err| {
io::Error::new( io::Error::new(
io::ErrorKind::Other, io::ErrorKind::Other,
format!("GetRecentBlockhash parse failure: {:?}", err), format!("GetRecentBlockhash parse failure: {:?}", err),
) )
})?; },
)?;
let blockhash = blockhash.parse().map_err(|err| { let blockhash = blockhash_str.parse().map_err(|err| {
io::Error::new( io::Error::new(
io::ErrorKind::Other, io::ErrorKind::Other,
format!("GetRecentBlockhash hash parse failure: {:?}", err), format!("GetRecentBlockhash hash parse failure: {:?}", err),
) )
})?; })?;
Ok((blockhash, fee_calculator)) Ok(Response {
context,
value: (blockhash, fee_calculator),
})
} }
pub fn get_new_blockhash(&self, blockhash: &Hash) -> io::Result<(Hash, FeeCalculator)> { pub fn get_new_blockhash(&self, blockhash: &Hash) -> io::Result<(Hash, FeeCalculator)> {
@ -658,7 +701,7 @@ impl RpcClient {
loop { loop {
match self.get_balance_with_commitment(&pubkey, commitment_config.clone()) { match self.get_balance_with_commitment(&pubkey, commitment_config.clone()) {
Ok(bal) => { Ok(bal) => {
return Ok(bal); return Ok(bal.value);
} }
Err(e) => { Err(e) => {
sleep(*polling_frequency); sleep(*polling_frequency);

View File

@ -1,9 +1,24 @@
use jsonrpc_core::Result as JsonResult;
use serde_json::{json, Value}; use serde_json::{json, Value};
use solana_sdk::{ use solana_sdk::{
clock::{Epoch, Slot}, clock::{Epoch, Slot},
commitment_config::CommitmentConfig, commitment_config::CommitmentConfig,
}; };
use std::{error, fmt}; use std::{error, fmt, io};
pub type RpcResponseIn<T> = JsonResult<Response<T>>;
pub type RpcResponse<T> = io::Result<Response<T>>;
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub struct RpcResponseContext {
pub slot: u64,
}
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub struct Response<T> {
pub context: RpcResponseContext,
pub value: T,
}
#[derive(Serialize, Deserialize, Clone, Debug)] #[derive(Serialize, Deserialize, Clone, Debug)]
#[serde(rename_all = "camelCase")] #[serde(rename_all = "camelCase")]

View File

@ -4,6 +4,7 @@
//! unstable and may change in future releases. //! unstable and may change in future releases.
use crate::rpc_client::RpcClient; use crate::rpc_client::RpcClient;
use crate::rpc_request::Response;
use bincode::{serialize_into, serialized_size}; use bincode::{serialize_into, serialized_size};
use log::*; use log::*;
use solana_sdk::{ use solana_sdk::{
@ -383,7 +384,11 @@ impl SyncClient for ThinClient {
} }
fn get_account(&self, pubkey: &Pubkey) -> TransportResult<Option<Account>> { fn get_account(&self, pubkey: &Pubkey) -> TransportResult<Option<Account>> {
Ok(self.rpc_client().get_account(pubkey).ok()) let account = self.rpc_client().get_account(pubkey);
match account {
Ok(value) => Ok(Some(value)),
Err(_) => Ok(None),
}
} }
fn get_account_with_commitment( fn get_account_with_commitment(
@ -393,13 +398,12 @@ impl SyncClient for ThinClient {
) -> TransportResult<Option<Account>> { ) -> TransportResult<Option<Account>> {
Ok(self Ok(self
.rpc_client() .rpc_client()
.get_account_with_commitment(pubkey, commitment_config) .get_account_with_commitment(pubkey, commitment_config)?
.ok()) .value)
} }
fn get_balance(&self, pubkey: &Pubkey) -> TransportResult<u64> { fn get_balance(&self, pubkey: &Pubkey) -> TransportResult<u64> {
let balance = self.rpc_client().get_balance(pubkey)?; Ok(self.rpc_client().get_balance(pubkey)?)
Ok(balance)
} }
fn get_balance_with_commitment( fn get_balance_with_commitment(
@ -410,7 +414,7 @@ impl SyncClient for ThinClient {
let balance = self let balance = self
.rpc_client() .rpc_client()
.get_balance_with_commitment(pubkey, commitment_config)?; .get_balance_with_commitment(pubkey, commitment_config)?;
Ok(balance) Ok(balance.value)
} }
fn get_recent_blockhash(&self) -> TransportResult<(Hash, FeeCalculator)> { fn get_recent_blockhash(&self) -> TransportResult<(Hash, FeeCalculator)> {
@ -426,9 +430,9 @@ impl SyncClient for ThinClient {
let recent_blockhash = let recent_blockhash =
self.rpc_clients[index].get_recent_blockhash_with_commitment(commitment_config); self.rpc_clients[index].get_recent_blockhash_with_commitment(commitment_config);
match recent_blockhash { match recent_blockhash {
Ok(recent_blockhash) => { Ok(Response { value, .. }) => {
self.optimizer.report(index, duration_as_ms(&now.elapsed())); self.optimizer.report(index, duration_as_ms(&now.elapsed()));
Ok(recent_blockhash) Ok(value)
} }
Err(e) => { Err(e) => {
self.optimizer.report(index, std::u64::MAX); self.optimizer.report(index, std::u64::MAX);

View File

@ -12,7 +12,9 @@ use crate::{
use bincode::serialize; use bincode::serialize;
use jsonrpc_core::{Error, Metadata, Result}; use jsonrpc_core::{Error, Metadata, Result};
use jsonrpc_derive::rpc; use jsonrpc_derive::rpc;
use solana_client::rpc_request::{RpcEpochInfo, RpcVoteAccountInfo, RpcVoteAccountStatus}; use solana_client::rpc_request::{
Response, RpcEpochInfo, RpcResponseContext, RpcVoteAccountInfo, RpcVoteAccountStatus,
};
use solana_drone::drone::request_airdrop_transaction; use solana_drone::drone::request_airdrop_transaction;
use solana_ledger::{ use solana_ledger::{
bank_forks::BankForks, blocktree::Blocktree, rooted_slot_iterator::RootedSlotIterator, bank_forks::BankForks, blocktree::Blocktree, rooted_slot_iterator::RootedSlotIterator,
@ -40,6 +42,13 @@ use std::{
time::{Duration, Instant}, time::{Duration, Instant},
}; };
type RpcResponse<T> = Result<Response<T>>;
fn new_response<T>(bank: &Bank, value: T) -> RpcResponse<T> {
let context = RpcResponseContext { slot: bank.slot() };
Ok(Response { context, value })
}
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
pub struct JsonRpcConfig { pub struct JsonRpcConfig {
pub enable_validator_exit: bool, // Enable the 'validatorExit' command pub enable_validator_exit: bool, // Enable the 'validatorExit' command
@ -100,12 +109,14 @@ impl JsonRpcRequestProcessor {
pub fn get_account_info( pub fn get_account_info(
&self, &self,
pubkey: &Pubkey, pubkey: Result<Pubkey>,
commitment: Option<CommitmentConfig>, commitment: Option<CommitmentConfig>,
) -> Result<Account> { ) -> RpcResponse<Option<Account>> {
self.bank(commitment) let bank = &*self.bank(commitment);
.get_account(&pubkey) match pubkey {
.ok_or_else(Error::invalid_request) Ok(key) => new_response(bank, bank.get_account(&key)),
Err(e) => Err(e),
}
} }
pub fn get_minimum_balance_for_rent_exemption( pub fn get_minimum_balance_for_rent_exemption(
@ -141,16 +152,43 @@ impl JsonRpcRequestProcessor {
Ok(*self.bank(None).epoch_schedule()) Ok(*self.bank(None).epoch_schedule())
} }
pub fn get_balance(&self, pubkey: &Pubkey, commitment: Option<CommitmentConfig>) -> u64 { pub fn get_balance(
self.bank(commitment).get_balance(&pubkey) &self,
pubkey: Result<Pubkey>,
commitment: Option<CommitmentConfig>,
) -> RpcResponse<u64> {
let bank = &*self.bank(commitment);
match pubkey {
Ok(key) => new_response(bank, bank.get_balance(&key)),
Err(e) => Err(e),
}
} }
fn get_recent_blockhash( fn get_recent_blockhash(
&self, &self,
commitment: Option<CommitmentConfig>, commitment: Option<CommitmentConfig>,
) -> (String, FeeCalculator) { ) -> RpcResponse<(String, FeeCalculator)> {
let (blockhash, fee_calculator) = self.bank(commitment).confirmed_last_blockhash(); let bank = &*self.bank(commitment);
(blockhash.to_string(), fee_calculator) let (blockhash, fee_calculator) = bank.confirmed_last_blockhash();
new_response(bank, (blockhash.to_string(), fee_calculator))
}
pub fn confirm_transaction(
&self,
signature: Result<Signature>,
commitment: Option<CommitmentConfig>,
) -> RpcResponse<bool> {
let bank = &*self.bank(commitment);
match signature {
Err(e) => Err(e),
Ok(sig) => {
let status = bank.get_signature_confirmation_status(&sig);
match status {
Some((_, result)) => new_response(bank, result.is_ok()),
None => new_response(bank, false),
}
}
}
} }
fn get_block_commitment(&self, block: Slot) -> (Option<BlockCommitment>, u64) { fn get_block_commitment(&self, block: Slot) -> (Option<BlockCommitment>, u64) {
@ -333,7 +371,7 @@ pub trait RpcSol {
meta: Self::Metadata, meta: Self::Metadata,
signature_str: String, signature_str: String,
commitment: Option<CommitmentConfig>, commitment: Option<CommitmentConfig>,
) -> Result<bool>; ) -> RpcResponse<bool>;
#[rpc(meta, name = "getAccountInfo")] #[rpc(meta, name = "getAccountInfo")]
fn get_account_info( fn get_account_info(
@ -341,7 +379,7 @@ pub trait RpcSol {
meta: Self::Metadata, meta: Self::Metadata,
pubkey_str: String, pubkey_str: String,
commitment: Option<CommitmentConfig>, commitment: Option<CommitmentConfig>,
) -> Result<Account>; ) -> RpcResponse<Option<Account>>;
#[rpc(meta, name = "getProgramAccounts")] #[rpc(meta, name = "getProgramAccounts")]
fn get_program_accounts( fn get_program_accounts(
@ -375,7 +413,7 @@ pub trait RpcSol {
meta: Self::Metadata, meta: Self::Metadata,
pubkey_str: String, pubkey_str: String,
commitment: Option<CommitmentConfig>, commitment: Option<CommitmentConfig>,
) -> Result<u64>; ) -> RpcResponse<u64>;
#[rpc(meta, name = "getClusterNodes")] #[rpc(meta, name = "getClusterNodes")]
fn get_cluster_nodes(&self, meta: Self::Metadata) -> Result<Vec<RpcContactInfo>>; fn get_cluster_nodes(&self, meta: Self::Metadata) -> Result<Vec<RpcContactInfo>>;
@ -409,7 +447,7 @@ pub trait RpcSol {
&self, &self,
meta: Self::Metadata, meta: Self::Metadata,
commitment: Option<CommitmentConfig>, commitment: Option<CommitmentConfig>,
) -> Result<(String, FeeCalculator)>; ) -> RpcResponse<(String, FeeCalculator)>;
#[rpc(meta, name = "getSignatureStatus")] #[rpc(meta, name = "getSignatureStatus")]
fn get_signature_status( fn get_signature_status(
@ -521,20 +559,15 @@ impl RpcSol for RpcSolImpl {
fn confirm_transaction( fn confirm_transaction(
&self, &self,
meta: Self::Metadata, meta: Self::Metadata,
signature_str: String, id: String,
commitment: Option<CommitmentConfig>, commitment: Option<CommitmentConfig>,
) -> Result<bool> { ) -> RpcResponse<bool> {
debug!( debug!("confirm_transaction rpc request received: {:?}", id);
"confirm_transaction rpc request received: {:?}", let signature = verify_signature(&id);
signature_str meta.request_processor
); .read()
self.get_signature_status(meta, signature_str, commitment) .unwrap()
.map(|status_option| { .confirm_transaction(signature, commitment)
if status_option.is_none() {
return false;
}
status_option.unwrap().is_ok()
})
} }
fn get_account_info( fn get_account_info(
@ -542,13 +575,13 @@ impl RpcSol for RpcSolImpl {
meta: Self::Metadata, meta: Self::Metadata,
pubkey_str: String, pubkey_str: String,
commitment: Option<CommitmentConfig>, commitment: Option<CommitmentConfig>,
) -> Result<Account> { ) -> RpcResponse<Option<Account>> {
debug!("get_account_info rpc request received: {:?}", pubkey_str); debug!("get_account_info rpc request received: {:?}", pubkey_str);
let pubkey = verify_pubkey(pubkey_str)?; let pubkey = verify_pubkey(pubkey_str);
meta.request_processor meta.request_processor
.read() .read()
.unwrap() .unwrap()
.get_account_info(&pubkey, commitment) .get_account_info(pubkey, commitment)
} }
fn get_minimum_balance_for_rent_exemption( fn get_minimum_balance_for_rent_exemption(
@ -613,14 +646,13 @@ impl RpcSol for RpcSolImpl {
meta: Self::Metadata, meta: Self::Metadata,
pubkey_str: String, pubkey_str: String,
commitment: Option<CommitmentConfig>, commitment: Option<CommitmentConfig>,
) -> Result<u64> { ) -> RpcResponse<u64> {
debug!("get_balance rpc request received: {:?}", pubkey_str); debug!("get_balance rpc request received: {:?}", pubkey_str);
let pubkey = verify_pubkey(pubkey_str)?; let pubkey = verify_pubkey(pubkey_str);
Ok(meta meta.request_processor
.request_processor
.read() .read()
.unwrap() .unwrap()
.get_balance(&pubkey, commitment)) .get_balance(pubkey, commitment)
} }
fn get_cluster_nodes(&self, meta: Self::Metadata) -> Result<Vec<RpcContactInfo>> { fn get_cluster_nodes(&self, meta: Self::Metadata) -> Result<Vec<RpcContactInfo>> {
@ -707,13 +739,12 @@ impl RpcSol for RpcSolImpl {
&self, &self,
meta: Self::Metadata, meta: Self::Metadata,
commitment: Option<CommitmentConfig>, commitment: Option<CommitmentConfig>,
) -> Result<(String, FeeCalculator)> { ) -> RpcResponse<(String, FeeCalculator)> {
debug!("get_recent_blockhash rpc request received"); debug!("get_recent_blockhash rpc request received");
Ok(meta meta.request_processor
.request_processor
.read() .read()
.unwrap() .unwrap()
.get_recent_blockhash(commitment)) .get_recent_blockhash(commitment)
} }
fn get_signature_status( fn get_signature_status(
@ -1150,10 +1181,15 @@ pub mod tests {
bob_pubkey bob_pubkey
); );
let res = io.handle_request_sync(&req, meta); let res = io.handle_request_sync(&req, meta);
let expected = format!(r#"{{"jsonrpc":"2.0","result":20,"id":1}}"#); let expected = json!({
let expected: Response = "jsonrpc": "2.0",
serde_json::from_str(&expected).expect("expected response deserialization"); "result": {
let result: Response = serde_json::from_str(&res.expect("actual response")) "context":{"slot":0},
"value":20,
},
"id": 1,
});
let result = serde_json::from_str::<Value>(&res.expect("actual response"))
.expect("actual response deserialization"); .expect("actual response deserialization");
assert_eq!(expected, result); assert_eq!(expected, result);
} }
@ -1328,19 +1364,22 @@ pub mod tests {
bob_pubkey bob_pubkey
); );
let res = io.handle_request_sync(&req, meta); let res = io.handle_request_sync(&req, meta);
let expected = r#"{ let expected = json!({
"jsonrpc":"2.0", "jsonrpc": "2.0",
"result":{ "result": {
"context":{"slot":0},
"value":{
"owner": [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0], "owner": [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],
"lamports": 20, "lamports": 20,
"data": [], "data": [],
"executable": false, "executable": false,
"rent_epoch": 0 "rent_epoch": 0
}, },
"id":1} },
"#; "id": 1,
});
let expected: Response = let expected: Response =
serde_json::from_str(&expected).expect("expected response deserialization"); serde_json::from_value(expected).expect("expected response deserialization");
let result: Response = serde_json::from_str(&res.expect("actual response")) let result: Response = serde_json::from_str(&res.expect("actual response"))
.expect("actual response deserialization"); .expect("actual response deserialization");
assert_eq!(expected, result); assert_eq!(expected, result);
@ -1404,9 +1443,16 @@ pub mod tests {
tx.signatures[0] tx.signatures[0]
); );
let res = io.handle_request_sync(&req, meta); let res = io.handle_request_sync(&req, meta);
let expected = format!(r#"{{"jsonrpc":"2.0","result":true,"id":1}}"#); let expected = json!({
"jsonrpc": "2.0",
"result": {
"context":{"slot":0},
"value":true,
},
"id": 1,
});
let expected: Response = let expected: Response =
serde_json::from_str(&expected).expect("expected response deserialization"); serde_json::from_value(expected).expect("expected response deserialization");
let result: Response = serde_json::from_str(&res.expect("actual response")) let result: Response = serde_json::from_str(&res.expect("actual response"))
.expect("actual response deserialization"); .expect("actual response deserialization");
assert_eq!(expected, result); assert_eq!(expected, result);
@ -1496,14 +1542,16 @@ pub mod tests {
let res = io.handle_request_sync(&req, meta); let res = io.handle_request_sync(&req, meta);
let expected = json!({ let expected = json!({
"jsonrpc": "2.0", "jsonrpc": "2.0",
"result": [ blockhash.to_string(), { "result": {
"context":{"slot":0},
"value":[ blockhash.to_string(), {
"burnPercent": DEFAULT_BURN_PERCENT, "burnPercent": DEFAULT_BURN_PERCENT,
"lamportsPerSignature": 0, "lamportsPerSignature": 0,
"maxLamportsPerSignature": 0, "maxLamportsPerSignature": 0,
"minLamportsPerSignature": 0, "minLamportsPerSignature": 0,
"targetLamportsPerSignature": 0, "targetLamportsPerSignature": 0,
"targetSignaturesPerSlot": 0 "targetSignaturesPerSlot": 0
}], }]},
"id": 1 "id": 1
}); });
let expected: Response = let expected: Response =

View File

@ -229,7 +229,9 @@ mod tests {
.request_processor .request_processor
.read() .read()
.unwrap() .unwrap()
.get_balance(&mint_keypair.pubkey(), None) .get_balance(Ok(mint_keypair.pubkey()), None)
.unwrap()
.value
); );
rpc_service.exit(); rpc_service.exit();
rpc_service.join().unwrap(); rpc_service.join().unwrap();

View File

@ -1,5 +1,6 @@
use solana_client::rpc_client::RpcClient; use solana_client::rpc_client::RpcClient;
use solana_core::validator::new_validator_for_tests; use solana_core::validator::new_validator_for_tests;
use solana_sdk::commitment_config::CommitmentConfig;
use solana_sdk::pubkey::Pubkey; use solana_sdk::pubkey::Pubkey;
use solana_sdk::signature::KeypairUtil; use solana_sdk::signature::KeypairUtil;
use solana_sdk::system_transaction; use solana_sdk::system_transaction;
@ -22,7 +23,6 @@ fn test_rpc_client() {
); );
assert_eq!(client.get_balance(&bob_pubkey).unwrap(), 0); assert_eq!(client.get_balance(&bob_pubkey).unwrap(), 0);
assert_eq!(client.get_balance(&alice.pubkey()).unwrap(), 10000); assert_eq!(client.get_balance(&alice.pubkey()).unwrap(), 10000);
let (blockhash, _fee_calculator) = client.get_recent_blockhash().unwrap(); let (blockhash, _fee_calculator) = client.get_recent_blockhash().unwrap();
@ -34,14 +34,13 @@ fn test_rpc_client() {
let now = Instant::now(); let now = Instant::now();
while now.elapsed().as_secs() <= 20 { while now.elapsed().as_secs() <= 20 {
let response = client.confirm_transaction(signature.as_str()); let response = client
.confirm_transaction_with_commitment(signature.as_str(), CommitmentConfig::default())
.unwrap();
match response { if response.value {
Ok(true) => { confirmed_tx = true;
confirmed_tx = true; break;
break;
}
_ => (),
} }
sleep(Duration::from_millis(500)); sleep(Duration::from_millis(500));

View File

@ -34,7 +34,11 @@ fn test_rpc_send_tx() {
.send() .send()
.unwrap(); .unwrap();
let json: Value = serde_json::from_str(&response.text().unwrap()).unwrap(); let json: Value = serde_json::from_str(&response.text().unwrap()).unwrap();
let blockhash: Hash = json["result"][0].as_str().unwrap().parse().unwrap(); let blockhash: Hash = json["result"]["value"][0]
.as_str()
.unwrap()
.parse()
.unwrap();
info!("blockhash: {:?}", blockhash); info!("blockhash: {:?}", blockhash);
let tx = system_transaction::transfer(&alice, &bob_pubkey, 20, blockhash); let tx = system_transaction::transfer(&alice, &bob_pubkey, 20, blockhash);
@ -78,7 +82,7 @@ fn test_rpc_send_tx() {
let response_json_text = response.text().unwrap(); let response_json_text = response.text().unwrap();
let json: Value = serde_json::from_str(&response_json_text).unwrap(); let json: Value = serde_json::from_str(&response_json_text).unwrap();
if true == json["result"] { if true == json["result"]["value"] {
confirmed_tx = true; confirmed_tx = true;
break; break;
} }