ckb_indexer_sync/
custom_filters.rs1use ckb_types::{
2 core::BlockView,
3 packed::{Bytes, CellOutput},
4};
5use numext_fixed_uint::U256;
6use rhai::{AST, Engine, EvalAltResult, Scope};
7
8pub struct CustomFilters {
12 engine: Engine,
13 block_filter: Option<AST>,
14 cell_filter: Option<AST>,
15}
16
17impl Clone for CustomFilters {
18 fn clone(&self) -> Self {
19 CustomFilters::from_filters(self.block_filter.clone(), self.cell_filter.clone())
20 }
21}
22
23fn to_uint(s: &str) -> Result<U256, Box<EvalAltResult>> {
24 match &s[..2] {
25 "0b" => U256::from_bin_str(&s[2..]),
26 "0o" => U256::from_oct_str(&s[2..]),
27 "0x" => U256::from_hex_str(&s[2..]),
28 _ => U256::from_dec_str(s),
29 }
30 .map_err(|e| e.to_string().into())
31}
32
33macro_rules! register_ops {
34 ($engine:ident $(, $op:tt)+ $(,)?) => {
35 $(
36 $engine.register_fn(stringify!($op), |a: U256, b: U256| a $op b);
37 )+
38 };
39}
40
41impl CustomFilters {
42 pub fn new(block_filter_str: Option<&str>, cell_filter_str: Option<&str>) -> Self {
44 let mut engine = Engine::new();
45 engine.register_fn("to_uint", to_uint);
46 register_ops!(engine, +, -, *, /, %, ==, !=, <, <=, >, >=);
47
48 let block_filter = block_filter_str.map(|block_filter| {
49 engine
50 .compile(block_filter)
51 .expect("compile block_filter should be ok")
52 });
53 let cell_filter = cell_filter_str.map(|cell_filter| {
54 engine
55 .compile(cell_filter)
56 .expect("compile cell_filter should be ok")
57 });
58
59 Self {
60 engine,
61 block_filter,
62 cell_filter,
63 }
64 }
65
66 pub fn from_filters(block_filter: Option<AST>, cell_filter: Option<AST>) -> Self {
68 let mut engine = Engine::new();
69 engine.register_fn("to_uint", to_uint);
70 register_ops!(engine, +, -, *, /, %, ==, !=, <, <=, >, >=);
71 Self {
72 engine,
73 block_filter,
74 cell_filter,
75 }
76 }
77
78 pub fn is_block_filter_match(&self, block: &BlockView) -> bool {
80 self.block_filter
81 .as_ref()
82 .map(|block_filter| {
83 let json_block: ckb_jsonrpc_types::BlockView = block.clone().into();
84 let parsed_block = self
85 .engine
86 .parse_json(serde_json::to_string(&json_block).unwrap(), true)
87 .unwrap();
88 let mut scope = Scope::new();
89 scope.push("block", parsed_block);
90 self.engine
91 .eval_ast_with_scope(&mut scope, block_filter)
92 .expect("eval block_filter should be ok")
93 })
94 .unwrap_or(true)
95 }
96
97 pub fn is_cell_filter_match(&self, output: &CellOutput, output_data: &Bytes) -> bool {
99 self.cell_filter
100 .as_ref()
101 .map(|cell_filter| {
102 let json_output: ckb_jsonrpc_types::CellOutput = output.clone().into();
103 let parsed_output = self
104 .engine
105 .parse_json(serde_json::to_string(&json_output).unwrap(), true)
106 .unwrap();
107 let mut scope = Scope::new();
108 scope.push("output", parsed_output);
109 scope.push("output_data", format!("{output_data:#x}"));
110 self.engine
111 .eval_ast_with_scope(&mut scope, cell_filter)
112 .expect("eval cell_filter should be ok")
113 })
114 .unwrap_or(true)
115 }
116
117 pub fn is_cell_filter_enabled(&self) -> bool {
119 self.cell_filter.is_some()
120 }
121}