ckb_sdk/rpc/
ckb_indexer.rs

1//! Simple http rpc client for [ckb-indexer](https://github.com/nervosnetwork/ckb-indexer)
2
3use ckb_jsonrpc_types::{
4    BlockNumber, Capacity, CellOutput, JsonBytes, OutPoint, Script, Uint32, Uint64,
5};
6use ckb_types::H256;
7use serde::{Deserialize, Serialize};
8
9use crate::traits::{CellQueryOptions, LiveCell, PrimaryScriptType, ValueRangeOption};
10
11#[derive(Serialize, Deserialize, Clone, Debug)]
12pub struct SearchKey {
13    pub script: Script,
14    pub script_type: ScriptType,
15    pub script_search_mode: Option<SearchMode>,
16    pub filter: Option<SearchKeyFilter>,
17    pub with_data: Option<bool>,
18    pub group_by_transaction: Option<bool>,
19}
20
21#[derive(Serialize, Deserialize, Clone, Debug, Eq, PartialEq, Hash)]
22#[serde(rename_all = "snake_case")]
23pub enum SearchMode {
24    // search with prefix
25    Prefix,
26    // search with exact match
27    Exact,
28    // search with partial match
29    Partial,
30}
31
32impl Default for SearchMode {
33    fn default() -> Self {
34        Self::Prefix
35    }
36}
37
38#[derive(Serialize, Deserialize, Default, Clone, Debug)]
39pub struct SearchKeyFilter {
40    pub script: Option<Script>,
41    pub script_len_range: Option<[Uint64; 2]>,
42    pub output_data: Option<JsonBytes>,
43    pub output_data_filter_mode: Option<SearchMode>,
44    pub output_data_len_range: Option<[Uint64; 2]>,
45    pub output_capacity_range: Option<[Uint64; 2]>,
46    pub block_range: Option<[BlockNumber; 2]>,
47}
48impl From<CellQueryOptions> for SearchKey {
49    fn from(opts: CellQueryOptions) -> SearchKey {
50        let convert_range =
51            |range: ValueRangeOption| [Uint64::from(range.start), Uint64::from(range.end)];
52        let filter = if opts.secondary_script.is_none()
53            && opts.secondary_script_len_range.is_none()
54            && opts.data_len_range.is_none()
55            && opts.capacity_range.is_none()
56            && opts.block_range.is_none()
57        {
58            None
59        } else {
60            Some(SearchKeyFilter {
61                script: opts.secondary_script.map(|v| v.into()),
62                script_len_range: opts.secondary_script_len_range.map(convert_range),
63                output_data: None,
64                output_data_filter_mode: None,
65                output_data_len_range: opts.data_len_range.map(convert_range),
66                output_capacity_range: opts.capacity_range.map(convert_range),
67                block_range: opts.block_range.map(convert_range),
68            })
69        };
70        SearchKey {
71            script: opts.primary_script.into(),
72            script_type: opts.primary_type.into(),
73            script_search_mode: opts.script_search_mode,
74            filter,
75            with_data: opts.with_data,
76            group_by_transaction: None,
77        }
78    }
79}
80
81#[derive(Serialize, Deserialize, Clone, Debug)]
82#[serde(rename_all = "snake_case")]
83pub enum ScriptType {
84    Lock,
85    Type,
86}
87impl From<PrimaryScriptType> for ScriptType {
88    fn from(t: PrimaryScriptType) -> ScriptType {
89        match t {
90            PrimaryScriptType::Lock => ScriptType::Lock,
91            PrimaryScriptType::Type => ScriptType::Type,
92        }
93    }
94}
95
96#[derive(Serialize, Deserialize, Clone, Debug)]
97#[serde(rename_all = "snake_case")]
98pub enum Order {
99    Desc,
100    Asc,
101}
102
103#[derive(Serialize, Deserialize, Clone, Debug)]
104pub struct Tip {
105    pub block_hash: H256,
106    pub block_number: BlockNumber,
107}
108
109#[derive(Serialize, Deserialize, Clone, Debug)]
110pub struct CellsCapacity {
111    pub capacity: Capacity,
112    pub block_hash: H256,
113    pub block_number: BlockNumber,
114}
115
116#[derive(Serialize, Deserialize, Clone, Debug)]
117pub struct Cell {
118    pub output: CellOutput,
119    pub output_data: Option<JsonBytes>,
120    pub out_point: OutPoint,
121    pub block_number: BlockNumber,
122    pub tx_index: Uint32,
123}
124impl From<Cell> for LiveCell {
125    fn from(cell: Cell) -> LiveCell {
126        LiveCell {
127            output: cell.output.into(),
128            output_data: cell
129                .output_data
130                .map(|data| data.into_bytes())
131                .unwrap_or_default(),
132            out_point: cell.out_point.into(),
133            block_number: cell.block_number.value(),
134            tx_index: cell.tx_index.value(),
135        }
136    }
137}
138
139#[derive(Serialize, Deserialize, Clone, Debug)]
140#[serde(untagged)]
141pub enum Tx {
142    Ungrouped(TxWithCell),
143    Grouped(TxWithCells),
144}
145
146impl Tx {
147    pub fn tx_hash(&self) -> H256 {
148        match self {
149            Tx::Ungrouped(tx) => tx.tx_hash.clone(),
150            Tx::Grouped(tx) => tx.tx_hash.clone(),
151        }
152    }
153}
154
155#[derive(Serialize, Deserialize, Clone, Debug)]
156pub struct TxWithCell {
157    pub tx_hash: H256,
158    pub block_number: BlockNumber,
159    pub tx_index: Uint32,
160    pub io_index: Uint32,
161    pub io_type: CellType,
162}
163
164#[derive(Serialize, Deserialize, Clone, Debug)]
165pub struct TxWithCells {
166    pub tx_hash: H256,
167    pub block_number: BlockNumber,
168    pub tx_index: Uint32,
169    pub cells: Vec<(CellType, Uint32)>,
170}
171
172#[derive(Serialize, Deserialize, Clone, Debug)]
173#[serde(rename_all = "snake_case")]
174pub enum CellType {
175    Input,
176    Output,
177}
178
179#[derive(Serialize, Deserialize, Clone, Debug)]
180#[serde(rename_all = "snake_case")]
181pub enum IOType {
182    Input,
183    Output,
184}
185
186#[derive(Serialize, Deserialize)]
187pub struct Pagination<T> {
188    pub objects: Vec<T>,
189    pub last_cursor: JsonBytes,
190}
191#[cfg(not(target_arch = "wasm32"))]
192crate::jsonrpc!(pub struct IndexerRpcClient {
193    pub fn get_indexer_tip(&self) -> Option<Tip>;
194    pub fn get_cells(&self, search_key: SearchKey, order: Order, limit: Uint32, after: Option<JsonBytes>) -> Pagination<Cell>;
195    pub fn get_transactions(&self, search_key: SearchKey, order: Order, limit: Uint32, after: Option<JsonBytes>) -> Pagination<Tx>;
196    pub fn get_cells_capacity(&self, search_key: SearchKey) -> Option<CellsCapacity>;
197});
198
199crate::jsonrpc_async!(pub struct IndexerRpcAsyncClient {
200    pub fn get_indexer_tip(&self) -> Option<Tip>;
201    pub fn get_cells(&self, search_key: SearchKey, order: Order, limit: Uint32, after: Option<JsonBytes>) -> Pagination<Cell>;
202    pub fn get_transactions(&self, search_key: SearchKey, order: Order, limit: Uint32, after: Option<JsonBytes>) -> Pagination<Tx>;
203    pub fn get_cells_capacity(&self, search_key: SearchKey) -> Option<CellsCapacity>;
204});
205#[cfg(not(target_arch = "wasm32"))]
206impl From<&IndexerRpcClient> for IndexerRpcAsyncClient {
207    fn from(value: &IndexerRpcClient) -> Self {
208        Self {
209            client: value.client.clone(),
210            id: 0.into(),
211        }
212    }
213}