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