@ckb-ccc/core 0.0.13-alpha.7 → 0.0.13

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (42) hide show
  1. package/CHANGELOG.md +58 -0
  2. package/dist/client/cache/cache.d.ts +29 -9
  3. package/dist/client/cache/cache.d.ts.map +1 -1
  4. package/dist/client/cache/cache.js +43 -1
  5. package/dist/client/cache/memory.d.ts +10 -6
  6. package/dist/client/cache/memory.d.ts.map +1 -1
  7. package/dist/client/cache/memory.js +49 -39
  8. package/dist/client/client.d.ts +2 -0
  9. package/dist/client/client.d.ts.map +1 -1
  10. package/dist/client/client.js +7 -0
  11. package/dist/client/clientTypes.d.ts +24 -2
  12. package/dist/client/clientTypes.d.ts.map +1 -1
  13. package/dist/client/clientTypes.js +25 -1
  14. package/dist/client/jsonRpc/index.d.ts +10 -1
  15. package/dist/client/jsonRpc/index.d.ts.map +1 -1
  16. package/dist/client/jsonRpc/index.js +42 -1
  17. package/dist/fixedPoint/index.d.ts +3 -3
  18. package/dist/fixedPoint/index.js +3 -3
  19. package/dist.commonjs/client/cache/cache.d.ts +29 -9
  20. package/dist.commonjs/client/cache/cache.d.ts.map +1 -1
  21. package/dist.commonjs/client/cache/cache.js +45 -0
  22. package/dist.commonjs/client/cache/memory.d.ts +10 -6
  23. package/dist.commonjs/client/cache/memory.d.ts.map +1 -1
  24. package/dist.commonjs/client/cache/memory.js +49 -39
  25. package/dist.commonjs/client/client.d.ts +2 -0
  26. package/dist.commonjs/client/client.d.ts.map +1 -1
  27. package/dist.commonjs/client/client.js +7 -0
  28. package/dist.commonjs/client/clientTypes.d.ts +24 -2
  29. package/dist.commonjs/client/clientTypes.d.ts.map +1 -1
  30. package/dist.commonjs/client/clientTypes.js +32 -5
  31. package/dist.commonjs/client/jsonRpc/index.d.ts +10 -1
  32. package/dist.commonjs/client/jsonRpc/index.d.ts.map +1 -1
  33. package/dist.commonjs/client/jsonRpc/index.js +58 -17
  34. package/dist.commonjs/fixedPoint/index.d.ts +3 -3
  35. package/dist.commonjs/fixedPoint/index.js +3 -3
  36. package/package.json +1 -1
  37. package/src/client/cache/cache.ts +58 -13
  38. package/src/client/cache/memory.ts +60 -52
  39. package/src/client/client.ts +21 -0
  40. package/src/client/clientTypes.ts +52 -3
  41. package/src/client/jsonRpc/index.ts +97 -3
  42. package/src/fixedPoint/index.ts +3 -3
@@ -1,10 +1,12 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.ClientJsonRpc = void 0;
4
- const index_js_1 = require("../../hex/index.js");
5
- const index_js_2 = require("../../num/index.js");
6
- const index_js_3 = require("../../utils/index.js");
4
+ const index_js_1 = require("../../ckb/index.js");
5
+ const index_js_2 = require("../../hex/index.js");
6
+ const index_js_3 = require("../../num/index.js");
7
+ const index_js_4 = require("../../utils/index.js");
7
8
  const client_js_1 = require("../client.js");
9
+ const clientTypes_js_1 = require("../clientTypes.js");
8
10
  const advanced_js_1 = require("../transports/advanced.js");
9
11
  const advanced_js_2 = require("./advanced.js");
10
12
  /**
@@ -45,14 +47,14 @@ class ClientJsonRpc extends client_js_1.Client {
45
47
  *
46
48
  * @returns Tip block number
47
49
  */
48
- this.getTip = this.buildSender("get_tip_block_number", [], index_js_2.numFrom);
50
+ this.getTip = this.buildSender("get_tip_block_number", [], index_js_3.numFrom);
49
51
  /**
50
52
  * Get tip block header
51
53
  *
52
54
  * @param verbosity - result format which allows 0 and 1. (Optional, the default is 1.)
53
55
  * @returns BlockHeader
54
56
  */
