Skip to content

Commit

Permalink
feat(core): more rpc calls cache
Browse files Browse the repository at this point in the history
  • Loading branch information
Hanssen0 committed Feb 13, 2025
1 parent 01d1eeb commit 1d8ef6b
Show file tree
Hide file tree
Showing 9 changed files with 644 additions and 110 deletions.
5 changes: 5 additions & 0 deletions .changeset/light-vans-arrive.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@ckb-ccc/core": minor
---

feat(core): more rpc calls cache
139 changes: 126 additions & 13 deletions packages/core/src/client/cache/cache.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,18 +6,44 @@ import {
TransactionLike,
} from "../../ckb/index.js";
import { HexLike } from "../../hex/index.js";
import { NumLike } from "../../num/index.js";
import { ClientCollectableSearchKeyLike } from "../clientTypes.advanced.js";
import {
ClientBlock,
ClientBlockHeader,
ClientBlockHeaderLike,
ClientBlockLike,
ClientTransactionResponse,
ClientTransactionResponseLike,
} from "../clientTypes.js";

/**
* @public
* The ClientCache class is mainly designed for chained transactions.
* Consumed & Created cells are "marked" so they can be correctly handled when composing transactions.
* It also act as cache for rpc requests to reduce cost, but this is optional.
*/
export abstract class ClientCache {
abstract markUsable(...cellLikes: (CellLike | CellLike[])[]): Promise<void>;
abstract markUsableNoCache(
...cellLikes: (CellLike | CellLike[])[]
): Promise<void>;
async markUsable(...cellLikes: (CellLike | CellLike[])[]): Promise<void> {
await this.recordCells(...cellLikes);
return this.markUsableNoCache(...cellLikes);
}
abstract markUnusable(
...outPointLike: (OutPointLike | OutPointLike[])[]
): Promise<void>;
async markTransactions(
...transactionLike: (TransactionLike | TransactionLike[])[]
): Promise<void> {
await Promise.all([
this.recordTransactions(...transactionLike),
this.recordTransactionResponses(
transactionLike.flat().map((transaction) => ({
transaction: transaction,
status: "sent",
})),
),
...transactionLike.flat().map((transactionLike) => {
const tx = Transaction.from(transactionLike);
const txHash = tx.hash();
Expand All @@ -42,34 +68,121 @@ export abstract class ClientCache {
abstract findCells(
filter: ClientCollectableSearchKeyLike,
): AsyncGenerator<Cell>;
abstract isUnusable(outPointLike: OutPointLike): Promise<boolean>;

// ======
// Following methods are for requests caching and optional.
// ======

/**
* Record known cells
* Implement this method to enable cells query caching
* @param _cells
*/
async recordCells(..._cells: (CellLike | CellLike[])[]): Promise<void> {}
/**
* Get a known cell by out point
* Implement this method to enable cells query caching
* @param _outPoint
*/
abstract getCell(_outPoint: OutPointLike): Promise<Cell | undefined>;
abstract isUnusable(outPointLike: OutPointLike): Promise<boolean>;
async getCell(_outPoint: OutPointLike): Promise<Cell | undefined> {
return;
}

/**
* Record known transactions
* Record known transaction responses.
* Implement this method to enable transactions query caching
* @param _transactions
*/
async recordTransactions(
..._transactions: (TransactionLike | TransactionLike[])[]
async recordTransactionResponses(
..._transactions: (
| ClientTransactionResponseLike
| ClientTransactionResponseLike[]
)[]
): Promise<void> {}
/**
* Get a known transaction by hash
* Get a known transaction response by hash
* Implement this method to enable transactions query caching
* @param _txHash
*/
async getTransaction(_txHash: HexLike): Promise<Transaction | undefined> {
async getTransactionResponse(
_txHash: HexLike,
): Promise<ClientTransactionResponse | undefined> {
return;
}
/**
* Record known transactions.
* @param transactions
*/
async recordTransactions(
...transactions: (TransactionLike | TransactionLike[])[]
): Promise<void> {
return this.recordTransactionResponses(
transactions.flat().map((transaction) => ({
transaction,
status: "unknown",
})),
);
}
/**
* Get a known transaction by hash
* @param txHash
*/
async getTransaction(txHash: HexLike): Promise<Transaction | undefined> {
return (await this.getTransactionResponse(txHash))?.transaction;
}

/**
* Record known block headers.
* Implement this method to enable block headers query caching
* @param _headers
*/
async recordHeaders(
..._headers: (ClientBlockHeaderLike | ClientBlockHeaderLike[])[]
): Promise<void> {}
/**
* Get a known block header by hash
* Implement this method to enable block headers query caching
* @param _hash
*/
async getHeaderByHash(
_hash: HexLike,
): Promise<ClientBlockHeader | undefined> {
return;
}
/**
* Get a known block header by number
* Implement this method to enable block headers query caching
* @param _number
*/
async getHeaderByNumber(
_number: NumLike,
): Promise<ClientBlockHeader | undefined> {
return;
}

/**
* Record known cells
* Implement this method to enable cells query caching
* @param _cells
* Record known blocks.
* Implement this method to enable blocks query caching
* @param _blocks
*/
async recordCells(..._cells: (CellLike | CellLike[])[]): Promise<void> {}
async recordBlocks(
..._blocks: (ClientBlockLike | ClientBlockLike[])[]
): Promise<void> {}
/**
* Get a known block header by hash
* Implement this method to enable block headers query caching
* @param _hash
*/
async getBlockByHash(_hash: HexLike): Promise<ClientBlock | undefined> {
return;
}
/**
* Get a known block header by number
* Implement this method to enable block headers query caching
* @param _number
*/
async getBlockByNumber(_number: NumLike): Promise<ClientBlock | undefined> {
return;
}
}
31 changes: 24 additions & 7 deletions packages/core/src/client/cache/memory.advanced.ts
Original file line number Diff line number Diff line change
Expand Up @@ -149,7 +149,12 @@ export class MapLru<K, V> extends Map<K, V> {
super();
}

access(key: K) {
get(key: K) {
const val = super.get(key);
if (val === undefined) {
return;
}

const index = this.lru.indexOf(key);
if (index !== -1) {
this.lru.splice(index, 1);
Expand All @@ -159,15 +164,27 @@ export class MapLru<K, V> extends Map<K, V> {
this.delete(this.lru[0]);
this.lru.shift();
}
}

get(key: K) {
this.access(key);
return super.get(key);
return val;
}

set(key: K, value: V) {
this.access(key);
return super.set(key, value);
this.get(key);

super.set(key, value);
return this;
}

delete(key: K): boolean {
if (!super.delete(key)) {
return false;
}

const index = this.lru.indexOf(key);
if (index !== -1) {
this.lru.splice(index, 1);
}

return true;
}
}
Loading

0 comments on commit 1d8ef6b

Please sign in to comment.