UNPKG

@ckb-ccc/core

Version:

Core of CCC - CKBer's Codebase

138 lines (137 loc) 4.98 kB
import { Cell, OutPoint } from "../../ckb/index.js"; import { hexFrom } from "../../hex/index.js"; import { numFrom } from "../../num/index.js"; import { ClientBlock, ClientBlockHeader, ClientTransactionResponse, } from "../clientTypes.js"; import { ClientCache } from "./cache.js"; import { filterCell, MapLru } from "./memory.advanced.js"; export class ClientCacheMemory extends ClientCache { constructor(maxCells = 512, maxTxs = 256, maxBlocks = 128) { super(); this.maxCells = maxCells; this.maxTxs = maxTxs; this.maxBlocks = maxBlocks; this.cells = new MapLru(this.maxCells); this.knownTransactions = new MapLru(this.maxTxs); this.knownBlockHashes = new MapLru(this.maxBlocks); this.knownBlocks = new MapLru(this.maxBlocks); } async markUsableNoCache(...cellLikes) { cellLikes.flat().forEach((cellLike) => { const cell = Cell.from(cellLike).clone(); const outPointStr = hexFrom(cell.outPoint.toBytes()); this.cells.set(outPointStr, [true, cell]); }); } async markUnusable(...outPointLikes) { outPointLikes.flat().forEach((outPointLike) => { const outPoint = OutPoint.from(outPointLike); const outPointStr = hexFrom(outPoint.toBytes()); const existed = this.cells.get(outPointStr); if (existed) { existed[0] = false; return; } this.cells.set(outPointStr, [false, { outPoint }]); }); } async clear() { this.cells.clear(); this.knownTransactions.clear(); } async *findCells(keyLike) { for (const [key, [isLive, cell]] of this.cells.entries()) { if (!isLive) { continue; } if (!filterCell(keyLike, cell)) { continue; } this.cells.get(key); yield cell.clone(); } } async isUnusable(outPointLike) { const outPoint = OutPoint.from(outPointLike); return !(this.cells.get(hexFrom(outPoint.toBytes()))?.[0] ?? true); } async recordCells(...cells) { cells.flat().map((cellLike) => { const cell = Cell.from(cellLike); const outPointStr = hexFrom(cell.outPoint.toBytes()); if (this.cells.get(outPointStr)) { return; } this.cells.set(outPointStr, [undefined, cell]); }); } async getCell(outPointLike) { const outPoint = OutPoint.from(outPointLike); const cell = this.cells.get(hexFrom(outPoint.toBytes()))?.[1]; if (cell && cell.cellOutput && cell.outputData) { return Cell.from(cell.clone()); } } async recordTransactionResponses(...transactions) { transactions.flat().map((txLike) => { const tx = ClientTransactionResponse.from(txLike); this.knownTransactions.set(tx.transaction.hash(), tx); }); } async getTransactionResponse(txHashLike) { const txHash = hexFrom(txHashLike); return this.knownTransactions.get(txHash)?.clone(); } async recordHeaders(...headers) { headers.flat().map((headerLike) => { const header = ClientBlockHeader.from(headerLike); this.knownBlockHashes.set(header.number, header.hash); const existed = this.knownBlocks.get(header.hash); if (existed) { return; } this.knownBlocks.set(header.hash, { header }); }); } async getHeaderByHash(hashLike) { const hash = hexFrom(hashLike); const block = this.knownBlocks.get(hash); if (block) { this.knownBlockHashes.get(block.header.number); // For LRU } return block?.header; } async getHeaderByNumber(numberLike) { const number = numFrom(numberLike); const hash = this.knownBlockHashes.get(number); if (!hash) { return; } return this.getHeaderByHash(hash); } async recordBlocks(...blocks) { blocks.flat().map((blockLike) => { const block = ClientBlock.from(blockLike); this.knownBlockHashes.set(block.header.number, block.header.hash); this.knownBlocks.set(block.header.hash, block); }); } async getBlockByHash(hashLike) { const hash = hexFrom(hashLike); const block = this.knownBlocks.get(hash); if (block) { this.knownBlockHashes.get(block.header.number); // For LRU if ("transactions" in block) { return block; } } return; } async getBlockByNumber(numberLike) { const number = numFrom(numberLike); const hash = this.knownBlockHashes.get(number); if (!hash) { return; } return this.getBlockByHash(hash); } }