55
- this.getTipHeader = this.buildSender("get_tip_header", [], (b) => (0, index_js_3.apply)(advanced_js_2.JsonRpcTransformers.blockHeaderTo, b));
57
+ this.getTipHeader = this.buildSender("get_tip_header", [], (b) => (0, index_js_4.apply)(advanced_js_2.JsonRpcTransformers.blockHeaderTo, b));
56
58
  /**
57
59
  * Get block by block number
58
60
  *
@@ -61,7 +63,7 @@ class ClientJsonRpc extends client_js_1.Client {
61
63
  * @param withCycles - whether the return cycles of block transactions. (Optional, default false.)
62
64
  * @returns Block
63
65
  */
64
- this.getBlockByNumber = this.buildSender("get_block_by_number", [(v) => (0, index_js_2.numToHex)((0, index_js_2.numFrom)(v))], (b) => (0, index_js_3.apply)(advanced_js_2.JsonRpcTransformers.blockTo, b));
66
+ this.getBlockByNumber = this.buildSender("get_block_by_number", [(v) => (0, index_js_3.numToHex)((0, index_js_3.numFrom)(v))], (b) => (0, index_js_4.apply)(advanced_js_2.JsonRpcTransformers.blockTo, b));
65
67
  /**
66
68
  * Get block by block hash
67
69
  *
@@ -70,7 +72,7 @@ class ClientJsonRpc extends client_js_1.Client {
70
72
  * @param withCycles - whether the return cycles of block transactions. (Optional, default false.)
71
73
  * @returns Block
72
74
  */
73
- this.getBlockByHash = this.buildSender("get_block", [index_js_1.hexFrom], (b) => (0, index_js_3.apply)(advanced_js_2.JsonRpcTransformers.blockTo, b));
75
+ this.getBlockByHash = this.buildSender("get_block", [index_js_2.hexFrom], (b) => (0, index_js_4.apply)(advanced_js_2.JsonRpcTransformers.blockTo, b));
74
76
  /**
75
77
  * Get header by block number
76
78
  *
@@ -78,7 +80,7 @@ class ClientJsonRpc extends client_js_1.Client {
78
80
  * @param verbosity - result format which allows 0 and 1. (Optional, the default is 1.)
79
81
  * @returns BlockHeader
80
82
  */
81
- this.getHeaderByNumber = this.buildSender("get_header_by_number", [(v) => (0, index_js_2.numToHex)((0, index_js_2.numFrom)(v))], (b) => (0, index_js_3.apply)(advanced_js_2.JsonRpcTransformers.blockHeaderTo, b));
83
+ this.getHeaderByNumber = this.buildSender("get_header_by_number", [(v) => (0, index_js_3.numToHex)((0, index_js_3.numFrom)(v))], (b) => (0, index_js_4.apply)(advanced_js_2.JsonRpcTransformers.blockHeaderTo, b));
82
84
  /**
83
85
  * Get header by block hash
84
86
  *
@@ -86,14 +88,14 @@ class ClientJsonRpc extends client_js_1.Client {
86
88
  * @param verbosity - result format which allows 0 and 1. (Optional, the default is 1.)
87
89
  * @returns BlockHeader
88
90
  */
89
- this.getHeaderByHash = this.buildSender("get_header", [index_js_1.hexFrom], (b) => (0, index_js_3.apply)(advanced_js_2.JsonRpcTransformers.blockHeaderTo, b));
91
+ this.getHeaderByHash = this.buildSender("get_header", [index_js_2.hexFrom], (b) => (0, index_js_4.apply)(advanced_js_2.JsonRpcTransformers.blockHeaderTo, b));
90
92
  /**
91
93
  * Estimate cycles of a transaction.
92
94
  *
93
95
  * @param transaction - The transaction to estimate.
94
96
  * @returns Consumed cycles
95
97
  */
