@ckb-ccc/core 1.19.1 → 1.20.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 +39 -0
- package/dist/advanced.d.mts +2 -2
- package/dist/advanced.mjs +1 -1
- package/{dist.commonjs/advancedBarrel-CSQ2SmeJ.d.ts → dist/advancedBarrel-CZxkR1dk.d.mts} +2025 -1639
- package/dist/advancedBarrel-CZxkR1dk.d.mts.map +1 -0
- package/dist/advancedBarrel.d.mts +2 -2
- package/dist/advancedBarrel.mjs +1 -1
- package/dist/advancedBarrel.mjs.map +1 -1
- package/dist/barrel-CqiwnGqc.mjs +7 -0
- package/dist/barrel-CqiwnGqc.mjs.map +1 -0
- package/dist/barrel.d.mts +2 -2
- package/dist/barrel.mjs +1 -1
- package/dist/index.d.mts +2 -2
- package/dist/index.mjs +1 -1
- package/dist/transformers-BJyj6caX.mjs +2 -0
- package/dist/transformers-BJyj6caX.mjs.map +1 -0
- package/dist.commonjs/advanced.d.ts +2 -2
- package/dist.commonjs/advanced.js +1 -1
- package/{dist/advancedBarrel-BwJIDnvL.d.mts → dist.commonjs/advancedBarrel-Czsr2VlG.d.ts} +2026 -1638
- package/dist.commonjs/advancedBarrel-Czsr2VlG.d.ts.map +1 -0
- package/dist.commonjs/advancedBarrel.d.ts +2 -2
- package/dist.commonjs/advancedBarrel.js +1 -1
- package/dist.commonjs/advancedBarrel.js.map +1 -1
- package/dist.commonjs/barrel-BCS94_-c.js +23 -0
- package/dist.commonjs/barrel-BCS94_-c.js.map +1 -0
- package/dist.commonjs/barrel.d.ts +2 -2
- package/dist.commonjs/barrel.js +1 -1
- package/dist.commonjs/index.d.ts +2 -2
- package/dist.commonjs/index.js +1 -1
- package/dist.commonjs/{rolldown-runtime-DWNI8pZO.js → rolldown-runtime-Chgba0Kb.js} +1 -1
- package/dist.commonjs/transformers-Cue1Z8Up.js +2 -0
- package/dist.commonjs/transformers-Cue1Z8Up.js.map +1 -0
- package/package.json +8 -7
- package/src/advancedBarrel.ts +1 -0
- package/src/bytes/advanced.ts +1 -6
- package/src/bytes/index.ts +37 -10
- package/src/ckb/transaction.ts +5 -5
- package/src/client/client.ts +75 -19
- package/src/client/clientPublicMainnet.ts +75 -36
- package/src/client/clientPublicTestnet.ts +75 -36
- package/src/client/jsonRpc/client.ts +77 -30
- package/src/client/jsonRpc/transformers.ts +4 -4
- package/src/jsonRpc/index.ts +1 -0
- package/src/jsonRpc/requestor.ts +74 -21
- package/src/jsonRpc/transports/advanced.ts +0 -4
- package/src/jsonRpc/transports/factory.ts +12 -5
- package/src/jsonRpc/transports/fallback.ts +9 -5
- package/src/jsonRpc/transports/http.ts +21 -17
- package/src/jsonRpc/transports/index.ts +4 -0
- package/src/jsonRpc/transports/transport.ts +32 -6
- package/src/jsonRpc/transports/webSocket.ts +67 -20
- package/src/keystore/index.ts +3 -3
- package/src/molecule/codec.ts +20 -17
- package/src/signer/advanced.ts +1 -0
- package/src/signer/btc/verify.ts +2 -2
- package/src/signer/ckb/secp256k1Signing.ts +3 -3
- package/src/signer/doge/signerDoge.ts +1 -1
- package/src/signer/doge/signerDogePrivateKey.ts +1 -1
- package/src/signer/index.ts +1 -0
- package/src/signer/jsonRpc/handler.ts +217 -0
- package/src/signer/jsonRpc/index.ts +2 -0
- package/src/signer/jsonRpc/network.ts +15 -0
- package/src/signer/jsonRpc/signer.ts +181 -0
- package/src/signer/jsonRpc/transformers.ts +67 -0
- package/src/utils/abortSignal.ts +42 -0
- package/src/utils/index.ts +2 -0
- package/src/utils/owner/aggregated.ts +56 -0
- package/src/utils/owner/index.ts +4 -0
- package/src/utils/owner/owner.ts +141 -0
- package/src/utils/owner/refCount.ts +78 -0
- package/src/utils/owner/unique.ts +30 -0
- package/tsdown.config.mts +1 -0
- package/dist/address.advanced-Cka_9tcR.mjs +0 -2
- package/dist/address.advanced-Cka_9tcR.mjs.map +0 -1
- package/dist/advancedBarrel-BwJIDnvL.d.mts.map +0 -1
- package/dist/barrel-DsK2p-Rh.mjs +0 -7
- package/dist/barrel-DsK2p-Rh.mjs.map +0 -1
- package/dist.commonjs/address.advanced-BTrmYDic.js +0 -2
- package/dist.commonjs/address.advanced-BTrmYDic.js.map +0 -1
- package/dist.commonjs/advancedBarrel-CSQ2SmeJ.d.ts.map +0 -1
- package/dist.commonjs/barrel-D8_wJLfr.js +0 -23
- package/dist.commonjs/barrel-D8_wJLfr.js.map +0 -1
|
@@ -10,8 +10,8 @@ import {
|
|
|
10
10
|
RequestorJsonRpcConfig,
|
|
11
11
|
} from "../../jsonRpc/requestor.js";
|
|
12
12
|
import { Num, NumLike, numFrom, numToHex } from "../../num/index.js";
|
|
13
|
-
import { apply } from "../../utils/index.js";
|
|
14
|
-
import {
|
|
13
|
+
import { Owner, apply } from "../../utils/index.js";
|
|
14
|
+
import type { ClientConfig } from "../client.js";
|
|
15
15
|
import { Client } from "../client.js";
|
|
16
16
|
import { DEFAULT_MIN_FEE_RATE } from "../clientTypes.advanced.js";
|
|
17
17
|
import {
|
|
@@ -68,10 +68,35 @@ const ERROR_PARSERS: [
|
|
|
68
68
|
],
|
|
69
69
|
];
|
|
70
70
|
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
71
|
+
function handleJsonRpcError(errAny: unknown): never {
|
|
72
|
+
if (
|
|
73
|
+
typeof errAny !== "object" ||
|
|
74
|
+
errAny === null ||
|
|
75
|
+
!("data" in errAny) ||
|
|
76
|
+
typeof errAny.data !== "string"
|
|
77
|
+
) {
|
|
78
|
+
throw errAny;
|
|
79
|
+
}
|
|
80
|
+
const err = errAny as ErrorClientBaseLike;
|
|
81
|
+
|
|
82
|
+
for (const [regexp, builder] of ERROR_PARSERS) {
|
|
83
|
+
const match = err.data.match(regexp);
|
|
84
|
+
if (match) {
|
|
85
|
+
throw builder(err, match);
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
throw new ErrorClientBase(err);
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
export type ClientJsonRpcConfig = RequestorJsonRpcConfig &
|
|
93
|
+
ClientConfig & {
|
|
94
|
+
/**
|
|
95
|
+
* @deprecated Requestor injection is supported only by legacy constructors.
|
|
96
|
+
* Use a borrowed Transport with `Client.new` or let `Client.open` create one.
|
|
97
|
+
*/
|
|
98
|
+
requestor?: RequestorJsonRpc;
|
|
99
|
+
};
|
|
75
100
|
|
|
76
101
|
/**
|
|
77
102
|
* An abstract class implementing JSON-RPC client functionality for a specific URL and timeout.
|
|
@@ -85,42 +110,64 @@ export abstract class ClientJsonRpc extends Client {
|
|
|
85
110
|
*
|
|
86
111
|
* @param url_ - The URL of the JSON-RPC server.
|
|
87
112
|
* @param timeout - The timeout for requests in milliseconds
|
|
113
|
+
* @deprecated Use the concrete Client's `new` or `open` method.
|
|
88
114
|
*/
|
|
89
115
|
|
|
90
|
-
constructor(
|
|
116
|
+
constructor(
|
|
117
|
+
private readonly url_: string,
|
|
118
|
+
config?: ClientJsonRpcConfig,
|
|
119
|
+
) {
|
|
91
120
|
super(config);
|
|
92
121
|
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
) {
|
|
102
|
-
throw errAny;
|
|
103
|
-
}
|
|
104
|
-
const err = errAny as ErrorClientBaseLike;
|
|
105
|
-
|
|
106
|
-
for (const [regexp, builder] of ERROR_PARSERS) {
|
|
107
|
-
const match = err.data.match(regexp);
|
|
108
|
-
if (match) {
|
|
109
|
-
throw builder(err, match);
|
|
110
|
-
}
|
|
111
|
-
}
|
|
112
|
-
|
|
113
|
-
throw new ErrorClientBase(err);
|
|
122
|
+
const requestor = config?.requestor;
|
|
123
|
+
if (requestor) {
|
|
124
|
+
this.requestor = requestor;
|
|
125
|
+
} else if (config?.transport) {
|
|
126
|
+
this.requestor = RequestorJsonRpc.new({
|
|
127
|
+
transport: config.transport,
|
|
128
|
+
maxConcurrent: config.maxConcurrent,
|
|
129
|
+
onError: handleJsonRpcError,
|
|
114
130
|
});
|
|
131
|
+
} else {
|
|
132
|
+
// Legacy constructor intentionally discards ownership.
|
|
133
|
+
this.requestor = RequestorJsonRpc.open({
|
|
134
|
+
urls: [url_, ...(config?.fallbacks ?? [])],
|
|
135
|
+
timeout: config?.timeout,
|
|
136
|
+
maxConcurrent: config?.maxConcurrent,
|
|
137
|
+
onError: handleJsonRpcError,
|
|
138
|
+
}).value;
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
/** Creates a Requestor that borrows an existing Transport. */
|
|
143
|
+
protected static newRequestor(
|
|
144
|
+
config: Omit<Parameters<typeof RequestorJsonRpc.new>[0], "onError">,
|
|
145
|
+
): RequestorJsonRpc {
|
|
146
|
+
return RequestorJsonRpc.new({
|
|
147
|
+
...config,
|
|
148
|
+
onError: handleJsonRpcError,
|
|
149
|
+
});
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
/** Opens a Requestor with ownership of its default Transport. */
|
|
153
|
+
protected static openRequestor(
|
|
154
|
+
config: Omit<Parameters<typeof RequestorJsonRpc.open>[0], "onError">,
|
|
155
|
+
): Owner<RequestorJsonRpc> {
|
|
156
|
+
return RequestorJsonRpc.open({
|
|
157
|
+
...config,
|
|
158
|
+
onError: handleJsonRpcError,
|
|
159
|
+
});
|
|
115
160
|
}
|
|
116
161
|
|
|
117
162
|
/**
|
|
118
|
-
* Returns the URL of the JSON-RPC server.
|
|
163
|
+
* Returns the legacy primary URL of the JSON-RPC server.
|
|
119
164
|
*
|
|
120
165
|
* @returns The URL of the JSON-RPC server.
|
|
166
|
+
* @deprecated A Client may use multiple endpoints or a Transport without a
|
|
167
|
+
* URL, so this value does not reliably identify its connection.
|
|
121
168
|
*/
|
|
122
169
|
get url(): string {
|
|
123
|
-
return this.
|
|
170
|
+
return this.url_;
|
|
124
171
|
}
|
|
125
172
|
|
|
126
173
|
/**
|
|
@@ -212,10 +212,10 @@ export class JsonRpcTransformers {
|
|
|
212
212
|
return {
|
|
213
213
|
compactTarget: numFrom(header.compact_target),
|
|
214
214
|
dao: {
|
|
215
|
-
c: numLeFromBytes(dao.
|
|
216
|
-
ar: numLeFromBytes(dao.
|
|
217
|
-
s: numLeFromBytes(dao.
|
|
218
|
-
u: numLeFromBytes(dao.
|
|
215
|
+
c: numLeFromBytes(dao.subarray(0, 8)),
|
|
216
|
+
ar: numLeFromBytes(dao.subarray(8, 16)),
|
|
217
|
+
s: numLeFromBytes(dao.subarray(16, 24)),
|
|
218
|
+
u: numLeFromBytes(dao.subarray(24, 32)),
|
|
219
219
|
},
|
|
220
220
|
epoch: Epoch.fromNum(header.epoch),
|
|
221
221
|
extraHash: header.extra_hash,
|
package/src/jsonRpc/index.ts
CHANGED
package/src/jsonRpc/requestor.ts
CHANGED
|
@@ -1,9 +1,24 @@
|
|
|
1
|
+
import { OwnerAggregated } from "../utils/owner/aggregated.js";
|
|
2
|
+
import { Owner } from "../utils/owner/owner.js";
|
|
3
|
+
import { jsonRpcTransportFromUri } from "./transports/factory.js";
|
|
4
|
+
import { JsonRpcTransportFallback } from "./transports/fallback.js";
|
|
1
5
|
import {
|
|
2
6
|
JsonRpcPayload,
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
+
JsonRpcResponse,
|
|
8
|
+
JsonRpcTransport,
|
|
9
|
+
} from "./transports/index.js";
|
|
10
|
+
|
|
11
|
+
function openTransports(
|
|
12
|
+
urls: readonly [string, ...string[]],
|
|
13
|
+
config?: { timeout?: number },
|
|
14
|
+
): Owner<JsonRpcTransportFallback> {
|
|
15
|
+
const transportOwners = Array.from(new Set(urls), (url) =>
|
|
16
|
+
jsonRpcTransportFromUri(url, config),
|
|
17
|
+
);
|
|
18
|
+
return OwnerAggregated.from(transportOwners).map(
|
|
19
|
+
(transports) => new JsonRpcTransportFallback([...transports]),
|
|
20
|
+
);
|
|
21
|
+
}
|
|
7
22
|
|
|
8
23
|
/**
|
|
9
24
|
* Applies a transformation function to a value if the transformer is provided.
|
|
@@ -25,11 +40,15 @@ function transform(value: unknown, transformer?: (i: unknown) => unknown) {
|
|
|
25
40
|
return value;
|
|
26
41
|
}
|
|
27
42
|
|
|
43
|
+
/**
|
|
44
|
+
* @deprecated Used only by the legacy positional constructor. Use the static
|
|
45
|
+
* {@link RequestorJsonRpc.new} or {@link RequestorJsonRpc.open} methods.
|
|
46
|
+
*/
|
|
28
47
|
export type RequestorJsonRpcConfig = {
|
|
29
48
|
fallbacks?: string[];
|
|
30
49
|
timeout?: number;
|
|
31
50
|
maxConcurrent?: number;
|
|
32
|
-
transport?:
|
|
51
|
+
transport?: JsonRpcTransport;
|
|
33
52
|
};
|
|
34
53
|
|
|
35
54
|
export class RequestorJsonRpc {
|
|
@@ -37,15 +56,17 @@ export class RequestorJsonRpc {
|
|
|
37
56
|
private concurrent = 0;
|
|
38
57
|
private readonly pending: (() => void)[] = [];
|
|
39
58
|
|
|
40
|
-
public readonly transport:
|
|
59
|
+
public readonly transport: JsonRpcTransport;
|
|
41
60
|
|
|
42
61
|
private id = 0;
|
|
43
62
|
|
|
44
63
|
/**
|
|
45
|
-
* Creates
|
|
64
|
+
* Creates a Requestor using legacy positional arguments.
|
|
46
65
|
*
|
|
47
66
|
* @param url_ - The URL of the JSON-RPC server.
|
|
48
67
|
* @param timeout - The timeout for requests in milliseconds
|
|
68
|
+
* @deprecated Use {@link RequestorJsonRpc.new} with a borrowed Transport or
|
|
69
|
+
* {@link RequestorJsonRpc.open} when creating Transports.
|
|
49
70
|
*/
|
|
50
71
|
constructor(
|
|
51
72
|
private readonly url_: string,
|
|
@@ -53,20 +74,56 @@ export class RequestorJsonRpc {
|
|
|
53
74
|
private readonly onError?: (err: unknown) => Promise<void> | void,
|
|
54
75
|
) {
|
|
55
76
|
this.maxConcurrent = config?.maxConcurrent;
|
|
56
|
-
|
|
57
|
-
config
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
77
|
+
if (config?.transport) {
|
|
78
|
+
this.transport = config.transport;
|
|
79
|
+
} else {
|
|
80
|
+
this.transport = openTransports(
|
|
81
|
+
[url_, ...(config?.fallbacks ?? [])],
|
|
82
|
+
config,
|
|
83
|
+
).value;
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
/** Creates a Requestor that borrows an existing Transport. */
|
|
88
|
+
static new({
|
|
89
|
+
transport,
|
|
90
|
+
maxConcurrent,
|
|
91
|
+
onError,
|
|
92
|
+
}: {
|
|
93
|
+
transport: JsonRpcTransport;
|
|
94
|
+
maxConcurrent?: number;
|
|
95
|
+
onError?: (err: unknown) => Promise<void> | void;
|
|
96
|
+
}): RequestorJsonRpc {
|
|
97
|
+
return new RequestorJsonRpc("", { transport, maxConcurrent }, onError);
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
/** Opens a Requestor with ownership of its default transports. */
|
|
101
|
+
static open({
|
|
102
|
+
urls: [url, ...fallbacks],
|
|
103
|
+
onError,
|
|
104
|
+
...config
|
|
105
|
+
}: {
|
|
106
|
+
urls: readonly [string, ...string[]];
|
|
107
|
+
timeout?: number;
|
|
108
|
+
maxConcurrent?: number;
|
|
109
|
+
onError?: (err: unknown) => Promise<void> | void;
|
|
110
|
+
}): Owner<RequestorJsonRpc> {
|
|
111
|
+
const transportOwner = openTransports([url, ...fallbacks], config);
|
|
112
|
+
return transportOwner.map((transport) =>
|
|
113
|
+
RequestorJsonRpc.new({
|
|
114
|
+
transport,
|
|
115
|
+
...config,
|
|
116
|
+
onError,
|
|
117
|
+
}),
|
|
118
|
+
);
|
|
64
119
|
}
|
|
65
120
|
|
|
66
121
|
/**
|
|
67
122
|
* Returns the URL of the JSON-RPC server.
|
|
68
123
|
*
|
|
69
124
|
* @returns The URL of the JSON-RPC server.
|
|
125
|
+
* @deprecated URL belongs to Transport construction and is unavailable for
|
|
126
|
+
* Requestors created with {@link RequestorJsonRpc.new}.
|
|
70
127
|
*/
|
|
71
128
|
|
|
72
129
|
get url(): string {
|
|
@@ -129,7 +186,7 @@ export class RequestorJsonRpc {
|
|
|
129
186
|
await pending;
|
|
130
187
|
}
|
|
131
188
|
|
|
132
|
-
const res =
|
|
189
|
+
const res: JsonRpcResponse = await (async () => {
|
|
133
190
|
this.concurrent += 1;
|
|
134
191
|
try {
|
|
135
192
|
return await this.transport.request(payload);
|
|
@@ -137,11 +194,7 @@ export class RequestorJsonRpc {
|
|
|
137
194
|
this.concurrent -= 1;
|
|
138
195
|
this.pending.shift()?.();
|
|
139
196
|
}
|
|
140
|
-
})()
|
|
141
|
-
id: number;
|
|
142
|
-
error: unknown;
|
|
143
|
-
result: unknown;
|
|
144
|
-
};
|
|
197
|
+
})();
|
|
145
198
|
|
|
146
199
|
if (res.id !== payload.id) {
|
|
147
200
|
throw new Error(`Id mismatched, got ${res.id}, expected ${payload.id}`);
|
|
@@ -1,10 +1,17 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
1
|
+
import { OwnerUnique } from "../../utils/owner/unique.js";
|
|
2
|
+
import { JsonRpcTransportHttp } from "./http.js";
|
|
3
|
+
import { JsonRpcTransportWebSocket } from "./webSocket.js";
|
|
3
4
|
|
|
4
|
-
export function
|
|
5
|
+
export function jsonRpcTransportFromUri(
|
|
6
|
+
uri: string,
|
|
7
|
+
config?: { timeout?: number },
|
|
8
|
+
) {
|
|
5
9
|
if (uri.startsWith("wss://") || uri.startsWith("ws://")) {
|
|
6
|
-
return
|
|
10
|
+
return JsonRpcTransportWebSocket.open(uri, config?.timeout);
|
|
7
11
|
}
|
|
8
12
|
|
|
9
|
-
return new
|
|
13
|
+
return new OwnerUnique(
|
|
14
|
+
new JsonRpcTransportHttp(uri, config?.timeout),
|
|
15
|
+
() => {},
|
|
16
|
+
);
|
|
10
17
|
}
|
|
@@ -1,15 +1,19 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import {
|
|
2
|
+
JsonRpcPayload,
|
|
3
|
+
JsonRpcResponse,
|
|
4
|
+
JsonRpcTransport,
|
|
5
|
+
} from "./transport.js";
|
|
2
6
|
|
|
3
|
-
export class
|
|
7
|
+
export class JsonRpcTransportFallback implements JsonRpcTransport {
|
|
4
8
|
// Current transport index
|
|
5
9
|
private i = 0;
|
|
6
10
|
|
|
7
|
-
constructor(private readonly transports:
|
|
11
|
+
constructor(private readonly transports: JsonRpcTransport[]) {}
|
|
8
12
|
|
|
9
|
-
async request(data: JsonRpcPayload): Promise<
|
|
13
|
+
async request(data: JsonRpcPayload): Promise<JsonRpcResponse> {
|
|
10
14
|
const startI = this.i;
|
|
11
15
|
let lastErr: unknown = new Error(
|
|
12
|
-
"
|
|
16
|
+
"JsonRpcTransportFallback requires at least one transport",
|
|
13
17
|
);
|
|
14
18
|
|
|
15
19
|
for (let tried = 0; tried < this.transports.length; tried += 1) {
|
|
@@ -1,28 +1,32 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import {
|
|
2
|
+
JsonRpcPayload,
|
|
3
|
+
JsonRpcResponse,
|
|
4
|
+
JsonRpcTransport,
|
|
5
|
+
} from "./transport.js";
|
|
2
6
|
|
|
3
|
-
export class
|
|
7
|
+
export class JsonRpcTransportHttp implements JsonRpcTransport {
|
|
4
8
|
constructor(
|
|
5
9
|
private readonly url: string,
|
|
6
10
|
private readonly timeout = 30000,
|
|
7
11
|
) {}
|
|
8
12
|
|
|
9
|
-
async request(payload: JsonRpcPayload) {
|
|
13
|
+
async request(payload: JsonRpcPayload): Promise<JsonRpcResponse> {
|
|
10
14
|
const aborter = new AbortController();
|
|
11
15
|
const abortTimer = setTimeout(() => aborter.abort(), this.timeout);
|
|
12
16
|
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
17
|
+
try {
|
|
18
|
+
return (await (
|
|
19
|
+
await fetch(this.url, {
|
|
20
|
+
method: "POST",
|
|
21
|
+
headers: {
|
|
22
|
+
"content-type": "application/json",
|
|
23
|
+
},
|
|
24
|
+
body: JSON.stringify(payload),
|
|
25
|
+
signal: aborter.signal,
|
|
26
|
+
})
|
|
27
|
+
).json()) as JsonRpcResponse;
|
|
28
|
+
} finally {
|
|
29
|
+
clearTimeout(abortTimer);
|
|
30
|
+
}
|
|
27
31
|
}
|
|
28
32
|
}
|
|
@@ -1,18 +1,44 @@
|
|
|
1
|
+
export type JsonRpcId = string | number;
|
|
2
|
+
|
|
1
3
|
export type JsonRpcPayload = {
|
|
2
|
-
id:
|
|
4
|
+
id: JsonRpcId;
|
|
3
5
|
jsonrpc: "2.0";
|
|
4
6
|
method: string;
|
|
5
7
|
params: unknown[] | Record<string, unknown>;
|
|
6
8
|
};
|
|
7
9
|
|
|
8
|
-
export
|
|
10
|
+
export type JsonRpcErrorLike<Data = unknown> = {
|
|
11
|
+
code: number;
|
|
12
|
+
message: string;
|
|
13
|
+
data?: Data;
|
|
14
|
+
};
|
|
15
|
+
|
|
16
|
+
export class JsonRpcError<Data = unknown> extends Error {
|
|
17
|
+
readonly code: number;
|
|
18
|
+
readonly data?: Data;
|
|
19
|
+
|
|
20
|
+
constructor(error: JsonRpcErrorLike<Data>) {
|
|
21
|
+
super(error.message);
|
|
22
|
+
this.name = "JsonRpcError";
|
|
23
|
+
this.code = error.code;
|
|
24
|
+
this.data = error.data;
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
export type JsonRpcResponse<Result = unknown, ErrorData = unknown> = {
|
|
29
|
+
id: JsonRpcId;
|
|
30
|
+
jsonrpc: "2.0";
|
|
31
|
+
} & (
|
|
32
|
+
| { result: Result; error?: never }
|
|
33
|
+
| { result?: never; error: JsonRpcErrorLike<ErrorData> }
|
|
34
|
+
);
|
|
35
|
+
|
|
36
|
+
export interface JsonRpcTransport {
|
|
9
37
|
/**
|
|
10
38
|
* Sends a JSON-RPC request to the server.
|
|
11
39
|
*
|
|
12
40
|
* @param payload - The JSON-RPC payload to send.
|
|
13
|
-
* @returns The
|
|
14
|
-
*
|
|
15
|
-
* @throws Will throw an error if the response ID does not match the request ID, or if the response contains an error.
|
|
41
|
+
* @returns The JSON-RPC response.
|
|
16
42
|
*/
|
|
17
|
-
request(
|
|
43
|
+
request(payload: JsonRpcPayload): Promise<JsonRpcResponse>;
|
|
18
44
|
}
|
|
@@ -1,46 +1,76 @@
|
|
|
1
1
|
import WebSocket from "isomorphic-ws";
|
|
2
|
-
import {
|
|
2
|
+
import { OwnerUnique } from "../../utils/owner/unique.js";
|
|
3
|
+
import {
|
|
4
|
+
JsonRpcId,
|
|
5
|
+
JsonRpcPayload,
|
|
6
|
+
JsonRpcResponse,
|
|
7
|
+
JsonRpcTransport,
|
|
8
|
+
} from "./transport.js";
|
|
3
9
|
|
|
4
|
-
export class
|
|
10
|
+
export class JsonRpcTransportWebSocket implements JsonRpcTransport {
|
|
5
11
|
private ongoing: Map<
|
|
6
|
-
|
|
12
|
+
JsonRpcId,
|
|
7
13
|
[
|
|
8
|
-
(response:
|
|
14
|
+
(response: JsonRpcResponse) => unknown,
|
|
9
15
|
(error: unknown) => unknown,
|
|
10
16
|
ReturnType<typeof setTimeout>,
|
|
11
17
|
]
|
|
12
18
|
> = new Map();
|
|
19
|
+
private disposed = false;
|
|
13
20
|
private socket?: WebSocket;
|
|
14
21
|
private openSocket?: Promise<WebSocket>;
|
|
15
22
|
|
|
23
|
+
/**
|
|
24
|
+
* @deprecated Use {@link JsonRpcTransportWebSocket.open} to make lifecycle
|
|
25
|
+
* ownership explicit. This constructor will become private in a future
|
|
26
|
+
* release.
|
|
27
|
+
*/
|
|
16
28
|
constructor(
|
|
17
29
|
private readonly url: string,
|
|
18
30
|
private readonly timeout = 30000,
|
|
19
31
|
) {}
|
|
20
32
|
|
|
21
|
-
|
|
22
|
-
|
|
33
|
+
/** Opens an owned WebSocket transport. */
|
|
34
|
+
static open(
|
|
35
|
+
url: string,
|
|
36
|
+
timeout = 30000,
|
|
37
|
+
): OwnerUnique<JsonRpcTransportWebSocket> {
|
|
38
|
+
const transport = new JsonRpcTransportWebSocket(url, timeout);
|
|
39
|
+
return new OwnerUnique(transport, (transport) => transport.dispose());
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
request(data: JsonRpcPayload): Promise<JsonRpcResponse> {
|
|
43
|
+
if (this.disposed) {
|
|
44
|
+
return Promise.reject(
|
|
45
|
+
new Error("Cannot use a disposed JsonRpcTransportWebSocket"),
|
|
46
|
+
);
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
const [socketUnsafe, socket] = (() => {
|
|
23
50
|
if (
|
|
24
51
|
this.socket &&
|
|
25
52
|
this.socket.readyState !== this.socket.CLOSING &&
|
|
26
53
|
this.socket.readyState !== this.socket.CLOSED &&
|
|
27
54
|
this.openSocket
|
|
28
55
|
) {
|
|
29
|
-
return this.openSocket;
|
|
56
|
+
return [this.socket, this.openSocket] as const;
|
|
30
57
|
}
|
|
31
58
|
const socket = new WebSocket(this.url);
|
|
32
59
|
const onMessage = ({ data }: WebSocket.MessageEvent) => {
|
|
33
|
-
|
|
34
|
-
|
|
60
|
+
let res: JsonRpcResponse;
|
|
61
|
+
try {
|
|
62
|
+
res = JSON.parse(data as string) as JsonRpcResponse;
|
|
63
|
+
} catch (_) {
|
|
64
|
+
return;
|
|
65
|
+
}
|
|
35
66
|
if (
|
|
36
67
|
typeof res !== "object" ||
|
|
37
68
|
res === null ||
|
|
38
|
-
typeof res.id !== "number"
|
|
69
|
+
(typeof res.id !== "number" && typeof res.id !== "string")
|
|
39
70
|
) {
|
|
40
|
-
|
|
71
|
+
return;
|
|
41
72
|
}
|
|
42
|
-
|
|
43
|
-
const id: number = res.id;
|
|
73
|
+
const id = res.id;
|
|
44
74
|
|
|
45
75
|
const req = this.ongoing.get(id);
|
|
46
76
|
if (!req) {
|
|
@@ -74,12 +104,12 @@ export class TransportWebSocket implements Transport {
|
|
|
74
104
|
};
|
|
75
105
|
}
|
|
76
106
|
});
|
|
77
|
-
return this.openSocket;
|
|
107
|
+
return [socket, this.openSocket] as const;
|
|
78
108
|
})();
|
|
79
109
|
|
|
80
|
-
return new Promise((resolve, reject) => {
|
|
110
|
+
return new Promise<JsonRpcResponse>((resolve, reject) => {
|
|
81
111
|
const req: [
|
|
82
|
-
(res:
|
|
112
|
+
(res: JsonRpcResponse) => unknown,
|
|
83
113
|
(err: unknown) => unknown,
|
|
84
114
|
ReturnType<typeof setTimeout>,
|
|
85
115
|
] = [
|
|
@@ -87,9 +117,7 @@ export class TransportWebSocket implements Transport {
|
|
|
87
117
|
reject,
|
|
88
118
|
setTimeout(() => {
|
|
89
119
|
this.ongoing.delete(data.id);
|
|
90
|
-
|
|
91
|
-
.then((socket) => socket.close())
|
|
92
|
-
.catch((err) => reject(err));
|
|
120
|
+
socketUnsafe.close();
|
|
93
121
|
reject(new Error("Request timeout"));
|
|
94
122
|
}, this.timeout),
|
|
95
123
|
];
|
|
@@ -97,6 +125,9 @@ export class TransportWebSocket implements Transport {
|
|
|
97
125
|
|
|
98
126
|
void socket
|
|
99
127
|
.then((socket) => {
|
|
128
|
+
if (!this.ongoing.has(data.id)) {
|
|
129
|
+
return;
|
|
130
|
+
}
|
|
100
131
|
if (
|
|
101
132
|
socket.readyState === socket.CLOSED ||
|
|
102
133
|
socket.readyState === socket.CLOSING
|
|
@@ -108,7 +139,23 @@ export class TransportWebSocket implements Transport {
|
|
|
108
139
|
socket.send(JSON.stringify(data));
|
|
109
140
|
}
|
|
110
141
|
})
|
|
111
|
-
.catch((err) =>
|
|
142
|
+
.catch((err) => {
|
|
143
|
+
clearTimeout(req[2]);
|
|
144
|
+
this.ongoing.delete(data.id);
|
|
145
|
+
reject(err);
|
|
146
|
+
});
|
|
147
|
+
});
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
private async dispose(): Promise<void> {
|
|
151
|
+
this.disposed = true;
|
|
152
|
+
const socket = this.socket;
|
|
153
|
+
|
|
154
|
+
if (!socket || socket.readyState === socket.CLOSED) return;
|
|
155
|
+
|
|
156
|
+
await new Promise<void>((resolve) => {
|
|
157
|
+
socket.addEventListener("close", () => resolve(), { once: true });
|
|
158
|
+
socket.close();
|
|
112
159
|
});
|
|
113
160
|
}
|
|
114
161
|
}
|
package/src/keystore/index.ts
CHANGED
|
@@ -14,7 +14,7 @@ const DEFAULT_SCRYPT_PARAM_N = 262144;
|
|
|
14
14
|
|
|
15
15
|
function mac(derivedKey: Bytes, cipherText: Bytes) {
|
|
16
16
|
return hexFrom(
|
|
17
|
-
keccak_256(bytesConcat(derivedKey.
|
|
17
|
+
keccak_256(bytesConcat(derivedKey.subarray(16, 32), cipherText)),
|
|
18
18
|
).slice(2);
|
|
19
19
|
}
|
|
20
20
|
|
|
@@ -60,7 +60,7 @@ export async function keystoreEncrypt(
|
|
|
60
60
|
dkLen: kdfparams.dklen,
|
|
61
61
|
});
|
|
62
62
|
const cipher = ctr(
|
|
63
|
-
derivedKey.
|
|
63
|
+
derivedKey.subarray(0, 16),
|
|
64
64
|
iv.map((v) => v),
|
|
65
65
|
);
|
|
66
66
|
const ciphertext = cipher.encrypt(
|
|
@@ -151,7 +151,7 @@ export async function keystoreDecrypt(
|
|
|
151
151
|
throw Error("Invalid password");
|
|
152
152
|
}
|
|
153
153
|
const cipher = ctr(
|
|
154
|
-
derivedKey.
|
|
154
|
+
derivedKey.subarray(0, 16),
|
|
155
155
|
bytesFrom(crypto.cipherparams.iv),
|
|
156
156
|
);
|
|
157
157
|
const result = cipher.decrypt(ciphertext);
|