From e0995dba9c79c46c6352f23f28a7fc2ea26886af Mon Sep 17 00:00:00 2001 From: Dellenar Date: Tue, 18 Nov 2025 11:43:07 +0300 Subject: [PATCH] feat:remove-transaction-schemas --- crates/core/src/lib.rs | 7 +- crates/core/src/pipeline.rs | 66 ++------ crates/core/src/schema.rs | 275 -------------------------------- crates/core/src/transaction.rs | 173 +++----------------- crates/core/src/transformers.rs | 55 +------ crates/macros/src/lib.rs | 21 +-- crates/macros/src/schemas.rs | 219 ------------------------- 7 files changed, 48 insertions(+), 768 deletions(-) delete mode 100644 crates/core/src/schema.rs delete mode 100644 crates/macros/src/schemas.rs diff --git a/crates/core/src/lib.rs b/crates/core/src/lib.rs index 2e368c339..26f005e0a 100644 --- a/crates/core/src/lib.rs +++ b/crates/core/src/lib.rs @@ -61,10 +61,6 @@ //! in the pipeline. This module allows for the creation of custom data //! processors that can be integrated into various stages of the pipeline. //! -//! - **[`schema`]**: Defines transaction schemas, allowing for structured -//! parsing and validation of transaction data based on specified rules. -//! Supports complex nested instruction matching for comprehensive transaction -//! analysis. //! //! - **[`transaction`]**: Manages transaction data, including metadata //! extraction and parsing. This module supports transaction validation and @@ -96,7 +92,7 @@ //! TestProgramDecoder, //! TestProgramAccountProcessor //! ) -//! .transaction(TEST_SCHEMA.clone(), TestProgramTransactionProcessor) +//! .transaction(TestProgramTransactionProcessor) //! .account_deletions(TestProgramAccountDeletionProcessor) //! .build()? //! .run() @@ -140,7 +136,6 @@ pub mod pipeline; #[cfg(feature = "postgres")] pub mod postgres; pub mod processor; -pub mod schema; pub mod transaction; pub mod transformers; diff --git a/crates/core/src/pipeline.rs b/crates/core/src/pipeline.rs index 8fcc22c2e..9b3a98db1 100644 --- a/crates/core/src/pipeline.rs +++ b/crates/core/src/pipeline.rs @@ -59,7 +59,6 @@ use { AccountDecoder, AccountMetadata, AccountPipe, AccountPipes, AccountProcessorInputType, }, account_deletion::{AccountDeletionPipe, AccountDeletionPipes}, - collection::InstructionDecoderCollection, datasource::{AccountDeletion, Datasource, Update}, error::CarbonResult, instruction::{ @@ -68,12 +67,10 @@ use { }, metrics::{Metrics, MetricsCollection}, processor::Processor, - schema::TransactionSchema, transaction::{TransactionPipe, TransactionPipes, TransactionProcessorInputType}, transformers, }, core::time, - serde::de::DeserializeOwned, std::{convert::TryInto, sync::Arc, time::Instant}, tokio_util::sync::CancellationToken, }; @@ -191,7 +188,7 @@ pub const DEFAULT_CHANNEL_BUFFER_SIZE: usize = 1_000; /// TestProgramDecoder, /// TestProgramAccountProcessor /// ) -/// .transaction(TEST_SCHEMA.clone(), TestProgramTransactionProcessor) +/// .transaction(TestProgramTransactionProcessor) /// .account_deletions(TestProgramAccountDeletionProcessor) /// .channel_buffer_size(1000) /// .build()? @@ -1167,15 +1164,11 @@ impl PipelineBuilder { /// Adds a transaction pipe for processing full transaction data. /// - /// This method requires a transaction schema for decoding and a `Processor` - /// to handle the processed transaction data. + /// This method creates a transaction pipe that processes the full transaction data. /// /// # Parameters /// - /// - `schema`: A `TransactionSchema` used to match and interpret - /// transaction data. - /// - `processor`: A `Processor` that processes the decoded transaction - /// data. + /// - `processor`: A `Processor` that processes the full transaction data. /// /// # Example /// @@ -1183,31 +1176,15 @@ impl PipelineBuilder { /// use carbon_core::pipeline::PipelineBuilder; /// /// let builder = PipelineBuilder::new() - /// .transaction(MY_SCHEMA.clone(), MyTransactionProcessor); + /// .transaction(MyTransactionProcessor); /// ``` - pub fn transaction( + pub fn transaction( mut self, - processor: impl Processor> - + Send - + Sync - + 'static, - schema: Option>, - ) -> Self - where - T: InstructionDecoderCollection + 'static, - U: DeserializeOwned + Send + Sync + 'static, - { - log::trace!( - "transaction(self, schema: {:?}, processor: {:?})", - stringify!(schema), - stringify!(processor) - ); + processor: impl Processor + Send + Sync + 'static, + ) -> Self { + log::trace!("transaction(self, processor: {:?})", stringify!(processor)); self.transaction_pipes - .push(Box::new(TransactionPipe::::new( - schema, - processor, - vec![], - ))); + .push(Box::new(TransactionPipe::new(processor, vec![]))); self } @@ -1221,8 +1198,6 @@ impl PipelineBuilder { /// # Parameters /// /// - `processor`: A `Processor` that processes the decoded transaction data - /// - `schema`: A `TransactionSchema` used to match and interpret - /// transaction data /// - `filters`: A collection of filters that determine which transactions /// should be processed /// @@ -1240,31 +1215,20 @@ impl PipelineBuilder { /// let filters = vec![Box::new(filter) as Box]; /// /// let builder = PipelineBuilder::new() - /// .transaction_with_filters(MyTransactionProcessor, MY_SCHEMA.clone(), filters); + /// .transaction_with_filters(MyTransactionProcessor, filters); /// ``` pub fn transaction_with_filters( mut self, - processor: impl Processor> - + Send - + Sync - + 'static, - schema: Option>, + processor: impl Processor + Send + Sync + 'static, filters: Vec>, - ) -> Self - where - T: InstructionDecoderCollection + 'static, - U: DeserializeOwned + Send + Sync + 'static, - { + ) -> Self { log::trace!( - "transaction_with_filters(self, schema: {:?}, processor: {:?}, filters: {:?})", - stringify!(schema), + "transaction_with_filters(self, processor: {:?}, filters: {:?})", stringify!(processor), stringify!(filters) ); self.transaction_pipes - .push(Box::new(TransactionPipe::::new( - schema, processor, filters, - ))); + .push(Box::new(TransactionPipe::new(processor, filters))); self } @@ -1396,7 +1360,7 @@ impl PipelineBuilder { /// TestProgramDecoder, /// TestProgramAccountProcessor /// ) - /// .transaction(TEST_SCHEMA.clone(), TestProgramTransactionProcessor) + /// .transaction(TestProgramTransactionProcessor) /// .account_deletions(TestProgramAccountDeletionProcessor) /// .channel_buffer_size(1000) /// .build()?; diff --git a/crates/core/src/schema.rs b/crates/core/src/schema.rs deleted file mode 100644 index bb48c0535..000000000 --- a/crates/core/src/schema.rs +++ /dev/null @@ -1,275 +0,0 @@ -//! Defines the structures and functions for constructing and matching -//! transaction schemas in `carbon-core`. -//! -//! This module provides the `TransactionSchema`, `SchemaNode`, and -//! `InstructionSchemaNode` types, enabling users to define and validate -//! transactions against a specific schema. Transaction schemas can be nested, -//! allowing for complex, multi-layered transaction structures that represent -//! various instructions and sub-instructions. -//! -//! ## Key Components -//! -//! - **TransactionSchema**: Represents the overall schema for a transaction, -//! consisting of a collection of schema nodes at its root. -//! - **SchemaNode**: A node in the schema that can either be an instruction -//! node or an `Any` node, allowing flexibility in matching instructions at -//! that level. -//! - **InstructionSchemaNode**: Represents an instruction with its type, name, -//! and any nested inner instructions. -//! -//! ## Usage -//! -//! The `TransactionSchema` type provides methods to match a given transaction’s -//! instructions against the schema and return a mapped representation of the -//! data if it conforms to the schema. The `match_schema` and `match_nodes` -//! methods allow for hierarchical matching and data extraction from -//! transactions. -//! -//! ## Notes -//! -//! - **Schema Matching**: Schema matching is sequential, with `Any` nodes -//! providing flexibility in handling unknown instructions within -//! transactions. Each `InstructionSchemaNode` defines specific instructions -//! to be matched, allowing for strict validation where needed. -//! - **Nested Instructions**: Instruction schemas can contain nested -//! instructions, enabling validation of complex transactions with inner -//! instructions. -//! - **Data Conversion**: The `match_schema` method returns data as a -//! deserialized type using `serde_json`. Ensure that your expected output -//! type implements `DeserializeOwned`. - -use { - crate::{collection::InstructionDecoderCollection, instruction::DecodedInstruction}, - serde::de::DeserializeOwned, - solana_instruction::AccountMeta, - solana_pubkey::Pubkey, - std::collections::HashMap, -}; - -/// Represents a node within a transaction schema, which can be either an -/// `Instruction` node or an `Any` node to allow for flexible matching. -#[derive(Debug, Clone)] -pub enum SchemaNode { - /// Represents a specific instruction type and its nested structure. - Instruction(InstructionSchemaNode), - /// Matches any instruction type, providing flexibility within the schema. - Any, -} - -/// Represents an instruction node within a schema, containing the instruction -/// type, name, and optional nested instructions for further validation. -#[derive(Debug, Clone)] -pub struct InstructionSchemaNode { - /// The type of the instruction, as defined by the associated collection. - pub ix_type: T::InstructionType, - /// A unique name identifier for the instruction node within the schema. - pub name: String, - /// A vector of nested schema nodes for matching nested instructions. - pub inner_instructions: Vec>, -} - -/// Represents a parsed instruction, containing its program ID, decoded -/// instruction data, and any nested instructions within the transaction. -#[derive(Debug)] -pub struct ParsedInstruction { - /// The program ID associated with this instruction. - pub program_id: Pubkey, - /// The decoded instruction data. - pub instruction: DecodedInstruction, - /// A vector of parsed nested instructions. - pub inner_instructions: Vec>, -} - -/// Represents the schema for a transaction, defining the structure and expected -/// instructions. -/// -/// `TransactionSchema` allows you to define the structure of a transaction by -/// specifying a list of `SchemaNode` elements at the root level. These nodes -/// can represent specific instruction types or allow for flexibility with `Any` -/// nodes. Nested instructions are supported to enable complex hierarchical -/// schemas. -/// -/// ## Methods -/// -/// - `match_schema`: Attempts to match the transaction’s instructions against -/// the schema, returning a deserialized representation of the data. -/// - `match_nodes`: Matches the instructions against the schema nodes, -/// returning a mapping of instruction names to data, if successful. -#[derive(Debug, Clone)] -pub struct TransactionSchema { - pub root: Vec>, -} - -impl TransactionSchema { - /// Matches the transaction's instructions against the schema and returns a - /// deserialized result. - /// - /// # Parameters - /// - /// - `instructions`: A slice of `ParsedInstruction` representing the - /// instructions to be matched. - /// - /// # Returns - /// - /// An `Option` containing the deserialized data if matching and - /// deserialization are successful. The U represents the expected output - /// type, manually made by the developer. - pub fn match_schema(&self, instructions: &[ParsedInstruction]) -> Option - where - U: DeserializeOwned, - { - log::trace!( - "Schema::match_schema(self: {:?}, instructions: {:?})", - self, - instructions - ); - let value = serde_json::to_value(self.match_nodes(instructions)).ok()?; - - log::trace!("Schema::match_schema: deserializing value: {:?}", value); - serde_json::from_value::(value).ok() - } - - /// Matches the instructions against the schema nodes and returns a mapping - /// of instruction names to data. - /// - /// This method processes the instructions and checks them against the - /// schema nodes sequentially. If the instructions match, a `HashMap` of - /// instruction names to decoded data and associated accounts is returned. - /// - /// # Parameters - /// - /// - `instructions`: A slice of `ParsedInstruction` representing the - /// instructions to be matched. - /// - /// # Returns - /// - /// An `Option)>>` containing the - /// matched instruction data, or `None` if the instructions do not match - /// the schema. - pub fn match_nodes( - &self, - instructions: &[ParsedInstruction], - ) -> Option)>> { - log::trace!( - "Schema::match_nodes(self: {:?}, instructions: {:?})", - self, - instructions - ); - let mut output = HashMap::)>::new(); - - let mut node_index = 0; - let mut instruction_index = 0; - - let mut any = false; - - while let Some(node) = self.root.get(node_index) { - log::trace!( - "Schema::match_nodes: current node ({}): {:?}", - node_index, - node - ); - - if let SchemaNode::Any = node { - log::trace!("Schema::match_nodes: Any node detected, skipping"); - any = true; - node_index += 1; - continue; - } - - let mut matched = false; - - while let Some(current_instruction) = instructions.get(instruction_index) { - log::trace!( - "Schema::match_nodes: current instruction ({}): {:?}", - instruction_index, - current_instruction - ); - - let SchemaNode::Instruction(instruction_node) = node else { - return None; - }; - - if current_instruction.instruction.data.get_type() != instruction_node.ix_type - && !any - { - log::trace!( - "Schema::match_nodes: instruction type mismatch, returning (any = false)" - ); - return None; - } - - if current_instruction.instruction.data.get_type() != instruction_node.ix_type - && any - { - log::trace!( - "Schema::match_nodes: instruction type mismatch, skipping (any = true)" - ); - instruction_index += 1; - continue; - } - - output.insert( - instruction_node.name.clone(), - ( - current_instruction.instruction.data.clone(), - current_instruction.instruction.accounts.clone(), - ), - ); - - if !instruction_node.inner_instructions.is_empty() { - let inner_output = TransactionSchema { - root: instruction_node.inner_instructions.clone(), - } - .match_nodes(¤t_instruction.inner_instructions)?; - output = merge_hashmaps(output, inner_output); - } - - log::trace!( - "Schema::match_nodes: instruction matched, output: {:?}", - output - ); - - instruction_index += 1; - node_index += 1; - any = false; - matched = true; - break; - } - - if !matched { - log::trace!("Schema::match_nodes: node not matched, returning"); - return None; - } - } - - log::trace!("Schema::match_nodes: final output: {:?}", output); - - Some(output) - } -} - -/// Merges two hash maps containing instruction data and account information. -/// -/// # Parameters -/// -/// - `a`: The first `HashMap` to be merged. -/// - `b`: The second `HashMap` to be merged. -/// -/// # Returns -/// -/// A new `HashMap` containing all elements from `a` and `b`. In the case of -/// duplicate keys, values from `b` will overwrite those from `a`. -pub fn merge_hashmaps( - a: HashMap)>, - b: HashMap)>, -) -> HashMap)> -where - K: std::cmp::Eq + std::hash::Hash, -{ - log::trace!("merge_hashmaps(a, b)"); - let mut output = a; - for (key, value) in b { - output.insert(key, value); - } - output -} diff --git a/crates/core/src/transaction.rs b/crates/core/src/transaction.rs index 633418952..2dd429099 100644 --- a/crates/core/src/transaction.rs +++ b/crates/core/src/transaction.rs @@ -1,50 +1,36 @@ //! Provides types and traits for handling transaction processing in the -//! `carbon-core` framework. It also provides utilities for matching -//! transactions to schemas and executing custom processing logic on matched -//! data. +//! `carbon-core` framework. //! //! ## Key Components //! -//! - **TransactionPipe**: Represents a processing pipe for transactions, with -//! functionality to parse and match instructions against a schema and handle -//! matched data with a specified processor. +//! - **TransactionPipe**: Represents a processing pipe for transactions that +//! processes full transaction context including metadata and all nested +//! instructions. //! - **TransactionMetadata**: Metadata associated with a transaction, including //! slot, signature, and fee payer information. -//! - **ParsedTransaction**: Represents a transaction with its metadata and -//! parsed instructions. //! //! ## Usage //! -//! To use this module, create a `TransactionPipe` with a transaction schema and -//! a processor. Then, run the transaction pipe with a set of instructions and -//! metrics to parse, match, and process transaction data. The `run` method will -//! asynchronously handle these steps. +//! To use this module, create a `TransactionPipe` with a processor. The pipe +//! will process full transactions with their metadata and all nested instructions, +//! providing complete transaction context to the processor. //! //! ## Notes //! //! - **Nested Instructions**: The `TransactionPipe` supports nested //! instructions within transactions, allowing for multi-level transaction //! processing. -//! - **Schema Matching**: The `TransactionPipe` will match transaction -//! instructions against the provided schema, only processing the data if it -//! conforms to the schema. use crate::filter::Filter; use solana_program::hash::Hash; use { crate::{ - collection::InstructionDecoderCollection, - error::CarbonResult, - instruction::{DecodedInstruction, InstructionMetadata, NestedInstruction}, - metrics::MetricsCollection, + error::CarbonResult, instruction::NestedInstruction, metrics::MetricsCollection, processor::Processor, - schema::{ParsedInstruction, TransactionSchema}, - transformers, }, async_trait::async_trait, core::convert::TryFrom, - serde::de::DeserializeOwned, solana_pubkey::Pubkey, solana_signature::Signature, std::sync::Arc, @@ -119,57 +105,34 @@ impl TryFrom for TransactionMetadata { /// The input type for the transaction processor. /// -/// - `T`: The instruction type, implementing `InstructionDecoderCollection`. -/// - `U`: The output type for the matched data, if schema-matching, -/// implementing `DeserializeOwned`. -pub type TransactionProcessorInputType = ( - Arc, - Vec<(InstructionMetadata, DecodedInstruction)>, - Option, -); +pub type TransactionProcessorInputType = (Arc, Vec); -/// A pipe for processing transactions based on a defined schema and processor. +/// A pipe for processing full transaction context. /// -/// The `TransactionPipe` parses a transaction's instructions, optionally checks -/// them against the schema, and runs the processor if the instructions match -/// the schema. It provides methods for parsing nested instructions and matching -/// transaction data to the schema. -/// -/// ## Generics -/// -/// - `T`: The instruction type, implementing `InstructionDecoderCollection`. -/// - `U`: The output type for the matched data, if schema-matching, -/// implementing `DeserializeOwned`. +/// The `TransactionPipe` processes complete transactions with their metadata and +/// all nested instructions, providing full transaction context to the processor. /// /// ## Fields /// -/// - `schema`: The schema against which to match transaction instructions. -/// - `processor`: The processor that will handle matched transaction data. +/// - `processor`: The processor that will handle full transaction data including +/// metadata and all nested instructions. /// - `filters`: A collection of filters that determine which transaction /// updates should be processed. Each filter in this collection is applied to /// incoming transaction updates, and only updates that pass all filters /// (return `true`) will be processed. If this collection is empty, all /// updates are processed. -pub struct TransactionPipe { - schema: Option>, - processor: Box> + Send + Sync>, +pub struct TransactionPipe { + processor: Box + Send + Sync>, filters: Vec>, } -/// Represents a parsed transaction, including its metadata and parsed -/// instructions. -pub struct ParsedTransaction { - pub metadata: TransactionMetadata, - pub instructions: Vec>, -} - -impl TransactionPipe { - /// Creates a new `TransactionPipe` with the specified schema and processor. +impl TransactionPipe { + /// Creates a new `TransactionPipe` with the specified processor. /// /// # Parameters /// - /// - `schema`: The schema against which to match transaction instructions. - /// - `processor`: The processor that will handle matched transaction data. + /// - `processor`: The processor that will handle full transaction data + /// including metadata and all nested instructions. /// - `filters`: A collection of filters for selective processing of /// transaction updates. Filters can be used to selectively process /// transactions based on criteria such as datasource ID, transaction @@ -177,89 +140,20 @@ impl TransactionPipe { /// /// # Returns /// - /// A `TransactionPipe` instance configured with the specified schema and - /// processor. + /// A `TransactionPipe` instance configured with the specified processor. pub fn new( - schema: Option>, - processor: impl Processor> - + Send - + Sync - + 'static, + processor: impl Processor + Send + Sync + 'static, filters: Vec>, ) -> Self { log::trace!( - "TransactionPipe::new(schema: {:?}, processor: {:?})", - schema, + "TransactionPipe::new(processor: {:?})", stringify!(processor) ); Self { - schema, processor: Box::new(processor), filters, } } - - /// Matches parsed instructions against the schema and returns the data as - /// type `U`. - /// - /// The method only returns data if the parsed instructions conform to the - /// schema. - /// - /// # Parameters - /// - /// - `instructions`: A slice of `ParsedInstruction` to be matched against - /// the schema. - /// - /// # Returns - /// - /// An `Option` containing the deserialized matched data if the - /// instructions match the schema. - fn matches_schema(&self, instructions: &[ParsedInstruction]) -> Option - where - U: DeserializeOwned, - { - match self.schema { - Some(ref schema) => schema.match_schema(instructions), - None => None, - } - } -} - -/// Parses nested instructions into a list of `ParsedInstruction`. -/// -/// This method recursively traverses the nested instructions and parses -/// each one, creating a structured representation of the instructions. -/// -/// # Parameters -/// -/// - `nested_ixs`: A slice of `NestedInstruction` representing the instructions -/// to be parsed. -/// -/// # Returns -/// -/// A `Box>>` containing the parsed instructions. -pub fn parse_instructions( - nested_ixs: &[NestedInstruction], -) -> Vec> { - log::trace!("parse_instructions(nested_ixs: {:?})", nested_ixs); - - let mut parsed_instructions: Vec> = Vec::new(); - - for nested_ix in nested_ixs { - if let Some(instruction) = T::parse_instruction(&nested_ix.instruction) { - parsed_instructions.push(ParsedInstruction { - program_id: nested_ix.instruction.program_id, - instruction, - inner_instructions: parse_instructions(&nested_ix.inner_instructions), - }); - } else { - for inner_ix in nested_ix.inner_instructions.iter() { - parsed_instructions.extend(parse_instructions(std::slice::from_ref(inner_ix))); - } - } - } - - parsed_instructions } /// An async trait for processing transactions. @@ -285,11 +179,7 @@ pub trait TransactionPipes<'a>: Send + Sync { } #[async_trait] -impl TransactionPipes<'_> for TransactionPipe -where - T: InstructionDecoderCollection + Sync + 'static, - U: DeserializeOwned + Send + Sync + 'static, -{ +impl TransactionPipes<'_> for TransactionPipe { async fn run( &mut self, transaction_metadata: Arc, @@ -301,21 +191,8 @@ where instructions, ); - let parsed_instructions = parse_instructions(instructions); - - let matched_data = self.matches_schema(&parsed_instructions); - - let unnested_instructions = transformers::unnest_parsed_instructions( - transaction_metadata.clone(), - parsed_instructions, - 0, - ); - self.processor - .process( - (transaction_metadata, unnested_instructions, matched_data), - metrics, - ) + .process((transaction_metadata, instructions.to_vec()), metrics) .await?; Ok(()) diff --git a/crates/core/src/transformers.rs b/crates/core/src/transformers.rs index ba7a84285..d002297e7 100644 --- a/crates/core/src/transformers.rs +++ b/crates/core/src/transformers.rs @@ -22,11 +22,9 @@ use { crate::{ - collection::InstructionDecoderCollection, datasource::TransactionUpdate, error::{CarbonResult, Error}, - instruction::{DecodedInstruction, InstructionMetadata, MAX_INSTRUCTION_STACK_DEPTH}, - schema::ParsedInstruction, + instruction::{InstructionMetadata, MAX_INSTRUCTION_STACK_DEPTH}, transaction::TransactionMetadata, }, solana_instruction::AccountMeta, @@ -269,57 +267,6 @@ pub fn extract_account_metas( Ok(accounts) } -/// Unnests parsed instructions, producing an array of `(InstructionMetadata, -/// DecodedInstruction)` tuple -/// -/// This function takes a vector of `ParsedInstruction` and unnests them into a -/// vector of `(InstructionMetadata, DecodedInstruction)` tuples. -/// It recursively processes nested instructions, increasing the stack height -/// for each level of nesting. -/// -/// # Parameters -/// -/// - `transaction_metadata`: The metadata of the transaction containing the -/// instructions. -/// - `instructions`: The vector of `ParsedInstruction` to be unnested. -/// - `stack_height`: The current stack height. -/// -/// # Returns -/// -/// A vector of `(InstructionMetadata, DecodedInstruction)` tuples -/// representing the unnested instructions. -pub fn unnest_parsed_instructions( - transaction_metadata: Arc, - instructions: Vec>, - stack_height: u32, -) -> Vec<(InstructionMetadata, DecodedInstruction)> { - log::trace!( - "unnest_parsed_instructions(instructions: {:?})", - instructions - ); - - let mut result = Vec::new(); - - for (ix_idx, parsed_instruction) in instructions.into_iter().enumerate() { - result.push(( - InstructionMetadata { - transaction_metadata: transaction_metadata.clone(), - stack_height, - index: ix_idx as u32 + 1, - absolute_path: vec![], - }, - parsed_instruction.instruction, - )); - result.extend(unnest_parsed_instructions( - transaction_metadata.clone(), - parsed_instruction.inner_instructions, - stack_height + 1, - )); - } - - result -} - /// Converts UI transaction metadata into `TransactionStatusMeta`. /// /// This function transforms the user interface format of transaction metadata diff --git a/crates/macros/src/lib.rs b/crates/macros/src/lib.rs index 8cbf05a4c..d3d503960 100644 --- a/crates/macros/src/lib.rs +++ b/crates/macros/src/lib.rs @@ -1,28 +1,19 @@ //! # Carbon Macros //! -//! This crate provides powerful macros for building and processing transaction -//! schemas and decoding instructions dynamically. It includes two main modules: -//! -//! - **`schema`**: Offers the `schema!` macro to construct hierarchical -//! transaction schemas with flexible node types, ideal for organizing and -//! validating complex transaction structures. -//! - **`try_decode_ix`**: Includes the `try_decode_instructions!` macro, -//! enabling dynamic decoding of instructions into various types based on -//! specified patterns. +//! This crate provides powerful macros for decoding instructions dynamically. +//! It includes the `try_decode_instructions!` macro, enabling dynamic decoding +//! of instructions into various types based on specified patterns. //! //! ## Overview //! -//! These modules are designed for applications that utilize Carbon, where +//! This module is designed for applications that utilize Carbon, where //! transaction processing and decoding are essential. The macros in this crate -//! simplify handling diverse instruction types and assembling transaction -//! schemas, reducing boilerplate code and enhancing flexibility in transaction -//! management. +//! simplify handling diverse instruction types, reducing boilerplate code and +//! enhancing flexibility in transaction management. //! //! ## Modules //! -//! - **`schema`**: For building transaction schemas. //! - **`try_decode_ix`**: For decoding instructions dynamically. #![no_std] -pub mod schemas; pub mod try_decode_ixs; diff --git a/crates/macros/src/schemas.rs b/crates/macros/src/schemas.rs deleted file mode 100644 index 802b3a745..000000000 --- a/crates/macros/src/schemas.rs +++ /dev/null @@ -1,219 +0,0 @@ -//! # Schema Module -//! -//! The `schema` module provides macros for constructing and organizing -//! transaction schemas in a hierarchical manner. These macros are designed to -//! simplify the creation of complex transaction structures by allowing inline -//! specification of schema elements, which represent instructions -//! within transactions. -//! -//! ## Overview -//! -//! This module includes two primary macros: -//! - **`schema!`**: The main macro for constructing a `TransactionSchema`, -//! which is a hierarchical schema representation. -//! - **`schema_inner!`**: A helper macro, used internally by `schema!` for -//! recursive schema node construction. -//! -//! Together, these macros enable you to define schema nodes in a flexible and -//! intuitive manner, allowing for combinations of `Any` and `Instruction` nodes -//! with optional nested instructions. -//! -//! ## Key Macros -//! -//! ### `schema!` -//! -//! The `schema!` macro is the primary entry point for constructing a -//! `TransactionSchema`. It parses provided tokens into a `TransactionSchema` -//! object, allowing inline definition of various schema elements in a tree-like -//! structure. This macro supports keywords like `any` to create branches that -//! can match multiple instruction types. -//! -//! #### Example -//! -//! ```ignore -//! use your_crate::schema; -//! -//! let transaction_schema = schema![ -//! any, -//! [ -//! AllInstructionTypes::JupSwap(JupiterInstructionType::SwapEvent), -//! "jup_swap_event", -//! [] -//! ], -//! any, -//! ]; -//! ``` -//! -//! This example defines a schema with an `any` branch, an `Instruction` node -//! with nested instructions, and another `any` branch, creating a flexible -//! transaction structure. In practical terms, this means that the schema -//! represents a transaction that has a Jupiter Swap Event instruction anywhere -//! within the transaction. -//! -//! ### `schema_inner!` -//! -//! This macro is used internally by `schema!` to build out individual -//! `SchemaNode` elements. It supports three main syntax patterns: `any`, single -//! `Instruction` nodes, and nested `Instruction` nodes. Users typically don’t -//! need to interact with this macro directly, as it’s invoked by `schema!` -//! to handle recursive node construction. -//! -//! #### Supported Syntax Patterns -//! -//! 1. **`any`**: Adds an `Any` node, which can match any instruction type, -//! multiple times. -//! 2. **`[$ix_type:expr, $name:expr]`**: Adds an `Instruction` node without -//! nested instructions. -//! 3. **`[$ix_type:expr, $name:expr, [$($inner:tt)*]]`**: Adds an `Instruction` -//! node with nested inner instructions. -//! -//! ## Notes -//! -//! - The `schema!` macro relies on `schema_inner!` for recursive parsing and -//! node creation. -//! - When using the `schema!` macro, ensure that all instruction types and -//! identifiers correspond to valid values expected by the `TransactionSchema` -//! to avoid compilation errors. -//! -//! ## Crate Dependencies -//! -//! This module relies on components like `SchemaNode` and -//! `InstructionSchemaNode` to build the schema tree. Make sure these types are -//! defined and accessible within the scope of the module’s usage. - -/// Constructs a `TransactionSchema` from provided tokens. -/// -/// The `schema!` macro facilitates the creation of a `TransactionSchema` by -/// parsing the provided tokens and assembling the structure. This macro -/// simplifies schema construction by allowing inline specification of schema -/// elements, including instruction types and associated names. -/// -/// # Syntax -/// -/// The `schema!` macro uses a flexible token-based syntax, enabling you to -/// define schema nodes inline. Nodes are defined in a hierarchical manner, with -/// keywords like `any` indicating schema branches, followed by instruction -/// types, string identifiers, and additional attributes or sub-nodes as needed. -/// -/// # Example -/// -/// ```ignore -/// use carbon_macros::schema; -/// use carbon_macros::schema_inner; -/// -/// let transaction_schema = schema![ -/// any -/// [ -/// AllInstructionTypes::JupSwap(JupiterInstructionType::SwapEvent), -/// "jup_swap_event", -/// [] -/// ] -/// any -/// ]; -/// ``` -/// -/// # Parameters -/// -/// - `$tt`: The token stream passed to the macro, which may include multiple -/// schema nodes and attributes. These tokens are parsed to construct the -/// schema tree, forming a `TransactionSchema` object with a root node -/// containing the specified elements. -/// -/// # Returns -/// -/// This macro returns a `TransactionSchema` instance with the constructed -/// schema tree based on the tokens provided. The schema is organized with nodes -/// added to the root, allowing for complex, multi-layered transaction -/// structures, which represent real transaction instructions, in order. -/// -/// # Notes -/// -/// - This macro requires that the inner macro `schema_inner!` is also defined, -/// as it handles the recursive parsing and node addition to the schema. -/// - Ensure that types and keywords used within the schema correspond to valid -/// identifiers and instructions expected by `TransactionSchema`. Inconsistent -/// tokens may lead to compilation errors or incorrect schema construction. -#[macro_export] -macro_rules! schema { - ($($tt:tt)*) => {{ - let mut nodes = Vec::new(); - schema_inner!(&mut nodes, $($tt)*); - carbon_core::schema::TransactionSchema { root: nodes } - }}; -} - -/// Recursively constructs schema nodes within the `schema!` macro. -/// -/// The `schema_inner!` macro is utilized internally by the `schema!` macro to -/// build a `TransactionSchema` structure by parsing tokens into individual -/// `SchemaNode` elements. This macro supports multiple node types, including -/// `Any` nodes and `Instruction` nodes with optional nested instructions. Each -/// parsed node is appended to the provided vector, forming a hierarchical -/// schema structure. -/// -/// # Syntax -/// -/// This macro supports three main syntax patterns: -/// -/// 1. `any`: Adds an `Any` node to the schema, indicating a branch point that -/// accepts multiple instructions of any type. -/// 2. `[$ix_type:expr, $name:expr]`: Adds an `Instruction` node with the -/// specified instruction type and name, without nested instructions. -/// 3. `[$ix_type:expr, $name:expr, [$($inner:tt)*]]`: Adds an `Instruction` -/// node with the specified instruction type and name, including inner -/// instructions which are parsed recursively. -/// -/// # Parameters -/// -/// - `$nodes`: A mutable reference to a `Vec`. This vector -/// accumulates the constructed schema nodes, which can include both `Any` and -/// `Instruction` node variants with nested instructions. -/// - `$ix_type`: The instruction type for the node, provided as an expression. -/// This identifies the specific instruction type in the schema. -/// - `$name`: A string literal representing the name of the instruction. This -/// name is associated with the `Instruction` node for identification. -/// -/// # Returns -/// -/// This macro modifies the `Vec` passed as `$nodes`, adding each -/// parsed `SchemaNode` to the vector. Nodes can be nested, with the structure -/// reflecting any provided inner instructions. -/// -/// # Notes -/// -/// - This macro is intended for internal use within the `schema!` macro and is -/// not typically called directly by users. -/// - Ensure that each `$ix_type` corresponds to a valid instruction type and -/// that `$name` is a string literal for compatibility with -/// `InstructionSchemaNode`. -/// - The recursive structure allows for complex, multi-level instruction -/// schemas suitable for detailed transaction validation and processing. -#[macro_export] -macro_rules! schema_inner { - ($nodes:expr, ) => {}; - - ($nodes:expr, any $($rest:tt)*) => { - $nodes.push(carbon_core::schema::SchemaNode::Any); - schema_inner!($nodes, $($rest)*); - }; - - ($nodes:expr, [$ix_type:expr, $name:expr] $($rest:tt)*) => { - $nodes.push(carbon_core::schema::SchemaNode::Instruction(carbon_core::schema::InstructionSchemaNode { - ix_type: $ix_type, - name: $name.to_string(), - inner_instructions: Vec::new(), - })); - schema_inner!($nodes, $($rest)*); - }; - - ($nodes:expr, [$ix_type:expr, $name:expr, [$($inner:tt)*]] $($rest:tt)*) => {{ - let mut inner_nodes = Vec::new(); - schema_inner!(&mut inner_nodes, $($inner)*); - $nodes.push(carbon_core::schema::SchemaNode::Instruction(carbon_core::schema::InstructionSchemaNode { - ix_type: $ix_type, - name: $name.to_string(), - inner_instructions: inner_nodes, - })); - schema_inner!($nodes, $($rest)*); - }}; -}