96
- this.estimateCycles = this.buildSender("estimate_cycles", [advanced_js_2.JsonRpcTransformers.transactionFrom], ({ cycles }) => (0, index_js_2.numFrom)(cycles));
98
+ this.estimateCycles = this.buildSender("estimate_cycles", [advanced_js_2.JsonRpcTransformers.transactionFrom], ({ cycles }) => (0, index_js_3.numFrom)(cycles));
97
99
  /**
98
100
  * Test a transaction.
99
101
  *
@@ -101,7 +103,7 @@ class ClientJsonRpc extends client_js_1.Client {
101
103
  * @param validator - "passthrough": Disable validation. "well_known_scripts_only": Only accept well known scripts in the transaction.
102
104
  * @returns Consumed cycles
103
105
  */
104
- this.sendTransactionDry = this.buildSender("test_tx_pool_accept", [advanced_js_2.JsonRpcTransformers.transactionFrom], ({ cycles }) => (0, index_js_2.numFrom)(cycles));
106
+ this.sendTransactionDry = this.buildSender("test_tx_pool_accept", [advanced_js_2.JsonRpcTransformers.transactionFrom], ({ cycles }) => (0, index_js_3.numFrom)(cycles));
105
107
  /**
106
108
  * Send a transaction to node.
107
109
  *
@@ -109,14 +111,14 @@ class ClientJsonRpc extends client_js_1.Client {
109
111
  * @param validator - "passthrough": Disable validation. "well_known_scripts_only": Only accept well known scripts in the transaction.
110
112
  * @returns Transaction hash.
111
113
  */
112
- this.sendTransactionNoCache = this.buildSender("send_transaction", [advanced_js_2.JsonRpcTransformers.transactionFrom], index_js_1.hexFrom);
114
+ this.sendTransactionNoCache = this.buildSender("send_transaction", [advanced_js_2.JsonRpcTransformers.transactionFrom], index_js_2.hexFrom);
113
115
  /**
114
116
  * Get a transaction from node.
115
117
  *
116
118
  * @param txHash - The hash of the transaction.
117
119
  * @returns The transaction with status.
118
120
  */
119
- this.getTransactionNoCache = this.buildSender("get_transaction", [index_js_1.hexFrom], advanced_js_2.JsonRpcTransformers.transactionResponseTo);
121
+ this.getTransactionNoCache = this.buildSender("get_transaction", [index_js_2.hexFrom], advanced_js_2.JsonRpcTransformers.transactionResponseTo);
120
122
  /**
121
123
  * find cells from node.
122
124
  *
@@ -129,7 +131,7 @@ class ClientJsonRpc extends client_js_1.Client {
129
131
  this.findCellsPagedNoCache = this.buildSender("get_cells", [
130
132
  advanced_js_2.JsonRpcTransformers.indexerSearchKeyFrom,
131
133
  (order) => order ?? "asc",
132
- (limit) => (0, index_js_2.numToHex)(limit ?? 10),
134
+ (limit) => (0, index_js_3.numToHex)(limit ?? 10),
133
135
  ], advanced_js_2.JsonRpcTransformers.findCellsResponseTo);
134
136
  /**
135
137
  * find transactions from node.
@@ -143,7 +145,7 @@ class ClientJsonRpc extends client_js_1.Client {
143
145
  this.findTransactionsPaged = this.buildSender("get_transactions", [
144
146
  advanced_js_2.JsonRpcTransformers.indexerSearchKeyTransactionFrom,
145
147
  (order) => order ?? "asc",
146
- (limit) => (0, index_js_2.numToHex)(limit ?? 10),
148
+ (limit) => (0, index_js_3.numToHex)(limit ?? 10),
147
149
  ], advanced_js_2.JsonRpcTransformers.findTransactionsResponseTo);
148
150
  /**
149
151
  * get cells capacity from node.
@@ -151,7 +153,7 @@ class ClientJsonRpc extends client_js_1.Client {
151
153
  * @param key - The search key of cells.
152
154
  * @returns The sum of cells capacity.
153
155
  */
