Files
khadhroony-solana-project/crates/ksp-onchain-transport-lib/src/rpc_blocks.rs

734 lines
27 KiB
Rust

// file: crates/ksp-onchain-transport-lib/src/rpc_blocks.rs
// version: 2
/// Transaction detail level accepted by modern `getBlock` requests.
#[derive(Clone, Copy, Debug, Default, Eq, Hash, PartialEq)]
pub enum SolanaTransactionDetails {
/// Return complete transaction payloads and metadata.
#[default]
Full,
/// Return transaction signatures only.
Signatures,
/// Return no transaction payloads.
None,
/// Return the account-list transaction representation.
Accounts,
}
impl SolanaTransactionDetails {
/// Returns the Solana JSON-RPC wire string.
#[must_use]
pub const fn as_str(self) -> &'static str {
return match self {
Self::Full => "full",
Self::Signatures => "signatures",
Self::None => "none",
Self::Accounts => "accounts",
};
}
}
/// Modern configuration object accepted by `getBlock`.
#[derive(Clone, Copy, Debug, Default, Eq, PartialEq)]
pub struct SolanaGetBlockConfig {
commitment: std::option::Option<crate::SolanaCommitment>,
encoding: std::option::Option<crate::SolanaTransactionEncoding>,
transaction_details: std::option::Option<crate::SolanaTransactionDetails>,
max_supported_transaction_version: std::option::Option<u8>,
rewards: std::option::Option<bool>,
}
impl SolanaGetBlockConfig {
/// Creates a modern `getBlock` configuration.
#[must_use]
pub const fn new(
commitment: std::option::Option<crate::SolanaCommitment>,
encoding: std::option::Option<crate::SolanaTransactionEncoding>,
transaction_details: std::option::Option<crate::SolanaTransactionDetails>,
max_supported_transaction_version: std::option::Option<u8>,
rewards: std::option::Option<bool>,
) -> Self {
return Self { commitment, encoding, transaction_details, max_supported_transaction_version, rewards };
}
/// Returns the optional commitment level.
#[must_use]
pub const fn commitment(&self) -> std::option::Option<crate::SolanaCommitment> {
return self.commitment;
}
/// Returns the optional transaction encoding.
#[must_use]
pub const fn encoding(&self) -> std::option::Option<crate::SolanaTransactionEncoding> {
return self.encoding;
}
/// Returns the optional transaction detail level.
#[must_use]
pub const fn transaction_details(&self) -> std::option::Option<crate::SolanaTransactionDetails> {
return self.transaction_details;
}
/// Returns the highest transaction version the caller declares it can consume.
#[must_use]
pub const fn max_supported_transaction_version(&self) -> std::option::Option<u8> {
return self.max_supported_transaction_version;
}
/// Returns whether rewards were explicitly requested or suppressed.
#[must_use]
pub const fn rewards(&self) -> std::option::Option<bool> {
return self.rewards;
}
/// Returns whether this config would serialize to an empty object.
#[cfg(test)]
pub(crate) const fn is_empty(&self) -> bool {
return self.commitment.is_none()
&& self.encoding.is_none()
&& self.transaction_details.is_none()
&& self.max_supported_transaction_version.is_none()
&& self.rewards.is_none();
}
/// Serializes this config to the exact Solana JSON-RPC object.
#[must_use]
#[cfg(test)]
pub(crate) fn to_json_value(self) -> serde_json::Value {
let mut object = serde_json::Map::new();
if let std::option::Option::Some(commitment) = self.commitment {
object.insert("commitment".to_owned(), serde_json::Value::String(commitment.as_str().to_owned()));
}
if let std::option::Option::Some(encoding) = self.encoding {
object.insert("encoding".to_owned(), serde_json::Value::String(encoding.as_str().to_owned()));
}
if let std::option::Option::Some(details) = self.transaction_details {
object.insert("transactionDetails".to_owned(), serde_json::Value::String(details.as_str().to_owned()));
}
if let std::option::Option::Some(version) = self.max_supported_transaction_version {
object.insert("maxSupportedTransactionVersion".to_owned(), serde_json::Value::Number(version.into()));
}
if let std::option::Option::Some(rewards) = self.rewards {
object.insert("rewards".to_owned(), serde_json::Value::Bool(rewards));
}
return serde_json::Value::Object(object);
}
}
/// Slot range accepted inside `getBlockProduction` configuration.
#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
pub struct SolanaBlockProductionRange {
first_slot: u64,
last_slot: std::option::Option<u64>,
}
impl SolanaBlockProductionRange {
/// Creates a block-production range.
#[must_use]
pub const fn new(first_slot: u64, last_slot: std::option::Option<u64>) -> Self {
return Self { first_slot, last_slot };
}
/// Returns the first slot in the requested range.
#[must_use]
pub const fn first_slot(&self) -> u64 {
return self.first_slot;
}
/// Returns the optional last slot in the requested range.
#[must_use]
pub const fn last_slot(&self) -> std::option::Option<u64> {
return self.last_slot;
}
/// Serializes this range to the exact Solana JSON-RPC object.
#[must_use]
#[cfg(test)]
pub(crate) fn to_json_value(self) -> serde_json::Value {
let mut object = serde_json::Map::new();
object.insert("firstSlot".to_owned(), serde_json::Value::Number(self.first_slot.into()));
if let std::option::Option::Some(last_slot) = self.last_slot {
object.insert("lastSlot".to_owned(), serde_json::Value::Number(last_slot.into()));
}
return serde_json::Value::Object(object);
}
}
/// Optional configuration accepted by `getBlockProduction`.
#[derive(Clone, Debug, Default, Eq, PartialEq)]
pub struct SolanaBlockProductionConfig {
commitment: std::option::Option<crate::SolanaCommitment>,
identity: std::option::Option<ksp_core_lib::Pubkey>,
range: std::option::Option<crate::SolanaBlockProductionRange>,
}
impl SolanaBlockProductionConfig {
/// Creates a block-production configuration.
#[must_use]
pub const fn new(
commitment: std::option::Option<crate::SolanaCommitment>,
identity: std::option::Option<ksp_core_lib::Pubkey>,
range: std::option::Option<crate::SolanaBlockProductionRange>,
) -> Self {
return Self { commitment, identity, range };
}
/// Returns the optional commitment level.
#[must_use]
pub const fn commitment(&self) -> std::option::Option<crate::SolanaCommitment> {
return self.commitment;
}
/// Returns the optional validator identity filter.
#[must_use]
pub const fn identity(&self) -> std::option::Option<&ksp_core_lib::Pubkey> {
return self.identity.as_ref();
}
/// Returns the optional slot range.
#[must_use]
pub const fn range(&self) -> std::option::Option<&crate::SolanaBlockProductionRange> {
return self.range.as_ref();
}
/// Returns whether this config would serialize to an empty object.
#[cfg(test)]
pub(crate) const fn is_empty(&self) -> bool {
return self.commitment.is_none() && self.identity.is_none() && self.range.is_none();
}
/// Serializes this config to the exact Solana JSON-RPC object.
#[must_use]
#[cfg(test)]
pub(crate) fn to_json_value(&self) -> serde_json::Value {
let mut object = serde_json::Map::new();
if let std::option::Option::Some(commitment) = self.commitment {
object.insert("commitment".to_owned(), serde_json::Value::String(commitment.as_str().to_owned()));
}
if let std::option::Option::Some(identity) = self.identity.as_ref() {
object.insert("identity".to_owned(), serde_json::Value::String(identity.to_string()));
}
if let std::option::Option::Some(range) = self.range {
object.insert("range".to_owned(), range.to_json_value());
}
return serde_json::Value::Object(object);
}
}
/// Commitment distribution returned by `getBlockCommitment`.
#[derive(Clone, Debug, Eq, PartialEq)]
pub struct SolanaBlockCommitment {
commitment: std::option::Option<std::vec::Vec<u64>>,
total_stake: u64,
}
impl SolanaBlockCommitment {
/// Returns the nullable commitment stake distribution.
#[must_use]
pub fn commitment(&self) -> std::option::Option<&[u64]> {
return self.commitment.as_deref();
}
/// Returns the total active stake considered by the response.
#[must_use]
pub const fn total_stake(&self) -> u64 {
return self.total_stake;
}
/// Decodes a block-commitment result from its Solana JSON wire shape.
#[cfg(test)]
pub(crate) fn decode_wire(method: &str, value: serde_json::Value) -> ksp_core_lib::Result<Self> {
let decoded = crate::decode_wire_json::<WireBlockCommitment>(method, value);
return match decoded {
std::result::Result::Ok(wire) => std::result::Result::Ok(Self { commitment: wire.commitment, total_stake: wire.total_stake }),
std::result::Result::Err(error) => std::result::Result::Err(error),
};
}
}
/// Effective range reported inside `getBlockProduction` results.
#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
pub struct SolanaBlockProductionResultRange {
first_slot: u64,
last_slot: u64,
}
impl SolanaBlockProductionResultRange {
/// Returns the first slot in the effective range.
#[must_use]
pub const fn first_slot(&self) -> u64 {
return self.first_slot;
}
/// Returns the last slot in the effective range.
#[must_use]
pub const fn last_slot(&self) -> u64 {
return self.last_slot;
}
}
/// Block-production counts returned by `getBlockProduction` before the shared RPC context wrapper is applied.
#[derive(Clone, Debug, Eq, PartialEq)]
pub struct SolanaBlockProduction {
by_identity: std::collections::BTreeMap<ksp_core_lib::Pubkey, (usize, usize)>,
range: crate::SolanaBlockProductionResultRange,
}
impl SolanaBlockProduction {
/// Returns validator identities mapped to `(leader slots, blocks produced)` counts.
#[must_use]
pub const fn by_identity(&self) -> &std::collections::BTreeMap<ksp_core_lib::Pubkey, (usize, usize)> {
return &self.by_identity;
}
/// Returns the effective slot range reported by the runtime.
#[must_use]
pub const fn range(&self) -> &crate::SolanaBlockProductionResultRange {
return &self.range;
}
/// Decodes a block-production result from its Solana JSON wire shape.
#[cfg(test)]
pub(crate) fn decode_wire(method: &str, value: serde_json::Value) -> ksp_core_lib::Result<Self> {
let decoded = crate::decode_wire_json::<WireBlockProduction>(method, value);
let wire = match decoded {
std::result::Result::Ok(wire) => wire,
std::result::Result::Err(error) => return std::result::Result::Err(error),
};
let mut by_identity = std::collections::BTreeMap::new();
for (identity, counts) in wire.by_identity {
let parsed = crate::parse_wire_pubkey(method, "byIdentity", identity.as_str());
let identity = match parsed {
std::result::Result::Ok(identity) => identity,
std::result::Result::Err(error) => return std::result::Result::Err(error),
};
by_identity.insert(identity, counts);
}
return std::result::Result::Ok(Self {
by_identity,
range: crate::SolanaBlockProductionResultRange { first_slot: wire.range.first_slot, last_slot: wire.range.last_slot },
});
}
}
/// One reward entry returned in a confirmed block.
#[derive(Clone, Debug, PartialEq)]
pub struct SolanaBlockReward {
pubkey: ksp_core_lib::Pubkey,
lamports: i64,
post_balance: u64,
reward_type: std::option::Option<std::string::String>,
commission: std::option::Option<u8>,
commission_bps: crate::SolanaWireField<u16>,
}
impl SolanaBlockReward {
/// Returns the rewarded account public key.
#[must_use]
pub const fn pubkey(&self) -> &ksp_core_lib::Pubkey {
return &self.pubkey;
}
/// Returns the signed lamport delta applied by the reward.
#[must_use]
pub const fn lamports(&self) -> i64 {
return self.lamports;
}
/// Returns the post-reward account balance in lamports.
#[must_use]
pub const fn post_balance(&self) -> u64 {
return self.post_balance;
}
/// Returns the runtime reward type text without imposing a local economic taxonomy.
#[must_use]
pub fn reward_type(&self) -> std::option::Option<&str> {
return self.reward_type.as_deref();
}
/// Returns the nullable legacy/effective commission percentage.
#[must_use]
pub const fn commission(&self) -> std::option::Option<u8> {
return self.commission;
}
/// Returns the basis-point commission while preserving omitted/null/present wire states.
#[must_use]
pub const fn commission_bps(&self) -> &crate::SolanaWireField<u16> {
return &self.commission_bps;
}
#[cfg(test)]
fn decode_wire(method: &str, value: serde_json::Value) -> ksp_core_lib::Result<Self> {
let decoded = crate::decode_wire_json::<WireBlockReward>(method, value);
let wire = match decoded {
std::result::Result::Ok(wire) => wire,
std::result::Result::Err(error) => return std::result::Result::Err(error),
};
let pubkey = crate::parse_wire_pubkey(method, "rewards.pubkey", wire.pubkey.as_str());
return match pubkey {
std::result::Result::Ok(pubkey) => std::result::Result::Ok(Self {
pubkey,
lamports: wire.lamports,
post_balance: wire.post_balance,
reward_type: wire.reward_type,
commission: wire.commission,
commission_bps: wire.commission_bps,
}),
std::result::Result::Err(error) => std::result::Result::Err(error),
};
}
}
/// One transaction entry returned inside a confirmed block.
#[derive(Clone, Debug, PartialEq)]
pub struct SolanaBlockTransaction {
transaction: crate::SolanaEncodedTransaction,
meta: crate::SolanaWireField<serde_json::Value>,
version: crate::SolanaWireField<crate::SolanaTransactionVersion>,
}
impl SolanaBlockTransaction {
/// Returns the encoded or JSON transaction payload without Program-specific decoding.
#[must_use]
pub const fn transaction(&self) -> &crate::SolanaEncodedTransaction {
return &self.transaction;
}
/// Returns transaction metadata while preserving omission versus explicit `null`.
#[must_use]
pub const fn meta(&self) -> &crate::SolanaWireField<serde_json::Value> {
return &self.meta;
}
/// Returns the transaction version while preserving omission versus explicit `null`.
#[must_use]
pub const fn version(&self) -> &crate::SolanaWireField<crate::SolanaTransactionVersion> {
return &self.version;
}
#[cfg(test)]
fn decode_wire(method: &str, value: serde_json::Value) -> ksp_core_lib::Result<Self> {
let decoded = crate::decode_wire_json::<WireBlockTransaction>(method, value);
let wire = match decoded {
std::result::Result::Ok(wire) => wire,
std::result::Result::Err(error) => return std::result::Result::Err(error),
};
let transaction = crate::SolanaEncodedTransaction::decode_wire(method, wire.transaction);
let transaction = match transaction {
std::result::Result::Ok(transaction) => transaction,
std::result::Result::Err(error) => return std::result::Result::Err(error),
};
let version = decode_block_transaction_version(method, wire.version);
return match version {
std::result::Result::Ok(version) => std::result::Result::Ok(Self { transaction, meta: wire.meta, version }),
std::result::Result::Err(error) => std::result::Result::Err(error),
};
}
}
/// Confirmed block wire result returned by `getBlock` when the RPC result is non-null.
#[derive(Clone, Debug, PartialEq)]
pub struct SolanaConfirmedBlock {
previous_blockhash: std::string::String,
blockhash: std::string::String,
parent_slot: u64,
transactions: crate::SolanaWireField<std::vec::Vec<crate::SolanaBlockTransaction>>,
signatures: crate::SolanaWireField<std::vec::Vec<std::string::String>>,
rewards: crate::SolanaWireField<std::vec::Vec<crate::SolanaBlockReward>>,
num_reward_partitions: crate::SolanaWireField<u64>,
block_time: std::option::Option<i64>,
block_height: std::option::Option<u64>,
}
impl SolanaConfirmedBlock {
/// Returns the previous blockhash exactly as reported by the RPC wire.
#[must_use]
pub fn previous_blockhash(&self) -> &str {
return self.previous_blockhash.as_str();
}
/// Returns this block's blockhash exactly as reported by the RPC wire.
#[must_use]
pub fn blockhash(&self) -> &str {
return self.blockhash.as_str();
}
/// Returns the parent slot.
#[must_use]
pub const fn parent_slot(&self) -> u64 {
return self.parent_slot;
}
/// Returns block transactions while preserving omitted/null/present states.
#[must_use]
pub const fn transactions(&self) -> &crate::SolanaWireField<std::vec::Vec<crate::SolanaBlockTransaction>> {
return &self.transactions;
}
/// Returns block signatures while preserving omitted/null/present states.
#[must_use]
pub const fn signatures(&self) -> &crate::SolanaWireField<std::vec::Vec<std::string::String>> {
return &self.signatures;
}
/// Returns block rewards while preserving omitted/null/present states.
#[must_use]
pub const fn rewards(&self) -> &crate::SolanaWireField<std::vec::Vec<crate::SolanaBlockReward>> {
return &self.rewards;
}
/// Returns the SIMD-0118 reward-partition count while preserving omission versus explicit `null`.
#[must_use]
pub const fn num_reward_partitions(&self) -> &crate::SolanaWireField<u64> {
return &self.num_reward_partitions;
}
/// Returns the nullable block time as a Unix timestamp.
#[must_use]
pub const fn block_time(&self) -> std::option::Option<i64> {
return self.block_time;
}
/// Returns the nullable block height.
#[must_use]
pub const fn block_height(&self) -> std::option::Option<u64> {
return self.block_height;
}
/// Decodes a confirmed block from its Solana JSON wire shape.
#[cfg(test)]
pub(crate) fn decode_wire(method: &str, value: serde_json::Value) -> ksp_core_lib::Result<Self> {
let decoded = crate::decode_wire_json::<WireConfirmedBlock>(method, value);
let wire = match decoded {
std::result::Result::Ok(wire) => wire,
std::result::Result::Err(error) => return std::result::Result::Err(error),
};
let transactions = decode_block_transactions(method, wire.transactions);
let transactions = match transactions {
std::result::Result::Ok(transactions) => transactions,
std::result::Result::Err(error) => return std::result::Result::Err(error),
};
let rewards = decode_block_rewards(method, wire.rewards);
let rewards = match rewards {
std::result::Result::Ok(rewards) => rewards,
std::result::Result::Err(error) => return std::result::Result::Err(error),
};
return std::result::Result::Ok(Self {
previous_blockhash: wire.previous_blockhash,
blockhash: wire.blockhash,
parent_slot: wire.parent_slot,
transactions,
signatures: wire.signatures,
rewards,
num_reward_partitions: wire.num_reward_partitions,
block_time: wire.block_time,
block_height: wire.block_height,
});
}
}
/// One entry returned by `getRecentPerformanceSamples`.
#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
pub struct SolanaPerformanceSample {
slot: u64,
num_transactions: u64,
num_non_vote_transactions: std::option::Option<u64>,
num_slots: u64,
sample_period_secs: u16,
}
impl SolanaPerformanceSample {
/// Returns the sample's highest slot.
#[must_use]
pub const fn slot(&self) -> u64 {
return self.slot;
}
/// Returns the total transaction count in the sample.
#[must_use]
pub const fn num_transactions(&self) -> u64 {
return self.num_transactions;
}
/// Returns the optional non-vote transaction count exposed by newer runtimes.
#[must_use]
pub const fn num_non_vote_transactions(&self) -> std::option::Option<u64> {
return self.num_non_vote_transactions;
}
/// Returns the number of slots covered by the sample.
#[must_use]
pub const fn num_slots(&self) -> u64 {
return self.num_slots;
}
/// Returns the sample duration in seconds.
#[must_use]
pub const fn sample_period_secs(&self) -> u16 {
return self.sample_period_secs;
}
/// Decodes one performance sample from its Solana JSON wire shape.
#[cfg(test)]
pub(crate) fn decode_wire(method: &str, value: serde_json::Value) -> ksp_core_lib::Result<Self> {
let decoded = crate::decode_wire_json::<WirePerformanceSample>(method, value);
return match decoded {
std::result::Result::Ok(wire) => std::result::Result::Ok(Self {
slot: wire.slot,
num_transactions: wire.num_transactions,
num_non_vote_transactions: wire.num_non_vote_transactions,
num_slots: wire.num_slots,
sample_period_secs: wire.sample_period_secs,
}),
std::result::Result::Err(error) => std::result::Result::Err(error),
};
}
}
#[cfg(test)]
fn decode_block_transaction_version(
method: &str,
field: crate::SolanaWireField<serde_json::Value>,
) -> ksp_core_lib::Result<crate::SolanaWireField<crate::SolanaTransactionVersion>> {
return match field {
crate::SolanaWireField::Omitted => std::result::Result::Ok(crate::SolanaWireField::Omitted),
crate::SolanaWireField::Null => std::result::Result::Ok(crate::SolanaWireField::Null),
crate::SolanaWireField::Value(value) => {
let decoded = crate::SolanaTransactionVersion::decode_wire(method, value);
match decoded {
std::result::Result::Ok(version) => std::result::Result::Ok(crate::SolanaWireField::Value(version)),
std::result::Result::Err(error) => std::result::Result::Err(error),
}
},
};
}
#[cfg(test)]
fn decode_block_transactions(
method: &str,
field: crate::SolanaWireField<std::vec::Vec<serde_json::Value>>,
) -> ksp_core_lib::Result<crate::SolanaWireField<std::vec::Vec<crate::SolanaBlockTransaction>>> {
let values = match field {
crate::SolanaWireField::Omitted => return std::result::Result::Ok(crate::SolanaWireField::Omitted),
crate::SolanaWireField::Null => return std::result::Result::Ok(crate::SolanaWireField::Null),
crate::SolanaWireField::Value(values) => values,
};
let mut transactions = std::vec::Vec::with_capacity(values.len());
for value in values {
let decoded = crate::SolanaBlockTransaction::decode_wire(method, value);
match decoded {
std::result::Result::Ok(transaction) => transactions.push(transaction),
std::result::Result::Err(error) => return std::result::Result::Err(error),
}
}
return std::result::Result::Ok(crate::SolanaWireField::Value(transactions));
}
#[cfg(test)]
fn decode_block_rewards(
method: &str,
field: crate::SolanaWireField<std::vec::Vec<serde_json::Value>>,
) -> ksp_core_lib::Result<crate::SolanaWireField<std::vec::Vec<crate::SolanaBlockReward>>> {
let values = match field {
crate::SolanaWireField::Omitted => return std::result::Result::Ok(crate::SolanaWireField::Omitted),
crate::SolanaWireField::Null => return std::result::Result::Ok(crate::SolanaWireField::Null),
crate::SolanaWireField::Value(values) => values,
};
let mut rewards = std::vec::Vec::with_capacity(values.len());
for value in values {
let decoded = crate::SolanaBlockReward::decode_wire(method, value);
match decoded {
std::result::Result::Ok(reward) => rewards.push(reward),
std::result::Result::Err(error) => return std::result::Result::Err(error),
}
}
return std::result::Result::Ok(crate::SolanaWireField::Value(rewards));
}
#[cfg(test)]
#[derive(serde::Deserialize)]
#[serde(rename_all = "camelCase")]
struct WireBlockCommitment {
commitment: std::option::Option<std::vec::Vec<u64>>,
total_stake: u64,
}
#[cfg(test)]
#[derive(serde::Deserialize)]
#[serde(rename_all = "camelCase")]
struct WireBlockProductionRange {
first_slot: u64,
last_slot: u64,
}
#[cfg(test)]
#[derive(serde::Deserialize)]
#[serde(rename_all = "camelCase")]
struct WireBlockProduction {
by_identity: std::collections::BTreeMap<std::string::String, (usize, usize)>,
range: WireBlockProductionRange,
}
#[cfg(test)]
#[derive(serde::Deserialize)]
#[serde(rename_all = "camelCase")]
struct WireBlockReward {
pubkey: std::string::String,
lamports: i64,
post_balance: u64,
#[serde(default)]
reward_type: std::option::Option<std::string::String>,
#[serde(default)]
commission: std::option::Option<u8>,
#[serde(default)]
commission_bps: crate::SolanaWireField<u16>,
}
#[cfg(test)]
#[derive(serde::Deserialize)]
#[serde(rename_all = "camelCase")]
struct WireBlockTransaction {
transaction: serde_json::Value,
#[serde(default)]
meta: crate::SolanaWireField<serde_json::Value>,
#[serde(default)]
version: crate::SolanaWireField<serde_json::Value>,
}
#[cfg(test)]
#[derive(serde::Deserialize)]
#[serde(rename_all = "camelCase")]
struct WireConfirmedBlock {
previous_blockhash: std::string::String,
blockhash: std::string::String,
parent_slot: u64,
#[serde(default)]
transactions: crate::SolanaWireField<std::vec::Vec<serde_json::Value>>,
#[serde(default)]
signatures: crate::SolanaWireField<std::vec::Vec<std::string::String>>,
#[serde(default)]
rewards: crate::SolanaWireField<std::vec::Vec<serde_json::Value>>,
#[serde(default)]
num_reward_partitions: crate::SolanaWireField<u64>,
block_time: std::option::Option<i64>,
block_height: std::option::Option<u64>,
}
#[cfg(test)]
#[derive(serde::Deserialize)]
#[serde(rename_all = "camelCase")]
struct WirePerformanceSample {
slot: u64,
num_transactions: u64,
#[serde(default)]
num_non_vote_transactions: std::option::Option<u64>,
num_slots: u64,
sample_period_secs: u16,
}
#[cfg(test)]
#[path = "../unit_tests/rpc_blocks.rs"]
mod tests;