openzeppelin_monitor/services/blockchain/client.rs
1//! Core blockchain client interface and traits.
2//!
3//! This module defines the common interface that all blockchain implementations
4//! must follow, ensuring consistent behavior across different blockchain types.
5
6use async_trait::async_trait;
7
8use crate::{
9 models::{BlockType, ContractSpec},
10 services::filter::BlockFilter,
11};
12
13/// Defines the core interface for blockchain clients
14///
15/// This trait must be implemented by all blockchain-specific clients to provide
16/// standardized access to blockchain data and operations.
17#[async_trait]
18pub trait BlockChainClient: Send + Sync + Clone {
19 /// Retrieves the latest block number from the blockchain
20 ///
21 /// # Returns
22 /// * `Result<u64, anyhow::Error>` - The latest block number or an error
23 async fn get_latest_block_number(&self) -> Result<u64, anyhow::Error>;
24
25 /// Retrieves a range of blocks from the blockchain
26 ///
27 /// # Arguments
28 /// * `start_block` - The starting block number
29 /// * `end_block` - Optional ending block number. If None, only fetches start_block
30 ///
31 /// # Returns
32 /// * `Result<Vec<BlockType>, anyhow::Error>` - Vector of blocks or an error
33 ///
34 /// # Note
35 /// The implementation should handle cases where end_block is None by returning
36 /// only the start_block data.
37 async fn get_blocks(
38 &self,
39 start_block: u64,
40 end_block: Option<u64>,
41 ) -> Result<Vec<BlockType>, anyhow::Error>;
42
43 /// Retrieves the contract spec for a given contract ID
44 ///
45 /// # Arguments
46 /// * `contract_id` - The ID of the contract to retrieve the spec for
47 ///
48 /// # Returns
49 /// * `Result<ContractSpec, anyhow::Error>` - The contract spec or an error
50 async fn get_contract_spec(&self, _contract_id: &str) -> Result<ContractSpec, anyhow::Error> {
51 Err(anyhow::anyhow!("get_contract_spec not implemented"))
52 }
53
54 /// Retrieves blocks containing only transactions relevant to the specified addresses
55 ///
56 /// This is an optimized method for chains that support address-based querying (like Solana).
57 /// For chains that don't support this optimization, the default implementation falls back
58 /// to `get_blocks` which fetches all transactions.
59 ///
60 /// # Arguments
61 /// * `addresses` - The addresses to filter transactions by (e.g., program IDs for Solana)
62 /// * `start_block` - The starting block number
63 /// * `end_block` - Optional ending block number
64 ///
65 /// # Returns
66 /// * `Result<Vec<BlockType>, anyhow::Error>` - Vector of blocks containing relevant transactions
67 async fn get_blocks_for_addresses(
68 &self,
69 _addresses: &[String],
70 start_block: u64,
71 end_block: Option<u64>,
72 ) -> Result<Vec<BlockType>, anyhow::Error> {
73 // Default implementation: fall back to fetching all blocks
74 // Blockchain-specific clients can override this with optimized implementations
75 self.get_blocks(start_block, end_block).await
76 }
77}
78
79/// Defines the factory interface for creating block filters
80///
81/// This trait must be implemented by all blockchain-specific clients to provide
82/// a way to create block filters.
83pub trait BlockFilterFactory<T> {
84 type Filter: BlockFilter<Client = T> + Send;
85 fn filter() -> Self::Filter;
86}