Skip to content

Commit f3f8626

Browse files
author
Chuankai Liu
authored
Merge pull request #55 from liuck8080/exact_search_mode
feat: 🎸 support ckb indexer exact search mode
2 parents acc7426 + f3a9f78 commit f3f8626

File tree

6 files changed

+322
-3
lines changed

6 files changed

+322
-3
lines changed

CHANGELOG.md

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
1-
# 2.4.1
1+
# 2.5.0
2+
* Support indexer `exact` search mode.
23
* Add `get_block_with_cycles` and `get_block_by_number_with_cycles` to support `get_block` and `get_block_by_number` with parameter `with_cycles`.
34

45
# 2.4.0

src/rpc/ckb.rs

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,9 @@ use ckb_jsonrpc_types::{
77
};
88
use ckb_types::{core::Cycle, H256};
99

10-
use super::ResponseFormatGetter;
10+
use super::{ckb_indexer::CellsCapacity, ResponseFormatGetter};
11+
12+
pub use super::ckb_indexer::{Cell, Order, Pagination, SearchKey, Tip, Tx};
1113

1214
crate::jsonrpc!(pub struct CkbRpcClient {
1315
// Chain
@@ -35,6 +37,12 @@ crate::jsonrpc!(pub struct CkbRpcClient {
3537
pub fn estimate_cycles(&mut self, tx: Transaction)-> EstimateCycles;
3638
pub fn get_fee_rate_statics(&mut self, tartet:Option<Uint64>)->FeeRateStatics;
3739

40+
// Indexer
41+
pub fn get_indexer_tip(&mut self) -> Option<Tip>;
42+
pub fn get_cells(&mut self, search_key: SearchKey, order: Order, limit: Uint32, after: Option<JsonBytes>) -> Pagination<Cell>;
43+
pub fn get_transactions(&mut self, search_key: SearchKey, order: Order, limit: Uint32, after: Option<JsonBytes>) -> Pagination<Tx>;
44+
pub fn get_cells_capacity(&mut self, search_key: SearchKey) -> Option<CellsCapacity>;
45+
3846
// Net
3947
pub fn get_banned_addresses(&mut self) -> Vec<BannedAddr>;
4048
pub fn get_peers(&mut self) -> Vec<RemoteNode>;

src/rpc/ckb_indexer.rs

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,11 +12,27 @@ use crate::traits::{CellQueryOptions, LiveCell, PrimaryScriptType, ValueRangeOpt
1212
pub struct SearchKey {
1313
pub script: Script,
1414
pub script_type: ScriptType,
15+
pub script_search_mode: Option<ScriptSearchMode>,
1516
pub filter: Option<SearchKeyFilter>,
1617
pub with_data: Option<bool>,
1718
pub group_by_transaction: Option<bool>,
1819
}
1920

21+
#[derive(Serialize, Deserialize, Clone, Debug, Eq, PartialEq, Hash)]
22+
#[serde(rename_all = "snake_case")]
23+
pub enum ScriptSearchMode {
24+
// search script with prefix
25+
Prefix,
26+
// search script with exact match
27+
Exact,
28+
}
29+
30+
impl Default for ScriptSearchMode {
31+
fn default() -> Self {
32+
Self::Prefix
33+
}
34+
}
35+
2036
#[derive(Serialize, Deserialize, Default, Clone, Debug)]
2137
pub struct SearchKeyFilter {
2238
pub script: Option<Script>,
@@ -48,6 +64,7 @@ impl From<CellQueryOptions> for SearchKey {
4864
SearchKey {
4965
script: opts.primary_script.into(),
5066
script_type: opts.primary_type.into(),
67+
script_search_mode: opts.script_search_mode,
5168
filter,
5269
with_data: opts.with_data,
5370
group_by_transaction: None,

src/tests/ckb_indexer_rpc.rs

Lines changed: 290 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,290 @@
1+
use crate::{
2+
rpc::{
3+
ckb_indexer::{Order, ScriptSearchMode, SearchKey},
4+
CkbRpcClient,
5+
},
6+
traits::{CellQueryOptions, ValueRangeOption},
7+
};
8+
use ckb_types::{core::ScriptHashType, h256, prelude::*, H256};
9+
// use serde_json;
10+
11+
const TEST_CKB_RPC_URL: &str = "https://testnet.ckb.dev";
12+
13+
const CODE_HASH: H256 = h256!("0x00000000000000000000000000000000000000000000000000545950455f4944");
14+
// 8536c9d5d908bd89fc70099e4284870708b6632356aad98734fcf43f6f71c304
15+
const ARGS: [u8; 32] = [
16+
0x85, 0x36, 0xc9, 0xd5, 0xd9, 0x08, 0xbd, 0x89, 0xfc, 0x70, 0x09, 0x9e, 0x42, 0x84, 0x87, 0x07,
17+
0x08, 0xb6, 0x63, 0x23, 0x56, 0xaa, 0xd9, 0x87, 0x34, 0xfc, 0xf4, 0x3f, 0x6f, 0x71, 0xc3, 0x04,
18+
];
19+
#[test]
20+
fn test_get_indexer_tip() {
21+
let mut ckb_client = CkbRpcClient::new(TEST_CKB_RPC_URL);
22+
let indexer_tip = ckb_client.get_indexer_tip().unwrap().unwrap();
23+
let tip_block_number = ckb_client.get_tip_block_number().unwrap().value();
24+
assert!(indexer_tip.block_number.value() - tip_block_number <= 1);
25+
}
26+
27+
#[test]
28+
fn test_cells_search_mode_default_partitial() {
29+
let mut ckb_client = CkbRpcClient::new(TEST_CKB_RPC_URL);
30+
31+
let block_range = Some(ValueRangeOption::new(0, 1));
32+
// default with partitial args
33+
let script = ckb_types::packed::Script::new_builder()
34+
.code_hash(CODE_HASH.pack())
35+
.hash_type(ScriptHashType::Type.into())
36+
.args(ARGS[0..2].pack())
37+
.build();
38+
39+
let mut query = CellQueryOptions::new(script, crate::traits::PrimaryScriptType::Type);
40+
query.block_range = block_range;
41+
query.script_search_mode = None;
42+
query.min_total_capacity = u64::MAX;
43+
44+
let search_key = SearchKey::from(query);
45+
let page = ckb_client
46+
.get_cells(search_key, Order::Desc, 10u32.into(), None)
47+
.unwrap();
48+
assert_eq!(page.objects.len(), 1);
49+
}
50+
#[test]
51+
fn test_cells_search_mode_prefix_partitial() {
52+
let mut ckb_client = CkbRpcClient::new(TEST_CKB_RPC_URL);
53+
54+
let block_range = Some(ValueRangeOption::new(0, 1));
55+
// prefix with partitial args
56+
let script = ckb_types::packed::Script::new_builder()
57+
.code_hash(CODE_HASH.pack())
58+
.hash_type(ScriptHashType::Type.into())
59+
.args(ARGS[0..2].pack())
60+
.build();
61+
62+
let mut query = CellQueryOptions::new(script, crate::traits::PrimaryScriptType::Type);
63+
query.block_range = block_range;
64+
query.script_search_mode = Some(ScriptSearchMode::Prefix);
65+
query.min_total_capacity = u64::MAX;
66+
67+
let search_key = SearchKey::from(query);
68+
let page = ckb_client
69+
.get_cells(search_key, Order::Desc, 10u32.into(), None)
70+
.unwrap();
71+
assert_eq!(page.objects.len(), 1);
72+
}
73+
#[test]
74+
fn test_cells_search_mode_exact_partitial() {
75+
let mut ckb_client = CkbRpcClient::new(TEST_CKB_RPC_URL);
76+
77+
let block_range = Some(ValueRangeOption::new(0, 1));
78+
let script = ckb_types::packed::Script::new_builder()
79+
.code_hash(CODE_HASH.pack())
80+
.hash_type(ScriptHashType::Type.into())
81+
.args(ARGS[0..2].pack())
82+
.build();
83+
// exact with partitial args
84+
let mut query = CellQueryOptions::new(script, crate::traits::PrimaryScriptType::Type);
85+
query.script_search_mode = Some(ScriptSearchMode::Exact);
86+
query.block_range = block_range;
87+
query.min_total_capacity = u64::MAX;
88+
89+
let search_key = SearchKey::from(query);
90+
let page = ckb_client
91+
.get_cells(search_key, Order::Desc, 10u32.into(), None)
92+
.unwrap();
93+
assert_eq!(0, page.objects.len());
94+
}
95+
#[test]
96+
fn test_cells_search_mode_exact() {
97+
let mut ckb_client = CkbRpcClient::new(TEST_CKB_RPC_URL);
98+
99+
let block_range = Some(ValueRangeOption::new(0, 1));
100+
let script = ckb_types::packed::Script::new_builder()
101+
.code_hash(CODE_HASH.pack())
102+
.hash_type(ScriptHashType::Type.into())
103+
.args(ARGS[..].pack())
104+
.build();
105+
106+
let mut query = CellQueryOptions::new(script, crate::traits::PrimaryScriptType::Type);
107+
query.script_search_mode = Some(ScriptSearchMode::Exact);
108+
query.block_range = block_range;
109+
query.min_total_capacity = u64::MAX;
110+
111+
let search_key = SearchKey::from(query);
112+
let page = ckb_client
113+
.get_cells(search_key, Order::Desc, 10u32.into(), None)
114+
.unwrap();
115+
assert_eq!(page.objects.len(), 1);
116+
}
117+
118+
#[test]
119+
fn test_get_transactions_search_mode_default() {
120+
let mut ckb_client = CkbRpcClient::new(TEST_CKB_RPC_URL);
121+
122+
let block_range = Some(ValueRangeOption::new(0, 1));
123+
let script = ckb_types::packed::Script::new_builder()
124+
.code_hash(CODE_HASH.pack())
125+
.hash_type(ScriptHashType::Type.into())
126+
.args(ARGS[0..2].pack())
127+
.build();
128+
129+
let mut query = CellQueryOptions::new(script, crate::traits::PrimaryScriptType::Type);
130+
query.block_range = block_range;
131+
query.script_search_mode = None;
132+
query.min_total_capacity = u64::MAX;
133+
134+
let search_key = SearchKey::from(query);
135+
let page = ckb_client
136+
.get_transactions(search_key, Order::Desc, 10u32.into(), None)
137+
.unwrap();
138+
assert_eq!(page.objects.len(), 1);
139+
}
140+
141+
#[test]
142+
fn test_get_transactions_search_mode_prefix_partial() {
143+
let mut ckb_client = CkbRpcClient::new(TEST_CKB_RPC_URL);
144+
145+
let block_range = Some(ValueRangeOption::new(0, 1));
146+
let script = ckb_types::packed::Script::new_builder()
147+
.code_hash(CODE_HASH.pack())
148+
.hash_type(ScriptHashType::Type.into())
149+
.args(ARGS[0..2].pack())
150+
.build();
151+
152+
let mut query = CellQueryOptions::new(script, crate::traits::PrimaryScriptType::Type);
153+
query.block_range = block_range;
154+
query.script_search_mode = Some(ScriptSearchMode::Prefix);
155+
query.min_total_capacity = u64::MAX;
156+
157+
let search_key = SearchKey::from(query);
158+
let page = ckb_client
159+
.get_transactions(search_key, Order::Desc, 10u32.into(), None)
160+
.unwrap();
161+
assert_eq!(page.objects.len(), 1);
162+
}
163+
#[test]
164+
fn test_get_transactions_search_mode_exact_partitial() {
165+
let mut ckb_client = CkbRpcClient::new(TEST_CKB_RPC_URL);
166+
167+
let block_range = Some(ValueRangeOption::new(0, 1));
168+
let script = ckb_types::packed::Script::new_builder()
169+
.code_hash(CODE_HASH.pack())
170+
.hash_type(ScriptHashType::Type.into())
171+
.args(ARGS[0..2].pack())
172+
.build();
173+
174+
let mut query = CellQueryOptions::new(script, crate::traits::PrimaryScriptType::Type);
175+
query.script_search_mode = Some(ScriptSearchMode::Exact);
176+
query.block_range = block_range;
177+
query.min_total_capacity = u64::MAX;
178+
179+
let search_key = SearchKey::from(query);
180+
let page = ckb_client
181+
.get_transactions(search_key, Order::Desc, 10u32.into(), None)
182+
.unwrap();
183+
assert_eq!(0, page.objects.len());
184+
}
185+
#[test]
186+
fn test_get_transactions_search_mode_exact_full() {
187+
let mut ckb_client = CkbRpcClient::new(TEST_CKB_RPC_URL);
188+
189+
let block_range = Some(ValueRangeOption::new(0, 1));
190+
// exact search
191+
let script = ckb_types::packed::Script::new_builder()
192+
.code_hash(CODE_HASH.pack())
193+
.hash_type(ScriptHashType::Type.into())
194+
.args(ARGS[..].pack())
195+
.build();
196+
197+
let mut query = CellQueryOptions::new(script, crate::traits::PrimaryScriptType::Type);
198+
query.script_search_mode = Some(ScriptSearchMode::Exact);
199+
query.block_range = block_range;
200+
query.min_total_capacity = u64::MAX;
201+
202+
let search_key = SearchKey::from(query);
203+
let page = ckb_client
204+
.get_transactions(search_key, Order::Desc, 10u32.into(), None)
205+
.unwrap();
206+
assert_eq!(page.objects.len(), 1);
207+
}
208+
#[test]
209+
fn test_get_cells_capacity_search_mode_default() {
210+
let mut ckb_client = CkbRpcClient::new(TEST_CKB_RPC_URL);
211+
212+
let block_range = Some(ValueRangeOption::new(0, 1));
213+
let script = ckb_types::packed::Script::new_builder()
214+
.code_hash(CODE_HASH.pack())
215+
.hash_type(ScriptHashType::Type.into())
216+
.args(ARGS[0..2].pack())
217+
.build();
218+
219+
let mut query = CellQueryOptions::new(script, crate::traits::PrimaryScriptType::Type);
220+
query.block_range = block_range;
221+
query.script_search_mode = None;
222+
query.min_total_capacity = u64::MAX;
223+
224+
let search_key = SearchKey::from(query);
225+
let cells_capacity = ckb_client.get_cells_capacity(search_key).unwrap().unwrap();
226+
assert_eq!(cells_capacity.capacity.value(), 0x9184e72a000);
227+
}
228+
229+
#[test]
230+
fn test_get_cells_capacity_search_mode_prefix_partial() {
231+
let mut ckb_client = CkbRpcClient::new(TEST_CKB_RPC_URL);
232+
233+
let block_range = Some(ValueRangeOption::new(0, 1));
234+
let script = ckb_types::packed::Script::new_builder()
235+
.code_hash(CODE_HASH.pack())
236+
.hash_type(ScriptHashType::Type.into())
237+
.args(ARGS[0..2].pack())
238+
.build();
239+
240+
let mut query = CellQueryOptions::new(script, crate::traits::PrimaryScriptType::Type);
241+
query.block_range = block_range;
242+
query.script_search_mode = Some(ScriptSearchMode::Prefix);
243+
query.min_total_capacity = u64::MAX;
244+
245+
let search_key = SearchKey::from(query);
246+
let cells_capacity = ckb_client.get_cells_capacity(search_key).unwrap().unwrap();
247+
assert_eq!(cells_capacity.capacity.value(), 0x9184e72a000);
248+
}
249+
250+
#[test]
251+
fn test_get_cells_capacity_search_mode_exact_partital() {
252+
let mut ckb_client = CkbRpcClient::new(TEST_CKB_RPC_URL);
253+
254+
let block_range = Some(ValueRangeOption::new(0, 1));
255+
let script = ckb_types::packed::Script::new_builder()
256+
.code_hash(CODE_HASH.pack())
257+
.hash_type(ScriptHashType::Type.into())
258+
.args(ARGS[0..2].pack())
259+
.build();
260+
// exact with partitial args
261+
let mut query = CellQueryOptions::new(script, crate::traits::PrimaryScriptType::Type);
262+
query.script_search_mode = Some(ScriptSearchMode::Exact);
263+
query.block_range = block_range;
264+
query.min_total_capacity = u64::MAX;
265+
266+
let search_key = SearchKey::from(query);
267+
let cells_capacity = ckb_client.get_cells_capacity(search_key).unwrap().unwrap();
268+
assert_eq!(cells_capacity.capacity.value(), 0);
269+
}
270+
271+
#[test]
272+
fn test_get_cells_capacity_search_mode_exact() {
273+
let mut ckb_client = CkbRpcClient::new(TEST_CKB_RPC_URL);
274+
275+
let block_range = Some(ValueRangeOption::new(0, 1));
276+
let script = ckb_types::packed::Script::new_builder()
277+
.code_hash(CODE_HASH.pack())
278+
.hash_type(ScriptHashType::Type.into())
279+
.args(ARGS[..].pack())
280+
.build();
281+
282+
let mut query = CellQueryOptions::new(script, crate::traits::PrimaryScriptType::Type);
283+
query.script_search_mode = Some(ScriptSearchMode::Exact);
284+
query.block_range = block_range;
285+
query.min_total_capacity = u64::MAX;
286+
287+
let search_key = SearchKey::from(query);
288+
let cells_capacity = ckb_client.get_cells_capacity(search_key).unwrap().unwrap();
289+
assert_eq!(cells_capacity.capacity.value(), 0x9184e72a000);
290+
}

src/tests/mod.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1085,6 +1085,7 @@ fn test_udt_transfer() {
10851085
ctx.verify(tx, FEE_RATE).unwrap();
10861086
}
10871087

1088+
pub mod ckb_indexer_rpc;
10881089
pub mod ckb_rpc;
10891090
pub mod cycle;
10901091
pub mod omni_lock;

src/traits/mod.rs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ use ckb_types::{
3434
prelude::*,
3535
};
3636

37-
use crate::util::is_mature;
37+
use crate::{rpc::ckb_indexer::ScriptSearchMode, util::is_mature};
3838

3939
/// Signer errors
4040
#[derive(Error, Debug)]
@@ -248,6 +248,7 @@ pub struct CellQueryOptions {
248248
/// satisfied will stop collecting. The default value is 1 shannon means
249249
/// collect only one cell at most.
250250
pub min_total_capacity: u64,
251+
pub script_search_mode: Option<ScriptSearchMode>,
251252
}
252253
impl CellQueryOptions {
253254
pub fn new(primary_script: Script, primary_type: PrimaryScriptType) -> CellQueryOptions {
@@ -264,6 +265,7 @@ impl CellQueryOptions {
264265
limit: None,
265266
maturity: MaturityOption::Mature,
266267
min_total_capacity: 1,
268+
script_search_mode: None,
267269
}
268270
}
269271
pub fn new_lock(primary_script: Script) -> CellQueryOptions {

0 commit comments

Comments
 (0)