use super::utils::decode_and_deserialize;
use jsonrpc_core::BoxFuture;
use jsonrpc_core::{Error, Result};
use jsonrpc_derive::rpc;
use solana_client::rpc_custom_error::RpcCustomError;
use solana_client::rpc_response::RpcApiVersion;
use solana_client::rpc_response::RpcResponseContext;
use solana_client::{
rpc_config::{
RpcBlockConfig, RpcBlocksConfigWrapper, RpcEncodingConfigWrapper, RpcEpochConfig,
RpcRequestAirdropConfig, RpcSendTransactionConfig, RpcSignatureStatusConfig,
RpcSignaturesForAddressConfig, RpcSimulateTransactionConfig, RpcTransactionConfig,
},
rpc_response::{
RpcBlockhash, RpcConfirmedTransactionStatusWithSignature, RpcContactInfo,
RpcInflationReward, RpcPerfSample, RpcPrioritizationFee, RpcSimulateTransactionResult,
},
};
use solana_rpc_client_api::response::Response as RpcResponse;
use solana_sdk::clock::UnixTimestamp;
use solana_sdk::transaction::VersionedTransaction;
use solana_send_transaction_service::send_transaction_service::TransactionInfo;
use solana_transaction_status::UiTransactionEncoding;
use solana_transaction_status::{
EncodedConfirmedTransactionWithStatusMeta, TransactionStatus, UiConfirmedBlock,
};
use {
super::*,
solana_sdk::message::{SanitizedVersionedMessage, VersionedMessage},
solana_transaction_status::parse_ui_inner_instructions,
};
#[rpc]
pub trait Full {
type Metadata;
#[rpc(meta, name = "getInflationReward")]
fn get_inflation_reward(
&self,
meta: Self::Metadata,
address_strs: Vec<String>,
config: Option<RpcEpochConfig>,
) -> BoxFuture<Result<Vec<Option<RpcInflationReward>>>>;
#[rpc(meta, name = "getClusterNodes")]
fn get_cluster_nodes(&self, meta: Self::Metadata) -> Result<Vec<RpcContactInfo>>;
#[rpc(meta, name = "getRecentPerformanceSamples")]
fn get_recent_performance_samples(
&self,
meta: Self::Metadata,
limit: Option<usize>,
) -> Result<Vec<RpcPerfSample>>;
#[rpc(meta, name = "getSignatureStatuses")]
fn get_signature_statuses(
&self,
meta: Self::Metadata,
signature_strs: Vec<String>,
config: Option<RpcSignatureStatusConfig>,
) -> BoxFuture<Result<RpcResponse<Vec<Option<TransactionStatus>>>>>;
#[rpc(meta, name = "getMaxRetransmitSlot")]
fn get_max_retransmit_slot(&self, meta: Self::Metadata) -> Result<Slot>;
#[rpc(meta, name = "getMaxShredInsertSlot")]
fn get_max_shred_insert_slot(&self, meta: Self::Metadata) -> Result<Slot>;
#[rpc(meta, name = "requestAirdrop")]
fn request_airdrop(
&self,
meta: Self::Metadata,
pubkey_str: String,
lamports: u64,
config: Option<RpcRequestAirdropConfig>,
) -> Result<String>;
#[rpc(meta, name = "sendTransaction")]
fn send_transaction(
&self,
meta: Self::Metadata,
data: String,
config: Option<RpcSendTransactionConfig>,
) -> Result<String>;
#[rpc(meta, name = "simulateTransaction")]
fn simulate_transaction(
&self,
meta: Self::Metadata,
data: String,
config: Option<RpcSimulateTransactionConfig>,
) -> Result<RpcResponse<RpcSimulateTransactionResult>>;
#[rpc(meta, name = "minimumLedgerSlot")]
fn minimum_ledger_slot(&self, meta: Self::Metadata) -> Result<Slot>;
#[rpc(meta, name = "getBlock")]
fn get_block(
&self,
meta: Self::Metadata,
slot: Slot,
config: Option<RpcEncodingConfigWrapper<RpcBlockConfig>>,
) -> BoxFuture<Result<Option<UiConfirmedBlock>>>;
#[rpc(meta, name = "getBlockTime")]
fn get_block_time(
&self,
meta: Self::Metadata,
slot: Slot,
) -> BoxFuture<Result<Option<UnixTimestamp>>>;
#[rpc(meta, name = "getBlocks")]
fn get_blocks(
&self,
meta: Self::Metadata,
start_slot: Slot,
wrapper: Option<RpcBlocksConfigWrapper>,
config: Option<RpcContextConfig>,
) -> BoxFuture<Result<Vec<Slot>>>;
#[rpc(meta, name = "getBlocksWithLimit")]
fn get_blocks_with_limit(
&self,
meta: Self::Metadata,
start_slot: Slot,
limit: usize,
config: Option<RpcContextConfig>,
) -> BoxFuture<Result<Vec<Slot>>>;
#[rpc(meta, name = "getTransaction")]
fn get_transaction(
&self,
meta: Self::Metadata,
signature_str: String,
config: Option<RpcEncodingConfigWrapper<RpcTransactionConfig>>,
) -> BoxFuture<Result<Option<EncodedConfirmedTransactionWithStatusMeta>>>;
#[rpc(meta, name = "getSignaturesForAddress")]
fn get_signatures_for_address(
&self,
meta: Self::Metadata,
address: String,
config: Option<RpcSignaturesForAddressConfig>,
) -> BoxFuture<Result<Vec<RpcConfirmedTransactionStatusWithSignature>>>;
#[rpc(meta, name = "getFirstAvailableBlock")]
fn get_first_available_block(&self, meta: Self::Metadata) -> BoxFuture<Result<Slot>>;
#[rpc(meta, name = "getLatestBlockhash")]
fn get_latest_blockhash(
&self,
meta: Self::Metadata,
config: Option<RpcContextConfig>,
) -> Result<RpcResponse<RpcBlockhash>>;
#[rpc(meta, name = "isBlockhashValid")]
fn is_blockhash_valid(
&self,
meta: Self::Metadata,
blockhash: String,
config: Option<RpcContextConfig>,
) -> Result<RpcResponse<bool>>;
#[rpc(meta, name = "getFeeForMessage")]
fn get_fee_for_message(
&self,
meta: Self::Metadata,
data: String,
config: Option<RpcContextConfig>,
) -> Result<RpcResponse<Option<u64>>>;
#[rpc(meta, name = "getStakeMinimumDelegation")]
fn get_stake_minimum_delegation(
&self,
meta: Self::Metadata,
config: Option<RpcContextConfig>,
) -> Result<RpcResponse<u64>>;
#[rpc(meta, name = "getRecentPrioritizationFees")]
fn get_recent_prioritization_fees(
&self,
meta: Self::Metadata,
pubkey_strs: Option<Vec<String>>,
) -> Result<Vec<RpcPrioritizationFee>>;
}
pub struct SurfpoolFullRpc;
impl Full for SurfpoolFullRpc {
type Metadata = Option<RunloopContext>;
fn get_inflation_reward(
&self,
meta: Self::Metadata,
address_strs: Vec<String>,
config: Option<RpcEpochConfig>,
) -> BoxFuture<Result<Vec<Option<RpcInflationReward>>>> {
unimplemented!()
}
fn get_cluster_nodes(&self, meta: Self::Metadata) -> Result<Vec<RpcContactInfo>> {
unimplemented!()
}
fn get_recent_performance_samples(
&self,
meta: Self::Metadata,
limit: Option<usize>,
) -> Result<Vec<RpcPerfSample>> {
unimplemented!()
}
fn get_signature_statuses(
&self,
meta: Self::Metadata,
signature_strs: Vec<String>,
config: Option<RpcSignatureStatusConfig>,
) -> BoxFuture<Result<RpcResponse<Vec<Option<TransactionStatus>>>>> {
unimplemented!()
}
fn get_max_retransmit_slot(&self, meta: Self::Metadata) -> Result<Slot> {
unimplemented!()
}
fn get_max_shred_insert_slot(&self, meta: Self::Metadata) -> Result<Slot> {
unimplemented!()
}
fn request_airdrop(
&self,
meta: Self::Metadata,
pubkey_str: String,
lamports: u64,
config: Option<RpcRequestAirdropConfig>,
) -> Result<String> {
unimplemented!()
}
fn send_transaction(
&self,
meta: Self::Metadata,
data: String,
config: Option<RpcSendTransactionConfig>,
) -> Result<String> {
let RpcSendTransactionConfig {
skip_preflight,
preflight_commitment,
encoding,
max_retries,
min_context_slot,
} = config.unwrap_or_default();
let tx_encoding = encoding.unwrap_or(UiTransactionEncoding::Base58);
let binary_encoding = tx_encoding.into_binary_encoding().ok_or_else(|| {
Error::invalid_params(format!(
"unsupported encoding: {tx_encoding}. Supported encodings: base58, base64"
))
})?;
let (wire_transaction, unsanitized_tx) =
decode_and_deserialize::<VersionedTransaction>(data, binary_encoding)?;
let Some(ctx) = meta else {
return Err(RpcCustomError::NodeUnhealthy {
num_slots_behind: None,
}
.into());
};
let Ok(state_reader) = ctx.state.try_read() else {
return Err(RpcCustomError::NodeUnhealthy {
num_slots_behind: None,
}
.into());
};
let _ = ctx.mempool_tx.send(unsanitized_tx);
Ok("ok".to_string())
}
fn simulate_transaction(
&self,
meta: Self::Metadata,
data: String,
config: Option<RpcSimulateTransactionConfig>,
) -> Result<RpcResponse<RpcSimulateTransactionResult>> {
unimplemented!()
}
fn minimum_ledger_slot(&self, meta: Self::Metadata) -> Result<Slot> {
unimplemented!()
}
fn get_block(
&self,
meta: Self::Metadata,
slot: Slot,
config: Option<RpcEncodingConfigWrapper<RpcBlockConfig>>,
) -> BoxFuture<Result<Option<UiConfirmedBlock>>> {
unimplemented!()
}
fn get_block_time(
&self,
meta: Self::Metadata,
slot: Slot,
) -> BoxFuture<Result<Option<UnixTimestamp>>> {
unimplemented!()
}
fn get_blocks(
&self,
meta: Self::Metadata,
start_slot: Slot,
wrapper: Option<RpcBlocksConfigWrapper>,
config: Option<RpcContextConfig>,
) -> BoxFuture<Result<Vec<Slot>>> {
unimplemented!()
}
fn get_blocks_with_limit(
&self,
meta: Self::Metadata,
start_slot: Slot,
limit: usize,
config: Option<RpcContextConfig>,
) -> BoxFuture<Result<Vec<Slot>>> {
unimplemented!()
}
fn get_transaction(
&self,
meta: Self::Metadata,
signature_str: String,
config: Option<RpcEncodingConfigWrapper<RpcTransactionConfig>>,
) -> BoxFuture<Result<Option<EncodedConfirmedTransactionWithStatusMeta>>> {
unimplemented!()
}
fn get_signatures_for_address(
&self,
meta: Self::Metadata,
address: String,
config: Option<RpcSignaturesForAddressConfig>,
) -> BoxFuture<Result<Vec<RpcConfirmedTransactionStatusWithSignature>>> {
unimplemented!()
}
fn get_first_available_block(&self, meta: Self::Metadata) -> BoxFuture<Result<Slot>> {
unimplemented!()
}
fn get_latest_blockhash(
&self,
meta: Self::Metadata,
config: Option<RpcContextConfig>,
) -> Result<RpcResponse<RpcBlockhash>> {
let Some(ctx) = meta else {
return Err(RpcCustomError::NodeUnhealthy {
num_slots_behind: None,
}
.into());
};
let Ok(state_reader) = ctx.state.try_read() else {
return Err(RpcCustomError::NodeUnhealthy {
num_slots_behind: None,
}
.into());
};
let last_valid_block_height = state_reader.epoch_info.block_height;
let value = RpcBlockhash {
blockhash: state_reader.svm.latest_blockhash().to_string(),
last_valid_block_height,
};
let response = RpcResponse {
context: RpcResponseContext {
slot: state_reader.epoch_info.absolute_slot,
api_version: Some(RpcApiVersion::default()),
},
value,
};
Ok(response)
}
fn is_blockhash_valid(
&self,
meta: Self::Metadata,
blockhash: String,
config: Option<RpcContextConfig>,
) -> Result<RpcResponse<bool>> {
unimplemented!()
}
fn get_fee_for_message(
&self,
meta: Self::Metadata,
data: String,
config: Option<RpcContextConfig>,
) -> Result<RpcResponse<Option<u64>>> {
unimplemented!()
}
fn get_stake_minimum_delegation(
&self,
meta: Self::Metadata,
config: Option<RpcContextConfig>,
) -> Result<RpcResponse<u64>> {
unimplemented!()
}
fn get_recent_prioritization_fees(
&self,
meta: Self::Metadata,
pubkey_strs: Option<Vec<String>>,
) -> Result<Vec<RpcPrioritizationFee>> {
unimplemented!()
}
}