154
- this.getCellsCapacity = this.buildSender("get_cells_capacity", [advanced_js_2.JsonRpcTransformers.indexerSearchKeyFrom], ({ capacity }) => (0, index_js_2.numFrom)(capacity));
156
+ this.getCellsCapacity = this.buildSender("get_cells_capacity", [advanced_js_2.JsonRpcTransformers.indexerSearchKeyFrom], ({ capacity }) => (0, index_js_3.numFrom)(capacity));
155
157
  this.transport = (0, advanced_js_1.transportFromUri)(url_, config);
156
158
  }
157
159
  /**
@@ -162,6 +164,21 @@ class ClientJsonRpc extends client_js_1.Client {
162
164
  get url() {
163
165
  return this.url_;
164
166
  }
167
+ /**
168
+ * Get a live cell from node.
169
+ *
170
+ * @param outPoint - The out point of the cell.
171
+ * @param withData - Include data in the response.
172
+ * @param includeTxPool - Include cells in the tx pool.
173
+ * @returns The cell
174
+ */
175
+ getCellLiveNoCache(outPoint, withData, includeTxPool) {
176
+ return this.buildSender("get_live_cell", [advanced_js_2.JsonRpcTransformers.outPointFrom], ({ cell, }) => (0, index_js_4.apply)(({ output, data, }) => index_js_1.Cell.from({
177
+ cellOutput: advanced_js_2.JsonRpcTransformers.cellOutputTo(output),
178
+ outputData: data?.content ?? "0x",
179
+ outPoint,
180
+ }), cell))(outPoint, withData ?? true, includeTxPool);
181
+ }
165
182
  /**
166
183
  * Builds a sender function for a JSON-RPC method.
167
184
  *
@@ -175,7 +192,31 @@ class ClientJsonRpc extends client_js_1.Client {
175
192
  const payload = ClientJsonRpc.buildPayload(rpcMethod, await Promise.all(req
176
193
  .concat(Array.from(new Array(Math.max(inTransformers.length - req.length, 0))))
177
194
  .map((v, i) => transform(v, inTransformers[i]))));
178
- return transform(await this.send(payload), outTransformer);
195
+ try {
196
+ return transform(await this.send(payload), outTransformer);
197
+ }
198
+ catch (errAny) {
199
+ if (typeof errAny !== "object" ||
200
+ errAny === null ||
201
+ !("data" in errAny) ||
202
+ typeof errAny.data !== "string") {
203
+ throw errAny;
204
+ }
205
+ const err = errAny;
206
+ const unknownOutPointMatch = err.data.match(new RegExp("Resolve\\(Unknown\\(OutPoint\\((0x.*)\\)\\)\\)"))?.[1];
207
+ if (unknownOutPointMatch) {
208
+ throw new clientTypes_js_1.ErrorClientResolveUnknown(err, index_js_1.OutPoint.fromBytes(unknownOutPointMatch));
209
+ }
210
+ const verificationFailedMatch = err.data.match(new RegExp("Verification\\(Error { kind: Script, inner: TransactionScriptError { source: (Inputs|Outputs)\\[([0-9]*)\\].(Lock|Type), cause: ValidationFailure: see error code (-?[0-9])* on page https://nervosnetwork\\.github\\.io/ckb-script-error-codes/by-(type|data)-hash/(.*)\\.html"));
211
+ if (verificationFailedMatch) {
212
+ throw new clientTypes_js_1.ErrorClientVerification(err, verificationFailedMatch[3] === "Lock"
213
+ ? "lock"
214
+ : verificationFailedMatch[1] === "Inputs"
215
+ ? "inputType"
216
+ : "outputType", verificationFailedMatch[2], Number(verificationFailedMatch[4]), verificationFailedMatch[5] === "data" ? "data" : "type", verificationFailedMatch[6]);
217
+ }
218
+ throw new clientTypes_js_1.ErrorClientBase(err);
219
+ }
179
220
  };
180
221
  }
181
222
  /**
@@ -20,8 +20,8 @@ export type FixedPointLike = bigint | string | number;
20
20
  * @example
21
21
  * ```typescript
22
22
  * const str = fixedPointToString(123456789n, 8); // Outputs "1.23456789"
23
- * const strFromString = fixedPointToString("123456789", 8); // Outputs "1.23456789"
24
- * const strFromNumber = fixedPointToString(123456789, 8); // Outputs "1.23456789"
23
+ * const strFromString = fixedPointToString("1.23456789", 8); // Outputs "1.23456789"
24
+ * const strFromNumber = fixedPointToString(1.23456789, 8); // Outputs "1.23456789"
25
25
  * ```
26
26
  */
