1use std::collections::HashMap;
2use std::sync::Arc;
3use std::time::Duration;
4
5use anyhow::anyhow;
6use ckb_crypto::secp::Pubkey;
7use lru::LruCache;
8use thiserror::Error;
9use tokio::sync::Mutex;
10
11use ckb_hash::blake2b_256;
12use ckb_jsonrpc_types::{self as json_types, Either};
13use ckb_types::{
14 bytes::Bytes,
15 core::{BlockView, DepType, HeaderView, TransactionView},
16 packed::{Byte32, CellDep, CellOutput, OutPoint, Script, Transaction, TransactionReader},
17 prelude::*,
18 H160,
19};
20
21use super::{
22 offchain_impls::CollectResult, OffchainCellCollector, OffchainCellDepResolver,
23 OffchainTransactionDependencyProvider,
24};
25use crate::{constants::MULTISIG_LEGACY_GROUP_OUTPUT_LOC, types::ScriptId};
26use crate::{constants::MULTISIG_LEGACY_OUTPUT_LOC, SECP256K1};
27use crate::{
28 constants::{MultisigScript, GENESIS_BLOCK_HASH_MAINNET, GENESIS_BLOCK_HASH_TESTNET},
29 rpc::ckb_indexer::{Order, SearchKey, Tip},
30};
31use crate::{
32 constants::{
33 DAO_OUTPUT_LOC, DAO_TYPE_HASH, SIGHASH_GROUP_OUTPUT_LOC, SIGHASH_OUTPUT_LOC,
34 SIGHASH_TYPE_HASH,
35 },
36 util::keccak160,
37};
38use crate::{
39 rpc::{CkbRpcAsyncClient, IndexerRpcAsyncClient},
40 traits::{
41 CellCollector, CellCollectorError, CellDepResolver, CellQueryOptions, HeaderDepResolver,
42 LiveCell, QueryOrder, Signer, SignerError, TransactionDependencyError,
43 TransactionDependencyProvider,
44 },
45};
46use crate::{
47 util::{get_max_mature_number_async, serialize_signature, zeroize_privkey},
48 NetworkInfo,
49};
50use ckb_resource::{
51 CODE_HASH_DAO, CODE_HASH_SECP256K1_BLAKE160_MULTISIG_ALL,
52 CODE_HASH_SECP256K1_BLAKE160_SIGHASH_ALL,
53};
54
55#[derive(Error, Debug)]
57pub enum ParseGenesisInfoError {
58 #[error("invalid block number, expected: 0, got: `{0}`")]
59 InvalidBlockNumber(u64),
60 #[error("data not found: `{0}`")]
61 DataHashNotFound(String),
62 #[error("type not found: `{0}`")]
63 TypeHashNotFound(String),
64}
65
66#[derive(Clone)]
68pub struct DefaultCellDepResolver {
69 offchain: OffchainCellDepResolver,
70}
71impl DefaultCellDepResolver {
72 #[cfg(not(target_arch = "wasm32"))]
76 pub fn from_genesis(
77 genesis_block: &BlockView,
78 ) -> Result<DefaultCellDepResolver, ParseGenesisInfoError> {
79 crate::rpc::block_on(Self::from_genesis_async(genesis_block))
80 }
81 pub async fn from_genesis_async(
85 genesis_block: &BlockView,
86 ) -> Result<DefaultCellDepResolver, ParseGenesisInfoError> {
87 let header = genesis_block.header();
88 if header.number() != 0 {
89 return Err(ParseGenesisInfoError::InvalidBlockNumber(header.number()));
90 }
91 let mut sighash_type_hash = None;
92 let mut multisig_legacy_type_hash = None;
93 let mut dao_type_hash = None;
94 let out_points = genesis_block
95 .transactions()
96 .iter()
97 .enumerate()
98 .map(|(tx_index, tx)| {
99 tx.outputs()
100 .into_iter()
101 .zip(tx.outputs_data())
102 .enumerate()
103 .map(|(index, (output, data))| {
104 if tx_index == SIGHASH_OUTPUT_LOC.0 && index == SIGHASH_OUTPUT_LOC.1 {
105 sighash_type_hash = output
106 .type_()
107 .to_opt()
108 .map(|script| script.calc_script_hash());
109 let data_hash = CellOutput::calc_data_hash(&data.raw_data());
110 if data_hash != CODE_HASH_SECP256K1_BLAKE160_SIGHASH_ALL.pack() {
111 log::error!(
112 "System sighash script code hash error! found: {}, expected: {}",
113 data_hash,
114 CODE_HASH_SECP256K1_BLAKE160_SIGHASH_ALL,
115 );
116 }
117 }
118 if tx_index == MULTISIG_LEGACY_OUTPUT_LOC.0 && index == MULTISIG_LEGACY_OUTPUT_LOC.1 {
119 multisig_legacy_type_hash = output
120 .type_()
121 .to_opt()
122 .map(|script| script.calc_script_hash());
123 let data_hash = CellOutput::calc_data_hash(&data.raw_data());
124 if data_hash != CODE_HASH_SECP256K1_BLAKE160_MULTISIG_ALL.pack() {
125 log::error!(
126 "System multisig script code hash error! found: {}, expected: {}",
127 data_hash,
128 CODE_HASH_SECP256K1_BLAKE160_MULTISIG_ALL,
129 );
130 }
131 }
132 if tx_index == DAO_OUTPUT_LOC.0 && index == DAO_OUTPUT_LOC.1 {
133 dao_type_hash = output
134 .type_()
135 .to_opt()
136 .map(|script| script.calc_script_hash());
137 let data_hash = CellOutput::calc_data_hash(&data.raw_data());
138 if data_hash != CODE_HASH_DAO.pack() {
139 log::error!(
140 "System dao script code hash error! found: {}, expected: {}",
141 data_hash,
142 CODE_HASH_DAO,
143 );
144 }
145 }
146 OutPoint::new(tx.hash(), index as u32)
147 })
148 .collect::<Vec<_>>()
149 })
150 .collect::<Vec<_>>();
151
152 let sighash_type_hash = sighash_type_hash
153 .ok_or_else(|| "No type hash(sighash) found in txs[0][1]".to_owned())
154 .map_err(ParseGenesisInfoError::TypeHashNotFound)?;
155 let dao_type_hash = dao_type_hash
156 .ok_or_else(|| "No type hash(dao) found in txs[0][2]".to_owned())
157 .map_err(ParseGenesisInfoError::TypeHashNotFound)?;
158
159 let sighash_dep = CellDep::new_builder()
160 .out_point(out_points[SIGHASH_GROUP_OUTPUT_LOC.0][SIGHASH_GROUP_OUTPUT_LOC.1].clone())
161 .dep_type(DepType::DepGroup)
162 .build();
163
164 let multisig_legacy_dep = CellDep::new_builder()
165 .out_point(
166 out_points[MULTISIG_LEGACY_GROUP_OUTPUT_LOC.0][MULTISIG_LEGACY_GROUP_OUTPUT_LOC.1]
167 .clone(),
168 )
169 .dep_type(DepType::DepGroup)
170 .build();
171
172 let dao_dep = CellDep::new_builder()
173 .out_point(out_points[DAO_OUTPUT_LOC.0][DAO_OUTPUT_LOC.1].clone())
174 .build();
175
176 let mut items = HashMap::default();
177 items.insert(
178 ScriptId::new_type(sighash_type_hash.unpack()),
179 (sighash_dep, "Secp256k1 blake160 sighash all".to_string()),
180 );
181
182 {
183 let network_info: NetworkInfo =
184 if genesis_block.hash().eq(&GENESIS_BLOCK_HASH_MAINNET.pack()) {
185 NetworkInfo::mainnet()
186 } else if genesis_block.hash().eq(&GENESIS_BLOCK_HASH_TESTNET.pack()) {
187 NetworkInfo::testnet()
188 } else {
189 NetworkInfo::devnet()
190 };
191
192 if let Some((v2_dep_hash, v2_dep_index)) = MultisigScript::V2
193 .dep_group_async(network_info, Some(genesis_block.to_owned()))
194 .await
195 {
196 let multisig_v2_dep = CellDep::new_builder()
197 .out_point(OutPoint::new(v2_dep_hash.pack(), v2_dep_index))
198 .dep_type(DepType::DepGroup)
199 .build();
200
201 items.insert(
202 MultisigScript::V2.script_id(),
203 (
204 multisig_v2_dep,
205 "Secp256k1 blake160 multisig(v2) all".to_string(),
206 ),
207 );
208 }
209 }
210
211 items.insert(
212 MultisigScript::Legacy.script_id(),
213 (
214 multisig_legacy_dep,
215 "Secp256k1 blake160 multisig(legacy) all".to_string(),
216 ),
217 );
218 items.insert(
219 ScriptId::new_type(dao_type_hash.unpack()),
220 (dao_dep, "Nervos DAO".to_string()),
221 );
222 let offchain = OffchainCellDepResolver { items };
223 Ok(DefaultCellDepResolver { offchain })
224 }
225
226 pub fn insert(
227 &mut self,
228 script_id: ScriptId,
229 cell_dep: CellDep,
230 name: String,
231 ) -> Option<(CellDep, String)> {
232 self.offchain.items.insert(script_id, (cell_dep, name))
233 }
234 pub fn remove(&mut self, script_id: &ScriptId) -> Option<(CellDep, String)> {
235 self.offchain.items.remove(script_id)
236 }
237 pub fn contains(&self, script_id: &ScriptId) -> bool {
238 self.offchain.items.contains_key(script_id)
239 }
240 pub fn get(&self, script_id: &ScriptId) -> Option<&(CellDep, String)> {
241 self.offchain.items.get(script_id)
242 }
243 pub fn sighash_dep(&self) -> Option<&(CellDep, String)> {
244 self.get(&ScriptId::new_type(SIGHASH_TYPE_HASH))
245 }
246 pub fn multisig_dep(&self, multisig_script: MultisigScript) -> Option<&(CellDep, String)> {
249 self.get(&multisig_script.script_id())
250 }
251 pub fn dao_dep(&self) -> Option<&(CellDep, String)> {
252 self.get(&ScriptId::new_type(DAO_TYPE_HASH))
253 }
254}
255
256impl CellDepResolver for DefaultCellDepResolver {
257 fn resolve(&self, script: &Script) -> Option<CellDep> {
258 self.offchain.resolve(script)
259 }
260}
261
262pub struct DefaultHeaderDepResolver {
264 pub ckb_client: CkbRpcAsyncClient,
265}
266impl DefaultHeaderDepResolver {
267 pub fn new(ckb_client: &str) -> DefaultHeaderDepResolver {
268 let ckb_client = CkbRpcAsyncClient::new(ckb_client);
269 DefaultHeaderDepResolver { ckb_client }
270 }
271}
272
273#[cfg_attr(target_arch="wasm32", async_trait::async_trait(?Send))]
274#[cfg_attr(not(target_arch = "wasm32"), async_trait::async_trait)]
275impl HeaderDepResolver for DefaultHeaderDepResolver {
276 async fn resolve_by_tx_async(
277 &self,
278 tx_hash: &Byte32,
279 ) -> Result<Option<HeaderView>, anyhow::Error> {
280 if let Some(block_hash) = self
281 .ckb_client
282 .get_transaction(tx_hash.unpack())
283 .await
284 .map_err(|e| anyhow!(e))?
285 .and_then(|tx_with_status| tx_with_status.tx_status.block_hash)
286 {
287 Ok(self
288 .ckb_client
289 .get_header(block_hash)
290 .await
291 .map_err(Box::new)?
292 .map(Into::into))
293 } else {
294 Ok(None)
295 }
296 }
297 async fn resolve_by_number_async(
298 &self,
299 number: u64,
300 ) -> Result<Option<HeaderView>, anyhow::Error> {
301 Ok(self
302 .ckb_client
303 .get_header_by_number(number.into())
304 .await
305 .map_err(|e| anyhow!(e))?
306 .map(Into::into))
307 }
308}
309
310#[derive(Clone)]
312pub struct DefaultCellCollector {
313 pub indexer_client: IndexerRpcAsyncClient,
314 pub ckb_client: CkbRpcAsyncClient,
315 pub offchain: OffchainCellCollector,
316 pub acceptable_indexer_leftbehind: u64,
317}
318
319impl DefaultCellCollector {
320 pub fn new(ckb_client: &str) -> DefaultCellCollector {
321 let indexer_client = IndexerRpcAsyncClient::new(ckb_client);
322 let ckb_client = CkbRpcAsyncClient::new(ckb_client);
323 DefaultCellCollector {
324 indexer_client,
325 ckb_client,
326 offchain: OffchainCellCollector::default(),
327 acceptable_indexer_leftbehind: 1,
328 }
329 }
330
331 #[cfg(not(target_arch = "wasm32"))]
332 pub fn new_with_timeout(
333 ckb_client: &str,
334 timeout: std::time::Duration,
335 ) -> Result<Self, anyhow::Error> {
336 let indexer_client =
337 IndexerRpcAsyncClient::with_builder(ckb_client, |builder| builder.timeout(timeout))?;
338 let ckb_client =
339 CkbRpcAsyncClient::with_builder(ckb_client, |builder| builder.timeout(timeout))?;
340 Ok(DefaultCellCollector {
341 indexer_client,
342 ckb_client,
343 offchain: OffchainCellCollector::default(),
344 acceptable_indexer_leftbehind: 1,
345 })
346 }
347
348 pub fn acceptable_indexer_leftbehind(&self) -> u64 {
350 self.acceptable_indexer_leftbehind
351 }
352 pub fn set_acceptable_indexer_leftbehind(&mut self, value: u64) {
354 self.acceptable_indexer_leftbehind = value;
355 }
356 #[cfg(not(target_arch = "wasm32"))]
357 pub fn check_ckb_chain(&mut self) -> Result<(), CellCollectorError> {
359 crate::rpc::block_on(self.check_ckb_chain_async())
360 }
361 pub async fn check_ckb_chain_async(&mut self) -> Result<(), CellCollectorError> {
363 let tip_number = self
364 .ckb_client
365 .get_tip_block_number()
366 .await
367 .map_err(|err| CellCollectorError::Internal(err.into()))?;
368
369 for _ in 0..100 {
370 match self
371 .indexer_client
372 .get_indexer_tip()
373 .await
374 .map_err(|err| CellCollectorError::Internal(err.into()))?
375 {
376 Some(Tip { block_number, .. }) => {
377 if tip_number.value()
378 > block_number.value() + self.acceptable_indexer_leftbehind
379 {
380 #[cfg(not(target_arch = "wasm32"))]
381 tokio::time::sleep(Duration::from_millis(50)).await;
382 #[cfg(target_arch = "wasm32")]
383 tokio_with_wasm::time::sleep(Duration::from_millis(50)).await;
384 } else {
385 return Ok(());
386 }
387 }
388 None => {
389 return Err(CellCollectorError::Other(anyhow!(
390 "ckb-indexer server not synced"
391 )));
392 }
393 }
394 }
395 Err(CellCollectorError::Other(anyhow!(
396 "ckb-indexer server inconsistent with currently connected ckb node or not synced!"
397 )))
398 }
399}
400
401#[cfg_attr(target_arch="wasm32", async_trait::async_trait(?Send))]
402#[cfg_attr(not(target_arch = "wasm32"), async_trait::async_trait)]
403impl CellCollector for DefaultCellCollector {
404 async fn collect_live_cells_async(
405 &mut self,
406 query: &CellQueryOptions,
407 apply_changes: bool,
408 ) -> Result<(Vec<LiveCell>, u64), CellCollectorError> {
409 let max_mature_number = get_max_mature_number_async(&self.ckb_client)
410 .await
411 .map_err(|err| CellCollectorError::Internal(anyhow!(err)))?;
412 self.offchain.max_mature_number = max_mature_number;
413 let tip_num = self
414 .ckb_client
415 .get_tip_block_number()
416 .await
417 .map_err(|err| CellCollectorError::Internal(anyhow!(err)))?
418 .value();
419 let CollectResult {
420 cells,
421 rest_cells,
422 mut total_capacity,
423 } = self.offchain.collect(query, tip_num);
424 let mut cells: Vec<_> = cells.into_iter().map(|c| c.0).collect();
425 if total_capacity < query.min_total_capacity {
426 self.check_ckb_chain_async().await?;
427 let order = match query.order {
428 QueryOrder::Asc => Order::Asc,
429 QueryOrder::Desc => Order::Desc,
430 };
431 let mut ret_cells: HashMap<_, _> = cells
432 .into_iter()
433 .map(|c| (c.out_point.clone(), c))
434 .collect();
435 let locked_cells = self.offchain.locked_cells.clone();
436 let search_key = SearchKey::from(query.clone());
437 const MAX_LIMIT: u32 = 4096;
438 let mut limit: u32 = query.limit.unwrap_or(16);
439 let mut last_cursor: Option<json_types::JsonBytes> = None;
440 while total_capacity < query.min_total_capacity {
441 let page = self
442 .indexer_client
443 .get_cells(search_key.clone(), order.clone(), limit.into(), last_cursor)
444 .await
445 .map_err(|err| CellCollectorError::Internal(err.into()))?;
446 if page.objects.is_empty() {
447 break;
448 }
449 for cell in page.objects {
450 let live_cell = LiveCell::from(cell);
451 if !query.match_cell(&live_cell, max_mature_number)
452 || locked_cells.contains_key(&(
453 live_cell.out_point.tx_hash().unpack(),
454 live_cell.out_point.index().unpack(),
455 ))
456 {
457 continue;
458 }
459 let capacity: u64 = live_cell.output.capacity().unpack();
460 if ret_cells
462 .insert(live_cell.out_point.clone(), live_cell)
463 .is_none()
464 {
465 total_capacity += capacity;
466 }
467 if total_capacity >= query.min_total_capacity {
468 break;
469 }
470 }
471 last_cursor = Some(page.last_cursor);
472 if limit < MAX_LIMIT {
473 limit *= 2;
474 }
475 }
476 cells = ret_cells.into_values().collect();
477 }
478 if apply_changes {
479 self.offchain.live_cells = rest_cells;
480 for cell in &cells {
481 self.lock_cell(cell.out_point.clone(), tip_num)?;
482 }
483 }
484 Ok((cells, total_capacity))
485 }
486
487 fn lock_cell(
488 &mut self,
489 out_point: OutPoint,
490 tip_block_number: u64,
491 ) -> Result<(), CellCollectorError> {
492 self.offchain.lock_cell(out_point, tip_block_number)
493 }
494 fn apply_tx(
495 &mut self,
496 tx: Transaction,
497 tip_block_number: u64,
498 ) -> Result<(), CellCollectorError> {
499 self.offchain.apply_tx(tx, tip_block_number)
500 }
501 fn reset(&mut self) {
502 self.offchain.reset();
503 }
504}
505
506pub struct DefaultTxDepProviderInner {
507 pub rpc_client: CkbRpcAsyncClient,
508 tx_cache: LruCache<Byte32, TransactionView>,
509 cell_cache: LruCache<OutPoint, (CellOutput, Bytes)>,
510 header_cache: LruCache<Byte32, HeaderView>,
511 offchain_cache: OffchainTransactionDependencyProvider,
512}
513
514pub struct DefaultTransactionDependencyProvider {
516 pub inner: Arc<Mutex<DefaultTxDepProviderInner>>,
518}
519
520impl Clone for DefaultTransactionDependencyProvider {
521 fn clone(&self) -> DefaultTransactionDependencyProvider {
522 let inner = Arc::clone(&self.inner);
523 DefaultTransactionDependencyProvider { inner }
524 }
525}
526
527impl DefaultTransactionDependencyProvider {
528 pub fn new(url: &str, cache_capacity: usize) -> DefaultTransactionDependencyProvider {
532 let rpc_client = CkbRpcAsyncClient::new(url);
533 let inner = DefaultTxDepProviderInner {
534 rpc_client,
535 tx_cache: LruCache::new(cache_capacity),
536 cell_cache: LruCache::new(cache_capacity),
537 header_cache: LruCache::new(cache_capacity),
538 offchain_cache: OffchainTransactionDependencyProvider::new(),
539 };
540 DefaultTransactionDependencyProvider {
541 inner: Arc::new(Mutex::new(inner)),
542 }
543 }
544 #[cfg(not(target_arch = "wasm32"))]
545 pub fn apply_tx(
546 &mut self,
547 tx: Transaction,
548 tip_block_number: u64,
549 ) -> Result<(), TransactionDependencyError> {
550 crate::rpc::block_on(self.apply_tx_async(tx, tip_block_number))
551 }
552
553 pub async fn apply_tx_async(
554 &mut self,
555 tx: Transaction,
556 tip_block_number: u64,
557 ) -> Result<(), TransactionDependencyError> {
558 let mut inner = self.inner.lock().await;
559 inner.offchain_cache.apply_tx(tx, tip_block_number)?;
560 Ok(())
561 }
562 #[cfg(not(target_arch = "wasm32"))]
563 pub fn get_cell_with_data(
564 &self,
565 out_point: &OutPoint,
566 ) -> Result<(CellOutput, Bytes), TransactionDependencyError> {
567 crate::rpc::block_on(self.get_cell_with_data_async(out_point))
568 }
569
570 pub async fn get_cell_with_data_async(
571 &self,
572 out_point: &OutPoint,
573 ) -> Result<(CellOutput, Bytes), TransactionDependencyError> {
574 let mut inner = self.inner.lock().await;
575 if let Some(pair) = inner.cell_cache.get(out_point) {
576 return Ok(pair.clone());
577 }
578
579 let cell_with_status = inner
580 .rpc_client
581 .get_live_cell(out_point.clone().into(), true)
582 .await
583 .map_err(|err| TransactionDependencyError::Other(err.into()))?;
584 if cell_with_status.status != "live" {
585 return Err(TransactionDependencyError::Other(anyhow!(
586 "invalid cell status: {:?}",
587 cell_with_status.status
588 )));
589 }
590 let cell = cell_with_status.cell.unwrap();
591 let output = CellOutput::from(cell.output);
592 let output_data = cell.data.unwrap().content.into_bytes();
593 inner
594 .cell_cache
595 .put(out_point.clone(), (output.clone(), output_data.clone()));
596 Ok((output, output_data))
597 }
598}
599
600#[cfg_attr(target_arch="wasm32", async_trait::async_trait(?Send))]
601#[cfg_attr(not(target_arch = "wasm32"), async_trait::async_trait)]
602impl TransactionDependencyProvider for DefaultTransactionDependencyProvider {
603 async fn get_transaction_async(
604 &self,
605 tx_hash: &Byte32,
606 ) -> Result<TransactionView, TransactionDependencyError> {
607 let mut inner = self.inner.lock().await;
608 if let Some(tx) = inner.tx_cache.get(tx_hash) {
609 return Ok(tx.clone());
610 }
611 let ret: Result<TransactionView, TransactionDependencyError> =
612 inner.offchain_cache.get_transaction_async(tx_hash).await;
613 if ret.is_ok() {
614 return ret;
615 }
616 let tx_with_status = inner
617 .rpc_client
618 .get_transaction(tx_hash.unpack())
619 .await
620 .map_err(|err| TransactionDependencyError::Other(err.into()))?
621 .ok_or_else(|| TransactionDependencyError::NotFound("transaction".to_string()))?;
622 if tx_with_status.tx_status.status != json_types::Status::Committed {
623 return Err(TransactionDependencyError::Other(anyhow!(
624 "invalid transaction status: {:?}",
625 tx_with_status.tx_status
626 )));
627 }
628 let tx = match tx_with_status.transaction.unwrap().inner {
629 Either::Left(t) => Transaction::from(t.inner).into_view(),
630 Either::Right(bytes) => TransactionReader::from_slice(bytes.as_bytes())
631 .map(|reader| reader.to_entity().into_view())
632 .map_err(|err| anyhow!("invalid molecule encoded TransactionView: {}", err))?,
633 };
634 inner.tx_cache.put(tx_hash.clone(), tx.clone());
635 Ok(tx)
636 }
637 async fn get_cell_async(
638 &self,
639 out_point: &OutPoint,
640 ) -> Result<CellOutput, TransactionDependencyError> {
641 {
642 let inner = self.inner.lock().await;
643 let ret = inner.offchain_cache.get_cell_async(out_point).await;
644 if ret.is_ok() {
645 return ret;
646 }
647 }
648 self.get_cell_with_data_async(out_point)
649 .await
650 .map(|(output, _)| output)
651 }
652 async fn get_cell_data_async(
653 &self,
654 out_point: &OutPoint,
655 ) -> Result<Bytes, TransactionDependencyError> {
656 {
657 let inner = self.inner.lock().await;
658 let ret = inner.offchain_cache.get_cell_data_async(out_point).await;
659 if ret.is_ok() {
660 return ret;
661 }
662 }
663 self.get_cell_with_data_async(out_point)
664 .await
665 .map(|(_, output_data)| output_data)
666 }
667 async fn get_header_async(
668 &self,
669 block_hash: &Byte32,
670 ) -> Result<HeaderView, TransactionDependencyError> {
671 let mut inner = self.inner.lock().await;
672 if let Some(header) = inner.header_cache.get(block_hash) {
673 return Ok(header.clone());
674 }
675 let header = inner
676 .rpc_client
677 .get_header(block_hash.unpack())
678 .await
679 .map_err(|err| TransactionDependencyError::Other(err.into()))?
680 .map(HeaderView::from)
681 .ok_or_else(|| TransactionDependencyError::NotFound("header".to_string()))?;
682 inner.header_cache.put(block_hash.clone(), header.clone());
683 Ok(header)
684 }
685
686 async fn get_block_extension_async(
687 &self,
688 block_hash: &Byte32,
689 ) -> Result<Option<ckb_types::packed::Bytes>, TransactionDependencyError> {
690 let inner = self.inner.lock().await;
691
692 let block = inner
693 .rpc_client
694 .get_block(block_hash.unpack())
695 .await
696 .map_err(|err| TransactionDependencyError::Other(err.into()))?;
697 match block {
698 Some(block) => Ok(block.extension.map(ckb_types::packed::Bytes::from)),
699 None => Ok(None),
700 }
701 }
702}
703
704#[derive(Default, Clone)]
706pub struct SecpCkbRawKeySigner {
707 keys: HashMap<H160, secp256k1::SecretKey>,
708}
709
710impl SecpCkbRawKeySigner {
711 pub fn new(keys: HashMap<H160, secp256k1::SecretKey>) -> SecpCkbRawKeySigner {
712 SecpCkbRawKeySigner { keys }
713 }
714 pub fn new_with_secret_keys(keys: Vec<secp256k1::SecretKey>) -> SecpCkbRawKeySigner {
715 let mut signer = SecpCkbRawKeySigner::default();
716 for key in keys {
717 signer.add_secret_key(key);
718 }
719 signer
720 }
721 pub fn add_secret_key(&mut self, key: secp256k1::SecretKey) {
722 let pubkey = secp256k1::PublicKey::from_secret_key(&SECP256K1, &key);
723 let hash160 = H160::from_slice(&blake2b_256(&pubkey.serialize()[..])[0..20])
724 .expect("Generate hash(H160) from pubkey failed");
725 self.keys.insert(hash160, key);
726 }
727
728 pub fn new_with_ethereum_secret_keys(keys: Vec<secp256k1::SecretKey>) -> SecpCkbRawKeySigner {
730 let mut signer = SecpCkbRawKeySigner::default();
731 for key in keys {
732 signer.add_ethereum_secret_key(key);
733 }
734 signer
735 }
736 pub fn add_ethereum_secret_key(&mut self, key: secp256k1::SecretKey) {
738 let pubkey = secp256k1::PublicKey::from_secret_key(&SECP256K1, &key);
739 let hash160 = keccak160(Pubkey::from(pubkey).as_ref());
740 self.keys.insert(hash160, key);
741 }
742}
743
744impl Signer for SecpCkbRawKeySigner {
745 fn match_id(&self, id: &[u8]) -> bool {
746 id.len() == 20 && self.keys.contains_key(&H160::from_slice(id).unwrap())
747 }
748
749 fn sign(
750 &self,
751 id: &[u8],
752 message: &[u8],
753 recoverable: bool,
754 _tx: &TransactionView,
755 ) -> Result<Bytes, SignerError> {
756 if !self.match_id(id) {
757 return Err(SignerError::IdNotFound);
758 }
759 if message.len() != 32 {
760 return Err(SignerError::InvalidMessage(format!(
761 "expected length: 32, got: {}",
762 message.len()
763 )));
764 }
765 let msg =
766 secp256k1::Message::from_digest_slice(message).expect("Convert to message failed");
767 let key = self.keys.get(&H160::from_slice(id).unwrap()).unwrap();
768 if recoverable {
769 let sig = SECP256K1.sign_ecdsa_recoverable(&msg, key);
770 Ok(Bytes::from(serialize_signature(&sig).to_vec()))
771 } else {
772 let sig = SECP256K1.sign_ecdsa(&msg, key);
773 Ok(Bytes::from(sig.serialize_compact().to_vec()))
774 }
775 }
776}
777
778impl Drop for SecpCkbRawKeySigner {
779 fn drop(&mut self) {
780 for (_, mut secret_key) in self.keys.drain() {
781 zeroize_privkey(&mut secret_key);
782 }
783 }
784}
785#[cfg(test)]
786mod anyhow_tests {
787 use anyhow::anyhow;
788 #[test]
789 fn test_parse_genesis_info_error() {
790 let error = super::ParseGenesisInfoError::DataHashNotFound("DataHashNotFound".to_string());
791 let error = anyhow!(error);
792 assert_eq!("data not found: `DataHashNotFound`", error.to_string());
793 }
794}