Remove tuples from JSON RPC responses (#7806)
* Remove RpcConfirmedBlock tuple * Remove getRecentBlockhash tuple * Remove getProgramAccounts tuple * Remove tuple from get_signature_confirmation_status * Collect Rpc response types * Camel-case epoch schedule for rpc response * Remove getBlockCommitment tuple * Remove getStorageTurn tuple * Update json-rpc docs
This commit is contained in:
parent
50c1c08235
commit
6d3b8b6d7d
|
@ -193,13 +193,13 @@ Returns commitment for particular block
|
|||
|
||||
#### Results:
|
||||
|
||||
The result field will be an array with two fields:
|
||||
The result field will be a JSON object containing:
|
||||
|
||||
* Commitment
|
||||
* `commitment` - commitment, comprising either:
|
||||
* `null` - Unknown block
|
||||
* `object` - BlockCommitment
|
||||
* `array` - commitment, array of u64 integers logging the amount of cluster stake in lamports that has voted on the block at each depth from 0 to `MAX_LOCKOUT_HISTORY`
|
||||
* 'integer' - total active stake, in lamports, of the current epoch
|
||||
* `totalStake` - total active stake, in lamports, of the current epoch
|
||||
|
||||
#### Example:
|
||||
|
||||
|
@ -287,9 +287,9 @@ The result field will be an object with the following fields:
|
|||
* `blockhash` - the blockhash of this block, as base-58 encoded string
|
||||
* `previousBlockhash` - the blockhash of this block's parent, as base-58 encoded string
|
||||
* `parentSlot` - the slot index of this block's parent
|
||||
* `transactions` - an array of tuples containing:
|
||||
* [Transaction](transaction-api.md) object, either in JSON format or base-58 encoded binary data, depending on encoding parameter
|
||||
* Transaction status object, containing:
|
||||
* `transactions` - an array of JSON objects containing:
|
||||
* `transaction` - [Transaction](transaction-api.md) object, either in JSON format or base-58 encoded binary data, depending on encoding parameter
|
||||
* `meta` - transaction status metadata object, containing `null` or:
|
||||
* `status` - Transaction status:
|
||||
* `"Ok": null` - Transaction was successful
|
||||
* `"Err": <ERR>` - Transaction failed with TransactionError [TransactionError definitions](https://github.com/solana-labs/solana/blob/master/sdk/src/transaction.rs#L14)
|
||||
|
@ -376,11 +376,11 @@ None
|
|||
|
||||
The result field will be an object with the following fields:
|
||||
|
||||
* `slots_per_epoch`, the maximum number of slots in each epoch
|
||||
* `leader_schedule_slot_offset`, the number of slots before beginning of an epoch to calculate a leader schedule for that epoch
|
||||
* `slotsPerEpoch`, the maximum number of slots in each epoch
|
||||
* `leaderScheduleSlotOffset`, the number of slots before beginning of an epoch to calculate a leader schedule for that epoch
|
||||
* `warmup`, whether epochs start short and grow
|
||||
* `first_normal_epoch`, first normal-length epoch, log2(slots_per_epoch) - log2(MINIMUM_SLOTS_PER_EPOCH)
|
||||
* `first_normal_slot`, MINIMUM_SLOTS_PER_EPOCH * (2.pow(first_normal_epoch) - 1)
|
||||
* `firstNormalEpoch`, first normal-length epoch, log2(slotsPerEpoch) - log2(MINIMUM_SLOTS_PER_EPOCH)
|
||||
* `firstNormalSlot`, MINIMUM_SLOTS_PER_EPOCH * (2.pow(firstNormalEpoch) - 1)
|
||||
|
||||
#### Example:
|
||||
|
||||
|
@ -389,7 +389,7 @@ The result field will be an object with the following fields:
|
|||
curl -X POST -H "Content-Type: application/json" -d '{"jsonrpc":"2.0","id":1, "method":"getEpochSchedule"}' http://localhost:8899
|
||||
|
||||
// Result
|
||||
{"jsonrpc":"2.0","result":{"first_normal_epoch":8,"first_normal_slot":8160,"leader_schedule_slot_offset":8192,"slots_per_epoch":8192,"warmup":true},"id":1}
|
||||
{"jsonrpc":"2.0","result":{"firstNormalEpoch":8,"firstNormalSlot":8160,"leaderScheduleSlotOffset":8192,"slotsPerEpoch":8192,"warmup":true},"id":1}
|
||||
```
|
||||
|
||||
### getGenesisHash
|
||||
|
@ -526,9 +526,9 @@ Returns a recent block hash from the ledger, and a fee schedule that can be used
|
|||
|
||||
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
|
||||
* `FeeCalculator object` - the fee schedule for this block hash
|
||||
* `RpcResponse<array>` - RpcResponse JSON object with `value` field set to a JSON object including:
|
||||
* `blockhash` - a Hash as base-58 encoded string
|
||||
* `feeCalculator` - FeeCalculator object, the fee schedule for this block hash
|
||||
|
||||
#### Example:
|
||||
|
||||
|
@ -641,10 +641,10 @@ None
|
|||
|
||||
#### Results:
|
||||
|
||||
An array consisting of
|
||||
A JSON object consisting of
|
||||
|
||||
* `string` - a Hash as base-58 encoded string indicating the blockhash of the turn slot
|
||||
* `u64` - the current storage turn slot
|
||||
* `blockhash` - a Hash as base-58 encoded string indicating the blockhash of the turn slot
|
||||
* `slot` - the current storage turn slot
|
||||
|
||||
#### Example:
|
||||
|
||||
|
@ -652,7 +652,7 @@ An array consisting of
|
|||
// Request
|
||||
curl -X POST -H "Content-Type: application/json" -d '{"jsonrpc":"2.0","id":1, "method":"getStorageTurn"}' http://localhost:8899
|
||||
// Result
|
||||
{"jsonrpc":"2.0","result":["GH7ome3EiwEr7tu9JuTh2dpYWBJK3z69Xm1ZE3MEE6JC", "2048"],"id":1}
|
||||
{"jsonrpc":"2.0","result":{"blockhash": "GH7ome3EiwEr7tu9JuTh2dpYWBJK3z69Xm1ZE3MEE6JC", "slot": "2048"},"id":1}
|
||||
```
|
||||
|
||||
### getStorageTurnRate
|
||||
|
@ -673,7 +673,7 @@ None
|
|||
// Request
|
||||
curl -X POST -H "Content-Type: application/json" -d '{"jsonrpc":"2.0","id":1, "method":"getStorageTurnRate"}' http://localhost:8899
|
||||
// Result
|
||||
{"jsonrpc":"2.0","result":"1024","id":1}
|
||||
{"jsonrpc":"2.0","result":1024,"id":1}
|
||||
```
|
||||
|
||||
### getTransactionCount
|
||||
|
|
|
@ -1989,7 +1989,8 @@ mod tests {
|
|||
use serde_json::Value;
|
||||
use solana_client::{
|
||||
mock_rpc_client_request::SIGNATURE,
|
||||
rpc_request::{self, RpcRequest, RpcResponseContext},
|
||||
rpc_request::RpcRequest,
|
||||
rpc_response::{Response, RpcResponseContext},
|
||||
};
|
||||
use solana_sdk::{
|
||||
account::Account,
|
||||
|
@ -2669,7 +2670,7 @@ mod tests {
|
|||
|
||||
// Nonced pay
|
||||
let blockhash = Hash::default();
|
||||
let nonce_response = json!(rpc_request::Response {
|
||||
let nonce_response = json!(Response {
|
||||
context: RpcResponseContext { slot: 1 },
|
||||
value: json!(Account::new_data(
|
||||
1,
|
||||
|
@ -2695,7 +2696,7 @@ mod tests {
|
|||
let bob_keypair = Keypair::new();
|
||||
let bob_pubkey = bob_keypair.pubkey();
|
||||
let blockhash = Hash::default();
|
||||
let nonce_authority_response = json!(rpc_request::Response {
|
||||
let nonce_authority_response = json!(Response {
|
||||
context: RpcResponseContext { slot: 1 },
|
||||
value: json!(Account::new_data(
|
||||
1,
|
||||
|
|
|
@ -9,7 +9,7 @@ use clap::{value_t, value_t_or_exit, App, Arg, ArgMatches, SubCommand};
|
|||
use console::{style, Emoji};
|
||||
use indicatif::{ProgressBar, ProgressStyle};
|
||||
use solana_clap_utils::{input_parsers::*, input_validators::*};
|
||||
use solana_client::{rpc_client::RpcClient, rpc_request::RpcVoteAccountInfo};
|
||||
use solana_client::{rpc_client::RpcClient, rpc_response::RpcVoteAccountInfo};
|
||||
use solana_sdk::{
|
||||
clock::{self, Slot},
|
||||
commitment_config::CommitmentConfig,
|
||||
|
|
|
@ -8,4 +8,5 @@ pub mod perf_utils;
|
|||
pub mod rpc_client;
|
||||
pub mod rpc_client_request;
|
||||
pub mod rpc_request;
|
||||
pub mod rpc_response;
|
||||
pub mod thin_client;
|
||||
|
|
|
@ -1,7 +1,8 @@
|
|||
use crate::rpc_request::{Response, RpcResponseContext};
|
||||
use crate::{
|
||||
client_error::ClientError, generic_rpc_client_request::GenericRpcClientRequest,
|
||||
client_error::ClientError,
|
||||
generic_rpc_client_request::GenericRpcClientRequest,
|
||||
rpc_request::RpcRequest,
|
||||
rpc_response::{Response, RpcResponseContext},
|
||||
};
|
||||
use serde_json::{Number, Value};
|
||||
use solana_sdk::{
|
||||
|
|
|
@ -1,12 +1,12 @@
|
|||
use crate::rpc_request::{Response, RpcResponse};
|
||||
use crate::{
|
||||
client_error::ClientError,
|
||||
generic_rpc_client_request::GenericRpcClientRequest,
|
||||
mock_rpc_client_request::{MockRpcClientRequest, Mocks},
|
||||
rpc_client_request::RpcClientRequest,
|
||||
rpc_request::{
|
||||
RpcConfirmedBlock, RpcContactInfo, RpcEpochInfo, RpcLeaderSchedule, RpcRequest,
|
||||
RpcVersionInfo, RpcVoteAccountStatus,
|
||||
rpc_request::RpcRequest,
|
||||
rpc_response::{
|
||||
Response, RpcBlockhashFeeCalculator, RpcConfirmedBlock, RpcContactInfo, RpcEpochInfo,
|
||||
RpcLeaderSchedule, RpcResponse, RpcVersionInfo, RpcVoteAccountStatus,
|
||||
},
|
||||
};
|
||||
use bincode::serialize;
|
||||
|
@ -753,8 +753,12 @@ impl RpcClient {
|
|||
|
||||
let Response {
|
||||
context,
|
||||
value: (blockhash_str, fee_calculator),
|
||||
} = serde_json::from_value::<Response<(String, FeeCalculator)>>(response).map_err(
|
||||
value:
|
||||
RpcBlockhashFeeCalculator {
|
||||
blockhash,
|
||||
fee_calculator,
|
||||
},
|
||||
} = serde_json::from_value::<Response<RpcBlockhashFeeCalculator>>(response).map_err(
|
||||
|err| {
|
||||
io::Error::new(
|
||||
io::ErrorKind::Other,
|
||||
|
@ -762,7 +766,7 @@ impl RpcClient {
|
|||
)
|
||||
},
|
||||
)?;
|
||||
let blockhash = blockhash_str.parse().map_err(|err| {
|
||||
let blockhash = blockhash.parse().map_err(|err| {
|
||||
io::Error::new(
|
||||
io::ErrorKind::Other,
|
||||
format!("GetRecentBlockhash hash parse failure: {:?}", err),
|
||||
|
|
|
@ -1,197 +1,5 @@
|
|||
use bincode::serialize;
|
||||
use jsonrpc_core::Result as JsonResult;
|
||||
use serde_json::{json, Value};
|
||||
use solana_sdk::{
|
||||
clock::{Epoch, Slot},
|
||||
message::MessageHeader,
|
||||
transaction::{Result, Transaction},
|
||||
};
|
||||
use std::{collections::HashMap, error, fmt, io, net::SocketAddr};
|
||||
|
||||
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(Debug, PartialEq, Serialize, Deserialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct RpcConfirmedBlock {
|
||||
pub previous_blockhash: String,
|
||||
pub blockhash: String,
|
||||
pub parent_slot: Slot,
|
||||
pub transactions: Vec<(RpcEncodedTransaction, Option<RpcTransactionStatus>)>,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Clone, Debug, PartialEq)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub enum RpcTransactionEncoding {
|
||||
Binary,
|
||||
Json,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
|
||||
#[serde(rename_all = "camelCase", untagged)]
|
||||
pub enum RpcEncodedTransaction {
|
||||
Binary(String),
|
||||
Json(RpcTransaction),
|
||||
}
|
||||
|
||||
impl RpcEncodedTransaction {
|
||||
pub fn encode(transaction: Transaction, encoding: RpcTransactionEncoding) -> Self {
|
||||
if encoding == RpcTransactionEncoding::Json {
|
||||
RpcEncodedTransaction::Json(RpcTransaction {
|
||||
signatures: transaction
|
||||
.signatures
|
||||
.iter()
|
||||
.map(|sig| sig.to_string())
|
||||
.collect(),
|
||||
message: RpcMessage {
|
||||
header: transaction.message.header,
|
||||
account_keys: transaction
|
||||
.message
|
||||
.account_keys
|
||||
.iter()
|
||||
.map(|pubkey| pubkey.to_string())
|
||||
.collect(),
|
||||
recent_blockhash: transaction.message.recent_blockhash.to_string(),
|
||||
instructions: transaction
|
||||
.message
|
||||
.instructions
|
||||
.iter()
|
||||
.map(|instruction| RpcCompiledInstruction {
|
||||
program_id_index: instruction.program_id_index,
|
||||
accounts: instruction.accounts.clone(),
|
||||
data: bs58::encode(instruction.data.clone()).into_string(),
|
||||
})
|
||||
.collect(),
|
||||
},
|
||||
})
|
||||
} else {
|
||||
RpcEncodedTransaction::Binary(
|
||||
bs58::encode(serialize(&transaction).unwrap()).into_string(),
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// A duplicate representation of a Transaction for pretty JSON serialization
|
||||
#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct RpcTransaction {
|
||||
pub signatures: Vec<String>,
|
||||
pub message: RpcMessage,
|
||||
}
|
||||
|
||||
/// A duplicate representation of a Message for pretty JSON serialization
|
||||
#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct RpcMessage {
|
||||
pub header: MessageHeader,
|
||||
pub account_keys: Vec<String>,
|
||||
pub recent_blockhash: String,
|
||||
pub instructions: Vec<RpcCompiledInstruction>,
|
||||
}
|
||||
|
||||
/// A duplicate representation of a Message for pretty JSON serialization
|
||||
#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct RpcCompiledInstruction {
|
||||
pub program_id_index: u8,
|
||||
pub accounts: Vec<u8>,
|
||||
pub data: String,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct RpcTransactionStatus {
|
||||
pub status: Result<()>,
|
||||
pub fee: u64,
|
||||
pub pre_balances: Vec<u64>,
|
||||
pub post_balances: Vec<u64>,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Clone, Debug)]
|
||||
pub struct RpcContactInfo {
|
||||
/// Pubkey of the node as a base-58 string
|
||||
pub pubkey: String,
|
||||
/// Gossip port
|
||||
pub gossip: Option<SocketAddr>,
|
||||
/// Tpu port
|
||||
pub tpu: Option<SocketAddr>,
|
||||
/// JSON RPC port
|
||||
pub rpc: Option<SocketAddr>,
|
||||
}
|
||||
|
||||
/// Map of leader base58 identity pubkeys to the slot indices relative to the first epoch slot
|
||||
pub type RpcLeaderSchedule = HashMap<String, Vec<usize>>;
|
||||
|
||||
#[derive(Serialize, Deserialize, Clone, Debug)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct RpcEpochInfo {
|
||||
/// The current epoch
|
||||
pub epoch: Epoch,
|
||||
|
||||
/// The current slot, relative to the start of the current epoch
|
||||
pub slot_index: u64,
|
||||
|
||||
/// The number of slots in this epoch
|
||||
pub slots_in_epoch: u64,
|
||||
|
||||
/// The absolute current slot
|
||||
pub absolute_slot: Slot,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Clone, Debug)]
|
||||
#[serde(rename_all = "kebab-case")]
|
||||
pub struct RpcVersionInfo {
|
||||
/// The current version of solana-core
|
||||
pub solana_core: String,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Clone, Debug)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct RpcVoteAccountStatus {
|
||||
pub current: Vec<RpcVoteAccountInfo>,
|
||||
pub delinquent: Vec<RpcVoteAccountInfo>,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Clone, Debug)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct RpcVoteAccountInfo {
|
||||
/// Vote account pubkey as base-58 encoded string
|
||||
pub vote_pubkey: String,
|
||||
|
||||
/// The pubkey of the node that votes using this account
|
||||
pub node_pubkey: String,
|
||||
|
||||
/// The current stake, in lamports, delegated to this vote account
|
||||
pub activated_stake: u64,
|
||||
|
||||
/// An 8-bit integer used as a fraction (commission/MAX_U8) for rewards payout
|
||||
pub commission: u8,
|
||||
|
||||
/// Whether this account is staked for the current epoch
|
||||
pub epoch_vote_account: bool,
|
||||
|
||||
/// History of how many credits earned by the end of each epoch
|
||||
/// each tuple is (Epoch, credits, prev_credits)
|
||||
pub epoch_credits: Vec<(Epoch, u64, u64)>,
|
||||
|
||||
/// Most recent slot voted on by this vote account (0 if no votes exist)
|
||||
pub last_vote: u64,
|
||||
|
||||
/// Current root slot for this vote account (0 if not root slot exists)
|
||||
pub root_slot: Slot,
|
||||
}
|
||||
use std::{error, fmt};
|
||||
|
||||
#[derive(Debug, PartialEq, Eq, Hash)]
|
||||
pub enum RpcRequest {
|
||||
|
|
|
@ -0,0 +1,237 @@
|
|||
use bincode::serialize;
|
||||
use jsonrpc_core::Result as JsonResult;
|
||||
use solana_sdk::{
|
||||
account::Account,
|
||||
clock::{Epoch, Slot},
|
||||
fee_calculator::FeeCalculator,
|
||||
message::MessageHeader,
|
||||
transaction::{Result, Transaction},
|
||||
};
|
||||
use std::{collections::HashMap, io, net::SocketAddr};
|
||||
|
||||
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(Debug, PartialEq, Serialize, Deserialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct RpcBlockCommitment<T> {
|
||||
pub commitment: Option<T>,
|
||||
pub total_stake: u64,
|
||||
}
|
||||
|
||||
#[derive(Debug, PartialEq, Serialize, Deserialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct RpcConfirmedBlock {
|
||||
pub previous_blockhash: String,
|
||||
pub blockhash: String,
|
||||
pub parent_slot: Slot,
|
||||
pub transactions: Vec<RpcTransactionWithStatusMeta>,
|
||||
}
|
||||
|
||||
#[derive(Debug, PartialEq, Serialize, Deserialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct RpcTransactionWithStatusMeta {
|
||||
pub transaction: RpcEncodedTransaction,
|
||||
pub meta: Option<RpcTransactionStatus>,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Clone, Debug, PartialEq)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub enum RpcTransactionEncoding {
|
||||
Binary,
|
||||
Json,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
|
||||
#[serde(rename_all = "camelCase", untagged)]
|
||||
pub enum RpcEncodedTransaction {
|
||||
Binary(String),
|
||||
Json(RpcTransaction),
|
||||
}
|
||||
|
||||
impl RpcEncodedTransaction {
|
||||
pub fn encode(transaction: Transaction, encoding: RpcTransactionEncoding) -> Self {
|
||||
if encoding == RpcTransactionEncoding::Json {
|
||||
RpcEncodedTransaction::Json(RpcTransaction {
|
||||
signatures: transaction
|
||||
.signatures
|
||||
.iter()
|
||||
.map(|sig| sig.to_string())
|
||||
.collect(),
|
||||
message: RpcMessage {
|
||||
header: transaction.message.header,
|
||||
account_keys: transaction
|
||||
.message
|
||||
.account_keys
|
||||
.iter()
|
||||
.map(|pubkey| pubkey.to_string())
|
||||
.collect(),
|
||||
recent_blockhash: transaction.message.recent_blockhash.to_string(),
|
||||
instructions: transaction
|
||||
.message
|
||||
.instructions
|
||||
.iter()
|
||||
.map(|instruction| RpcCompiledInstruction {
|
||||
program_id_index: instruction.program_id_index,
|
||||
accounts: instruction.accounts.clone(),
|
||||
data: bs58::encode(instruction.data.clone()).into_string(),
|
||||
})
|
||||
.collect(),
|
||||
},
|
||||
})
|
||||
} else {
|
||||
RpcEncodedTransaction::Binary(
|
||||
bs58::encode(serialize(&transaction).unwrap()).into_string(),
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// A duplicate representation of a Transaction for pretty JSON serialization
|
||||
#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct RpcTransaction {
|
||||
pub signatures: Vec<String>,
|
||||
pub message: RpcMessage,
|
||||
}
|
||||
|
||||
/// A duplicate representation of a Message for pretty JSON serialization
|
||||
#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct RpcMessage {
|
||||
pub header: MessageHeader,
|
||||
pub account_keys: Vec<String>,
|
||||
pub recent_blockhash: String,
|
||||
pub instructions: Vec<RpcCompiledInstruction>,
|
||||
}
|
||||
|
||||
/// A duplicate representation of a Message for pretty JSON serialization
|
||||
#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct RpcCompiledInstruction {
|
||||
pub program_id_index: u8,
|
||||
pub accounts: Vec<u8>,
|
||||
pub data: String,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct RpcTransactionStatus {
|
||||
pub status: Result<()>,
|
||||
pub fee: u64,
|
||||
pub pre_balances: Vec<u64>,
|
||||
pub post_balances: Vec<u64>,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Clone, Debug)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct RpcBlockhashFeeCalculator {
|
||||
pub blockhash: String,
|
||||
pub fee_calculator: FeeCalculator,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Clone, Debug)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct RpcKeyedAccount {
|
||||
pub pubkey: String,
|
||||
pub account: Account,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Clone, Debug)]
|
||||
pub struct RpcContactInfo {
|
||||
/// Pubkey of the node as a base-58 string
|
||||
pub pubkey: String,
|
||||
/// Gossip port
|
||||
pub gossip: Option<SocketAddr>,
|
||||
/// Tpu port
|
||||
pub tpu: Option<SocketAddr>,
|
||||
/// JSON RPC port
|
||||
pub rpc: Option<SocketAddr>,
|
||||
}
|
||||
|
||||
/// Map of leader base58 identity pubkeys to the slot indices relative to the first epoch slot
|
||||
pub type RpcLeaderSchedule = HashMap<String, Vec<usize>>;
|
||||
|
||||
#[derive(Serialize, Deserialize, Clone, Debug)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct RpcEpochInfo {
|
||||
/// The current epoch
|
||||
pub epoch: Epoch,
|
||||
|
||||
/// The current slot, relative to the start of the current epoch
|
||||
pub slot_index: u64,
|
||||
|
||||
/// The number of slots in this epoch
|
||||
pub slots_in_epoch: u64,
|
||||
|
||||
/// The absolute current slot
|
||||
pub absolute_slot: Slot,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Clone, Debug)]
|
||||
#[serde(rename_all = "kebab-case")]
|
||||
pub struct RpcVersionInfo {
|
||||
/// The current version of solana-core
|
||||
pub solana_core: String,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Clone, Debug)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct RpcVoteAccountStatus {
|
||||
pub current: Vec<RpcVoteAccountInfo>,
|
||||
pub delinquent: Vec<RpcVoteAccountInfo>,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Clone, Debug)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct RpcVoteAccountInfo {
|
||||
/// Vote account pubkey as base-58 encoded string
|
||||
pub vote_pubkey: String,
|
||||
|
||||
/// The pubkey of the node that votes using this account
|
||||
pub node_pubkey: String,
|
||||
|
||||
/// The current stake, in lamports, delegated to this vote account
|
||||
pub activated_stake: u64,
|
||||
|
||||
/// An 8-bit integer used as a fraction (commission/MAX_U8) for rewards payout
|
||||
pub commission: u8,
|
||||
|
||||
/// Whether this account is staked for the current epoch
|
||||
pub epoch_vote_account: bool,
|
||||
|
||||
/// History of how many credits earned by the end of each epoch
|
||||
/// each tuple is (Epoch, credits, prev_credits)
|
||||
pub epoch_credits: Vec<(Epoch, u64, u64)>,
|
||||
|
||||
/// Most recent slot voted on by this vote account (0 if no votes exist)
|
||||
pub last_vote: u64,
|
||||
|
||||
/// Current root slot for this vote account (0 if not root slot exists)
|
||||
pub root_slot: Slot,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Clone, Debug)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct RpcSignatureConfirmation {
|
||||
pub confirmations: usize,
|
||||
pub status: Result<()>,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Clone, Debug)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct RpcStorageTurn {
|
||||
pub blockhash: String,
|
||||
pub slot: Slot,
|
||||
}
|
|
@ -3,8 +3,7 @@
|
|||
//! messages to the network directly. The binary encoding of its messages are
|
||||
//! unstable and may change in future releases.
|
||||
|
||||
use crate::rpc_client::RpcClient;
|
||||
use crate::rpc_request::Response;
|
||||
use crate::{rpc_client::RpcClient, rpc_response::Response};
|
||||
use bincode::{serialize_into, serialized_size};
|
||||
use log::*;
|
||||
use solana_sdk::{
|
||||
|
|
|
@ -17,7 +17,10 @@ use crossbeam_channel::unbounded;
|
|||
use ed25519_dalek;
|
||||
use rand::{thread_rng, Rng, SeedableRng};
|
||||
use rand_chacha::ChaChaRng;
|
||||
use solana_client::{rpc_client::RpcClient, rpc_request::RpcRequest, thin_client::ThinClient};
|
||||
use solana_client::{
|
||||
rpc_client::RpcClient, rpc_request::RpcRequest, rpc_response::RpcStorageTurn,
|
||||
thin_client::ThinClient,
|
||||
};
|
||||
use solana_ledger::{
|
||||
blockstore::Blockstore, leader_schedule_cache::LeaderScheduleCache, shred::Shred,
|
||||
};
|
||||
|
@ -811,13 +814,15 @@ impl Archiver {
|
|||
warn!("Error while making rpc request {:?}", err);
|
||||
Error::IO(io::Error::new(ErrorKind::Other, "rpc error"))
|
||||
})?;
|
||||
let (storage_blockhash, turn_slot) =
|
||||
serde_json::from_value::<(String, u64)>(response).map_err(|err| {
|
||||
io::Error::new(
|
||||
io::ErrorKind::Other,
|
||||
format!("Couldn't parse response: {:?}", err),
|
||||
)
|
||||
})?;
|
||||
let RpcStorageTurn {
|
||||
blockhash: storage_blockhash,
|
||||
slot: turn_slot,
|
||||
} = serde_json::from_value::<RpcStorageTurn>(response).map_err(|err| {
|
||||
io::Error::new(
|
||||
io::ErrorKind::Other,
|
||||
format!("Couldn't parse response: {:?}", err),
|
||||
)
|
||||
})?;
|
||||
let turn_blockhash = storage_blockhash.parse().map_err(|err| {
|
||||
io::Error::new(
|
||||
io::ErrorKind::Other,
|
||||
|
|
|
@ -1020,7 +1020,7 @@ mod tests {
|
|||
};
|
||||
use crossbeam_channel::unbounded;
|
||||
use itertools::Itertools;
|
||||
use solana_client::rpc_request::RpcEncodedTransaction;
|
||||
use solana_client::rpc_response::{RpcEncodedTransaction, RpcTransactionWithStatusMeta};
|
||||
use solana_ledger::{
|
||||
blockstore::entries_to_test_shreds,
|
||||
entry::{next_entry, Entry, EntrySlice},
|
||||
|
@ -1978,20 +1978,22 @@ mod tests {
|
|||
let confirmed_block = blockstore.get_confirmed_block(bank.slot(), None).unwrap();
|
||||
assert_eq!(confirmed_block.transactions.len(), 3);
|
||||
|
||||
for (transaction, result) in confirmed_block.transactions.into_iter() {
|
||||
for RpcTransactionWithStatusMeta { transaction, meta } in
|
||||
confirmed_block.transactions.into_iter()
|
||||
{
|
||||
if let RpcEncodedTransaction::Json(transaction) = transaction {
|
||||
if transaction.signatures[0] == success_signature.to_string() {
|
||||
assert_eq!(result.unwrap().status, Ok(()));
|
||||
assert_eq!(meta.unwrap().status, Ok(()));
|
||||
} else if transaction.signatures[0] == ix_error_signature.to_string() {
|
||||
assert_eq!(
|
||||
result.unwrap().status,
|
||||
meta.unwrap().status,
|
||||
Err(TransactionError::InstructionError(
|
||||
0,
|
||||
InstructionError::CustomError(1)
|
||||
))
|
||||
);
|
||||
} else {
|
||||
assert_eq!(result, None);
|
||||
assert_eq!(meta, None);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -997,7 +997,7 @@ pub(crate) mod tests {
|
|||
transaction_status_service::TransactionStatusService,
|
||||
};
|
||||
use crossbeam_channel::unbounded;
|
||||
use solana_client::rpc_request::RpcEncodedTransaction;
|
||||
use solana_client::rpc_response::{RpcEncodedTransaction, RpcTransactionWithStatusMeta};
|
||||
use solana_ledger::{
|
||||
block_error::BlockError,
|
||||
blockstore::make_slot_entries,
|
||||
|
@ -1011,22 +1011,21 @@ pub(crate) mod tests {
|
|||
},
|
||||
};
|
||||
use solana_runtime::genesis_utils::GenesisConfigInfo;
|
||||
use solana_sdk::account::Account;
|
||||
use solana_sdk::rent::Rent;
|
||||
use solana_sdk::{
|
||||
account::Account,
|
||||
hash::{hash, Hash},
|
||||
instruction::InstructionError,
|
||||
packet::PACKET_DATA_SIZE,
|
||||
rent::Rent,
|
||||
signature::{Keypair, KeypairUtil, Signature},
|
||||
system_transaction,
|
||||
transaction::TransactionError,
|
||||
};
|
||||
use solana_stake_program::stake_state;
|
||||
use solana_vote_program::vote_state;
|
||||
use solana_vote_program::vote_state::{Vote, VoteState};
|
||||
use std::iter;
|
||||
use solana_vote_program::vote_state::{self, Vote, VoteState};
|
||||
use std::{
|
||||
fs::remove_dir_all,
|
||||
iter,
|
||||
sync::{Arc, RwLock},
|
||||
};
|
||||
|
||||
|
@ -1803,20 +1802,22 @@ pub(crate) mod tests {
|
|||
let confirmed_block = blockstore.get_confirmed_block(slot, None).unwrap();
|
||||
assert_eq!(confirmed_block.transactions.len(), 3);
|
||||
|
||||
for (transaction, result) in confirmed_block.transactions.into_iter() {
|
||||
for RpcTransactionWithStatusMeta { transaction, meta } in
|
||||
confirmed_block.transactions.into_iter()
|
||||
{
|
||||
if let RpcEncodedTransaction::Json(transaction) = transaction {
|
||||
if transaction.signatures[0] == signatures[0].to_string() {
|
||||
assert_eq!(result.unwrap().status, Ok(()));
|
||||
assert_eq!(meta.unwrap().status, Ok(()));
|
||||
} else if transaction.signatures[0] == signatures[1].to_string() {
|
||||
assert_eq!(
|
||||
result.unwrap().status,
|
||||
meta.unwrap().status,
|
||||
Err(TransactionError::InstructionError(
|
||||
0,
|
||||
InstructionError::CustomError(1)
|
||||
))
|
||||
);
|
||||
} else {
|
||||
assert_eq!(result, None);
|
||||
assert_eq!(meta, None);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
185
core/src/rpc.rs
185
core/src/rpc.rs
|
@ -11,9 +11,10 @@ use crate::{
|
|||
use bincode::serialize;
|
||||
use jsonrpc_core::{Error, Metadata, Result};
|
||||
use jsonrpc_derive::rpc;
|
||||
use solana_client::rpc_request::{
|
||||
Response, RpcConfirmedBlock, RpcContactInfo, RpcEpochInfo, RpcLeaderSchedule,
|
||||
RpcResponseContext, RpcTransactionEncoding, RpcVersionInfo, RpcVoteAccountInfo,
|
||||
use solana_client::rpc_response::{
|
||||
Response, RpcBlockCommitment, RpcBlockhashFeeCalculator, RpcConfirmedBlock, RpcContactInfo,
|
||||
RpcEpochInfo, RpcKeyedAccount, RpcLeaderSchedule, RpcResponseContext, RpcSignatureConfirmation,
|
||||
RpcStorageTurn, RpcTransactionEncoding, RpcVersionInfo, RpcVoteAccountInfo,
|
||||
RpcVoteAccountStatus,
|
||||
};
|
||||
use solana_faucet::faucet::request_airdrop_transaction;
|
||||
|
@ -26,7 +27,6 @@ use solana_sdk::{
|
|||
clock::{Slot, UnixTimestamp},
|
||||
commitment_config::{CommitmentConfig, CommitmentLevel},
|
||||
epoch_schedule::EpochSchedule,
|
||||
fee_calculator::FeeCalculator,
|
||||
hash::Hash,
|
||||
inflation::Inflation,
|
||||
pubkey::Pubkey,
|
||||
|
@ -134,12 +134,15 @@ impl JsonRpcRequestProcessor {
|
|||
&self,
|
||||
program_id: &Pubkey,
|
||||
commitment: Option<CommitmentConfig>,
|
||||
) -> Result<Vec<(String, Account)>> {
|
||||
) -> Result<Vec<RpcKeyedAccount>> {
|
||||
Ok(self
|
||||
.bank(commitment)
|
||||
.get_program_accounts(&program_id)
|
||||
.into_iter()
|
||||
.map(|(pubkey, account)| (pubkey.to_string(), account))
|
||||
.map(|(pubkey, account)| RpcKeyedAccount {
|
||||
pubkey: pubkey.to_string(),
|
||||
account,
|
||||
})
|
||||
.collect())
|
||||
}
|
||||
|
||||
|
@ -168,10 +171,16 @@ impl JsonRpcRequestProcessor {
|
|||
fn get_recent_blockhash(
|
||||
&self,
|
||||
commitment: Option<CommitmentConfig>,
|
||||
) -> RpcResponse<(String, FeeCalculator)> {
|
||||
) -> RpcResponse<RpcBlockhashFeeCalculator> {
|
||||
let bank = &*self.bank(commitment);
|
||||
let (blockhash, fee_calculator) = bank.confirmed_last_blockhash();
|
||||
new_response(bank, (blockhash.to_string(), fee_calculator))
|
||||
new_response(
|
||||
bank,
|
||||
RpcBlockhashFeeCalculator {
|
||||
blockhash: blockhash.to_string(),
|
||||
fee_calculator,
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
pub fn confirm_transaction(
|
||||
|
@ -192,21 +201,25 @@ impl JsonRpcRequestProcessor {
|
|||
}
|
||||
}
|
||||
|
||||
fn get_block_commitment(&self, block: Slot) -> (Option<BlockCommitment>, u64) {
|
||||
fn get_block_commitment(&self, block: Slot) -> RpcBlockCommitment<BlockCommitment> {
|
||||
let r_block_commitment = self.block_commitment_cache.read().unwrap();
|
||||
(
|
||||
r_block_commitment.get_block_commitment(block).cloned(),
|
||||
r_block_commitment.total_stake(),
|
||||
)
|
||||
RpcBlockCommitment {
|
||||
commitment: r_block_commitment.get_block_commitment(block).cloned(),
|
||||
total_stake: r_block_commitment.total_stake(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get_signature_confirmation_status(
|
||||
&self,
|
||||
signature: Signature,
|
||||
commitment: Option<CommitmentConfig>,
|
||||
) -> Option<(usize, transaction::Result<()>)> {
|
||||
) -> Option<RpcSignatureConfirmation> {
|
||||
self.bank(commitment)
|
||||
.get_signature_confirmation_status(&signature)
|
||||
.map(|(confirmations, status)| RpcSignatureConfirmation {
|
||||
confirmations,
|
||||
status,
|
||||
})
|
||||
}
|
||||
|
||||
fn get_slot(&self, commitment: Option<CommitmentConfig>) -> Result<u64> {
|
||||
|
@ -283,11 +296,11 @@ impl JsonRpcRequestProcessor {
|
|||
Ok(self.storage_state.get_storage_turn_rate())
|
||||
}
|
||||
|
||||
fn get_storage_turn(&self) -> Result<(String, u64)> {
|
||||
Ok((
|
||||
self.storage_state.get_storage_blockhash().to_string(),
|
||||
self.storage_state.get_slot(),
|
||||
))
|
||||
fn get_storage_turn(&self) -> Result<RpcStorageTurn> {
|
||||
Ok(RpcStorageTurn {
|
||||
blockhash: self.storage_state.get_storage_blockhash().to_string(),
|
||||
slot: self.storage_state.get_slot(),
|
||||
})
|
||||
}
|
||||
|
||||
fn get_slots_per_segment(&self, commitment: Option<CommitmentConfig>) -> Result<u64> {
|
||||
|
@ -407,7 +420,7 @@ pub trait RpcSol {
|
|||
meta: Self::Metadata,
|
||||
program_id_str: String,
|
||||
commitment: Option<CommitmentConfig>,
|
||||
) -> Result<Vec<(String, Account)>>;
|
||||
) -> Result<Vec<RpcKeyedAccount>>;
|
||||
|
||||
#[rpc(meta, name = "getMinimumBalanceForRentExemption")]
|
||||
fn get_minimum_balance_for_rent_exemption(
|
||||
|
@ -450,7 +463,7 @@ pub trait RpcSol {
|
|||
&self,
|
||||
meta: Self::Metadata,
|
||||
block: Slot,
|
||||
) -> Result<(Option<BlockCommitment>, u64)>;
|
||||
) -> Result<RpcBlockCommitment<BlockCommitment>>;
|
||||
|
||||
#[rpc(meta, name = "getGenesisHash")]
|
||||
fn get_genesis_hash(&self, meta: Self::Metadata) -> Result<String>;
|
||||
|
@ -468,7 +481,7 @@ pub trait RpcSol {
|
|||
&self,
|
||||
meta: Self::Metadata,
|
||||
commitment: Option<CommitmentConfig>,
|
||||
) -> RpcResponse<(String, FeeCalculator)>;
|
||||
) -> RpcResponse<RpcBlockhashFeeCalculator>;
|
||||
|
||||
#[rpc(meta, name = "getSignatureStatus")]
|
||||
fn get_signature_status(
|
||||
|
@ -525,7 +538,7 @@ pub trait RpcSol {
|
|||
fn get_storage_turn_rate(&self, meta: Self::Metadata) -> Result<u64>;
|
||||
|
||||
#[rpc(meta, name = "getStorageTurn")]
|
||||
fn get_storage_turn(&self, meta: Self::Metadata) -> Result<(String, u64)>;
|
||||
fn get_storage_turn(&self, meta: Self::Metadata) -> Result<RpcStorageTurn>;
|
||||
|
||||
#[rpc(meta, name = "getSlotsPerSegment")]
|
||||
fn get_slots_per_segment(
|
||||
|
@ -554,7 +567,7 @@ pub trait RpcSol {
|
|||
meta: Self::Metadata,
|
||||
signature_str: String,
|
||||
commitment: Option<CommitmentConfig>,
|
||||
) -> Result<Option<(usize, transaction::Result<()>)>>;
|
||||
) -> Result<Option<RpcSignatureConfirmation>>;
|
||||
|
||||
#[rpc(meta, name = "getVersion")]
|
||||
fn get_version(&self, meta: Self::Metadata) -> Result<RpcVersionInfo>;
|
||||
|
@ -635,7 +648,7 @@ impl RpcSol for RpcSolImpl {
|
|||
meta: Self::Metadata,
|
||||
program_id_str: String,
|
||||
commitment: Option<CommitmentConfig>,
|
||||
) -> Result<Vec<(String, Account)>> {
|
||||
) -> Result<Vec<RpcKeyedAccount>> {
|
||||
debug!(
|
||||
"get_program_accounts rpc request received: {:?}",
|
||||
program_id_str
|
||||
|
@ -734,7 +747,7 @@ impl RpcSol for RpcSolImpl {
|
|||
&self,
|
||||
meta: Self::Metadata,
|
||||
block: Slot,
|
||||
) -> Result<(Option<BlockCommitment>, u64)> {
|
||||
) -> Result<RpcBlockCommitment<BlockCommitment>> {
|
||||
Ok(meta
|
||||
.request_processor
|
||||
.read()
|
||||
|
@ -778,7 +791,7 @@ impl RpcSol for RpcSolImpl {
|
|||
&self,
|
||||
meta: Self::Metadata,
|
||||
commitment: Option<CommitmentConfig>,
|
||||
) -> RpcResponse<(String, FeeCalculator)> {
|
||||
) -> RpcResponse<RpcBlockhashFeeCalculator> {
|
||||
debug!("get_recent_blockhash rpc request received");
|
||||
meta.request_processor
|
||||
.read()
|
||||
|
@ -793,7 +806,7 @@ impl RpcSol for RpcSolImpl {
|
|||
commitment: Option<CommitmentConfig>,
|
||||
) -> Result<Option<transaction::Result<()>>> {
|
||||
self.get_signature_confirmation(meta, signature_str, commitment)
|
||||
.map(|res| res.map(|x| x.1))
|
||||
.map(|res| res.map(|x| x.status))
|
||||
}
|
||||
|
||||
fn get_slot(&self, meta: Self::Metadata, commitment: Option<CommitmentConfig>) -> Result<u64> {
|
||||
|
@ -807,7 +820,7 @@ impl RpcSol for RpcSolImpl {
|
|||
commitment: Option<CommitmentConfig>,
|
||||
) -> Result<Option<usize>> {
|
||||
self.get_signature_confirmation(meta, signature_str, commitment)
|
||||
.map(|res| res.map(|x| x.0))
|
||||
.map(|res| res.map(|x| x.confirmations))
|
||||
}
|
||||
|
||||
fn get_signature_confirmation(
|
||||
|
@ -815,7 +828,7 @@ impl RpcSol for RpcSolImpl {
|
|||
meta: Self::Metadata,
|
||||
signature_str: String,
|
||||
commitment: Option<CommitmentConfig>,
|
||||
) -> Result<Option<(usize, transaction::Result<()>)>> {
|
||||
) -> Result<Option<RpcSignatureConfirmation>> {
|
||||
debug!(
|
||||
"get_signature_confirmation rpc request received: {:?}",
|
||||
signature_str
|
||||
|
@ -915,7 +928,7 @@ impl RpcSol for RpcSolImpl {
|
|||
.read()
|
||||
.unwrap()
|
||||
.get_signature_confirmation_status(signature, commitment.clone())
|
||||
.map(|x| x.1);
|
||||
.map(|x| x.status);
|
||||
|
||||
if signature_status == Some(Ok(())) {
|
||||
info!("airdrop signature ok");
|
||||
|
@ -992,7 +1005,7 @@ impl RpcSol for RpcSolImpl {
|
|||
.get_storage_turn_rate()
|
||||
}
|
||||
|
||||
fn get_storage_turn(&self, meta: Self::Metadata) -> Result<(String, u64)> {
|
||||
fn get_storage_turn(&self, meta: Self::Metadata) -> Result<RpcStorageTurn> {
|
||||
meta.request_processor.read().unwrap().get_storage_turn()
|
||||
}
|
||||
|
||||
|
@ -1072,7 +1085,7 @@ pub mod tests {
|
|||
};
|
||||
use bincode::deserialize;
|
||||
use jsonrpc_core::{MetaIoHandler, Output, Response, Value};
|
||||
use solana_client::rpc_request::RpcEncodedTransaction;
|
||||
use solana_client::rpc_response::{RpcEncodedTransaction, RpcTransactionWithStatusMeta};
|
||||
use solana_ledger::{
|
||||
blockstore::entries_to_test_shreds, blockstore_processor::fill_blockstore_slot_with_ticks,
|
||||
entry::next_entry_mut, get_tmp_ledger_path,
|
||||
|
@ -1538,7 +1551,7 @@ pub mod tests {
|
|||
"lamports": 20,
|
||||
"data": [],
|
||||
"executable": false,
|
||||
"rent_epoch": 0
|
||||
"rentEpoch": 0
|
||||
},
|
||||
},
|
||||
"id": 1,
|
||||
|
@ -1572,13 +1585,18 @@ pub mod tests {
|
|||
let expected = format!(
|
||||
r#"{{
|
||||
"jsonrpc":"2.0",
|
||||
"result":[["{}", {{
|
||||
"owner": {:?},
|
||||
"lamports": 20,
|
||||
"data": [],
|
||||
"executable": false,
|
||||
"rent_epoch": 0
|
||||
}}]],
|
||||
"result":[
|
||||
{{
|
||||
"pubkey": "{}",
|
||||
"account": {{
|
||||
"owner": {:?},
|
||||
"lamports": 20,
|
||||
"data": [],
|
||||
"executable": false,
|
||||
"rentEpoch": 0
|
||||
}}
|
||||
}}
|
||||
],
|
||||
"id":1}}
|
||||
"#,
|
||||
bob.pubkey(),
|
||||
|
@ -1709,14 +1727,17 @@ pub mod tests {
|
|||
"jsonrpc": "2.0",
|
||||
"result": {
|
||||
"context":{"slot":0},
|
||||
"value":[ blockhash.to_string(), {
|
||||
"burnPercent": DEFAULT_BURN_PERCENT,
|
||||
"lamportsPerSignature": 0,
|
||||
"maxLamportsPerSignature": 0,
|
||||
"minLamportsPerSignature": 0,
|
||||
"targetLamportsPerSignature": 0,
|
||||
"targetSignaturesPerSlot": 0
|
||||
}]},
|
||||
"value":{
|
||||
"blockhash": blockhash.to_string(),
|
||||
"feeCalculator": {
|
||||
"burnPercent": DEFAULT_BURN_PERCENT,
|
||||
"lamportsPerSignature": 0,
|
||||
"maxLamportsPerSignature": 0,
|
||||
"minLamportsPerSignature": 0,
|
||||
"targetLamportsPerSignature": 0,
|
||||
"targetSignaturesPerSlot": 0
|
||||
}
|
||||
}},
|
||||
"id": 1
|
||||
});
|
||||
let expected: Response =
|
||||
|
@ -1941,13 +1962,25 @@ pub mod tests {
|
|||
);
|
||||
assert_eq!(
|
||||
request_processor.get_block_commitment(0),
|
||||
(Some(commitment_slot0), 42)
|
||||
RpcBlockCommitment {
|
||||
commitment: Some(commitment_slot0),
|
||||
total_stake: 42,
|
||||
}
|
||||
);
|
||||
assert_eq!(
|
||||
request_processor.get_block_commitment(1),
|
||||
(Some(commitment_slot1), 42)
|
||||
RpcBlockCommitment {
|
||||
commitment: Some(commitment_slot1),
|
||||
total_stake: 42,
|
||||
}
|
||||
);
|
||||
assert_eq!(
|
||||
request_processor.get_block_commitment(2),
|
||||
RpcBlockCommitment {
|
||||
commitment: None,
|
||||
total_stake: 42,
|
||||
}
|
||||
);
|
||||
assert_eq!(request_processor.get_block_commitment(2), (None, 42));
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
@ -1965,16 +1998,18 @@ pub mod tests {
|
|||
let res = io.handle_request_sync(&req, meta.clone());
|
||||
let result: Response = serde_json::from_str(&res.expect("actual response"))
|
||||
.expect("actual response deserialization");
|
||||
let (commitment, total_staked): (Option<BlockCommitment>, u64) =
|
||||
if let Response::Single(res) = result {
|
||||
if let Output::Success(res) = res {
|
||||
serde_json::from_value(res.result).unwrap()
|
||||
} else {
|
||||
panic!("Expected success");
|
||||
}
|
||||
let RpcBlockCommitment {
|
||||
commitment,
|
||||
total_stake,
|
||||
} = if let Response::Single(res) = result {
|
||||
if let Output::Success(res) = res {
|
||||
serde_json::from_value(res.result).unwrap()
|
||||
} else {
|
||||
panic!("Expected single response");
|
||||
};
|
||||
panic!("Expected success");
|
||||
}
|
||||
} else {
|
||||
panic!("Expected single response");
|
||||
};
|
||||
assert_eq!(
|
||||
commitment,
|
||||
block_commitment_cache
|
||||
|
@ -1983,14 +2018,14 @@ pub mod tests {
|
|||
.get_block_commitment(0)
|
||||
.cloned()
|
||||
);
|
||||
assert_eq!(total_staked, 42);
|
||||
assert_eq!(total_stake, 42);
|
||||
|
||||
let req =
|
||||
format!(r#"{{"jsonrpc":"2.0","id":1,"method":"getBlockCommitment","params":[2]}}"#);
|
||||
let res = io.handle_request_sync(&req, meta);
|
||||
let result: Response = serde_json::from_str(&res.expect("actual response"))
|
||||
.expect("actual response deserialization");
|
||||
let (commitment, total_staked): (Option<BlockCommitment>, u64) =
|
||||
let commitment_response: RpcBlockCommitment<BlockCommitment> =
|
||||
if let Response::Single(res) = result {
|
||||
if let Output::Success(res) = res {
|
||||
serde_json::from_value(res.result).unwrap()
|
||||
|
@ -2000,8 +2035,8 @@ pub mod tests {
|
|||
} else {
|
||||
panic!("Expected single response");
|
||||
};
|
||||
assert_eq!(commitment, None);
|
||||
assert_eq!(total_staked, 42);
|
||||
assert_eq!(commitment_response.commitment, None);
|
||||
assert_eq!(commitment_response.total_stake, 42);
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
@ -2025,21 +2060,23 @@ pub mod tests {
|
|||
let confirmed_block = confirmed_block.unwrap();
|
||||
assert_eq!(confirmed_block.transactions.len(), 3);
|
||||
|
||||
for (transaction, result) in confirmed_block.transactions.into_iter() {
|
||||
for RpcTransactionWithStatusMeta { transaction, meta } in
|
||||
confirmed_block.transactions.into_iter()
|
||||
{
|
||||
if let RpcEncodedTransaction::Json(transaction) = transaction {
|
||||
if transaction.signatures[0] == confirmed_block_signatures[0].to_string() {
|
||||
assert_eq!(transaction.message.recent_blockhash, blockhash.to_string());
|
||||
assert_eq!(result.unwrap().status, Ok(()));
|
||||
assert_eq!(meta.unwrap().status, Ok(()));
|
||||
} else if transaction.signatures[0] == confirmed_block_signatures[1].to_string() {
|
||||
assert_eq!(
|
||||
result.unwrap().status,
|
||||
meta.unwrap().status,
|
||||
Err(TransactionError::InstructionError(
|
||||
0,
|
||||
InstructionError::CustomError(1)
|
||||
))
|
||||
);
|
||||
} else {
|
||||
assert_eq!(result, None);
|
||||
assert_eq!(meta, None);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -2055,23 +2092,25 @@ pub mod tests {
|
|||
let confirmed_block = confirmed_block.unwrap();
|
||||
assert_eq!(confirmed_block.transactions.len(), 3);
|
||||
|
||||
for (transaction, result) in confirmed_block.transactions.into_iter() {
|
||||
for RpcTransactionWithStatusMeta { transaction, meta } in
|
||||
confirmed_block.transactions.into_iter()
|
||||
{
|
||||
if let RpcEncodedTransaction::Binary(transaction) = transaction {
|
||||
let decoded_transaction: Transaction =
|
||||
deserialize(&bs58::decode(&transaction).into_vec().unwrap()).unwrap();
|
||||
if decoded_transaction.signatures[0] == confirmed_block_signatures[0] {
|
||||
assert_eq!(decoded_transaction.message.recent_blockhash, blockhash);
|
||||
assert_eq!(result.unwrap().status, Ok(()));
|
||||
assert_eq!(meta.unwrap().status, Ok(()));
|
||||
} else if decoded_transaction.signatures[0] == confirmed_block_signatures[1] {
|
||||
assert_eq!(
|
||||
result.unwrap().status,
|
||||
meta.unwrap().status,
|
||||
Err(TransactionError::InstructionError(
|
||||
0,
|
||||
InstructionError::CustomError(1)
|
||||
))
|
||||
);
|
||||
} else {
|
||||
assert_eq!(result, None);
|
||||
assert_eq!(meta, None);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -471,7 +471,7 @@ mod tests {
|
|||
"lamports": 51,
|
||||
"data": expected_data,
|
||||
"executable": false,
|
||||
"rent_epoch": 1,
|
||||
"rentEpoch": 1,
|
||||
},
|
||||
"subscription": 0,
|
||||
}
|
||||
|
@ -618,7 +618,7 @@ mod tests {
|
|||
"lamports": 100,
|
||||
"data": [],
|
||||
"executable": false,
|
||||
"rent_epoch": 1,
|
||||
"rentEpoch": 1,
|
||||
},
|
||||
"subscription": 0,
|
||||
}
|
||||
|
|
|
@ -376,7 +376,7 @@ mod tests {
|
|||
let string = transport_receiver.poll();
|
||||
if let Async::Ready(Some(response)) = string.unwrap() {
|
||||
let expected = format!(
|
||||
r#"{{"jsonrpc":"2.0","method":"accountNotification","params":{{"result":{{"data":[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],"executable":false,"lamports":1,"owner":[2,203,81,223,225,24,34,35,203,214,138,130,144,208,35,77,63,16,87,51,47,198,115,123,98,188,19,160,0,0,0,0],"rent_epoch":1}},"subscription":0}}}}"#
|
||||
r#"{{"jsonrpc":"2.0","method":"accountNotification","params":{{"result":{{"data":[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],"executable":false,"lamports":1,"owner":[2,203,81,223,225,24,34,35,203,214,138,130,144,208,35,77,63,16,87,51,47,198,115,123,98,188,19,160,0,0,0,0],"rentEpoch":1}},"subscription":0}}}}"#
|
||||
);
|
||||
assert_eq!(expected, response);
|
||||
}
|
||||
|
@ -433,7 +433,7 @@ mod tests {
|
|||
let string = transport_receiver.poll();
|
||||
if let Async::Ready(Some(response)) = string.unwrap() {
|
||||
let expected = format!(
|
||||
r#"{{"jsonrpc":"2.0","method":"programNotification","params":{{"result":["{:?}",{{"data":[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],"executable":false,"lamports":1,"owner":[2,203,81,223,225,24,34,35,203,214,138,130,144,208,35,77,63,16,87,51,47,198,115,123,98,188,19,160,0,0,0,0],"rent_epoch":1}}],"subscription":0}}}}"#,
|
||||
r#"{{"jsonrpc":"2.0","method":"programNotification","params":{{"result":["{:?}",{{"data":[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],"executable":false,"lamports":1,"owner":[2,203,81,223,225,24,34,35,203,214,138,130,144,208,35,77,63,16,87,51,47,198,115,123,98,188,19,160,0,0,0,0],"rentEpoch":1}}],"subscription":0}}}}"#,
|
||||
alice.pubkey()
|
||||
);
|
||||
assert_eq!(expected, response);
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
use crossbeam_channel::{Receiver, RecvTimeoutError};
|
||||
use solana_client::rpc_request::RpcTransactionStatus;
|
||||
use solana_client::rpc_response::RpcTransactionStatus;
|
||||
use solana_ledger::{blockstore::Blockstore, blockstore_processor::TransactionStatusBatch};
|
||||
use solana_runtime::bank::{Bank, HashAgeKind};
|
||||
use std::{
|
||||
|
|
|
@ -34,7 +34,7 @@ fn test_rpc_send_tx() {
|
|||
.send()
|
||||
.unwrap();
|
||||
let json: Value = serde_json::from_str(&response.text().unwrap()).unwrap();
|
||||
let blockhash: Hash = json["result"]["value"][0]
|
||||
let blockhash: Hash = json["result"]["value"]["blockhash"]
|
||||
.as_str()
|
||||
.unwrap()
|
||||
.parse()
|
||||
|
|
|
@ -21,8 +21,9 @@ use rayon::{
|
|||
ThreadPool,
|
||||
};
|
||||
use rocksdb::DBRawIterator;
|
||||
use solana_client::rpc_request::{
|
||||
use solana_client::rpc_response::{
|
||||
RpcConfirmedBlock, RpcEncodedTransaction, RpcTransactionEncoding, RpcTransactionStatus,
|
||||
RpcTransactionWithStatusMeta,
|
||||
};
|
||||
use solana_measure::measure::Measure;
|
||||
use solana_metrics::{datapoint_debug, datapoint_error};
|
||||
|
@ -1403,18 +1404,19 @@ impl Blockstore {
|
|||
slot: Slot,
|
||||
encoding: RpcTransactionEncoding,
|
||||
iterator: impl Iterator<Item = Transaction> + 'a,
|
||||
) -> Vec<(RpcEncodedTransaction, Option<RpcTransactionStatus>)> {
|
||||
) -> Vec<RpcTransactionWithStatusMeta> {
|
||||
iterator
|
||||
.map(|transaction| {
|
||||
let signature = transaction.signatures[0];
|
||||
let encoded_transaction =
|
||||
RpcEncodedTransaction::encode(transaction, encoding.clone());
|
||||
(
|
||||
encoded_transaction,
|
||||
self.transaction_status_cf
|
||||
RpcTransactionWithStatusMeta {
|
||||
transaction: encoded_transaction,
|
||||
meta: self
|
||||
.transaction_status_cf
|
||||
.get((slot, signature))
|
||||
.expect("Expect database get to succeed"),
|
||||
)
|
||||
}
|
||||
})
|
||||
.collect()
|
||||
}
|
||||
|
@ -4748,11 +4750,9 @@ pub mod tests {
|
|||
transactions: expected_transactions
|
||||
.iter()
|
||||
.cloned()
|
||||
.map(|(tx, status)| {
|
||||
(
|
||||
RpcEncodedTransaction::encode(tx, RpcTransactionEncoding::Json),
|
||||
status,
|
||||
)
|
||||
.map(|(tx, meta)| RpcTransactionWithStatusMeta {
|
||||
transaction: RpcEncodedTransaction::encode(tx, RpcTransactionEncoding::Json),
|
||||
meta,
|
||||
})
|
||||
.collect(),
|
||||
parent_slot: slot - 1,
|
||||
|
@ -4770,11 +4770,9 @@ pub mod tests {
|
|||
transactions: expected_transactions
|
||||
.iter()
|
||||
.cloned()
|
||||
.map(|(tx, status)| {
|
||||
(
|
||||
RpcEncodedTransaction::encode(tx, RpcTransactionEncoding::Json),
|
||||
status,
|
||||
)
|
||||
.map(|(tx, meta)| RpcTransactionWithStatusMeta {
|
||||
transaction: RpcEncodedTransaction::encode(tx, RpcTransactionEncoding::Json),
|
||||
meta,
|
||||
})
|
||||
.collect(),
|
||||
parent_slot: slot,
|
||||
|
@ -5007,9 +5005,9 @@ pub mod tests {
|
|||
);
|
||||
assert_eq!(map.len(), 5);
|
||||
for x in 0..4 {
|
||||
assert_eq!(map[x].1.as_ref().unwrap().fee, x as u64);
|
||||
assert_eq!(map[x].meta.as_ref().unwrap().fee, x as u64);
|
||||
}
|
||||
assert_eq!(map[4].1.as_ref(), None);
|
||||
assert_eq!(map[4].meta, None);
|
||||
}
|
||||
Blockstore::destroy(&blockstore_path).expect("Expected successful database destruction");
|
||||
}
|
||||
|
|
|
@ -10,7 +10,7 @@ use rocksdb::{
|
|||
};
|
||||
use serde::de::DeserializeOwned;
|
||||
use serde::Serialize;
|
||||
use solana_client::rpc_request::RpcTransactionStatus;
|
||||
use solana_client::rpc_response::RpcTransactionStatus;
|
||||
use solana_sdk::{clock::Slot, signature::Signature};
|
||||
use std::{collections::HashMap, fs, marker::PhantomData, path::Path, sync::Arc};
|
||||
use thiserror::Error;
|
||||
|
|
|
@ -5,6 +5,7 @@ use std::{cmp, fmt, iter::FromIterator};
|
|||
/// An Account with data that is stored on chain
|
||||
#[repr(C)]
|
||||
#[derive(Serialize, Deserialize, Clone, Default)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct Account {
|
||||
/// lamports in the account
|
||||
pub lamports: u64,
|
||||
|
|
|
@ -13,6 +13,7 @@ pub const MINIMUM_SLOTS_PER_EPOCH: u64 = 32;
|
|||
|
||||
#[repr(C)]
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Deserialize, Serialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct EpochSchedule {
|
||||
/// The maximum number of slots in each epoch.
|
||||
pub slots_per_epoch: u64,
|
||||
|
|
Loading…
Reference in New Issue