carbon_core/account.rs
1//! Provides structures and traits for processing and decoding Solana accounts
2//! within the pipeline.
3//!
4//! This module includes the necessary components for handling account data
5//! updates in the `carbon-core` pipeline. It provides abstractions for decoding
6//! accounts, processing account metadata, and implementing account-specific
7//! pipes, which are integral to the pipeline's account update processing.
8//!
9//! # Overview
10//!
11//! The `account` module supports various tasks related to Solana account
12//! processing:
13//! - **Account Metadata**: Metadata about accounts, including slot and public
14//! key information.
15//! - **Decoded Account**: Holds detailed account data after decoding, such as
16//! lamports, owner, and rent epoch.
17//! - **Account Decoders**: A trait-based mechanism to decode raw Solana account
18//! data into structured formats for processing.
19//! - **Account Pipes**: Encapsulates account processing logic, allowing custom
20//! processing of decoded account data in the pipeline.
21//!
22//! # Example
23//!
24//! ```ignore
25//! struct MyAccountDecoder;
26//!
27//! impl<'a> AccountDecoder<'a> for MyAccountDecoder {
28//! type AccountType = (AccountMetadata, DecodedAccount<PumpAccount>);
29//!
30//! fn decode_account(
31//! &self,
32//! account: &'a solana_account::Account,
33//! ) -> Option<DecodedAccount<Self::AccountType>> {
34//! // Custom decoding logic here
35//! Some(DecodedAccount {
36//! lamports: account.lamports,
37//! data: String::from_utf8(account.data.clone()).ok()?,
38//! owner: account.owner,
39//! executable: account.executable,
40//! rent_epoch: account.rent_epoch,
41//! })
42//! }
43//! }
44//! ```
45//!
46//! # Notes
47//!
48//! - This module requires access to Solana SDK structures, specifically
49//! `Account` and `Pubkey`.
50//! - All components support asynchronous processing to enable concurrent data
51//! handling in the pipeline.
52
53use {
54 crate::{
55 error::CarbonResult, filter::Filter, metrics::MetricsCollection, processor::Processor,
56 },
57 async_trait::async_trait,
58 solana_pubkey::Pubkey,
59 solana_signature::Signature,
60 std::sync::Arc,
61};
62
63/// Holds metadata for an account update, including the slot and public key.
64///
65/// `AccountMetadata` provides essential information about an account update,
66/// such as the slot number where the account was updated and the account's
67/// public key. This metadata is used within the pipeline to identify and
68/// process account updates.
69///
70/// # Fields
71///
72/// - `slot`: The Solana slot number where the account was updated.
73/// - `pubkey`: The public key of the account.
74/// - `transaction_signature`: Signature of the transaction that caused the update.
75#[derive(Debug, Clone)]
76pub struct AccountMetadata {
77 pub slot: u64,
78 pub pubkey: Pubkey,
79 pub transaction_signature: Option<Signature>,
80}
81
82/// Represents the decoded data of a Solana account, including account-specific
83/// details.
84///
85/// `DecodedAccount` holds the detailed data of a Solana account after it has
86/// been decoded. It includes the account's lamports, owner, executable status,
87/// and rent epoch, as well as any decoded data specific to the account.
88///
89/// # Type Parameters
90///
91/// - `T`: The type of data specific to the account, which is determined by the
92/// decoder used.
93///
94/// # Fields
95///
96/// - `lamports`: The number of lamports in the account.
97/// - `data`: The decoded data specific to the account.
98/// - `owner`: The public key of the account's owner.
99/// - `executable`: Whether the account is executable.
100/// - `rent_epoch`: The rent epoch of the account.
101#[derive(Debug, Clone)]
102pub struct DecodedAccount<T> {
103 pub lamports: u64,
104 pub data: T,
105 pub owner: Pubkey,
106 pub executable: bool,
107 pub rent_epoch: u64,
108}
109
110/// Defines a trait for decoding Solana accounts into structured data types.
111///
112/// `AccountDecoder` provides a way to convert raw Solana `Account` data into
113/// structured `DecodedAccount` instances. By implementing this trait, you can
114/// define custom decoding logic to interpret account data in a way that suits
115/// your application's requirements.
116///
117/// # Associated Types
118///
119/// - `AccountType`: The data type resulting from decoding the account, specific
120/// to the application.
121pub trait AccountDecoder<'a> {
122 type AccountType;
123
124 fn decode_account(
125 &self,
126 account: &'a solana_account::Account,
127 ) -> Option<DecodedAccount<Self::AccountType>>;
128}
129
130/// The input type for the account processor.
131///
132/// - `T`: The account type, as determined by the decoder.
133pub type AccountProcessorInputType<T> =
134 (AccountMetadata, DecodedAccount<T>, solana_account::Account);
135
136/// A processing pipe that decodes and processes Solana account updates.
137///
138/// `AccountPipe` combines an `AccountDecoder` and a `Processor` to manage
139/// account updates in the pipeline. This struct decodes the raw account data
140/// and then processes the resulting `DecodedAccount` with the specified
141/// processing logic.
142///
143/// # Type Parameters
144///
145/// - `T`: The data type of the decoded account information, as determined by
146/// the decoder.
147///
148/// # Fields
149///
150/// - `decoder`: An `AccountDecoder` that decodes raw account data into
151/// structured form.
152/// - `processor`: A `Processor` that handles the processing logic for decoded
153/// accounts.
154/// - `filters`: A collection of filters that determine which account updates
155/// should be processed. Each filter in this collection is applied to incoming
156/// account updates, and only updates that pass all filters (return `true`)
157/// will be processed. If this collection is empty, all updates are processed.
158pub struct AccountPipe<T: Send> {
159 pub decoder: Box<dyn for<'a> AccountDecoder<'a, AccountType = T> + Send + Sync + 'static>,
160 pub processor: Box<dyn Processor<InputType = AccountProcessorInputType<T>> + Send + Sync>,
161 pub filters: Vec<Box<dyn Filter + Send + Sync + 'static>>,
162}
163
164/// An async trait for processing account updates.
165///
166/// The `AccountPipes` trait allows for processing of account updates.
167///
168/// # Required Methods
169///
170/// - `run`: Processes an account update and tracks the operation with metrics.
171/// - `filters`: Returns a reference to the filters associated with this pipe,
172/// which are used by the pipeline to determine which account updates should
173/// be processed.
174#[async_trait]
175pub trait AccountPipes: Send + Sync {
176 async fn run(
177 &mut self,
178 account_with_metadata: (AccountMetadata, solana_account::Account),
179 metrics: Arc<MetricsCollection>,
180 ) -> CarbonResult<()>;
181
182 fn filters(&self) -> &Vec<Box<dyn Filter + Send + Sync + 'static>>;
183}
184
185#[async_trait]
186impl<T: Send> AccountPipes for AccountPipe<T> {
187 async fn run(
188 &mut self,
189 account_with_metadata: (AccountMetadata, solana_account::Account),
190 metrics: Arc<MetricsCollection>,
191 ) -> CarbonResult<()> {
192 log::trace!(
193 "AccountPipe::run(account_with_metadata: {:?}, metrics)",
194 account_with_metadata,
195 );
196
197 if let Some(decoded_account) = self.decoder.decode_account(&account_with_metadata.1) {
198 self.processor
199 .process(
200 (
201 account_with_metadata.0.clone(),
202 decoded_account,
203 account_with_metadata.1,
204 ),
205 metrics.clone(),
206 )
207 .await?;
208 }
209 Ok(())
210 }
211
212 fn filters(&self) -> &Vec<Box<dyn Filter + Send + Sync + 'static>> {
213 &self.filters
214 }
215}