1use std::collections::HashMap;
2
3use crossbeam_channel::Sender;
4use jsonrpc_core::Result as RpcError;
5use locker::SurfnetSvmLocker;
6use solana_account::Account;
7use solana_account_decoder::{encode_ui_account, UiAccount, UiAccountEncoding, UiDataSliceConfig};
8use solana_clock::Slot;
9use solana_commitment_config::CommitmentLevel;
10use solana_epoch_info::EpochInfo;
11use solana_pubkey::Pubkey;
12use solana_sdk::transaction::VersionedTransaction;
13use solana_signature::Signature;
14use solana_transaction_error::TransactionError;
15use solana_transaction_status::{EncodedConfirmedTransactionWithStatusMeta, TransactionStatus};
16use surfpool_types::TransactionMetadata;
17use svm::SurfnetSvm;
18
19use crate::error::{SurfpoolError, SurfpoolResult};
20
21pub mod locker;
22pub mod remote;
23pub mod svm;
24
25pub const FINALIZATION_SLOT_THRESHOLD: u64 = 31;
26pub const SLOTS_PER_EPOCH: u64 = 432000;
27pub type AccountFactory = Box<dyn Fn(SurfnetSvmLocker) -> GetAccountResult + Send + Sync>;
35
36pub enum GeyserEvent {
37 NewTransaction(VersionedTransaction, TransactionMetadata, Slot),
38}
39
40#[derive(Debug, Eq, PartialEq, Hash, Clone)]
41pub struct BlockIdentifier {
42 pub index: u64,
43 pub hash: String,
44}
45
46impl BlockIdentifier {
47 pub fn zero() -> Self {
48 Self::new(0, "")
49 }
50
51 pub fn new(index: u64, hash: &str) -> Self {
52 Self {
53 index,
54 hash: hash.to_string(),
55 }
56 }
57}
58
59#[derive(Debug, Clone)]
60pub struct BlockHeader {
61 pub hash: String,
62 pub previous_blockhash: String,
63 pub parent_slot: Slot,
64 pub block_time: i64,
65 pub block_height: u64,
66 pub signatures: Vec<Signature>,
67}
68
69#[derive(PartialEq, Eq, Clone)]
70pub enum SurfnetDataConnection {
71 Offline,
72 Connected(String, EpochInfo),
73}
74
75pub type SignatureSubscriptionData = (
76 SignatureSubscriptionType,
77 Sender<(Slot, Option<TransactionError>)>,
78);
79
80pub type AccountSubscriptionData =
81 HashMap<Pubkey, Vec<(Option<UiAccountEncoding>, Sender<UiAccount>)>>;
82
83#[derive(Debug, Clone, PartialEq)]
84pub enum SignatureSubscriptionType {
85 Received,
86 Commitment(CommitmentLevel),
87}
88
89type DoUpdateSvm = bool;
90
91#[derive(Clone, Debug)]
92pub enum GetAccountResult {
94 None(Pubkey),
96 FoundAccount(Pubkey, Account, DoUpdateSvm),
102 FoundProgramAccount((Pubkey, Account), (Pubkey, Option<Account>)),
103}
104
105impl GetAccountResult {
106 pub fn try_into_ui_account(
107 &self,
108 encoding: Option<UiAccountEncoding>,
109 data_slice: Option<UiDataSliceConfig>,
110 ) -> Option<UiAccount> {
111 match &self {
112 Self::None(_) => None,
113 Self::FoundAccount(pubkey, account, _)
114 | Self::FoundProgramAccount((pubkey, account), _) => Some(encode_ui_account(
115 pubkey,
116 account,
117 encoding.unwrap_or(UiAccountEncoding::Base64),
118 None,
119 data_slice,
120 )),
121 }
122 }
123
124 pub fn expected_data(&self) -> &Vec<u8> {
125 match &self {
126 Self::None(_) => unreachable!(),
127 Self::FoundAccount(_, account, _) | Self::FoundProgramAccount((_, account), _) => {
128 &account.data
129 }
130 }
131 }
132
133 pub fn apply_update<T>(&mut self, update: T) -> RpcError<()>
134 where
135 T: Fn(&mut Account) -> RpcError<()>,
136 {
137 match self {
138 Self::None(_) => unreachable!(),
139 Self::FoundAccount(_, ref mut account, ref mut do_update_account) => {
140 update(account)?;
141 *do_update_account = true;
142 }
143 Self::FoundProgramAccount((_, ref mut account), _) => {
144 update(account)?;
145 }
146 }
147 Ok(())
148 }
149
150 pub fn map_found_account(self) -> Result<Account, SurfpoolError> {
151 match self {
152 Self::None(pubkey) => Err(SurfpoolError::account_not_found(pubkey)),
153 Self::FoundAccount(_, account, _) => Ok(account),
154 Self::FoundProgramAccount((pubkey, _), _) => Err(SurfpoolError::invalid_account_data(
155 pubkey,
156 "account should not be executable",
157 None::<String>,
158 )),
159 }
160 }
161
162 pub fn map_account(self) -> SurfpoolResult<Account> {
163 match self {
164 Self::None(pubkey) => Err(SurfpoolError::account_not_found(pubkey)),
165 Self::FoundAccount(_, account, _) => Ok(account),
166 Self::FoundProgramAccount((_, account), _) => Ok(account),
167 }
168 }
169
170 pub fn is_none(&self) -> bool {
171 matches!(self, Self::None(_))
172 }
173
174 pub fn requires_update(&self) -> bool {
175 match self {
176 Self::None(_) => false,
177 Self::FoundAccount(_, _, do_update) => *do_update,
178 Self::FoundProgramAccount(_, _) => true,
179 }
180 }
181}
182
183impl From<GetAccountResult> for Result<Account, SurfpoolError> {
184 fn from(value: GetAccountResult) -> Self {
185 value.map_account()
186 }
187}
188
189impl SignatureSubscriptionType {
190 pub fn received() -> Self {
191 SignatureSubscriptionType::Received
192 }
193
194 pub fn processed() -> Self {
195 SignatureSubscriptionType::Commitment(CommitmentLevel::Processed)
196 }
197
198 pub fn confirmed() -> Self {
199 SignatureSubscriptionType::Commitment(CommitmentLevel::Confirmed)
200 }
201
202 pub fn finalized() -> Self {
203 SignatureSubscriptionType::Commitment(CommitmentLevel::Finalized)
204 }
205}
206
207pub enum GetTransactionResult {
208 None(Signature),
209 FoundTransaction(
210 Signature,
211 EncodedConfirmedTransactionWithStatusMeta,
212 TransactionStatus,
213 ),
214}
215
216impl GetTransactionResult {
217 pub fn found_transaction(
218 signature: Signature,
219 tx: EncodedConfirmedTransactionWithStatusMeta,
220 latest_absolute_slot: u64,
221 ) -> Self {
222 let status = TransactionStatus {
223 slot: tx.slot,
224 confirmations: Some((latest_absolute_slot - tx.slot) as usize),
225 status: tx.transaction.clone().meta.map_or(Ok(()), |m| m.status),
226 err: tx.transaction.clone().meta.and_then(|m| m.err),
227 confirmation_status: Some(
228 solana_transaction_status::TransactionConfirmationStatus::Confirmed,
229 ),
230 };
231
232 Self::FoundTransaction(signature, tx, status)
233 }
234
235 pub fn is_none(&self) -> bool {
236 matches!(self, Self::None(_))
237 }
238
239 pub fn map_found_transaction(&self) -> SurfpoolResult<TransactionStatus> {
240 match self {
241 Self::None(sig) => Err(SurfpoolError::transaction_not_found(sig)),
242 Self::FoundTransaction(_, _, status) => Ok(status.clone()),
243 }
244 }
245
246 pub fn map_some_transaction_status(&self) -> Option<TransactionStatus> {
247 match self {
248 Self::None(_) => None,
249 Self::FoundTransaction(_, _, status) => Some(status.clone()),
250 }
251 }
252}