27
27
  export declare function fixedPointToString(val: FixedPointLike, decimals?: number): string;
@@ -35,7 +35,7 @@ export declare function fixedPointToString(val: FixedPointLike, decimals?: numbe
35
35
  *
36
36
  * @example
37
37
  * ```typescript
38
- * const fixedPoint = fixedPointFrom(1.23456789, 8); // Outputs 123456789n
38
+ * const fixedPoint = fixedPointFrom(123456789n, 8); // Outputs 123456789n
39
39
  * const fixedPointFromString = fixedPointFrom("1.23456789", 8); // Outputs 123456789n
40
40
  * const fixedPointFromNumber = fixedPointFrom(1.23456789, 8); // Outputs 123456789n
41
41
  * ```
@@ -16,8 +16,8 @@ exports.One = exports.Zero = exports.fixedPointFrom = exports.fixedPointToString
16
16
  * @example
17
17
  * ```typescript
18
18
  * const str = fixedPointToString(123456789n, 8); // Outputs "1.23456789"
19
- * const strFromString = fixedPointToString("123456789", 8); // Outputs "1.23456789"
20
- * const strFromNumber = fixedPointToString(123456789, 8); // Outputs "1.23456789"
19
+ * const strFromString = fixedPointToString("1.23456789", 8); // Outputs "1.23456789"
20
+ * const strFromNumber = fixedPointToString(1.23456789, 8); // Outputs "1.23456789"
21
21
  * ```
22
22
  */
23
23
  function fixedPointToString(val, decimals = 8) {
@@ -43,7 +43,7 @@ exports.fixedPointToString = fixedPointToString;
43
43
  *
44
44
  * @example
45
45
  * ```typescript
46
- * const fixedPoint = fixedPointFrom(1.23456789, 8); // Outputs 123456789n
46
+ * const fixedPoint = fixedPointFrom(123456789n, 8); // Outputs 123456789n
47
47
  * const fixedPointFromString = fixedPointFrom("1.23456789", 8); // Outputs 123456789n
48
48
  * const fixedPointFromNumber = fixedPointFrom(1.23456789, 8); // Outputs 123456789n
49
49
  * ```
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ckb-ccc/core",
3
- "version": "0.0.13-alpha.7",
3
+ "version": "0.0.13",
4
4
  "description": "Core of CCC - CKBer's Codebase",
5
5
  "author": "Hanssen0 <hanssen0@hanssen0.com>",
6
6
  "license": "MIT",
@@ -8,23 +8,68 @@ import {
8
8
  import { HexLike } from "../../hex/index.js";
9
9
  import { ClientCollectableSearchKeyLike } from "../clientTypes.advanced.js";
10
10
 
11
- export interface ClientCache {
12
- markUsable(...cellLikes: (CellLike | CellLike[])[]): Promise<void>;
13
- markUnusable(
11
+ export abstract class ClientCache {
12
+ abstract markUsable(...cellLikes: (CellLike | CellLike[])[]): Promise<void>;
13
+ abstract markUnusable(
14
14
  ...outPointLike: (OutPointLike | OutPointLike[])[]
15
15
  ): Promise<void>;
16
- markTransactions(
16
+ async markTransactions(
17
17
  ...transactionLike: (TransactionLike | TransactionLike[])[]
18
- ): Promise<void>;
18
+ ): Promise<void> {
19
+ await Promise.all([
20
+ this.recordTransactions(...transactionLike),
21
+ ...transactionLike.flat().map((transactionLike) => {
22
+ const tx = Transaction.from(transactionLike);
23
+ const txHash = tx.hash();
19
24
 
20
- isUnusable(outPointLike: OutPointLike): Promise<boolean>;
25
+ return Promise.all([
26
+ ...tx.inputs.map((i) => this.markUnusable(i.previousOutput)),
27
+ ...tx.outputs.map((o, i) =>
28
+ this.markUsable({
29
+ cellOutput: o,
30
+ outputData: tx.outputsData[i],
31
+ outPoint: {
32
+ txHash,
33
+ index: i,
34
+ },
35
+ }),
36
+ ),
37
+ ]);
38
+ }),
39
+ ]);
40
+ }
41
+ abstract clear(): Promise<void>;
42
+ abstract findCells(
43
+ filter: ClientCollectableSearchKeyLike,
44
+ ): AsyncGenerator<Cell>;
45
+ /**
46
+ * Get a known cell by out point
47
+ * @param _outPoint
48
+ */
49
+ abstract getCell(_outPoint: OutPointLike): Promise<Cell | undefined>;
50
+ abstract isUnusable(outPointLike: OutPointLike): Promise<boolean>;
21
51
 
22
- recordTransactions(
23
- ...transactions: (TransactionLike | TransactionLike[])[]
24
- ): Promise<void>;
25
- getTransaction(txHash: HexLike): Promise<Transaction | undefined>;
52
+ /**
53
+ * Record known transactions
54
+ * Implement this method to enable transactions query caching
55
+ * @param _transactions
56
+ */
57
+ async recordTransactions(
58
+ ..._transactions: (TransactionLike | TransactionLike[])[]
59
+ ): Promise<void> {}
60
+ /**
61
+ * Get a known transaction by hash
62
+ * Implement this method to enable transactions query caching
63
+ * @param _txHash
64
+ */
65
+ async getTransaction(_txHash: HexLike): Promise<Transaction | undefined> {
66
+ return;
67
+ }
26
68
 
27
- recordCells(...cells: (CellLike | CellLike[])[]): Promise<void>;
28
- getCell(outPoint: OutPointLike): Promise<Cell | undefined>;
29
- findCells(filter: ClientCollectableSearchKeyLike): AsyncGenerator<Cell>;
69
+ /**
70
+ * Record known cells
71
+ * Implement this method to enable cells query caching
72
+ * @param _cells
73
+ */
74
+ async recordCells(..._cells: (CellLike | CellLike[])[]): Promise<void> {}
30
75
  }
@@ -11,24 +11,32 @@ import { ClientCollectableSearchKeyLike } from "../clientTypes.advanced.js";
11
11
  import { ClientCache } from "./cache.js";
12
12
  import { filterCell } from "./memory.advanced.js";
13
13
 
14
- export class ClientCacheMemory implements ClientCache {
15
- private readonly unusableOutPoints: OutPoint[] = [];
16
- private readonly usableCells: Cell[] = [];
17
- private readonly knownTransactions: Transaction[] = [];
18
- private readonly knownCells: Cell[] = [];
14
+ export class ClientCacheMemory extends ClientCache {
15
+ /**
16
+ * OutPoint => [isLive, Cell | OutPoint]
17
+ */
18
+ private readonly cells: Map<
19
+ string,
20
+ | [
21
+ false,
22
+ Pick<Cell, "outPoint"> &
23
+ Partial<Pick<Cell, "cellOutput" | "outputData">>,
24
+ ]
25
+ | [true, Cell]
26
+ | [undefined, Cell]
27
+ > = new Map();
28
+
29
+ /**
30
+ * TX Hash => Transaction
31
+ */
32
+ private readonly knownTransactions: Map<string, Transaction> = new Map();
19
33
 
20
34
  async markUsable(...cellLikes: (CellLike | CellLike[])[]): Promise<void> {
21
35
  cellLikes.flat().forEach((cellLike) => {
22
36
  const cell = Cell.from(cellLike).clone();
23
- this.usableCells.push(cell);
24
- this.knownCells.push(cell);
37
+ const outPointStr = hexFrom(cell.outPoint.toBytes());
25
38
 
26
- const index = this.unusableOutPoints.findIndex((o) =>
27
- cell.outPoint.eq(o),
28
- );
29
- if (index !== -1) {
30
- this.unusableOutPoints.splice(index, 1);
31
- }
39
+ this.cells.set(outPointStr, [true, cell]);
32
40
  });
33
41
  }
34
42
 
@@ -37,74 +45,74 @@ export class ClientCacheMemory implements ClientCache {
37
45
  ): Promise<void> {
38
46
  outPointLikes.flat().forEach((outPointLike) => {
39
47
  const outPoint = OutPoint.from(outPointLike);
40
- this.unusableOutPoints.push(outPoint.clone());
48
+ const outPointStr = hexFrom(outPoint.toBytes());
41
49
 
42
- const index = this.usableCells.findIndex((c) => c.outPoint.eq(outPoint));
43
- if (index !== -1) {
44
- this.usableCells.splice(index, 1);
50
+ const existed = this.cells.get(outPointStr);
51
+ if (existed) {
52
+ existed[0] = false;
53
+ return;
45
54
  }
55
+ this.cells.set(outPointStr, [false, { outPoint }]);
46
56
  });
47
57
  }
48
58
 
49
- async markTransactions(
50
- ...transactionLike: (TransactionLike | TransactionLike[])[]
51
- ): Promise<void> {
52
- await Promise.all(
53
- transactionLike.flat().map(async (transactionLike) => {
54
- const tx = Transaction.from(transactionLike);
55
- const txHash = tx.hash();
56
-
57
- await Promise.all(
58
- tx.inputs.map((i) => this.markUnusable(i.previousOutput)),
59
- );
60
- await Promise.all(
61
- tx.outputs.map((o, i) =>
62
- this.markUsable({
63
- cellOutput: o,
64
- outputData: tx.outputsData[i],
65
- outPoint: {
66
- txHash,
67
- index: i,
68
- },
69
- }),
70
- ),
71
- );
72
- }),
73
- );
59
+ async clear(): Promise<void> {
60
+ for (const val of this.cells.values()) {
61
+ val[0] = undefined;
62
+ }
74
63
  }
75
64
 
76
65
  async *findCells(
77
66
  keyLike: ClientCollectableSearchKeyLike,
78
67
  ): AsyncGenerator<Cell> {
79
- for (const cell of this.usableCells) {
68
+ for (const [isLive, cell] of this.cells.values()) {
69
+ if (!isLive) {
70
+ continue;
71
+ }
80
72
  if (!filterCell(keyLike, cell)) {
81
73
  continue;
82
74
  }
83
75
 
84
- yield cell;
76
+ yield cell.clone();
77
+ }
78
+ }
79
+ async getCell(outPointLike: OutPointLike): Promise<Cell | undefined> {
80
+ const outPoint = OutPoint.from(outPointLike);
81
+
82
+ const cell = this.cells.get(hexFrom(outPoint.toBytes()))?.[1];
83
+ if (cell && cell.cellOutput && cell.outputData) {
84
+ return Cell.from((cell as Cell).clone());
85
85
  }
86
86
  }
87
87
 
88
88
  async isUnusable(outPointLike: OutPointLike): Promise<boolean> {
89
89
  const outPoint = OutPoint.from(outPointLike);
90
- return this.unusableOutPoints.find((o) => o.eq(outPoint)) !== undefined;
90
+
91
+ return !(this.cells.get(hexFrom(outPoint.toBytes()))?.[0] ?? true);
91
92
  }
92
93
 
93
94
  async recordTransactions(
94
95
  ...transactions: (TransactionLike | TransactionLike[])[]
95
96
  ): Promise<void> {
96
- this.knownTransactions.push(...transactions.flat().map(Transaction.from));
97
+ transactions.flat().map((txLike) => {
98
+ const tx = Transaction.from(txLike);
99
+ this.knownTransactions.set(tx.hash(), tx);
100
+ });
97
101
  }
98
102
  async getTransaction(txHashLike: HexLike): Promise<Transaction | undefined> {
99
103
  const txHash = hexFrom(txHashLike);
100
- return this.knownTransactions.find((tx) => tx.hash() === txHash);
104
+ return this.knownTransactions.get(txHash)?.clone();
101
105
  }
102
106
 
103
107
  async recordCells(...cells: (CellLike | CellLike[])[]): Promise<void> {
104
- this.knownCells.push(...cells.flat().map(Cell.from));
105
- }
106
- async getCell(outPointLike: OutPointLike): Promise<Cell | undefined> {
107
- const outPoint = OutPoint.from(outPointLike);
108
- return this.knownCells.find((cell) => cell.outPoint.eq(outPoint));
108
+ cells.flat().map((cellLike) => {
109
+ const cell = Cell.from(cellLike);
110
+ const outPointStr = hexFrom(cell.outPoint.toBytes());
111
+
112
+ if (this.cells.get(outPointStr)) {
113
+ return;
114
+ }
115
+ this.cells.set(outPointStr, [undefined, cell]);
116
+ });
109
117
  }
110
118
  }
@@ -155,6 +155,27 @@ export abstract class Client {
155
155
  return cell;
156
156
  }
157
157
 
158
+ abstract getCellLiveNoCache(
159
+ outPointLike: OutPointLike,
160
+ withData?: boolean | null,
161
+ includeTxPool?: boolean | null,
162
+ ): Promise<Cell | undefined>;
163
+ async getCellLive(
164
+ outPointLike: OutPointLike,
165
+ withData?: boolean | null,
166
+ includeTxPool?: boolean | null,
167
+ ): Promise<Cell | undefined> {
168
+ const cell = await this.getCellLiveNoCache(
169
+ outPointLike,
170
+ withData,
171
+ includeTxPool,
172
+ );
173
+ if (withData && cell) {
174
+ await this.cache.recordCells(cell);
175
+ }
176
+ return cell;
177
+ }
178
+
158
179
  abstract findCellsPagedNoCache(
159
180
  key: ClientIndexerSearchKeyLike,
160
181
  order?: "asc" | "desc",
@@ -1,6 +1,13 @@
1
- import { Cell, Epoch, Script, Transaction } from "../ckb/index.js";
2
- import { Hex, hexFrom } from "../hex/index.js";
3
- import { Num, NumLike } from "../num/index.js";
1
+ import {
2
+ Cell,
3
+ Epoch,
4
+ OutPoint,
5
+ OutPointLike,
6
+ Script,
7
+ Transaction,
8
+ } from "../ckb/index.js";
9
+ import { Hex, HexLike, hexFrom } from "../hex/index.js";
10
+ import { Num, NumLike, numFrom } from "../num/index.js";
4
11
  import { apply } from "../utils/index.js";
5
12
  import {
6
13
  ClientCollectableSearchKeyFilterLike,
@@ -231,3 +238,45 @@ export type ClientBlock = {
231
238
  transactions: Transaction[];
232
239
  uncles: ClientBlockUncle[];
233
240
  };
241
+
242
+ export interface ErrorClientBaseLike {
243
+ message?: string;
244
+ code?: number;
245
+ data: string;
246
+ }
247
+ export class ErrorClientBase extends Error {
248
+ public readonly code?: number;
249
+ public readonly data: string;
250
+
251
+ constructor(origin: ErrorClientBaseLike) {
252
+ super(origin.message);
253
+ this.code = origin.code;
254
+ this.data = origin.data;
255
+ }
256
+ }
257
+
258
+ export class ErrorClientResolveUnknown extends ErrorClientBase {
259
+ public readonly outPoint: OutPoint;
260
+ constructor(origin: ErrorClientBaseLike, outPointLike: OutPointLike) {
261
+ super(origin);
262
+ this.outPoint = OutPoint.from(outPointLike);
263
+ }
264
+ }
265
+
266
+ export class ErrorClientVerification extends ErrorClientBase {
267
+ public readonly sourceIndex: Num;
268
+ public readonly scriptCodeHash: Hex;
269
+
270
+ constructor(
271
+ origin: ErrorClientBaseLike,
272
+ public readonly source: "lock" | "inputType" | "outputType",
273
+ sourceIndex: NumLike,
274
+ public readonly errorCode: number,
275
+ public readonly scriptHashType: "data" | "type",
276
+ scriptCodeHash: HexLike,
277
+ ) {
278
+ super(origin);
279
+ this.sourceIndex = numFrom(sourceIndex);
280
+ this.scriptCodeHash = hexFrom(scriptCodeHash);
281
+ }
282
+ }