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:
@ -193,13 +193,13 @@ Returns commitment for particular block
|
|||||||
|
|
||||||
#### Results:
|
#### 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
|
* `null` - Unknown block
|
||||||
* `object` - BlockCommitment
|
* `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`
|
* `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:
|
#### 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
|
* `blockhash` - the blockhash of this block, as base-58 encoded string
|
||||||
* `previousBlockhash` - the blockhash of this block's parent, 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
|
* `parentSlot` - the slot index of this block's parent
|
||||||
* `transactions` - an array of tuples containing:
|
* `transactions` - an array of JSON objects containing:
|
||||||
* [Transaction](transaction-api.md) object, either in JSON format or base-58 encoded binary data, depending on encoding parameter
|
* `transaction` - [Transaction](transaction-api.md) object, either in JSON format or base-58 encoded binary data, depending on encoding parameter
|
||||||
* Transaction status object, containing:
|
* `meta` - transaction status metadata object, containing `null` or:
|
||||||
* `status` - Transaction status:
|
* `status` - Transaction status:
|
||||||
* `"Ok": null` - Transaction was successful
|
* `"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)
|
* `"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:
|
The result field will be an object with the following fields:
|
||||||
|
|
||||||
* `slots_per_epoch`, the maximum number of slots in each epoch
|
* `slotsPerEpoch`, 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
|
* `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
|
* `warmup`, whether epochs start short and grow
|
||||||
* `first_normal_epoch`, first normal-length epoch, log2(slots_per_epoch) - log2(MINIMUM_SLOTS_PER_EPOCH)
|
* `firstNormalEpoch`, first normal-length epoch, log2(slotsPerEpoch) - log2(MINIMUM_SLOTS_PER_EPOCH)
|
||||||
* `first_normal_slot`, MINIMUM_SLOTS_PER_EPOCH * (2.pow(first_normal_epoch) - 1)
|
* `firstNormalSlot`, MINIMUM_SLOTS_PER_EPOCH * (2.pow(firstNormalEpoch) - 1)
|
||||||
|
|
||||||
#### Example:
|
#### 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
|
curl -X POST -H "Content-Type: application/json" -d '{"jsonrpc":"2.0","id":1, "method":"getEpochSchedule"}' http://localhost:8899
|
||||||
|
|
||||||
// Result
|
// 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
|
### 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.
|
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:
|
* `RpcResponse<array>` - RpcResponse JSON object with `value` field set to a JSON object including:
|
||||||
* `string` - a Hash as base-58 encoded string
|
* `blockhash` - a Hash as base-58 encoded string
|
||||||
* `FeeCalculator object` - the fee schedule for this block hash
|
* `feeCalculator` - FeeCalculator object, the fee schedule for this block hash
|
||||||
|
|
||||||
#### Example:
|
#### Example:
|
||||||
|
|
||||||
@ -641,10 +641,10 @@ None
|
|||||||
|
|
||||||
#### Results:
|
#### 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
|
* `blockhash` - a Hash as base-58 encoded string indicating the blockhash of the turn slot
|
||||||
* `u64` - the current storage turn slot
|
* `slot` - the current storage turn slot
|
||||||
|
|
||||||
#### Example:
|
#### Example:
|
||||||
|
|
||||||
@ -652,7 +652,7 @@ An array consisting of
|
|||||||
// Request
|
// Request
|
||||||
curl -X POST -H "Content-Type: application/json" -d '{"jsonrpc":"2.0","id":1, "method":"getStorageTurn"}' http://localhost:8899
|
curl -X POST -H "Content-Type: application/json" -d '{"jsonrpc":"2.0","id":1, "method":"getStorageTurn"}' http://localhost:8899
|
||||||
// Result
|
// Result
|
||||||
{"jsonrpc":"2.0","result":["GH7ome3EiwEr7tu9JuTh2dpYWBJK3z69Xm1ZE3MEE6JC", "2048"],"id":1}
|
{"jsonrpc":"2.0","result":{"blockhash": "GH7ome3EiwEr7tu9JuTh2dpYWBJK3z69Xm1ZE3MEE6JC", "slot": "2048"},"id":1}
|
||||||
```
|
```
|
||||||
|
|
||||||
### getStorageTurnRate
|
### getStorageTurnRate
|
||||||
@ -673,7 +673,7 @@ None
|
|||||||
// Request
|
// Request
|
||||||
curl -X POST -H "Content-Type: application/json" -d '{"jsonrpc":"2.0","id":1, "method":"getStorageTurnRate"}' http://localhost:8899
|
curl -X POST -H "Content-Type: application/json" -d '{"jsonrpc":"2.0","id":1, "method":"getStorageTurnRate"}' http://localhost:8899
|
||||||
// Result
|
// Result
|
||||||
{"jsonrpc":"2.0","result":"1024","id":1}
|
{"jsonrpc":"2.0","result":1024,"id":1}
|
||||||
```
|
```
|
||||||
|
|
||||||
### getTransactionCount
|
### getTransactionCount
|
||||||
|
@ -1989,7 +1989,8 @@ mod tests {
|
|||||||
use serde_json::Value;
|
use serde_json::Value;
|
||||||
use solana_client::{
|
use solana_client::{
|
||||||
mock_rpc_client_request::SIGNATURE,
|
mock_rpc_client_request::SIGNATURE,
|
||||||
rpc_request::{self, RpcRequest, RpcResponseContext},
|
rpc_request::RpcRequest,
|
||||||
|
rpc_response::{Response, RpcResponseContext},
|
||||||
};
|
};
|
||||||
use solana_sdk::{
|
use solana_sdk::{
|
||||||
account::Account,
|
account::Account,
|
||||||
@ -2669,7 +2670,7 @@ mod tests {
|
|||||||
|
|
||||||
// Nonced pay
|
// Nonced pay
|
||||||
let blockhash = Hash::default();
|
let blockhash = Hash::default();
|
||||||
let nonce_response = json!(rpc_request::Response {
|
let nonce_response = json!(Response {
|
||||||
context: RpcResponseContext { slot: 1 },
|
context: RpcResponseContext { slot: 1 },
|
||||||
value: json!(Account::new_data(
|
value: json!(Account::new_data(
|
||||||
1,
|
1,
|
||||||
@ -2695,7 +2696,7 @@ mod tests {
|
|||||||
let bob_keypair = Keypair::new();
|
let bob_keypair = Keypair::new();
|
||||||
let bob_pubkey = bob_keypair.pubkey();
|
let bob_pubkey = bob_keypair.pubkey();
|
||||||
let blockhash = Hash::default();
|
let blockhash = Hash::default();
|
||||||
let nonce_authority_response = json!(rpc_request::Response {
|
let nonce_authority_response = json!(Response {
|
||||||
context: RpcResponseContext { slot: 1 },
|
context: RpcResponseContext { slot: 1 },
|
||||||
value: json!(Account::new_data(
|
value: json!(Account::new_data(
|
||||||
1,
|
1,
|
||||||
|
@ -9,7 +9,7 @@ use clap::{value_t, value_t_or_exit, App, Arg, ArgMatches, SubCommand};
|
|||||||
use console::{style, Emoji};
|
use console::{style, Emoji};
|
||||||
use indicatif::{ProgressBar, ProgressStyle};
|
use indicatif::{ProgressBar, ProgressStyle};
|
||||||
use solana_clap_utils::{input_parsers::*, input_validators::*};
|
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::{
|
use solana_sdk::{
|
||||||
clock::{self, Slot},
|
clock::{self, Slot},
|
||||||
commitment_config::CommitmentConfig,
|
commitment_config::CommitmentConfig,
|
||||||
|
@ -8,4 +8,5 @@ pub mod perf_utils;
|
|||||||
pub mod rpc_client;
|
pub mod rpc_client;
|
||||||
pub mod rpc_client_request;
|
pub mod rpc_client_request;
|
||||||
pub mod rpc_request;
|
pub mod rpc_request;
|
||||||
|
pub mod rpc_response;
|
||||||
pub mod thin_client;
|
pub mod thin_client;
|
||||||
|
@ -1,7 +1,8 @@
|
|||||||
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,
|
||||||
|
rpc_response::{Response, RpcResponseContext},
|
||||||
};
|
};
|
||||||
use serde_json::{Number, Value};
|
use serde_json::{Number, Value};
|
||||||
use solana_sdk::{
|
use solana_sdk::{
|
||||||
|
@ -1,12 +1,12 @@
|
|||||||
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,
|
||||||
mock_rpc_client_request::{MockRpcClientRequest, Mocks},
|
mock_rpc_client_request::{MockRpcClientRequest, Mocks},
|
||||||
rpc_client_request::RpcClientRequest,
|
rpc_client_request::RpcClientRequest,
|
||||||
rpc_request::{
|
rpc_request::RpcRequest,
|
||||||
RpcConfirmedBlock, RpcContactInfo, RpcEpochInfo, RpcLeaderSchedule, RpcRequest,
|
rpc_response::{
|
||||||
RpcVersionInfo, RpcVoteAccountStatus,
|
Response, RpcBlockhashFeeCalculator, RpcConfirmedBlock, RpcContactInfo, RpcEpochInfo,
|
||||||
|
RpcLeaderSchedule, RpcResponse, RpcVersionInfo, RpcVoteAccountStatus,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
use bincode::serialize;
|
use bincode::serialize;
|
||||||
@ -753,8 +753,12 @@ impl RpcClient {
|
|||||||
|
|
||||||
let Response {
|
let Response {
|
||||||
context,
|
context,
|
||||||
value: (blockhash_str, fee_calculator),
|
value:
|
||||||
} = serde_json::from_value::<Response<(String, FeeCalculator)>>(response).map_err(
|
RpcBlockhashFeeCalculator {
|
||||||
|
blockhash,
|
||||||
|
fee_calculator,
|
||||||
|
},
|
||||||
|
} = serde_json::from_value::<Response<RpcBlockhashFeeCalculator>>(response).map_err(
|
||||||
|err| {
|
|err| {
|
||||||
io::Error::new(
|
io::Error::new(
|
||||||
io::ErrorKind::Other,
|
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::Error::new(
|
||||||
io::ErrorKind::Other,
|
io::ErrorKind::Other,
|
||||||
format!("GetRecentBlockhash hash parse failure: {:?}", err),
|
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 serde_json::{json, Value};
|
||||||
use solana_sdk::{
|
use std::{error, fmt};
|
||||||
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,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug, PartialEq, Eq, Hash)]
|
#[derive(Debug, PartialEq, Eq, Hash)]
|
||||||
pub enum RpcRequest {
|
pub enum RpcRequest {
|
||||||
|
237
client/src/rpc_response.rs
Normal file
237
client/src/rpc_response.rs
Normal file
@ -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
|
//! messages to the network directly. The binary encoding of its messages are
|
||||||
//! unstable and may change in future releases.
|
//! unstable and may change in future releases.
|
||||||
|
|
||||||
use crate::rpc_client::RpcClient;
|
use crate::{rpc_client::RpcClient, rpc_response::Response};
|
||||||
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::{
|
||||||
|
@ -17,7 +17,10 @@ use crossbeam_channel::unbounded;
|
|||||||
use ed25519_dalek;
|
use ed25519_dalek;
|
||||||
use rand::{thread_rng, Rng, SeedableRng};
|
use rand::{thread_rng, Rng, SeedableRng};
|
||||||
use rand_chacha::ChaChaRng;
|
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::{
|
use solana_ledger::{
|
||||||
blockstore::Blockstore, leader_schedule_cache::LeaderScheduleCache, shred::Shred,
|
blockstore::Blockstore, leader_schedule_cache::LeaderScheduleCache, shred::Shred,
|
||||||
};
|
};
|
||||||
@ -811,13 +814,15 @@ impl Archiver {
|
|||||||
warn!("Error while making rpc request {:?}", err);
|
warn!("Error while making rpc request {:?}", err);
|
||||||
Error::IO(io::Error::new(ErrorKind::Other, "rpc error"))
|
Error::IO(io::Error::new(ErrorKind::Other, "rpc error"))
|
||||||
})?;
|
})?;
|
||||||
let (storage_blockhash, turn_slot) =
|
let RpcStorageTurn {
|
||||||
serde_json::from_value::<(String, u64)>(response).map_err(|err| {
|
blockhash: storage_blockhash,
|
||||||
io::Error::new(
|
slot: turn_slot,
|
||||||
io::ErrorKind::Other,
|
} = serde_json::from_value::<RpcStorageTurn>(response).map_err(|err| {
|
||||||
format!("Couldn't parse response: {:?}", err),
|
io::Error::new(
|
||||||
)
|
io::ErrorKind::Other,
|
||||||
})?;
|
format!("Couldn't parse response: {:?}", err),
|
||||||
|
)
|
||||||
|
})?;
|
||||||
let turn_blockhash = storage_blockhash.parse().map_err(|err| {
|
let turn_blockhash = storage_blockhash.parse().map_err(|err| {
|
||||||
io::Error::new(
|
io::Error::new(
|
||||||
io::ErrorKind::Other,
|
io::ErrorKind::Other,
|
||||||
|
@ -1020,7 +1020,7 @@ mod tests {
|
|||||||
};
|
};
|
||||||
use crossbeam_channel::unbounded;
|
use crossbeam_channel::unbounded;
|
||||||
use itertools::Itertools;
|
use itertools::Itertools;
|
||||||
use solana_client::rpc_request::RpcEncodedTransaction;
|
use solana_client::rpc_response::{RpcEncodedTransaction, RpcTransactionWithStatusMeta};
|
||||||
use solana_ledger::{
|
use solana_ledger::{
|
||||||
blockstore::entries_to_test_shreds,
|
blockstore::entries_to_test_shreds,
|
||||||
entry::{next_entry, Entry, EntrySlice},
|
entry::{next_entry, Entry, EntrySlice},
|
||||||
@ -1978,20 +1978,22 @@ mod tests {
|
|||||||
let confirmed_block = blockstore.get_confirmed_block(bank.slot(), None).unwrap();
|
let confirmed_block = blockstore.get_confirmed_block(bank.slot(), None).unwrap();
|
||||||
assert_eq!(confirmed_block.transactions.len(), 3);
|
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 let RpcEncodedTransaction::Json(transaction) = transaction {
|
||||||
if transaction.signatures[0] == success_signature.to_string() {
|
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() {
|
} else if transaction.signatures[0] == ix_error_signature.to_string() {
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
result.unwrap().status,
|
meta.unwrap().status,
|
||||||
Err(TransactionError::InstructionError(
|
Err(TransactionError::InstructionError(
|
||||||
0,
|
0,
|
||||||
InstructionError::CustomError(1)
|
InstructionError::CustomError(1)
|
||||||
))
|
))
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
assert_eq!(result, None);
|
assert_eq!(meta, None);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -997,7 +997,7 @@ pub(crate) mod tests {
|
|||||||
transaction_status_service::TransactionStatusService,
|
transaction_status_service::TransactionStatusService,
|
||||||
};
|
};
|
||||||
use crossbeam_channel::unbounded;
|
use crossbeam_channel::unbounded;
|
||||||
use solana_client::rpc_request::RpcEncodedTransaction;
|
use solana_client::rpc_response::{RpcEncodedTransaction, RpcTransactionWithStatusMeta};
|
||||||
use solana_ledger::{
|
use solana_ledger::{
|
||||||
block_error::BlockError,
|
block_error::BlockError,
|
||||||
blockstore::make_slot_entries,
|
blockstore::make_slot_entries,
|
||||||
@ -1011,22 +1011,21 @@ pub(crate) mod tests {
|
|||||||
},
|
},
|
||||||
};
|
};
|
||||||
use solana_runtime::genesis_utils::GenesisConfigInfo;
|
use solana_runtime::genesis_utils::GenesisConfigInfo;
|
||||||
use solana_sdk::account::Account;
|
|
||||||
use solana_sdk::rent::Rent;
|
|
||||||
use solana_sdk::{
|
use solana_sdk::{
|
||||||
|
account::Account,
|
||||||
hash::{hash, Hash},
|
hash::{hash, Hash},
|
||||||
instruction::InstructionError,
|
instruction::InstructionError,
|
||||||
packet::PACKET_DATA_SIZE,
|
packet::PACKET_DATA_SIZE,
|
||||||
|
rent::Rent,
|
||||||
signature::{Keypair, KeypairUtil, Signature},
|
signature::{Keypair, KeypairUtil, Signature},
|
||||||
system_transaction,
|
system_transaction,
|
||||||
transaction::TransactionError,
|
transaction::TransactionError,
|
||||||
};
|
};
|
||||||
use solana_stake_program::stake_state;
|
use solana_stake_program::stake_state;
|
||||||
use solana_vote_program::vote_state;
|
use solana_vote_program::vote_state::{self, Vote, VoteState};
|
||||||
use solana_vote_program::vote_state::{Vote, VoteState};
|
|
||||||
use std::iter;
|
|
||||||
use std::{
|
use std::{
|
||||||
fs::remove_dir_all,
|
fs::remove_dir_all,
|
||||||
|
iter,
|
||||||
sync::{Arc, RwLock},
|
sync::{Arc, RwLock},
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -1803,20 +1802,22 @@ pub(crate) mod tests {
|
|||||||
let confirmed_block = blockstore.get_confirmed_block(slot, None).unwrap();
|
let confirmed_block = blockstore.get_confirmed_block(slot, None).unwrap();
|
||||||
assert_eq!(confirmed_block.transactions.len(), 3);
|
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 let RpcEncodedTransaction::Json(transaction) = transaction {
|
||||||
if transaction.signatures[0] == signatures[0].to_string() {
|
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() {
|
} else if transaction.signatures[0] == signatures[1].to_string() {
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
result.unwrap().status,
|
meta.unwrap().status,
|
||||||
Err(TransactionError::InstructionError(
|
Err(TransactionError::InstructionError(
|
||||||
0,
|
0,
|
||||||
InstructionError::CustomError(1)
|
InstructionError::CustomError(1)
|
||||||
))
|
))
|
||||||
);
|
);
|
||||||
} else {
|
} 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 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::{
|
use solana_client::rpc_response::{
|
||||||
Response, RpcConfirmedBlock, RpcContactInfo, RpcEpochInfo, RpcLeaderSchedule,
|
Response, RpcBlockCommitment, RpcBlockhashFeeCalculator, RpcConfirmedBlock, RpcContactInfo,
|
||||||
RpcResponseContext, RpcTransactionEncoding, RpcVersionInfo, RpcVoteAccountInfo,
|
RpcEpochInfo, RpcKeyedAccount, RpcLeaderSchedule, RpcResponseContext, RpcSignatureConfirmation,
|
||||||
|
RpcStorageTurn, RpcTransactionEncoding, RpcVersionInfo, RpcVoteAccountInfo,
|
||||||
RpcVoteAccountStatus,
|
RpcVoteAccountStatus,
|
||||||
};
|
};
|
||||||
use solana_faucet::faucet::request_airdrop_transaction;
|
use solana_faucet::faucet::request_airdrop_transaction;
|
||||||
@ -26,7 +27,6 @@ use solana_sdk::{
|
|||||||
clock::{Slot, UnixTimestamp},
|
clock::{Slot, UnixTimestamp},
|
||||||
commitment_config::{CommitmentConfig, CommitmentLevel},
|
commitment_config::{CommitmentConfig, CommitmentLevel},
|
||||||
epoch_schedule::EpochSchedule,
|
epoch_schedule::EpochSchedule,
|
||||||
fee_calculator::FeeCalculator,
|
|
||||||
hash::Hash,
|
hash::Hash,
|
||||||
inflation::Inflation,
|
inflation::Inflation,
|
||||||
pubkey::Pubkey,
|
pubkey::Pubkey,
|
||||||
@ -134,12 +134,15 @@ impl JsonRpcRequestProcessor {
|
|||||||
&self,
|
&self,
|
||||||
program_id: &Pubkey,
|
program_id: &Pubkey,
|
||||||
commitment: Option<CommitmentConfig>,
|
commitment: Option<CommitmentConfig>,
|
||||||
) -> Result<Vec<(String, Account)>> {
|
) -> Result<Vec<RpcKeyedAccount>> {
|
||||||
Ok(self
|
Ok(self
|
||||||
.bank(commitment)
|
.bank(commitment)
|
||||||
.get_program_accounts(&program_id)
|
.get_program_accounts(&program_id)
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.map(|(pubkey, account)| (pubkey.to_string(), account))
|
.map(|(pubkey, account)| RpcKeyedAccount {
|
||||||
|
pubkey: pubkey.to_string(),
|
||||||
|
account,
|
||||||
|
})
|
||||||
.collect())
|
.collect())
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -168,10 +171,16 @@ impl JsonRpcRequestProcessor {
|
|||||||
fn get_recent_blockhash(
|
fn get_recent_blockhash(
|
||||||
&self,
|
&self,
|
||||||
commitment: Option<CommitmentConfig>,
|
commitment: Option<CommitmentConfig>,
|
||||||
) -> RpcResponse<(String, FeeCalculator)> {
|
) -> RpcResponse<RpcBlockhashFeeCalculator> {
|
||||||
let bank = &*self.bank(commitment);
|
let bank = &*self.bank(commitment);
|
||||||
let (blockhash, fee_calculator) = bank.confirmed_last_blockhash();
|
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(
|
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();
|
let r_block_commitment = self.block_commitment_cache.read().unwrap();
|
||||||
(
|
RpcBlockCommitment {
|
||||||
r_block_commitment.get_block_commitment(block).cloned(),
|
commitment: r_block_commitment.get_block_commitment(block).cloned(),
|
||||||
r_block_commitment.total_stake(),
|
total_stake: r_block_commitment.total_stake(),
|
||||||
)
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_signature_confirmation_status(
|
pub fn get_signature_confirmation_status(
|
||||||
&self,
|
&self,
|
||||||
signature: Signature,
|
signature: Signature,
|
||||||
commitment: Option<CommitmentConfig>,
|
commitment: Option<CommitmentConfig>,
|
||||||
) -> Option<(usize, transaction::Result<()>)> {
|
) -> Option<RpcSignatureConfirmation> {
|
||||||
self.bank(commitment)
|
self.bank(commitment)
|
||||||
.get_signature_confirmation_status(&signature)
|
.get_signature_confirmation_status(&signature)
|
||||||
|
.map(|(confirmations, status)| RpcSignatureConfirmation {
|
||||||
|
confirmations,
|
||||||
|
status,
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_slot(&self, commitment: Option<CommitmentConfig>) -> Result<u64> {
|
fn get_slot(&self, commitment: Option<CommitmentConfig>) -> Result<u64> {
|
||||||
@ -283,11 +296,11 @@ impl JsonRpcRequestProcessor {
|
|||||||
Ok(self.storage_state.get_storage_turn_rate())
|
Ok(self.storage_state.get_storage_turn_rate())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_storage_turn(&self) -> Result<(String, u64)> {
|
fn get_storage_turn(&self) -> Result<RpcStorageTurn> {
|
||||||
Ok((
|
Ok(RpcStorageTurn {
|
||||||
self.storage_state.get_storage_blockhash().to_string(),
|
blockhash: self.storage_state.get_storage_blockhash().to_string(),
|
||||||
self.storage_state.get_slot(),
|
slot: self.storage_state.get_slot(),
|
||||||
))
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_slots_per_segment(&self, commitment: Option<CommitmentConfig>) -> Result<u64> {
|
fn get_slots_per_segment(&self, commitment: Option<CommitmentConfig>) -> Result<u64> {
|
||||||
@ -407,7 +420,7 @@ pub trait RpcSol {
|
|||||||
meta: Self::Metadata,
|
meta: Self::Metadata,
|
||||||
program_id_str: String,
|
program_id_str: String,
|
||||||
commitment: Option<CommitmentConfig>,
|
commitment: Option<CommitmentConfig>,
|
||||||
) -> Result<Vec<(String, Account)>>;
|
) -> Result<Vec<RpcKeyedAccount>>;
|
||||||
|
|
||||||
#[rpc(meta, name = "getMinimumBalanceForRentExemption")]
|
#[rpc(meta, name = "getMinimumBalanceForRentExemption")]
|
||||||
fn get_minimum_balance_for_rent_exemption(
|
fn get_minimum_balance_for_rent_exemption(
|
||||||
@ -450,7 +463,7 @@ pub trait RpcSol {
|
|||||||
&self,
|
&self,
|
||||||
meta: Self::Metadata,
|
meta: Self::Metadata,
|
||||||
block: Slot,
|
block: Slot,
|
||||||
) -> Result<(Option<BlockCommitment>, u64)>;
|
) -> Result<RpcBlockCommitment<BlockCommitment>>;
|
||||||
|
|
||||||
#[rpc(meta, name = "getGenesisHash")]
|
#[rpc(meta, name = "getGenesisHash")]
|
||||||
fn get_genesis_hash(&self, meta: Self::Metadata) -> Result<String>;
|
fn get_genesis_hash(&self, meta: Self::Metadata) -> Result<String>;
|
||||||
@ -468,7 +481,7 @@ pub trait RpcSol {
|
|||||||
&self,
|
&self,
|
||||||
meta: Self::Metadata,
|
meta: Self::Metadata,
|
||||||
commitment: Option<CommitmentConfig>,
|
commitment: Option<CommitmentConfig>,
|
||||||
) -> RpcResponse<(String, FeeCalculator)>;
|
) -> RpcResponse<RpcBlockhashFeeCalculator>;
|
||||||
|
|
||||||
#[rpc(meta, name = "getSignatureStatus")]
|
#[rpc(meta, name = "getSignatureStatus")]
|
||||||
fn get_signature_status(
|
fn get_signature_status(
|
||||||
@ -525,7 +538,7 @@ pub trait RpcSol {
|
|||||||
fn get_storage_turn_rate(&self, meta: Self::Metadata) -> Result<u64>;
|
fn get_storage_turn_rate(&self, meta: Self::Metadata) -> Result<u64>;
|
||||||
|
|
||||||
#[rpc(meta, name = "getStorageTurn")]
|
#[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")]
|
#[rpc(meta, name = "getSlotsPerSegment")]
|
||||||
fn get_slots_per_segment(
|
fn get_slots_per_segment(
|
||||||
@ -554,7 +567,7 @@ pub trait RpcSol {
|
|||||||
meta: Self::Metadata,
|
meta: Self::Metadata,
|
||||||
signature_str: String,
|
signature_str: String,
|
||||||
commitment: Option<CommitmentConfig>,
|
commitment: Option<CommitmentConfig>,
|
||||||
) -> Result<Option<(usize, transaction::Result<()>)>>;
|
) -> Result<Option<RpcSignatureConfirmation>>;
|
||||||
|
|
||||||
#[rpc(meta, name = "getVersion")]
|
#[rpc(meta, name = "getVersion")]
|
||||||
fn get_version(&self, meta: Self::Metadata) -> Result<RpcVersionInfo>;
|
fn get_version(&self, meta: Self::Metadata) -> Result<RpcVersionInfo>;
|
||||||
@ -635,7 +648,7 @@ impl RpcSol for RpcSolImpl {
|
|||||||
meta: Self::Metadata,
|
meta: Self::Metadata,
|
||||||
program_id_str: String,
|
program_id_str: String,
|
||||||
commitment: Option<CommitmentConfig>,
|
commitment: Option<CommitmentConfig>,
|
||||||
) -> Result<Vec<(String, Account)>> {
|
) -> Result<Vec<RpcKeyedAccount>> {
|
||||||
debug!(
|
debug!(
|
||||||
"get_program_accounts rpc request received: {:?}",
|
"get_program_accounts rpc request received: {:?}",
|
||||||
program_id_str
|
program_id_str
|
||||||
@ -734,7 +747,7 @@ impl RpcSol for RpcSolImpl {
|
|||||||
&self,
|
&self,
|
||||||
meta: Self::Metadata,
|
meta: Self::Metadata,
|
||||||
block: Slot,
|
block: Slot,
|
||||||
) -> Result<(Option<BlockCommitment>, u64)> {
|
) -> Result<RpcBlockCommitment<BlockCommitment>> {
|
||||||
Ok(meta
|
Ok(meta
|
||||||
.request_processor
|
.request_processor
|
||||||
.read()
|
.read()
|
||||||
@ -778,7 +791,7 @@ impl RpcSol for RpcSolImpl {
|
|||||||
&self,
|
&self,
|
||||||
meta: Self::Metadata,
|
meta: Self::Metadata,
|
||||||
commitment: Option<CommitmentConfig>,
|
commitment: Option<CommitmentConfig>,
|
||||||
) -> RpcResponse<(String, FeeCalculator)> {
|
) -> RpcResponse<RpcBlockhashFeeCalculator> {
|
||||||
debug!("get_recent_blockhash rpc request received");
|
debug!("get_recent_blockhash rpc request received");
|
||||||
meta.request_processor
|
meta.request_processor
|
||||||
.read()
|
.read()
|
||||||
@ -793,7 +806,7 @@ impl RpcSol for RpcSolImpl {
|
|||||||
commitment: Option<CommitmentConfig>,
|
commitment: Option<CommitmentConfig>,
|
||||||
) -> Result<Option<transaction::Result<()>>> {
|
) -> Result<Option<transaction::Result<()>>> {
|
||||||
self.get_signature_confirmation(meta, signature_str, commitment)
|
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> {
|
fn get_slot(&self, meta: Self::Metadata, commitment: Option<CommitmentConfig>) -> Result<u64> {
|
||||||
@ -807,7 +820,7 @@ impl RpcSol for RpcSolImpl {
|
|||||||
commitment: Option<CommitmentConfig>,
|
commitment: Option<CommitmentConfig>,
|
||||||
) -> Result<Option<usize>> {
|
) -> Result<Option<usize>> {
|
||||||
self.get_signature_confirmation(meta, signature_str, commitment)
|
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(
|
fn get_signature_confirmation(
|
||||||
@ -815,7 +828,7 @@ impl RpcSol for RpcSolImpl {
|
|||||||
meta: Self::Metadata,
|
meta: Self::Metadata,
|
||||||
signature_str: String,
|
signature_str: String,
|
||||||
commitment: Option<CommitmentConfig>,
|
commitment: Option<CommitmentConfig>,
|
||||||
) -> Result<Option<(usize, transaction::Result<()>)>> {
|
) -> Result<Option<RpcSignatureConfirmation>> {
|
||||||
debug!(
|
debug!(
|
||||||
"get_signature_confirmation rpc request received: {:?}",
|
"get_signature_confirmation rpc request received: {:?}",
|
||||||
signature_str
|
signature_str
|
||||||
@ -915,7 +928,7 @@ impl RpcSol for RpcSolImpl {
|
|||||||
.read()
|
.read()
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.get_signature_confirmation_status(signature, commitment.clone())
|
.get_signature_confirmation_status(signature, commitment.clone())
|
||||||
.map(|x| x.1);
|
.map(|x| x.status);
|
||||||
|
|
||||||
if signature_status == Some(Ok(())) {
|
if signature_status == Some(Ok(())) {
|
||||||
info!("airdrop signature ok");
|
info!("airdrop signature ok");
|
||||||
@ -992,7 +1005,7 @@ impl RpcSol for RpcSolImpl {
|
|||||||
.get_storage_turn_rate()
|
.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()
|
meta.request_processor.read().unwrap().get_storage_turn()
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1072,7 +1085,7 @@ pub mod tests {
|
|||||||
};
|
};
|
||||||
use bincode::deserialize;
|
use bincode::deserialize;
|
||||||
use jsonrpc_core::{MetaIoHandler, Output, Response, Value};
|
use jsonrpc_core::{MetaIoHandler, Output, Response, Value};
|
||||||
use solana_client::rpc_request::RpcEncodedTransaction;
|
use solana_client::rpc_response::{RpcEncodedTransaction, RpcTransactionWithStatusMeta};
|
||||||
use solana_ledger::{
|
use solana_ledger::{
|
||||||
blockstore::entries_to_test_shreds, blockstore_processor::fill_blockstore_slot_with_ticks,
|
blockstore::entries_to_test_shreds, blockstore_processor::fill_blockstore_slot_with_ticks,
|
||||||
entry::next_entry_mut, get_tmp_ledger_path,
|
entry::next_entry_mut, get_tmp_ledger_path,
|
||||||
@ -1538,7 +1551,7 @@ pub mod tests {
|
|||||||
"lamports": 20,
|
"lamports": 20,
|
||||||
"data": [],
|
"data": [],
|
||||||
"executable": false,
|
"executable": false,
|
||||||
"rent_epoch": 0
|
"rentEpoch": 0
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
"id": 1,
|
"id": 1,
|
||||||
@ -1572,13 +1585,18 @@ pub mod tests {
|
|||||||
let expected = format!(
|
let expected = format!(
|
||||||
r#"{{
|
r#"{{
|
||||||
"jsonrpc":"2.0",
|
"jsonrpc":"2.0",
|
||||||
"result":[["{}", {{
|
"result":[
|
||||||
"owner": {:?},
|
{{
|
||||||
"lamports": 20,
|
"pubkey": "{}",
|
||||||
"data": [],
|
"account": {{
|
||||||
"executable": false,
|
"owner": {:?},
|
||||||
"rent_epoch": 0
|
"lamports": 20,
|
||||||
}}]],
|
"data": [],
|
||||||
|
"executable": false,
|
||||||
|
"rentEpoch": 0
|
||||||
|
}}
|
||||||
|
}}
|
||||||
|
],
|
||||||
"id":1}}
|
"id":1}}
|
||||||
"#,
|
"#,
|
||||||
bob.pubkey(),
|
bob.pubkey(),
|
||||||
@ -1709,14 +1727,17 @@ pub mod tests {
|
|||||||
"jsonrpc": "2.0",
|
"jsonrpc": "2.0",
|
||||||
"result": {
|
"result": {
|
||||||
"context":{"slot":0},
|
"context":{"slot":0},
|
||||||
"value":[ blockhash.to_string(), {
|
"value":{
|
||||||
"burnPercent": DEFAULT_BURN_PERCENT,
|
"blockhash": blockhash.to_string(),
|
||||||
"lamportsPerSignature": 0,
|
"feeCalculator": {
|
||||||
"maxLamportsPerSignature": 0,
|
"burnPercent": DEFAULT_BURN_PERCENT,
|
||||||
"minLamportsPerSignature": 0,
|
"lamportsPerSignature": 0,
|
||||||
"targetLamportsPerSignature": 0,
|
"maxLamportsPerSignature": 0,
|
||||||
"targetSignaturesPerSlot": 0
|
"minLamportsPerSignature": 0,
|
||||||
}]},
|
"targetLamportsPerSignature": 0,
|
||||||
|
"targetSignaturesPerSlot": 0
|
||||||
|
}
|
||||||
|
}},
|
||||||
"id": 1
|
"id": 1
|
||||||
});
|
});
|
||||||
let expected: Response =
|
let expected: Response =
|
||||||
@ -1941,13 +1962,25 @@ pub mod tests {
|
|||||||
);
|
);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
request_processor.get_block_commitment(0),
|
request_processor.get_block_commitment(0),
|
||||||
(Some(commitment_slot0), 42)
|
RpcBlockCommitment {
|
||||||
|
commitment: Some(commitment_slot0),
|
||||||
|
total_stake: 42,
|
||||||
|
}
|
||||||
);
|
);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
request_processor.get_block_commitment(1),
|
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]
|
#[test]
|
||||||
@ -1965,16 +1998,18 @@ pub mod tests {
|
|||||||
let res = io.handle_request_sync(&req, meta.clone());
|
let res = io.handle_request_sync(&req, meta.clone());
|
||||||
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");
|
||||||
let (commitment, total_staked): (Option<BlockCommitment>, u64) =
|
let RpcBlockCommitment {
|
||||||
if let Response::Single(res) = result {
|
commitment,
|
||||||
if let Output::Success(res) = res {
|
total_stake,
|
||||||
serde_json::from_value(res.result).unwrap()
|
} = if let Response::Single(res) = result {
|
||||||
} else {
|
if let Output::Success(res) = res {
|
||||||
panic!("Expected success");
|
serde_json::from_value(res.result).unwrap()
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
panic!("Expected single response");
|
panic!("Expected success");
|
||||||
};
|
}
|
||||||
|
} else {
|
||||||
|
panic!("Expected single response");
|
||||||
|
};
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
commitment,
|
commitment,
|
||||||
block_commitment_cache
|
block_commitment_cache
|
||||||
@ -1983,14 +2018,14 @@ pub mod tests {
|
|||||||
.get_block_commitment(0)
|
.get_block_commitment(0)
|
||||||
.cloned()
|
.cloned()
|
||||||
);
|
);
|
||||||
assert_eq!(total_staked, 42);
|
assert_eq!(total_stake, 42);
|
||||||
|
|
||||||
let req =
|
let req =
|
||||||
format!(r#"{{"jsonrpc":"2.0","id":1,"method":"getBlockCommitment","params":[2]}}"#);
|
format!(r#"{{"jsonrpc":"2.0","id":1,"method":"getBlockCommitment","params":[2]}}"#);
|
||||||
let res = io.handle_request_sync(&req, meta);
|
let res = io.handle_request_sync(&req, meta);
|
||||||
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");
|
||||||
let (commitment, total_staked): (Option<BlockCommitment>, u64) =
|
let commitment_response: RpcBlockCommitment<BlockCommitment> =
|
||||||
if let Response::Single(res) = result {
|
if let Response::Single(res) = result {
|
||||||
if let Output::Success(res) = res {
|
if let Output::Success(res) = res {
|
||||||
serde_json::from_value(res.result).unwrap()
|
serde_json::from_value(res.result).unwrap()
|
||||||
@ -2000,8 +2035,8 @@ pub mod tests {
|
|||||||
} else {
|
} else {
|
||||||
panic!("Expected single response");
|
panic!("Expected single response");
|
||||||
};
|
};
|
||||||
assert_eq!(commitment, None);
|
assert_eq!(commitment_response.commitment, None);
|
||||||
assert_eq!(total_staked, 42);
|
assert_eq!(commitment_response.total_stake, 42);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
@ -2025,21 +2060,23 @@ pub mod tests {
|
|||||||
let confirmed_block = confirmed_block.unwrap();
|
let confirmed_block = confirmed_block.unwrap();
|
||||||
assert_eq!(confirmed_block.transactions.len(), 3);
|
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 let RpcEncodedTransaction::Json(transaction) = transaction {
|
||||||
if transaction.signatures[0] == confirmed_block_signatures[0].to_string() {
|
if transaction.signatures[0] == confirmed_block_signatures[0].to_string() {
|
||||||
assert_eq!(transaction.message.recent_blockhash, blockhash.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() {
|
} else if transaction.signatures[0] == confirmed_block_signatures[1].to_string() {
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
result.unwrap().status,
|
meta.unwrap().status,
|
||||||
Err(TransactionError::InstructionError(
|
Err(TransactionError::InstructionError(
|
||||||
0,
|
0,
|
||||||
InstructionError::CustomError(1)
|
InstructionError::CustomError(1)
|
||||||
))
|
))
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
assert_eq!(result, None);
|
assert_eq!(meta, None);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -2055,23 +2092,25 @@ pub mod tests {
|
|||||||
let confirmed_block = confirmed_block.unwrap();
|
let confirmed_block = confirmed_block.unwrap();
|
||||||
assert_eq!(confirmed_block.transactions.len(), 3);
|
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 {
|
if let RpcEncodedTransaction::Binary(transaction) = transaction {
|
||||||
let decoded_transaction: Transaction =
|
let decoded_transaction: Transaction =
|
||||||
deserialize(&bs58::decode(&transaction).into_vec().unwrap()).unwrap();
|
deserialize(&bs58::decode(&transaction).into_vec().unwrap()).unwrap();
|
||||||
if decoded_transaction.signatures[0] == confirmed_block_signatures[0] {
|
if decoded_transaction.signatures[0] == confirmed_block_signatures[0] {
|
||||||
assert_eq!(decoded_transaction.message.recent_blockhash, blockhash);
|
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] {
|
} else if decoded_transaction.signatures[0] == confirmed_block_signatures[1] {
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
result.unwrap().status,
|
meta.unwrap().status,
|
||||||
Err(TransactionError::InstructionError(
|
Err(TransactionError::InstructionError(
|
||||||
0,
|
0,
|
||||||
InstructionError::CustomError(1)
|
InstructionError::CustomError(1)
|
||||||
))
|
))
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
assert_eq!(result, None);
|
assert_eq!(meta, None);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -471,7 +471,7 @@ mod tests {
|
|||||||
"lamports": 51,
|
"lamports": 51,
|
||||||
"data": expected_data,
|
"data": expected_data,
|
||||||
"executable": false,
|
"executable": false,
|
||||||
"rent_epoch": 1,
|
"rentEpoch": 1,
|
||||||
},
|
},
|
||||||
"subscription": 0,
|
"subscription": 0,
|
||||||
}
|
}
|
||||||
@ -618,7 +618,7 @@ mod tests {
|
|||||||
"lamports": 100,
|
"lamports": 100,
|
||||||
"data": [],
|
"data": [],
|
||||||
"executable": false,
|
"executable": false,
|
||||||
"rent_epoch": 1,
|
"rentEpoch": 1,
|
||||||
},
|
},
|
||||||
"subscription": 0,
|
"subscription": 0,
|
||||||
}
|
}
|
||||||
|
@ -376,7 +376,7 @@ mod tests {
|
|||||||
let string = transport_receiver.poll();
|
let string = transport_receiver.poll();
|
||||||
if let Async::Ready(Some(response)) = string.unwrap() {
|
if let Async::Ready(Some(response)) = string.unwrap() {
|
||||||
let expected = format!(
|
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);
|
assert_eq!(expected, response);
|
||||||
}
|
}
|
||||||
@ -433,7 +433,7 @@ mod tests {
|
|||||||
let string = transport_receiver.poll();
|
let string = transport_receiver.poll();
|
||||||
if let Async::Ready(Some(response)) = string.unwrap() {
|
if let Async::Ready(Some(response)) = string.unwrap() {
|
||||||
let expected = format!(
|
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()
|
alice.pubkey()
|
||||||
);
|
);
|
||||||
assert_eq!(expected, response);
|
assert_eq!(expected, response);
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
use crossbeam_channel::{Receiver, RecvTimeoutError};
|
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_ledger::{blockstore::Blockstore, blockstore_processor::TransactionStatusBatch};
|
||||||
use solana_runtime::bank::{Bank, HashAgeKind};
|
use solana_runtime::bank::{Bank, HashAgeKind};
|
||||||
use std::{
|
use std::{
|
||||||
|
@ -34,7 +34,7 @@ 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"]["value"][0]
|
let blockhash: Hash = json["result"]["value"]["blockhash"]
|
||||||
.as_str()
|
.as_str()
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.parse()
|
.parse()
|
||||||
|
@ -21,8 +21,9 @@ use rayon::{
|
|||||||
ThreadPool,
|
ThreadPool,
|
||||||
};
|
};
|
||||||
use rocksdb::DBRawIterator;
|
use rocksdb::DBRawIterator;
|
||||||
use solana_client::rpc_request::{
|
use solana_client::rpc_response::{
|
||||||
RpcConfirmedBlock, RpcEncodedTransaction, RpcTransactionEncoding, RpcTransactionStatus,
|
RpcConfirmedBlock, RpcEncodedTransaction, RpcTransactionEncoding, RpcTransactionStatus,
|
||||||
|
RpcTransactionWithStatusMeta,
|
||||||
};
|
};
|
||||||
use solana_measure::measure::Measure;
|
use solana_measure::measure::Measure;
|
||||||
use solana_metrics::{datapoint_debug, datapoint_error};
|
use solana_metrics::{datapoint_debug, datapoint_error};
|
||||||
@ -1403,18 +1404,19 @@ impl Blockstore {
|
|||||||
slot: Slot,
|
slot: Slot,
|
||||||
encoding: RpcTransactionEncoding,
|
encoding: RpcTransactionEncoding,
|
||||||
iterator: impl Iterator<Item = Transaction> + 'a,
|
iterator: impl Iterator<Item = Transaction> + 'a,
|
||||||
) -> Vec<(RpcEncodedTransaction, Option<RpcTransactionStatus>)> {
|
) -> Vec<RpcTransactionWithStatusMeta> {
|
||||||
iterator
|
iterator
|
||||||
.map(|transaction| {
|
.map(|transaction| {
|
||||||
let signature = transaction.signatures[0];
|
let signature = transaction.signatures[0];
|
||||||
let encoded_transaction =
|
let encoded_transaction =
|
||||||
RpcEncodedTransaction::encode(transaction, encoding.clone());
|
RpcEncodedTransaction::encode(transaction, encoding.clone());
|
||||||
(
|
RpcTransactionWithStatusMeta {
|
||||||
encoded_transaction,
|
transaction: encoded_transaction,
|
||||||
self.transaction_status_cf
|
meta: self
|
||||||
|
.transaction_status_cf
|
||||||
.get((slot, signature))
|
.get((slot, signature))
|
||||||
.expect("Expect database get to succeed"),
|
.expect("Expect database get to succeed"),
|
||||||
)
|
}
|
||||||
})
|
})
|
||||||
.collect()
|
.collect()
|
||||||
}
|
}
|
||||||
@ -4748,11 +4750,9 @@ pub mod tests {
|
|||||||
transactions: expected_transactions
|
transactions: expected_transactions
|
||||||
.iter()
|
.iter()
|
||||||
.cloned()
|
.cloned()
|
||||||
.map(|(tx, status)| {
|
.map(|(tx, meta)| RpcTransactionWithStatusMeta {
|
||||||
(
|
transaction: RpcEncodedTransaction::encode(tx, RpcTransactionEncoding::Json),
|
||||||
RpcEncodedTransaction::encode(tx, RpcTransactionEncoding::Json),
|
meta,
|
||||||
status,
|
|
||||||
)
|
|
||||||
})
|
})
|
||||||
.collect(),
|
.collect(),
|
||||||
parent_slot: slot - 1,
|
parent_slot: slot - 1,
|
||||||
@ -4770,11 +4770,9 @@ pub mod tests {
|
|||||||
transactions: expected_transactions
|
transactions: expected_transactions
|
||||||
.iter()
|
.iter()
|
||||||
.cloned()
|
.cloned()
|
||||||
.map(|(tx, status)| {
|
.map(|(tx, meta)| RpcTransactionWithStatusMeta {
|
||||||
(
|
transaction: RpcEncodedTransaction::encode(tx, RpcTransactionEncoding::Json),
|
||||||
RpcEncodedTransaction::encode(tx, RpcTransactionEncoding::Json),
|
meta,
|
||||||
status,
|
|
||||||
)
|
|
||||||
})
|
})
|
||||||
.collect(),
|
.collect(),
|
||||||
parent_slot: slot,
|
parent_slot: slot,
|
||||||
@ -5007,9 +5005,9 @@ pub mod tests {
|
|||||||
);
|
);
|
||||||
assert_eq!(map.len(), 5);
|
assert_eq!(map.len(), 5);
|
||||||
for x in 0..4 {
|
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");
|
Blockstore::destroy(&blockstore_path).expect("Expected successful database destruction");
|
||||||
}
|
}
|
||||||
|
@ -10,7 +10,7 @@ use rocksdb::{
|
|||||||
};
|
};
|
||||||
use serde::de::DeserializeOwned;
|
use serde::de::DeserializeOwned;
|
||||||
use serde::Serialize;
|
use serde::Serialize;
|
||||||
use solana_client::rpc_request::RpcTransactionStatus;
|
use solana_client::rpc_response::RpcTransactionStatus;
|
||||||
use solana_sdk::{clock::Slot, signature::Signature};
|
use solana_sdk::{clock::Slot, signature::Signature};
|
||||||
use std::{collections::HashMap, fs, marker::PhantomData, path::Path, sync::Arc};
|
use std::{collections::HashMap, fs, marker::PhantomData, path::Path, sync::Arc};
|
||||||
use thiserror::Error;
|
use thiserror::Error;
|
||||||
|
@ -5,6 +5,7 @@ use std::{cmp, fmt, iter::FromIterator};
|
|||||||
/// An Account with data that is stored on chain
|
/// An Account with data that is stored on chain
|
||||||
#[repr(C)]
|
#[repr(C)]
|
||||||
#[derive(Serialize, Deserialize, Clone, Default)]
|
#[derive(Serialize, Deserialize, Clone, Default)]
|
||||||
|
#[serde(rename_all = "camelCase")]
|
||||||
pub struct Account {
|
pub struct Account {
|
||||||
/// lamports in the account
|
/// lamports in the account
|
||||||
pub lamports: u64,
|
pub lamports: u64,
|
||||||
|
@ -13,6 +13,7 @@ pub const MINIMUM_SLOTS_PER_EPOCH: u64 = 32;
|
|||||||
|
|
||||||
#[repr(C)]
|
#[repr(C)]
|
||||||
#[derive(Debug, Clone, Copy, PartialEq, Deserialize, Serialize)]
|
#[derive(Debug, Clone, Copy, PartialEq, Deserialize, Serialize)]
|
||||||
|
#[serde(rename_all = "camelCase")]
|
||||||
pub struct EpochSchedule {
|
pub struct EpochSchedule {
|
||||||
/// The maximum number of slots in each epoch.
|
/// The maximum number of slots in each epoch.
|
||||||
pub slots_per_epoch: u64,
|
pub slots_per_epoch: u64,
|
||||||
|
Reference in New Issue
Block a user