carbon_core/
transaction.rs1use {
16 crate::{
17 collection::InstructionDecoderCollection, error::CarbonResult, filter::Filter,
18 instruction::InstructionMetadata, processor::Processor,
19 },
20 async_trait::async_trait,
21 core::convert::TryFrom,
22 solana_hash::Hash,
23 solana_instruction::Instruction,
24 solana_pubkey::Pubkey,
25 solana_signature::Signature,
26 std::sync::Arc,
27};
28#[derive(Debug, Clone, Default)]
33pub struct TransactionMetadata {
34 pub slot: u64,
35 pub signature: Signature,
36 pub fee_payer: Pubkey,
37 pub meta: solana_transaction_status::TransactionStatusMeta,
38 pub message: solana_message::VersionedMessage,
39 pub index: Option<u64>,
40 pub block_time: Option<i64>,
41 pub block_hash: Option<Hash>,
42}
43
44impl TryFrom<crate::datasource::TransactionUpdate> for TransactionMetadata {
45 type Error = crate::error::Error;
46
47 fn try_from(value: crate::datasource::TransactionUpdate) -> Result<Self, Self::Error> {
48 let accounts = value.transaction.message.static_account_keys();
49
50 Ok(TransactionMetadata {
51 slot: value.slot,
52 signature: value.signature,
53 fee_payer: *accounts
54 .first()
55 .ok_or(crate::error::Error::MissingFeePayer)?,
56 meta: value.meta.clone(),
57 message: value.transaction.message.clone(),
58 index: value.index,
59 block_time: value.block_time,
60 block_hash: value.block_hash,
61 })
62 }
63}
64
65#[derive(Debug)]
69pub struct TransactionProcessorInputType<'a, T> {
70 pub metadata: &'a Arc<TransactionMetadata>,
71 pub instructions: &'a [(InstructionMetadata, T)],
72}
73
74pub struct TransactionPipe<T: InstructionDecoderCollection, P> {
75 processor: P,
76 filters: Vec<Box<dyn Filter + 'static>>,
77 _phantom: std::marker::PhantomData<T>,
78}
79
80impl<T: InstructionDecoderCollection, P> TransactionPipe<T, P> {
81 pub fn new(processor: P, filters: Vec<Box<dyn Filter + 'static>>) -> Self {
82 Self {
83 processor,
84 filters,
85 _phantom: std::marker::PhantomData,
86 }
87 }
88}
89
90#[async_trait]
91pub trait TransactionPipes<'a>: Send + Sync {
92 async fn run(
93 &mut self,
94 transaction_metadata: Arc<TransactionMetadata>,
95 instructions: &[(InstructionMetadata, Instruction)],
96 ) -> CarbonResult<()>;
97
98 fn filters(&self) -> &[Box<dyn Filter + 'static>];
99}
100
101#[async_trait]
102impl<T, P> TransactionPipes<'_> for TransactionPipe<T, P>
103where
104 T: InstructionDecoderCollection + Sync + 'static,
105 P: for<'a> Processor<TransactionProcessorInputType<'a, T>> + Send + Sync + 'static,
106{
107 async fn run(
108 &mut self,
109 transaction_metadata: Arc<TransactionMetadata>,
110 instructions: &[(InstructionMetadata, Instruction)],
111 ) -> CarbonResult<()> {
112 let parsed_instructions = parse_instructions_flat::<T>(instructions);
113
114 let data = TransactionProcessorInputType {
115 metadata: &transaction_metadata,
116 instructions: &parsed_instructions,
117 };
118
119 self.processor.process(&data).await?;
120
121 Ok(())
122 }
123
124 fn filters(&self) -> &[Box<dyn Filter + 'static>] {
125 &self.filters
126 }
127}
128
129pub fn parse_instructions_flat<T: InstructionDecoderCollection>(
130 instructions: &[(InstructionMetadata, Instruction)],
131) -> Vec<(InstructionMetadata, T)> {
132 instructions
133 .iter()
134 .filter_map(|(metadata, instruction)| {
135 T::parse_instruction(instruction).map(|parsed| (metadata.clone(), parsed))
136 })
137 .collect()
138}