ckb_verification/
cache.rs1use ckb_script::TransactionState;
4use ckb_types::{
5 core::{Capacity, Cycle, EntryCompleted, TransactionView},
6 packed::Byte32,
7};
8use std::collections::HashMap;
9use std::sync::Arc;
10
11#[derive(Clone, Debug, PartialEq, Eq, Hash)]
16pub struct VerifyCacheKey(Byte32);
17
18impl From<&TransactionView> for VerifyCacheKey {
19 fn from(tx: &TransactionView) -> Self {
20 Self(tx.witness_hash())
21 }
22}
23
24pub type TxVerificationCache = lru::LruCache<VerifyCacheKey, CachedScriptCycles>;
26
27pub type FetchedTxVerificationCache = HashMap<VerifyCacheKey, CachedScriptCycles>;
29
30pub trait TxVerificationCacheLookup {
32 fn get_by_wtx_hash(&self, key: &VerifyCacheKey) -> Option<&CachedScriptCycles>;
34}
35
36impl TxVerificationCacheLookup for TxVerificationCache {
37 fn get_by_wtx_hash(&self, key: &VerifyCacheKey) -> Option<&CachedScriptCycles> {
38 self.peek(key)
39 }
40}
41
42impl TxVerificationCacheLookup for FetchedTxVerificationCache {
43 fn get_by_wtx_hash(&self, key: &VerifyCacheKey) -> Option<&CachedScriptCycles> {
44 self.get(key)
45 }
46}
47
48const CACHE_SIZE: usize = 1000 * 30;
49
50pub fn init_cache() -> TxVerificationCache {
52 lru::LruCache::new(CACHE_SIZE)
53}
54
55#[derive(Clone, Copy, Debug, PartialEq, Eq)]
57pub struct CachedScriptCycles {
58 pub cycles: Cycle,
60}
61
62impl CachedScriptCycles {
63 pub fn new(cycles: Cycle) -> CachedScriptCycles {
65 Self { cycles }
66 }
67}
68
69#[derive(Clone, Debug)]
71pub struct Suspended {
72 pub fee: Capacity,
74 pub state: Arc<TransactionState>,
76}
77
78#[derive(Clone, Copy, Debug, PartialEq, Eq)]
80pub struct Completed {
81 pub cycles: Cycle,
83 pub fee: Capacity,
85}
86
87impl From<Completed> for EntryCompleted {
88 fn from(value: Completed) -> Self {
89 EntryCompleted {
90 cycles: value.cycles,
91 fee: value.fee,
92 }
93 }
94}
95
96#[cfg(test)]
97mod tests {
98 use super::*;
99 use ckb_types::{bytes::Bytes, core::TransactionBuilder};
100
101 #[test]
102 fn cache_key_distinguishes_transactions_with_different_witnesses() {
103 let tx = TransactionBuilder::default().build();
104 let cousin = tx.as_advanced_builder().witness(Bytes::new()).build();
105
106 assert_eq!(tx.hash(), cousin.hash());
107 assert_ne!(tx.witness_hash(), cousin.witness_hash());
108
109 let cached_cycles = CachedScriptCycles::new(42);
110 let tx_key = VerifyCacheKey::from(&tx);
111 let cousin_key = VerifyCacheKey::from(&cousin);
112
113 let mut cache = init_cache();
114 cache.put(tx_key.clone(), cached_cycles);
115 assert_eq!(cache.get_by_wtx_hash(&tx_key), Some(&cached_cycles));
116 assert_eq!(cache.get_by_wtx_hash(&cousin_key), None);
117
118 let fetched_cache = FetchedTxVerificationCache::from([(tx_key.clone(), cached_cycles)]);
119 assert_eq!(fetched_cache.get_by_wtx_hash(&tx_key), Some(&cached_cycles));
120 assert_eq!(fetched_cache.get_by_wtx_hash(&cousin_key), None);
121 }
122}