@ckb-ccc/core 1.5.0 → 1.6.0
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.
- package/CHANGELOG.md +18 -0
- package/dist/ckb/transaction.d.ts +57 -4
- package/dist/ckb/transaction.d.ts.map +1 -1
- package/dist/ckb/transaction.js +83 -26
- package/dist/client/cache/cache.d.ts +67 -11
- package/dist/client/cache/cache.d.ts.map +1 -1
- package/dist/client/cache/cache.js +94 -9
- package/dist/client/cache/memory.advanced.d.ts +2 -2
- package/dist/client/cache/memory.advanced.d.ts.map +1 -1
- package/dist/client/cache/memory.advanced.js +19 -7
- package/dist/client/cache/memory.d.ts +24 -7
- package/dist/client/cache/memory.d.ts.map +1 -1
- package/dist/client/cache/memory.js +76 -18
- package/dist/client/client.d.ts +27 -6
- package/dist/client/client.d.ts.map +1 -1
- package/dist/client/client.js +113 -22
- package/dist/client/clientPublicMainnet.d.ts.map +1 -1
- package/dist/client/clientPublicMainnet.js +1 -6
- package/dist/client/clientTypes.advanced.d.ts +3 -0
- package/dist/client/clientTypes.advanced.d.ts.map +1 -1
- package/dist/client/clientTypes.advanced.js +3 -0
- package/dist/client/clientTypes.d.ts +110 -13
- package/dist/client/clientTypes.d.ts.map +1 -1
- package/dist/client/clientTypes.js +118 -4
- package/dist/client/jsonRpc/client.d.ts +4 -4
- package/dist/client/jsonRpc/client.d.ts.map +1 -1
- package/dist/client/jsonRpc/client.js +4 -4
- package/dist/client/jsonRpc/transformers.js +3 -3
- package/dist/jsonRpc/transports/webSocket.d.ts.map +1 -1
- package/dist/jsonRpc/transports/webSocket.js +7 -3
- package/dist/molecule/predefined.d.ts +10 -10
- package/dist/molecule/predefined.d.ts.map +1 -1
- package/dist/utils/index.d.ts +4 -0
- package/dist/utils/index.d.ts.map +1 -1
- package/dist/utils/index.js +13 -1
- package/dist.commonjs/advanced.js +17 -7
- package/dist.commonjs/ckb/transaction.d.ts +57 -4
- package/dist.commonjs/ckb/transaction.d.ts.map +1 -1
- package/dist.commonjs/ckb/transaction.js +83 -26
- package/dist.commonjs/client/cache/cache.d.ts +67 -11
- package/dist.commonjs/client/cache/cache.d.ts.map +1 -1
- package/dist.commonjs/client/cache/cache.js +94 -9
- package/dist.commonjs/client/cache/memory.advanced.d.ts +2 -2
- package/dist.commonjs/client/cache/memory.advanced.d.ts.map +1 -1
- package/dist.commonjs/client/cache/memory.advanced.js +19 -7
- package/dist.commonjs/client/cache/memory.d.ts +24 -7
- package/dist.commonjs/client/cache/memory.d.ts.map +1 -1
- package/dist.commonjs/client/cache/memory.js +75 -17
- package/dist.commonjs/client/client.d.ts +27 -6
- package/dist.commonjs/client/client.d.ts.map +1 -1
- package/dist.commonjs/client/client.js +111 -20
- package/dist.commonjs/client/clientPublicMainnet.d.ts.map +1 -1
- package/dist.commonjs/client/clientPublicMainnet.js +1 -6
- package/dist.commonjs/client/clientTypes.advanced.d.ts +3 -0
- package/dist.commonjs/client/clientTypes.advanced.d.ts.map +1 -1
- package/dist.commonjs/client/clientTypes.advanced.js +4 -0
- package/dist.commonjs/client/clientTypes.d.ts +110 -13
- package/dist.commonjs/client/clientTypes.d.ts.map +1 -1
- package/dist.commonjs/client/clientTypes.js +123 -4
- package/dist.commonjs/client/jsonRpc/client.d.ts +4 -4
- package/dist.commonjs/client/jsonRpc/client.d.ts.map +1 -1
- package/dist.commonjs/client/jsonRpc/client.js +4 -4
- package/dist.commonjs/client/jsonRpc/transformers.js +2 -2
- package/dist.commonjs/index.js +17 -7
- package/dist.commonjs/jsonRpc/transports/webSocket.d.ts.map +1 -1
- package/dist.commonjs/jsonRpc/transports/webSocket.js +7 -3
- package/dist.commonjs/molecule/index.js +17 -7
- package/dist.commonjs/utils/index.d.ts +4 -0
- package/dist.commonjs/utils/index.d.ts.map +1 -1
- package/dist.commonjs/utils/index.js +13 -0
- package/package.json +1 -1
- package/src/ckb/transaction.ts +112 -41
- package/src/client/cache/cache.ts +126 -13
- package/src/client/cache/memory.advanced.ts +24 -7
- package/src/client/cache/memory.ts +130 -30
- package/src/client/client.ts +170 -27
- package/src/client/clientPublicMainnet.ts +1 -6
- package/src/client/clientTypes.advanced.ts +4 -0
- package/src/client/clientTypes.ts +224 -33
- package/src/client/jsonRpc/client.ts +11 -9
- package/src/client/jsonRpc/transformers.ts +2 -2
- package/src/jsonRpc/transports/webSocket.ts +17 -13
- package/src/utils/index.ts +14 -1
package/src/ckb/transaction.ts
CHANGED
|
@@ -229,8 +229,12 @@ export const CellOutputVec = mol.vector(CellOutput);
|
|
|
229
229
|
/**
|
|
230
230
|
* @public
|
|
231
231
|
*/
|
|
232
|
-
export type CellLike =
|
|
233
|
-
|
|
232
|
+
export type CellLike = (
|
|
233
|
+
| {
|
|
234
|
+
outPoint: OutPointLike;
|
|
235
|
+
}
|
|
236
|
+
| { previousOutput: OutPointLike }
|
|
237
|
+
) & {
|
|
234
238
|
cellOutput: CellOutputLike;
|
|
235
239
|
outputData: HexLike;
|
|
236
240
|
};
|
|
@@ -265,7 +269,7 @@ export class Cell {
|
|
|
265
269
|
}
|
|
266
270
|
|
|
267
271
|
return new Cell(
|
|
268
|
-
OutPoint.from(cell.outPoint),
|
|
272
|
+
OutPoint.from("outPoint" in cell ? cell.outPoint : cell.previousOutput),
|
|
269
273
|
CellOutput.from(cell.cellOutput),
|
|
270
274
|
hexFrom(cell.outputData),
|
|
271
275
|
);
|
|
@@ -450,8 +454,12 @@ export class Since extends mol.Entity.Base<SinceLike, Since>() {
|
|
|
450
454
|
/**
|
|
451
455
|
* @public
|
|
452
456
|
*/
|
|
453
|
-
export type CellInputLike =
|
|
454
|
-
|
|
457
|
+
export type CellInputLike = (
|
|
458
|
+
| {
|
|
459
|
+
previousOutput: OutPointLike;
|
|
460
|
+
}
|
|
461
|
+
| { outPoint: OutPointLike }
|
|
462
|
+
) & {
|
|
455
463
|
since?: SinceLike | NumLike | null;
|
|
456
464
|
cellOutput?: CellOutputLike | null;
|
|
457
465
|
outputData?: HexLike | null;
|
|
@@ -465,10 +473,7 @@ export type CellInputLike = {
|
|
|
465
473
|
since: Since,
|
|
466
474
|
previousOutput: OutPoint,
|
|
467
475
|
})
|
|
468
|
-
.mapIn((encodable: CellInputLike) => (
|
|
469
|
-
...encodable,
|
|
470
|
-
since: encodable.since ?? 0,
|
|
471
|
-
})),
|
|
476
|
+
.mapIn((encodable: CellInputLike) => CellInput.from(encodable)),
|
|
472
477
|
)
|
|
473
478
|
export class CellInput extends mol.Entity.Base<CellInputLike, CellInput>() {
|
|
474
479
|
/**
|
|
@@ -509,7 +514,11 @@ export class CellInput extends mol.Entity.Base<CellInputLike, CellInput>() {
|
|
|
509
514
|
}
|
|
510
515
|
|
|
511
516
|
return new CellInput(
|
|
512
|
-
OutPoint.from(
|
|
517
|
+
OutPoint.from(
|
|
518
|
+
"previousOutput" in cellInput
|
|
519
|
+
? cellInput.previousOutput
|
|
520
|
+
: cellInput.outPoint,
|
|
521
|
+
),
|
|
513
522
|
Since.from(cellInput.since ?? 0).toNum(),
|
|
514
523
|
apply(CellOutput.from, cellInput.cellOutput),
|
|
515
524
|
apply(hexFrom, cellInput.outputData),
|
|
@@ -539,6 +548,14 @@ export class CellInput extends mol.Entity.Base<CellInputLike, CellInput>() {
|
|
|
539
548
|
this.cellOutput = cell.cellOutput;
|
|
540
549
|
this.outputData = cell.outputData;
|
|
541
550
|
}
|
|
551
|
+
|
|
552
|
+
clone(): CellInput {
|
|
553
|
+
const cloned = super.clone();
|
|
554
|
+
cloned.cellOutput = this.cellOutput;
|
|
555
|
+
cloned.outputData = this.outputData;
|
|
556
|
+
|
|
557
|
+
return cloned;
|
|
558
|
+
}
|
|
542
559
|
}
|
|
543
560
|
export const CellInputVec = mol.vector(CellInput);
|
|
544
561
|
|
|
@@ -891,6 +908,11 @@ export class Transaction extends mol.Entity.Base<
|
|
|
891
908
|
});
|
|
892
909
|
}
|
|
893
910
|
|
|
911
|
+
/**
|
|
912
|
+
* @deprecated
|
|
913
|
+
* Use ccc.stringify instead.
|
|
914
|
+
* stringify the tx to JSON string.
|
|
915
|
+
*/
|
|
894
916
|
stringify(): string {
|
|
895
917
|
return JSON.stringify(this, (_, value) => {
|
|
896
918
|
if (typeof value === "bigint") {
|
|
@@ -1230,6 +1252,58 @@ export class Transaction extends mol.Entity.Base<
|
|
|
1230
1252
|
this.outputsData[index] = hexFrom(witness);
|
|
1231
1253
|
}
|
|
1232
1254
|
|
|
1255
|
+
/**
|
|
1256
|
+
* get input
|
|
1257
|
+
*
|
|
1258
|
+
* @param index - The cell input index
|
|
1259
|
+
*
|
|
1260
|
+
* @example
|
|
1261
|
+
* ```typescript
|
|
1262
|
+
* await tx.getInput(0);
|
|
1263
|
+
* ```
|
|
1264
|
+
*/
|
|
1265
|
+
getInput(index: NumLike): CellInput | undefined {
|
|
1266
|
+
return this.inputs[Number(numFrom(index))];
|
|
1267
|
+
}
|
|
1268
|
+
/**
|
|
1269
|
+
* add input
|
|
1270
|
+
*
|
|
1271
|
+
* @param inputLike - The cell input.
|
|
1272
|
+
*
|
|
1273
|
+
* @example
|
|
1274
|
+
* ```typescript
|
|
1275
|
+
* await tx.addInput({ });
|
|
1276
|
+
* ```
|
|
1277
|
+
*/
|
|
1278
|
+
addInput(inputLike: CellInputLike): number {
|
|
1279
|
+
return this.inputs.push(CellInput.from(inputLike));
|
|
1280
|
+
}
|
|
1281
|
+
|
|
1282
|
+
/**
|
|
1283
|
+
* get output
|
|
1284
|
+
*
|
|
1285
|
+
* @param index - The cell output index
|
|
1286
|
+
*
|
|
1287
|
+
* @example
|
|
1288
|
+
* ```typescript
|
|
1289
|
+
* await tx.getOutput(0);
|
|
1290
|
+
* ```
|
|
1291
|
+
*/
|
|
1292
|
+
getOutput(index: NumLike):
|
|
1293
|
+
| {
|
|
1294
|
+
cellOutput: CellOutput;
|
|
1295
|
+
outputData: Hex;
|
|
1296
|
+
}
|
|
1297
|
+
| undefined {
|
|
1298
|
+
const i = Number(numFrom(index));
|
|
1299
|
+
if (i >= this.outputs.length) {
|
|
1300
|
+
return;
|
|
1301
|
+
}
|
|
1302
|
+
return {
|
|
1303
|
+
cellOutput: this.outputs[i],
|
|
1304
|
+
outputData: this.outputsData[i] ?? "0x",
|
|
1305
|
+
};
|
|
1306
|
+
}
|
|
1233
1307
|
/**
|
|
1234
1308
|
* Add output
|
|
1235
1309
|
*
|
|
@@ -1245,7 +1319,7 @@ export class Transaction extends mol.Entity.Base<
|
|
|
1245
1319
|
outputLike: Omit<CellOutputLike, "capacity"> &
|
|
1246
1320
|
Partial<Pick<CellOutputLike, "capacity">>,
|
|
1247
1321
|
outputData: HexLike = "0x",
|
|
1248
|
-
):
|
|
1322
|
+
): number {
|
|
1249
1323
|
const output = CellOutput.from({
|
|
1250
1324
|
...outputLike,
|
|
1251
1325
|
capacity: outputLike.capacity ?? 0,
|
|
@@ -1255,8 +1329,10 @@ export class Transaction extends mol.Entity.Base<
|
|
|
1255
1329
|
output.occupiedSize + bytesFrom(outputData).length,
|
|
1256
1330
|
);
|
|
1257
1331
|
}
|
|
1258
|
-
const
|
|
1259
|
-
this.setOutputDataAt(
|
|
1332
|
+
const len = this.outputs.push(output);
|
|
1333
|
+
this.setOutputDataAt(len - 1, outputData);
|
|
1334
|
+
|
|
1335
|
+
return len;
|
|
1260
1336
|
}
|
|
1261
1337
|
|
|
1262
1338
|
/**
|
|
@@ -1415,15 +1491,7 @@ export class Transaction extends mol.Entity.Base<
|
|
|
1415
1491
|
acc = next;
|
|
1416
1492
|
}
|
|
1417
1493
|
|
|
1418
|
-
this.
|
|
1419
|
-
...collectedCells.map(({ outPoint, outputData, cellOutput }) =>
|
|
1420
|
-
CellInput.from({
|
|
1421
|
-
previousOutput: outPoint,
|
|
1422
|
-
outputData,
|
|
1423
|
-
cellOutput,
|
|
1424
|
-
}),
|
|
1425
|
-
),
|
|
1426
|
-
);
|
|
1494
|
+
collectedCells.forEach((cell) => this.addInput(cell));
|
|
1427
1495
|
if (fulfilled) {
|
|
1428
1496
|
return {
|
|
1429
1497
|
addedCount: collectedCells.length,
|
|
@@ -1543,13 +1611,7 @@ export class Transaction extends mol.Entity.Base<
|
|
|
1543
1611
|
continue;
|
|
1544
1612
|
}
|
|
1545
1613
|
|
|
1546
|
-
this.
|
|
1547
|
-
CellInput.from({
|
|
1548
|
-
previousOutput: cell.outPoint,
|
|
1549
|
-
outputData: cell.outputData,
|
|
1550
|
-
cellOutput: cell.cellOutput,
|
|
1551
|
-
}),
|
|
1552
|
-
);
|
|
1614
|
+
this.addInput(cell);
|
|
1553
1615
|
return 1;
|
|
1554
1616
|
}
|
|
1555
1617
|
|
|
@@ -1567,9 +1629,21 @@ export class Transaction extends mol.Entity.Base<
|
|
|
1567
1629
|
return this.completeInputsAddOne(from, filter);
|
|
1568
1630
|
}
|
|
1569
1631
|
|
|
1632
|
+
async fee(client: Client): Promise<Num> {
|
|
1633
|
+
return (await this.getInputsCapacity(client)) - this.getOutputsCapacity();
|
|
1634
|
+
}
|
|
1635
|
+
|
|
1636
|
+
async feeRate(client: Client): Promise<Num> {
|
|
1637
|
+
return (
|
|
1638
|
+
((await this.fee(client)) * numFrom(1000)) /
|
|
1639
|
+
numFrom(this.toBytes().length + 4)
|
|
1640
|
+
);
|
|
1641
|
+
}
|
|
1642
|
+
|
|
1570
1643
|
estimateFee(feeRate: NumLike): Num {
|
|
1571
1644
|
const txSize = this.toBytes().length + 4;
|
|
1572
|
-
|
|
1645
|
+
// + 999 then / 1000 to ceil the calculated fee
|
|
1646
|
+
return (numFrom(txSize) * numFrom(feeRate) + numFrom(999)) / numFrom(1000);
|
|
1573
1647
|
}
|
|
1574
1648
|
|
|
1575
1649
|
async completeFee(
|
|
@@ -1577,8 +1651,11 @@ export class Transaction extends mol.Entity.Base<
|
|
|
1577
1651
|
change: (tx: Transaction, capacity: Num) => Promise<NumLike> | NumLike,
|
|
1578
1652
|
expectedFeeRate?: NumLike,
|
|
1579
1653
|
filter?: ClientCollectableSearchKeyFilterLike,
|
|
1654
|
+
options?: { feeRateBlockRange?: NumLike; maxFeeRate?: NumLike },
|
|
1580
1655
|
): Promise<[number, boolean]> {
|
|
1581
|
-
const feeRate =
|
|
1656
|
+
const feeRate =
|
|
1657
|
+
expectedFeeRate ??
|
|
1658
|
+
(await from.client.getFeeRate(options?.feeRateBlockRange, options));
|
|
1582
1659
|
|
|
1583
1660
|
// Complete all inputs extra infos for cache
|
|
1584
1661
|
await this.getInputsCapacity(from.client);
|
|
@@ -1609,27 +1686,21 @@ export class Transaction extends mol.Entity.Base<
|
|
|
1609
1686
|
// The initial fee is calculated based on prepared transaction
|
|
1610
1687
|
leastFee = tx.estimateFee(feeRate);
|
|
1611
1688
|
}
|
|
1612
|
-
const
|
|
1613
|
-
(await tx.getInputsCapacity(from.client)) - tx.getOutputsCapacity();
|
|
1689
|
+
const fee = await tx.fee(from.client);
|
|
1614
1690
|
// The extra capacity paid the fee without a change
|
|
1615
|
-
if (
|
|
1691
|
+
if (fee === leastFee) {
|
|
1616
1692
|
this.copy(tx);
|
|
1617
1693
|
return [collected, false];
|
|
1618
1694
|
}
|
|
1619
1695
|
|
|
1620
|
-
const needed = numFrom(
|
|
1621
|
-
await Promise.resolve(change(tx, extraCapacity - leastFee)),
|
|
1622
|
-
);
|
|
1696
|
+
const needed = numFrom(await Promise.resolve(change(tx, fee - leastFee)));
|
|
1623
1697
|
// No enough extra capacity to create new cells for change
|
|
1624
1698
|
if (needed > Zero) {
|
|
1625
1699
|
leastExtraCapacity = needed;
|
|
1626
1700
|
continue;
|
|
1627
1701
|
}
|
|
1628
1702
|
|
|
1629
|
-
if (
|
|
1630
|
-
(await tx.getInputsCapacity(from.client)) - tx.getOutputsCapacity() !==
|
|
1631
|
-
leastFee
|
|
1632
|
-
) {
|
|
1703
|
+
if ((await tx.fee(from.client)) !== leastFee) {
|
|
1633
1704
|
throw new Error(
|
|
1634
1705
|
"The change function doesn't use all available capacity",
|
|
1635
1706
|
);
|
|
@@ -6,10 +6,31 @@ import {
|
|
|
6
6
|
TransactionLike,
|
|
7
7
|
} from "../../ckb/index.js";
|
|
8
8
|
import { HexLike } from "../../hex/index.js";
|
|
9
|
+
import { NumLike } from "../../num/index.js";
|
|
9
10
|
import { ClientCollectableSearchKeyLike } from "../clientTypes.advanced.js";
|
|
11
|
+
import {
|
|
12
|
+
ClientBlock,
|
|
13
|
+
ClientBlockHeader,
|
|
14
|
+
ClientBlockHeaderLike,
|
|
15
|
+
ClientBlockLike,
|
|
16
|
+
ClientTransactionResponse,
|
|
17
|
+
ClientTransactionResponseLike,
|
|
18
|
+
} from "../clientTypes.js";
|
|
10
19
|
|
|
20
|
+
/**
|
|
21
|
+
* @public
|
|
22
|
+
* The ClientCache class is mainly designed for chained transactions.
|
|
23
|
+
* Consumed & Created cells are "marked" so they can be correctly handled when composing transactions.
|
|
24
|
+
* It also act as cache for rpc requests to reduce cost, but this is optional.
|
|
25
|
+
*/
|
|
11
26
|
export abstract class ClientCache {
|
|
12
|
-
abstract
|
|
27
|
+
abstract markUsableNoCache(
|
|
28
|
+
...cellLikes: (CellLike | CellLike[])[]
|
|
29
|
+
): Promise<void>;
|
|
30
|
+
async markUsable(...cellLikes: (CellLike | CellLike[])[]): Promise<void> {
|
|
31
|
+
await this.recordCells(...cellLikes);
|
|
32
|
+
return this.markUsableNoCache(...cellLikes);
|
|
33
|
+
}
|
|
13
34
|
abstract markUnusable(
|
|
14
35
|
...outPointLike: (OutPointLike | OutPointLike[])[]
|
|
15
36
|
): Promise<void>;
|
|
@@ -17,7 +38,12 @@ export abstract class ClientCache {
|
|
|
17
38
|
...transactionLike: (TransactionLike | TransactionLike[])[]
|
|
18
39
|
): Promise<void> {
|
|
19
40
|
await Promise.all([
|
|
20
|
-
this.
|
|
41
|
+
this.recordTransactionResponses(
|
|
42
|
+
transactionLike.flat().map((transaction) => ({
|
|
43
|
+
transaction: transaction,
|
|
44
|
+
status: "sent",
|
|
45
|
+
})),
|
|
46
|
+
),
|
|
21
47
|
...transactionLike.flat().map((transactionLike) => {
|
|
22
48
|
const tx = Transaction.from(transactionLike);
|
|
23
49
|
const txHash = tx.hash();
|
|
@@ -42,34 +68,121 @@ export abstract class ClientCache {
|
|
|
42
68
|
abstract findCells(
|
|
43
69
|
filter: ClientCollectableSearchKeyLike,
|
|
44
70
|
): AsyncGenerator<Cell>;
|
|
71
|
+
abstract isUnusable(outPointLike: OutPointLike): Promise<boolean>;
|
|
72
|
+
|
|
73
|
+
// ======
|
|
74
|
+
// Following methods are for requests caching and optional.
|
|
75
|
+
// ======
|
|
76
|
+
|
|
77
|
+
/**
|
|
78
|
+
* Record known cells
|
|
79
|
+
* Implement this method to enable cells query caching
|
|
80
|
+
* @param _cells
|
|
81
|
+
*/
|
|
82
|
+
async recordCells(..._cells: (CellLike | CellLike[])[]): Promise<void> {}
|
|
45
83
|
/**
|
|
46
84
|
* Get a known cell by out point
|
|
85
|
+
* Implement this method to enable cells query caching
|
|
47
86
|
* @param _outPoint
|
|
48
87
|
*/
|
|
49
|
-
|
|
50
|
-
|
|
88
|
+
async getCell(_outPoint: OutPointLike): Promise<Cell | undefined> {
|
|
89
|
+
return;
|
|
90
|
+
}
|
|
51
91
|
|
|
52
92
|
/**
|
|
53
|
-
* Record known
|
|
93
|
+
* Record known transaction responses.
|
|
54
94
|
* Implement this method to enable transactions query caching
|
|
55
95
|
* @param _transactions
|
|
56
96
|
*/
|
|
57
|
-
async
|
|
58
|
-
..._transactions: (
|
|
97
|
+
async recordTransactionResponses(
|
|
98
|
+
..._transactions: (
|
|
99
|
+
| ClientTransactionResponseLike
|
|
100
|
+
| ClientTransactionResponseLike[]
|
|
101
|
+
)[]
|
|
59
102
|
): Promise<void> {}
|
|
60
103
|
/**
|
|
61
|
-
* Get a known transaction by hash
|
|
104
|
+
* Get a known transaction response by hash
|
|
62
105
|
* Implement this method to enable transactions query caching
|
|
63
106
|
* @param _txHash
|
|
64
107
|
*/
|
|
65
|
-
async
|
|
108
|
+
async getTransactionResponse(
|
|
109
|
+
_txHash: HexLike,
|
|
110
|
+
): Promise<ClientTransactionResponse | undefined> {
|
|
111
|
+
return;
|
|
112
|
+
}
|
|
113
|
+
/**
|
|
114
|
+
* Record known transactions.
|
|
115
|
+
* @param transactions
|
|
116
|
+
*/
|
|
117
|
+
async recordTransactions(
|
|
118
|
+
...transactions: (TransactionLike | TransactionLike[])[]
|
|
119
|
+
): Promise<void> {
|
|
120
|
+
return this.recordTransactionResponses(
|
|
121
|
+
transactions.flat().map((transaction) => ({
|
|
122
|
+
transaction,
|
|
123
|
+
status: "unknown",
|
|
124
|
+
})),
|
|
125
|
+
);
|
|
126
|
+
}
|
|
127
|
+
/**
|
|
128
|
+
* Get a known transaction by hash
|
|
129
|
+
* @param txHash
|
|
130
|
+
*/
|
|
131
|
+
async getTransaction(txHash: HexLike): Promise<Transaction | undefined> {
|
|
132
|
+
return (await this.getTransactionResponse(txHash))?.transaction;
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
/**
|
|
136
|
+
* Record known block headers.
|
|
137
|
+
* Implement this method to enable block headers query caching
|
|
138
|
+
* @param _headers
|
|
139
|
+
*/
|
|
140
|
+
async recordHeaders(
|
|
141
|
+
..._headers: (ClientBlockHeaderLike | ClientBlockHeaderLike[])[]
|
|
142
|
+
): Promise<void> {}
|
|
143
|
+
/**
|
|
144
|
+
* Get a known block header by hash
|
|
145
|
+
* Implement this method to enable block headers query caching
|
|
146
|
+
* @param _hash
|
|
147
|
+
*/
|
|
148
|
+
async getHeaderByHash(
|
|
149
|
+
_hash: HexLike,
|
|
150
|
+
): Promise<ClientBlockHeader | undefined> {
|
|
151
|
+
return;
|
|
152
|
+
}
|
|
153
|
+
/**
|
|
154
|
+
* Get a known block header by number
|
|
155
|
+
* Implement this method to enable block headers query caching
|
|
156
|
+
* @param _number
|
|
157
|
+
*/
|
|
158
|
+
async getHeaderByNumber(
|
|
159
|
+
_number: NumLike,
|
|
160
|
+
): Promise<ClientBlockHeader | undefined> {
|
|
66
161
|
return;
|
|
67
162
|
}
|
|
68
163
|
|
|
69
164
|
/**
|
|
70
|
-
* Record known
|
|
71
|
-
* Implement this method to enable
|
|
72
|
-
* @param
|
|
165
|
+
* Record known blocks.
|
|
166
|
+
* Implement this method to enable blocks query caching
|
|
167
|
+
* @param _blocks
|
|
73
168
|
*/
|
|
74
|
-
async
|
|
169
|
+
async recordBlocks(
|
|
170
|
+
..._blocks: (ClientBlockLike | ClientBlockLike[])[]
|
|
171
|
+
): Promise<void> {}
|
|
172
|
+
/**
|
|
173
|
+
* Get a known block header by hash
|
|
174
|
+
* Implement this method to enable block headers query caching
|
|
175
|
+
* @param _hash
|
|
176
|
+
*/
|
|
177
|
+
async getBlockByHash(_hash: HexLike): Promise<ClientBlock | undefined> {
|
|
178
|
+
return;
|
|
179
|
+
}
|
|
180
|
+
/**
|
|
181
|
+
* Get a known block header by number
|
|
182
|
+
* Implement this method to enable block headers query caching
|
|
183
|
+
* @param _number
|
|
184
|
+
*/
|
|
185
|
+
async getBlockByNumber(_number: NumLike): Promise<ClientBlock | undefined> {
|
|
186
|
+
return;
|
|
187
|
+
}
|
|
75
188
|
}
|
|
@@ -149,7 +149,12 @@ export class MapLru<K, V> extends Map<K, V> {
|
|
|
149
149
|
super();
|
|
150
150
|
}
|
|
151
151
|
|
|
152
|
-
|
|
152
|
+
get(key: K) {
|
|
153
|
+
const val = super.get(key);
|
|
154
|
+
if (val === undefined) {
|
|
155
|
+
return;
|
|
156
|
+
}
|
|
157
|
+
|
|
153
158
|
const index = this.lru.indexOf(key);
|
|
154
159
|
if (index !== -1) {
|
|
155
160
|
this.lru.splice(index, 1);
|
|
@@ -159,15 +164,27 @@ export class MapLru<K, V> extends Map<K, V> {
|
|
|
159
164
|
this.delete(this.lru[0]);
|
|
160
165
|
this.lru.shift();
|
|
161
166
|
}
|
|
162
|
-
}
|
|
163
167
|
|
|
164
|
-
|
|
165
|
-
this.access(key);
|
|
166
|
-
return super.get(key);
|
|
168
|
+
return val;
|
|
167
169
|
}
|
|
168
170
|
|
|
169
171
|
set(key: K, value: V) {
|
|
170
|
-
this.
|
|
171
|
-
|
|
172
|
+
this.get(key);
|
|
173
|
+
|
|
174
|
+
super.set(key, value);
|
|
175
|
+
return this;
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
delete(key: K): boolean {
|
|
179
|
+
if (!super.delete(key)) {
|
|
180
|
+
return false;
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
const index = this.lru.indexOf(key);
|
|
184
|
+
if (index !== -1) {
|
|
185
|
+
this.lru.splice(index, 1);
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
return true;
|
|
172
189
|
}
|
|
173
190
|
}
|
|
@@ -1,13 +1,15 @@
|
|
|
1
|
-
import {
|
|
2
|
-
Cell,
|
|
3
|
-
CellLike,
|
|
4
|
-
OutPoint,
|
|
5
|
-
OutPointLike,
|
|
6
|
-
Transaction,
|
|
7
|
-
TransactionLike,
|
|
8
|
-
} from "../../ckb/index.js";
|
|
1
|
+
import { Cell, CellLike, OutPoint, OutPointLike } from "../../ckb/index.js";
|
|
9
2
|
import { hexFrom, HexLike } from "../../hex/index.js";
|
|
3
|
+
import { Num, numFrom, NumLike } from "../../num/index.js";
|
|
10
4
|
import { ClientCollectableSearchKeyLike } from "../clientTypes.advanced.js";
|
|
5
|
+
import {
|
|
6
|
+
ClientBlock,
|
|
7
|
+
ClientBlockHeader,
|
|
8
|
+
ClientBlockHeaderLike,
|
|
9
|
+
ClientBlockLike,
|
|
10
|
+
ClientTransactionResponse,
|
|
11
|
+
ClientTransactionResponseLike,
|
|
12
|
+
} from "../clientTypes.js";
|
|
11
13
|
import { ClientCache } from "./cache.js";
|
|
12
14
|
import { CellRecord, filterCell, MapLru } from "./memory.advanced.js";
|
|
13
15
|
|
|
@@ -18,21 +20,44 @@ export class ClientCacheMemory extends ClientCache {
|
|
|
18
20
|
private readonly cells: MapLru<string, CellRecord>;
|
|
19
21
|
|
|
20
22
|
/**
|
|
21
|
-
* TX Hash => Transaction
|
|
23
|
+
* TX Hash => Transaction Response
|
|
24
|
+
*/
|
|
25
|
+
private readonly knownTransactions: MapLru<string, ClientTransactionResponse>;
|
|
26
|
+
|
|
27
|
+
/**
|
|
28
|
+
* Block Number => Block Hash
|
|
29
|
+
*/
|
|
30
|
+
private readonly knownBlockHashes: MapLru<Num, string>;
|
|
31
|
+
|
|
32
|
+
/**
|
|
33
|
+
* Block Hash => Block Header / Full Block
|
|
22
34
|
*/
|
|
23
|
-
private readonly
|
|
35
|
+
private readonly knownBlocks: MapLru<
|
|
36
|
+
string,
|
|
37
|
+
Pick<ClientBlock, "header"> | ClientBlock
|
|
38
|
+
>;
|
|
24
39
|
|
|
25
40
|
constructor(
|
|
26
41
|
private readonly maxCells = 512,
|
|
27
42
|
private readonly maxTxs = 256,
|
|
43
|
+
private readonly maxBlocks = 128,
|
|
28
44
|
) {
|
|
29
45
|
super();
|
|
30
46
|
|
|
31
47
|
this.cells = new MapLru<string, CellRecord>(this.maxCells);
|
|
32
|
-
this.knownTransactions = new MapLru<string,
|
|
48
|
+
this.knownTransactions = new MapLru<string, ClientTransactionResponse>(
|
|
49
|
+
this.maxTxs,
|
|
50
|
+
);
|
|
51
|
+
this.knownBlockHashes = new MapLru<Num, string>(this.maxBlocks);
|
|
52
|
+
this.knownBlocks = new MapLru<
|
|
53
|
+
string,
|
|
54
|
+
Pick<ClientBlock, "header"> | ClientBlock
|
|
55
|
+
>(this.maxBlocks);
|
|
33
56
|
}
|
|
34
57
|
|
|
35
|
-
async
|
|
58
|
+
async markUsableNoCache(
|
|
59
|
+
...cellLikes: (CellLike | CellLike[])[]
|
|
60
|
+
): Promise<void> {
|
|
36
61
|
cellLikes.flat().forEach((cellLike) => {
|
|
37
62
|
const cell = Cell.from(cellLike).clone();
|
|
38
63
|
const outPointStr = hexFrom(cell.outPoint.toBytes());
|
|
@@ -73,10 +98,28 @@ export class ClientCacheMemory extends ClientCache {
|
|
|
73
98
|
continue;
|
|
74
99
|
}
|
|
75
100
|
|
|
76
|
-
this.cells.
|
|
101
|
+
this.cells.get(key);
|
|
77
102
|
yield cell.clone();
|
|
78
103
|
}
|
|
79
104
|
}
|
|
105
|
+
|
|
106
|
+
async isUnusable(outPointLike: OutPointLike): Promise<boolean> {
|
|
107
|
+
const outPoint = OutPoint.from(outPointLike);
|
|
108
|
+
|
|
109
|
+
return !(this.cells.get(hexFrom(outPoint.toBytes()))?.[0] ?? true);
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
async recordCells(...cells: (CellLike | CellLike[])[]): Promise<void> {
|
|
113
|
+
cells.flat().map((cellLike) => {
|
|
114
|
+
const cell = Cell.from(cellLike);
|
|
115
|
+
const outPointStr = hexFrom(cell.outPoint.toBytes());
|
|
116
|
+
|
|
117
|
+
if (this.cells.get(outPointStr)) {
|
|
118
|
+
return;
|
|
119
|
+
}
|
|
120
|
+
this.cells.set(outPointStr, [undefined, cell]);
|
|
121
|
+
});
|
|
122
|
+
}
|
|
80
123
|
async getCell(outPointLike: OutPointLike): Promise<Cell | undefined> {
|
|
81
124
|
const outPoint = OutPoint.from(outPointLike);
|
|
82
125
|
|
|
@@ -86,34 +129,91 @@ export class ClientCacheMemory extends ClientCache {
|
|
|
86
129
|
}
|
|
87
130
|
}
|
|
88
131
|
|
|
89
|
-
async
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
async recordTransactions(
|
|
96
|
-
...transactions: (TransactionLike | TransactionLike[])[]
|
|
132
|
+
async recordTransactionResponses(
|
|
133
|
+
...transactions: (
|
|
134
|
+
| ClientTransactionResponseLike
|
|
135
|
+
| ClientTransactionResponseLike[]
|
|
136
|
+
)[]
|
|
97
137
|
): Promise<void> {
|
|
98
138
|
transactions.flat().map((txLike) => {
|
|
99
|
-
const tx =
|
|
100
|
-
this.knownTransactions.set(tx.hash(), tx);
|
|
139
|
+
const tx = ClientTransactionResponse.from(txLike);
|
|
140
|
+
this.knownTransactions.set(tx.transaction.hash(), tx);
|
|
101
141
|
});
|
|
102
142
|
}
|
|
103
|
-
async
|
|
143
|
+
async getTransactionResponse(
|
|
144
|
+
txHashLike: HexLike,
|
|
145
|
+
): Promise<ClientTransactionResponse | undefined> {
|
|
104
146
|
const txHash = hexFrom(txHashLike);
|
|
105
147
|
return this.knownTransactions.get(txHash)?.clone();
|
|
106
148
|
}
|
|
107
149
|
|
|
108
|
-
async
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
150
|
+
async recordHeaders(
|
|
151
|
+
...headers: (ClientBlockHeaderLike | ClientBlockHeaderLike[])[]
|
|
152
|
+
): Promise<void> {
|
|
153
|
+
headers.flat().map((headerLike) => {
|
|
154
|
+
const header = ClientBlockHeader.from(headerLike);
|
|
112
155
|
|
|
113
|
-
|
|
156
|
+
this.knownBlockHashes.set(header.number, header.hash);
|
|
157
|
+
|
|
158
|
+
const existed = this.knownBlocks.get(header.hash);
|
|
159
|
+
if (existed) {
|
|
114
160
|
return;
|
|
115
161
|
}
|
|
116
|
-
this.
|
|
162
|
+
this.knownBlocks.set(header.hash, { header });
|
|
117
163
|
});
|
|
118
164
|
}
|
|
165
|
+
async getHeaderByHash(
|
|
166
|
+
hashLike: HexLike,
|
|
167
|
+
): Promise<ClientBlockHeader | undefined> {
|
|
168
|
+
const hash = hexFrom(hashLike);
|
|
169
|
+
const block = this.knownBlocks.get(hash);
|
|
170
|
+
if (block) {
|
|
171
|
+
this.knownBlockHashes.get(block.header.number); // For LRU
|
|
172
|
+
}
|
|
173
|
+
return block?.header;
|
|
174
|
+
}
|
|
175
|
+
async getHeaderByNumber(
|
|
176
|
+
numberLike: NumLike,
|
|
177
|
+
): Promise<ClientBlockHeader | undefined> {
|
|
178
|
+
const number = numFrom(numberLike);
|
|
179
|
+
|
|
180
|
+
const hash = this.knownBlockHashes.get(number);
|
|
181
|
+
if (!hash) {
|
|
182
|
+
return;
|
|
183
|
+
}
|
|
184
|
+
return this.getHeaderByHash(hash);
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
async recordBlocks(
|
|
188
|
+
...blocks: (ClientBlockLike | ClientBlockLike[])[]
|
|
189
|
+
): Promise<void> {
|
|
190
|
+
blocks.flat().map((blockLike) => {
|
|
191
|
+
const block = ClientBlock.from(blockLike);
|
|
192
|
+
|
|
193
|
+
this.knownBlockHashes.set(block.header.number, block.header.hash);
|
|
194
|
+
this.knownBlocks.set(block.header.hash, block);
|
|
195
|
+
});
|
|
196
|
+
}
|
|
197
|
+
async getBlockByHash(hashLike: HexLike): Promise<ClientBlock | undefined> {
|
|
198
|
+
const hash = hexFrom(hashLike);
|
|
199
|
+
const block = this.knownBlocks.get(hash);
|
|
200
|
+
if (block) {
|
|
201
|
+
this.knownBlockHashes.get(block.header.number); // For LRU
|
|
202
|
+
if ("transactions" in block) {
|
|
203
|
+
return block;
|
|
204
|
+
}
|
|
205
|
+
}
|
|
206
|
+
return;
|
|
207
|
+
}
|
|
208
|
+
async getBlockByNumber(
|
|
209
|
+
numberLike: NumLike,
|
|
210
|
+
): Promise<ClientBlock | undefined> {
|
|
211
|
+
const number = numFrom(numberLike);
|
|
212
|
+
|
|
213
|
+
const hash = this.knownBlockHashes.get(number);
|
|
214
|
+
if (!hash) {
|
|
215
|
+
return;
|
|
216
|
+
}
|
|
217
|
+
return this.getBlockByHash(hash);
|
|
218
|
+
}
|
|
119
219
|
}
|