use ckb_script::TransactionState;
use ckb_types::{
core::{Capacity, Cycle, EntryCompleted, TransactionView},
packed::Byte32,
};
use std::collections::HashMap;
use std::sync::Arc;
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
pub struct VerifyCacheKey(Byte32);
impl From<&TransactionView> for VerifyCacheKey {
fn from(tx: &TransactionView) -> Self {
Self(tx.witness_hash())
}
}
pub type TxVerificationCache = lru::LruCache<VerifyCacheKey, CachedScriptCycles>;
pub type FetchedTxVerificationCache = HashMap<VerifyCacheKey, CachedScriptCycles>;
pub trait TxVerificationCacheLookup {
fn get_by_wtx_hash(&self, key: &VerifyCacheKey) -> Option<&CachedScriptCycles>;
}
impl TxVerificationCacheLookup for TxVerificationCache {
fn get_by_wtx_hash(&self, key: &VerifyCacheKey) -> Option<&CachedScriptCycles> {
self.peek(key)
}
}
impl TxVerificationCacheLookup for FetchedTxVerificationCache {
fn get_by_wtx_hash(&self, key: &VerifyCacheKey) -> Option<&CachedScriptCycles> {
self.get(key)
}
}
const CACHE_SIZE: usize = 1000 * 30;
pub fn init_cache() -> TxVerificationCache {
lru::LruCache::new(CACHE_SIZE)
}
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub struct CachedScriptCycles {
pub cycles: Cycle,
}
impl CachedScriptCycles {
pub fn new(cycles: Cycle) -> CachedScriptCycles {
Self { cycles }
}
}
#[derive(Clone, Debug)]
pub struct Suspended {
pub fee: Capacity,
pub state: Arc<TransactionState>,
}
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub struct Completed {
pub cycles: Cycle,
pub fee: Capacity,
}
impl From<Completed> for EntryCompleted {
fn from(value: Completed) -> Self {
EntryCompleted {
cycles: value.cycles,
fee: value.fee,
}
}
}
#[cfg(test)]
mod tests {
use super::*;
use ckb_types::{bytes::Bytes, core::TransactionBuilder};
#[test]
fn cache_key_distinguishes_transactions_with_different_witnesses() {
let tx = TransactionBuilder::default().build();
let cousin = tx.as_advanced_builder().witness(Bytes::new()).build();
assert_eq!(tx.hash(), cousin.hash());
assert_ne!(tx.witness_hash(), cousin.witness_hash());
let cached_cycles = CachedScriptCycles::new(42);
let tx_key = VerifyCacheKey::from(&tx);
let cousin_key = VerifyCacheKey::from(&cousin);
let mut cache = init_cache();
cache.put(tx_key.clone(), cached_cycles);
assert_eq!(cache.get_by_wtx_hash(&tx_key), Some(&cached_cycles));
assert_eq!(cache.get_by_wtx_hash(&cousin_key), None);
let fetched_cache = FetchedTxVerificationCache::from([(tx_key.clone(), cached_cycles)]);
assert_eq!(fetched_cache.get_by_wtx_hash(&tx_key), Some(&cached_cycles));
assert_eq!(fetched_cache.get_by_wtx_hash(&cousin_key), None);
}
}