@acala-network/chopsticks-core 0.16.2 → 1.0.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/dist/cjs/blockchain/index.js +1 -0
- package/dist/cjs/blockchain/storage-layer.js +3 -3
- package/dist/cjs/blockchain/txpool.js +3 -3
- package/dist/cjs/logger.d.ts +2 -2
- package/dist/cjs/rpc/rpc-spec/chainHead_v1.d.ts +6 -0
- package/dist/cjs/rpc/rpc-spec/chainHead_v1.js +111 -41
- package/dist/cjs/rpc/shared.d.ts +1 -1
- package/dist/cjs/rpc/shared.js +1 -2
- package/dist/cjs/utils/index.js +1 -1
- package/dist/cjs/xcm/index.d.ts +1 -1
- package/dist/esm/blockchain/index.js +1 -0
- package/dist/esm/blockchain/storage-layer.js +3 -3
- package/dist/esm/blockchain/txpool.js +3 -3
- package/dist/esm/logger.d.ts +2 -2
- package/dist/esm/rpc/rpc-spec/chainHead_v1.d.ts +6 -0
- package/dist/esm/rpc/rpc-spec/chainHead_v1.js +116 -42
- package/dist/esm/rpc/shared.d.ts +1 -1
- package/dist/esm/utils/index.js +1 -1
- package/dist/esm/xcm/index.d.ts +1 -1
- package/package.json +17 -17
|
@@ -492,6 +492,7 @@ class Blockchain {
|
|
|
492
492
|
function registerBlock(block) {
|
|
493
493
|
// if exceed max memory block count, delete the oldest block
|
|
494
494
|
if (_class_private_field_get(this, _blocksByNumber).size === _class_private_field_get(this, _maxMemoryBlockCount)) {
|
|
495
|
+
// #blocksByNumber can't be empty so the force unwrap is safe
|
|
495
496
|
const { hash, number } = _class_private_field_get(this, _blocksByNumber).values().next().value;
|
|
496
497
|
_class_private_field_get(this, _blocksByNumber).delete(number);
|
|
497
498
|
_class_private_field_get(this, _blocksByHash).delete(hash);
|
|
@@ -82,11 +82,11 @@ const logger = _logger.defaultLogger.child({
|
|
|
82
82
|
name: 'layer'
|
|
83
83
|
});
|
|
84
84
|
const BATCH_SIZE = 1000;
|
|
85
|
-
var StorageValueKind
|
|
86
|
-
(function(StorageValueKind) {
|
|
85
|
+
var StorageValueKind = /*#__PURE__*/ function(StorageValueKind) {
|
|
87
86
|
StorageValueKind["Deleted"] = "Deleted";
|
|
88
87
|
StorageValueKind["DeletedPrefix"] = "DeletedPrefix";
|
|
89
|
-
|
|
88
|
+
return StorageValueKind;
|
|
89
|
+
}({});
|
|
90
90
|
var _api = /*#__PURE__*/ new WeakMap(), _at = /*#__PURE__*/ new WeakMap(), _db = /*#__PURE__*/ new WeakMap(), _keyCache = /*#__PURE__*/ new WeakMap(), _defaultChildKeyCache = /*#__PURE__*/ new WeakMap();
|
|
91
91
|
class RemoteStorageLayer {
|
|
92
92
|
async get(key, _cache) {
|
|
@@ -97,12 +97,12 @@ const logger = _logger.defaultLogger.child({
|
|
|
97
97
|
name: 'txpool'
|
|
98
98
|
});
|
|
99
99
|
const APPLY_EXTRINSIC_ERROR = 'TxPool::ApplyExtrinsicError';
|
|
100
|
-
var BuildBlockMode
|
|
101
|
-
(function(BuildBlockMode) {
|
|
100
|
+
var BuildBlockMode = /*#__PURE__*/ function(BuildBlockMode) {
|
|
102
101
|
/** One block per batch (default) */ BuildBlockMode["Batch"] = "Batch";
|
|
103
102
|
/** One block per tx */ BuildBlockMode["Instant"] = "Instant";
|
|
104
103
|
/** Only build when triggered */ BuildBlockMode["Manual"] = "Manual";
|
|
105
|
-
|
|
104
|
+
return BuildBlockMode;
|
|
105
|
+
}({});
|
|
106
106
|
var _chain = /*#__PURE__*/ new WeakMap(), _pool = /*#__PURE__*/ new WeakMap(), _ump = /*#__PURE__*/ new WeakMap(), _dmp = /*#__PURE__*/ new WeakMap(), _hrmp = /*#__PURE__*/ new WeakMap(), _mode = /*#__PURE__*/ new WeakMap(), _inherentProviders = /*#__PURE__*/ new WeakMap(), _pendingBlocks = /*#__PURE__*/ new WeakMap(), _isBuilding = /*#__PURE__*/ new WeakMap(), _getSigner = /*#__PURE__*/ new WeakSet(), _maybeBuildBlock = /*#__PURE__*/ new WeakSet(), _batchBuildBlock = /*#__PURE__*/ new WeakMap(), _buildBlockIfNeeded = /*#__PURE__*/ new WeakSet(), _buildBlock = /*#__PURE__*/ new WeakSet();
|
|
107
107
|
class TxPool {
|
|
108
108
|
get pendingExtrinsics() {
|
package/dist/cjs/logger.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
1
|
import { pino } from 'pino';
|
|
2
|
-
export declare const pinoLogger: import("pino").Logger<never>;
|
|
3
|
-
export declare const defaultLogger: pino.Logger<never>;
|
|
2
|
+
export declare const pinoLogger: import("pino").Logger<never, boolean>;
|
|
3
|
+
export declare const defaultLogger: pino.Logger<never, boolean>;
|
|
4
4
|
export declare const truncate: (val: any) => any;
|
|
@@ -73,6 +73,12 @@ export type LimitReached = {
|
|
|
73
73
|
* @return OperationStarted event with operationId to receive the result on the follow subscription
|
|
74
74
|
*/
|
|
75
75
|
export declare const chainHead_v1_body: Handler<[string, HexString], OperationStarted | LimitReached>;
|
|
76
|
+
/**
|
|
77
|
+
* Resume an operation paused through `operationWaitingForContinue`
|
|
78
|
+
*
|
|
79
|
+
* @param context
|
|
80
|
+
* @param params - [`followSubscription`, `operationId`]
|
|
81
|
+
*/
|
|
76
82
|
export declare const chainHead_v1_continue: Handler<[string, HexString], null>;
|
|
77
83
|
export declare const chainHead_v1_stopOperation: Handler<[string, HexString], null>;
|
|
78
84
|
export declare const chainHead_v1_unpin: Handler<[string, HexString | HexString[]], null>;
|
|
@@ -42,7 +42,7 @@ const _logger = require("../../logger.js");
|
|
|
42
42
|
const logger = _logger.defaultLogger.child({
|
|
43
43
|
name: 'rpc-chainHead_v1'
|
|
44
44
|
});
|
|
45
|
-
const
|
|
45
|
+
const following = new Map();
|
|
46
46
|
async function afterResponse(fn) {
|
|
47
47
|
await new Promise((resolve)=>setTimeout(resolve, 0));
|
|
48
48
|
fn();
|
|
@@ -82,10 +82,13 @@ const chainHead_v1_follow = async (context, [withRuntime], { subscribe })=>{
|
|
|
82
82
|
const id = context.chain.headState.subscribeHead(update);
|
|
83
83
|
const cleanup = ()=>{
|
|
84
84
|
context.chain.headState.unsubscribeHead(id);
|
|
85
|
-
|
|
85
|
+
following.delete(id);
|
|
86
86
|
};
|
|
87
87
|
const callback = subscribe('chainHead_v1_followEvent', id, cleanup);
|
|
88
|
-
|
|
88
|
+
following.set(id, {
|
|
89
|
+
callback,
|
|
90
|
+
pendingDescendantValues: new Map()
|
|
91
|
+
});
|
|
89
92
|
afterResponse(async ()=>{
|
|
90
93
|
callback({
|
|
91
94
|
event: 'initialized',
|
|
@@ -102,7 +105,7 @@ const chainHead_v1_unfollow = async (_, [followSubscription], { unsubscribe })=>
|
|
|
102
105
|
return null;
|
|
103
106
|
};
|
|
104
107
|
const chainHead_v1_header = async (context, [followSubscription, hash])=>{
|
|
105
|
-
if (!
|
|
108
|
+
if (!following.has(followSubscription)) return null;
|
|
106
109
|
const block = await context.chain.getBlock(hash);
|
|
107
110
|
return block ? (await block.header).toHex() : null;
|
|
108
111
|
};
|
|
@@ -116,7 +119,7 @@ const chainHead_v1_call = async (context, [followSubscription, hash, method, cal
|
|
|
116
119
|
afterResponse(async ()=>{
|
|
117
120
|
const block = await context.chain.getBlock(hash);
|
|
118
121
|
if (!block) {
|
|
119
|
-
|
|
122
|
+
following.get(followSubscription)?.callback({
|
|
120
123
|
event: 'operationError',
|
|
121
124
|
operationId,
|
|
122
125
|
error: `Block ${hash} not found`
|
|
@@ -126,13 +129,13 @@ const chainHead_v1_call = async (context, [followSubscription, hash, method, cal
|
|
|
126
129
|
const resp = await block.call(method, [
|
|
127
130
|
callParameters
|
|
128
131
|
]);
|
|
129
|
-
|
|
132
|
+
following.get(followSubscription)?.callback({
|
|
130
133
|
event: 'operationCallDone',
|
|
131
134
|
operationId,
|
|
132
135
|
output: resp.result
|
|
133
136
|
});
|
|
134
137
|
} catch (ex) {
|
|
135
|
-
|
|
138
|
+
following.get(followSubscription)?.callback({
|
|
136
139
|
event: 'operationError',
|
|
137
140
|
operationId,
|
|
138
141
|
error: ex.message
|
|
@@ -142,12 +145,36 @@ const chainHead_v1_call = async (context, [followSubscription, hash, method, cal
|
|
|
142
145
|
});
|
|
143
146
|
return operationStarted(operationId);
|
|
144
147
|
};
|
|
148
|
+
const PAGE_SIZE = 1000;
|
|
149
|
+
async function getDescendantValues(block, params) {
|
|
150
|
+
const keys = await block.getKeysPaged({
|
|
151
|
+
...params,
|
|
152
|
+
pageSize: PAGE_SIZE
|
|
153
|
+
});
|
|
154
|
+
const items = await Promise.all(keys.map((key)=>block.get(key).then((value)=>({
|
|
155
|
+
key,
|
|
156
|
+
value
|
|
157
|
+
}))));
|
|
158
|
+
if (keys.length < PAGE_SIZE) {
|
|
159
|
+
return {
|
|
160
|
+
items,
|
|
161
|
+
next: null
|
|
162
|
+
};
|
|
163
|
+
}
|
|
164
|
+
return {
|
|
165
|
+
items,
|
|
166
|
+
next: {
|
|
167
|
+
...params,
|
|
168
|
+
startKey: keys[PAGE_SIZE - 1]
|
|
169
|
+
}
|
|
170
|
+
};
|
|
171
|
+
}
|
|
145
172
|
const chainHead_v1_storage = async (context, [followSubscription, hash, items, _childTrie])=>{
|
|
146
173
|
const operationId = randomId();
|
|
147
174
|
afterResponse(async ()=>{
|
|
148
175
|
const block = await context.chain.getBlock(hash);
|
|
149
176
|
if (!block) {
|
|
150
|
-
|
|
177
|
+
following.get(followSubscription)?.callback({
|
|
151
178
|
event: 'operationError',
|
|
152
179
|
operationId,
|
|
153
180
|
error: 'Block not found'
|
|
@@ -160,7 +187,7 @@ const chainHead_v1_storage = async (context, [followSubscription, hash, items, _
|
|
|
160
187
|
{
|
|
161
188
|
const value = await block.get(sir.key);
|
|
162
189
|
if (value) {
|
|
163
|
-
|
|
190
|
+
following.get(followSubscription)?.callback({
|
|
164
191
|
event: 'operationStorageItems',
|
|
165
192
|
operationId,
|
|
166
193
|
items: [
|
|
@@ -171,43 +198,47 @@ const chainHead_v1_storage = async (context, [followSubscription, hash, items, _
|
|
|
171
198
|
]
|
|
172
199
|
});
|
|
173
200
|
}
|
|
174
|
-
|
|
201
|
+
return null;
|
|
175
202
|
}
|
|
176
203
|
case 'descendantsValues':
|
|
177
204
|
{
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
const items = await Promise.all(keys.map((key)=>block.get(key).then((value)=>({
|
|
189
|
-
key,
|
|
190
|
-
value
|
|
191
|
-
}))));
|
|
192
|
-
callbacks.get(followSubscription)?.({
|
|
193
|
-
event: 'operationStorageItems',
|
|
194
|
-
operationId,
|
|
195
|
-
items
|
|
196
|
-
});
|
|
197
|
-
break;
|
|
198
|
-
}
|
|
199
|
-
break;
|
|
205
|
+
const { items, next } = await getDescendantValues(block, {
|
|
206
|
+
prefix: sir.key,
|
|
207
|
+
startKey: '0x'
|
|
208
|
+
});
|
|
209
|
+
following.get(followSubscription)?.callback({
|
|
210
|
+
event: 'operationStorageItems',
|
|
211
|
+
operationId,
|
|
212
|
+
items
|
|
213
|
+
});
|
|
214
|
+
return next;
|
|
200
215
|
}
|
|
201
216
|
default:
|
|
202
217
|
// TODO
|
|
203
218
|
console.warn(`Storage type not implemented ${sir.type}`);
|
|
219
|
+
return null;
|
|
204
220
|
}
|
|
205
221
|
};
|
|
206
|
-
await Promise.all(items.map(handleStorageItemRequest));
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
222
|
+
const listResult = await Promise.all(items.map(handleStorageItemRequest));
|
|
223
|
+
const pending = listResult.filter((v)=>v !== null);
|
|
224
|
+
if (!pending.length) {
|
|
225
|
+
following.get(followSubscription)?.callback({
|
|
226
|
+
event: 'operationStorageDone',
|
|
227
|
+
operationId
|
|
228
|
+
});
|
|
229
|
+
} else {
|
|
230
|
+
const follower = following.get(followSubscription);
|
|
231
|
+
if (follower) {
|
|
232
|
+
follower.pendingDescendantValues.set(operationId, {
|
|
233
|
+
hash,
|
|
234
|
+
params: pending
|
|
235
|
+
});
|
|
236
|
+
follower.callback({
|
|
237
|
+
event: 'operationWaitingForContinue',
|
|
238
|
+
operationId
|
|
239
|
+
});
|
|
240
|
+
}
|
|
241
|
+
}
|
|
211
242
|
});
|
|
212
243
|
return {
|
|
213
244
|
...operationStarted(operationId),
|
|
@@ -218,7 +249,7 @@ const limitReached = {
|
|
|
218
249
|
result: 'limitReached'
|
|
219
250
|
};
|
|
220
251
|
const chainHead_v1_body = async (context, [followSubscription, hash])=>{
|
|
221
|
-
if (!
|
|
252
|
+
if (!following.has(followSubscription)) return limitReached;
|
|
222
253
|
const block = await context.chain.getBlock(hash);
|
|
223
254
|
if (!block) {
|
|
224
255
|
throw new _shared.ResponseError(-32801, 'Block not found');
|
|
@@ -226,7 +257,7 @@ const chainHead_v1_body = async (context, [followSubscription, hash])=>{
|
|
|
226
257
|
const operationId = randomId();
|
|
227
258
|
afterResponse(async ()=>{
|
|
228
259
|
const body = await block.extrinsics;
|
|
229
|
-
|
|
260
|
+
following.get(followSubscription)?.callback({
|
|
230
261
|
event: 'operationBodyDone',
|
|
231
262
|
operationId,
|
|
232
263
|
value: body
|
|
@@ -234,10 +265,49 @@ const chainHead_v1_body = async (context, [followSubscription, hash])=>{
|
|
|
234
265
|
});
|
|
235
266
|
return operationStarted(operationId);
|
|
236
267
|
};
|
|
237
|
-
const chainHead_v1_continue = async (
|
|
268
|
+
const chainHead_v1_continue = async (context, [followSubscription, operationId])=>{
|
|
269
|
+
const follower = following.get(followSubscription);
|
|
270
|
+
const pendingOp = follower?.pendingDescendantValues.get(operationId);
|
|
271
|
+
if (!pendingOp || !follower) {
|
|
272
|
+
throw new _shared.ResponseError(-32803, "Operation ID doesn't have anything pending");
|
|
273
|
+
}
|
|
274
|
+
const block = await context.chain.getBlock(pendingOp.hash);
|
|
275
|
+
if (!block) {
|
|
276
|
+
throw new _shared.ResponseError(-32801, 'Block not found');
|
|
277
|
+
}
|
|
278
|
+
afterResponse(async ()=>{
|
|
279
|
+
const handlePendingOperation = async (params)=>{
|
|
280
|
+
const { items, next } = await getDescendantValues(block, params);
|
|
281
|
+
follower.callback({
|
|
282
|
+
event: 'operationStorageItems',
|
|
283
|
+
operationId,
|
|
284
|
+
items
|
|
285
|
+
});
|
|
286
|
+
return next;
|
|
287
|
+
};
|
|
288
|
+
const listResult = await Promise.all(pendingOp.params.map(handlePendingOperation));
|
|
289
|
+
const pending = listResult.filter((v)=>v !== null);
|
|
290
|
+
if (!pending.length) {
|
|
291
|
+
follower.pendingDescendantValues.delete(operationId);
|
|
292
|
+
follower.callback({
|
|
293
|
+
event: 'operationStorageDone',
|
|
294
|
+
operationId
|
|
295
|
+
});
|
|
296
|
+
} else {
|
|
297
|
+
follower.pendingDescendantValues.set(operationId, {
|
|
298
|
+
hash: pendingOp.hash,
|
|
299
|
+
params: pending
|
|
300
|
+
});
|
|
301
|
+
follower.callback({
|
|
302
|
+
event: 'operationWaitingForContinue',
|
|
303
|
+
operationId
|
|
304
|
+
});
|
|
305
|
+
}
|
|
306
|
+
});
|
|
238
307
|
return null;
|
|
239
308
|
};
|
|
240
|
-
const chainHead_v1_stopOperation = async (_context, [
|
|
309
|
+
const chainHead_v1_stopOperation = async (_context, [followSubscription, operationId])=>{
|
|
310
|
+
following.get(followSubscription)?.pendingDescendantValues.delete(operationId);
|
|
241
311
|
return null;
|
|
242
312
|
};
|
|
243
313
|
const chainHead_v1_unpin = async (_context, [_followSubscription, _hashOrHashes])=>{
|
package/dist/cjs/rpc/shared.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { z } from 'zod';
|
|
2
2
|
import { Blockchain } from '../blockchain/index.js';
|
|
3
|
-
export declare const logger: import("pino").default.Logger<never>;
|
|
3
|
+
export declare const logger: import("pino").default.Logger<never, boolean>;
|
|
4
4
|
export declare const zHex: z.ZodType<`0x${string}`, z.ZodTypeDef, `0x${string}`>;
|
|
5
5
|
export declare const zHash: z.ZodIntersection<z.ZodString, z.ZodType<`0x${string}`, z.ZodTypeDef, `0x${string}`>>;
|
|
6
6
|
export declare class ResponseError extends Error {
|
package/dist/cjs/rpc/shared.js
CHANGED
package/dist/cjs/utils/index.js
CHANGED
package/dist/cjs/xcm/index.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
1
|
import { Blockchain } from '../blockchain/index.js';
|
|
2
|
-
export declare const xcmLogger: import("pino").default.Logger<never>;
|
|
2
|
+
export declare const xcmLogger: import("pino").default.Logger<never, boolean>;
|
|
3
3
|
export declare const connectVertical: (relaychain: Blockchain, parachain: Blockchain) => Promise<void>;
|
|
4
4
|
export declare const connectParachains: (parachains: Blockchain[], disableAutoHrmp?: boolean) => Promise<void>;
|
|
@@ -87,6 +87,7 @@ const logger = defaultLogger.child({
|
|
|
87
87
|
#registerBlock(block) {
|
|
88
88
|
// if exceed max memory block count, delete the oldest block
|
|
89
89
|
if (this.#blocksByNumber.size === this.#maxMemoryBlockCount) {
|
|
90
|
+
// #blocksByNumber can't be empty so the force unwrap is safe
|
|
90
91
|
const { hash, number } = this.#blocksByNumber.values().next().value;
|
|
91
92
|
this.#blocksByNumber.delete(number);
|
|
92
93
|
this.#blocksByHash.delete(hash);
|
|
@@ -6,11 +6,11 @@ const logger = defaultLogger.child({
|
|
|
6
6
|
name: 'layer'
|
|
7
7
|
});
|
|
8
8
|
const BATCH_SIZE = 1000;
|
|
9
|
-
export var StorageValueKind
|
|
10
|
-
(function(StorageValueKind) {
|
|
9
|
+
export var StorageValueKind = /*#__PURE__*/ function(StorageValueKind) {
|
|
11
10
|
StorageValueKind["Deleted"] = "Deleted";
|
|
12
11
|
StorageValueKind["DeletedPrefix"] = "DeletedPrefix";
|
|
13
|
-
|
|
12
|
+
return StorageValueKind;
|
|
13
|
+
}({});
|
|
14
14
|
export class RemoteStorageLayer {
|
|
15
15
|
#api;
|
|
16
16
|
#at;
|
|
@@ -8,12 +8,12 @@ const logger = defaultLogger.child({
|
|
|
8
8
|
name: 'txpool'
|
|
9
9
|
});
|
|
10
10
|
export const APPLY_EXTRINSIC_ERROR = 'TxPool::ApplyExtrinsicError';
|
|
11
|
-
export var BuildBlockMode
|
|
12
|
-
(function(BuildBlockMode) {
|
|
11
|
+
export var BuildBlockMode = /*#__PURE__*/ function(BuildBlockMode) {
|
|
13
12
|
/** One block per batch (default) */ BuildBlockMode["Batch"] = "Batch";
|
|
14
13
|
/** One block per tx */ BuildBlockMode["Instant"] = "Instant";
|
|
15
14
|
/** Only build when triggered */ BuildBlockMode["Manual"] = "Manual";
|
|
16
|
-
|
|
15
|
+
return BuildBlockMode;
|
|
16
|
+
}({});
|
|
17
17
|
export class TxPool {
|
|
18
18
|
#chain;
|
|
19
19
|
#pool = [];
|
package/dist/esm/logger.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
1
|
import { pino } from 'pino';
|
|
2
|
-
export declare const pinoLogger: import("pino").Logger<never>;
|
|
3
|
-
export declare const defaultLogger: pino.Logger<never>;
|
|
2
|
+
export declare const pinoLogger: import("pino").Logger<never, boolean>;
|
|
3
|
+
export declare const defaultLogger: pino.Logger<never, boolean>;
|
|
4
4
|
export declare const truncate: (val: any) => any;
|
|
@@ -73,6 +73,12 @@ export type LimitReached = {
|
|
|
73
73
|
* @return OperationStarted event with operationId to receive the result on the follow subscription
|
|
74
74
|
*/
|
|
75
75
|
export declare const chainHead_v1_body: Handler<[string, HexString], OperationStarted | LimitReached>;
|
|
76
|
+
/**
|
|
77
|
+
* Resume an operation paused through `operationWaitingForContinue`
|
|
78
|
+
*
|
|
79
|
+
* @param context
|
|
80
|
+
* @param params - [`followSubscription`, `operationId`]
|
|
81
|
+
*/
|
|
76
82
|
export declare const chainHead_v1_continue: Handler<[string, HexString], null>;
|
|
77
83
|
export declare const chainHead_v1_stopOperation: Handler<[string, HexString], null>;
|
|
78
84
|
export declare const chainHead_v1_unpin: Handler<[string, HexString | HexString[]], null>;
|
|
@@ -3,7 +3,7 @@ import { defaultLogger } from '../../logger.js';
|
|
|
3
3
|
const logger = defaultLogger.child({
|
|
4
4
|
name: 'rpc-chainHead_v1'
|
|
5
5
|
});
|
|
6
|
-
const
|
|
6
|
+
const following = new Map();
|
|
7
7
|
async function afterResponse(fn) {
|
|
8
8
|
await new Promise((resolve)=>setTimeout(resolve, 0));
|
|
9
9
|
fn();
|
|
@@ -51,10 +51,13 @@ async function afterResponse(fn) {
|
|
|
51
51
|
const id = context.chain.headState.subscribeHead(update);
|
|
52
52
|
const cleanup = ()=>{
|
|
53
53
|
context.chain.headState.unsubscribeHead(id);
|
|
54
|
-
|
|
54
|
+
following.delete(id);
|
|
55
55
|
};
|
|
56
56
|
const callback = subscribe('chainHead_v1_followEvent', id, cleanup);
|
|
57
|
-
|
|
57
|
+
following.set(id, {
|
|
58
|
+
callback,
|
|
59
|
+
pendingDescendantValues: new Map()
|
|
60
|
+
});
|
|
58
61
|
afterResponse(async ()=>{
|
|
59
62
|
callback({
|
|
60
63
|
event: 'initialized',
|
|
@@ -84,7 +87,7 @@ async function afterResponse(fn) {
|
|
|
84
87
|
*
|
|
85
88
|
* @return SCALE-encoded header, or null if the block is not found.
|
|
86
89
|
*/ export const chainHead_v1_header = async (context, [followSubscription, hash])=>{
|
|
87
|
-
if (!
|
|
90
|
+
if (!following.has(followSubscription)) return null;
|
|
88
91
|
const block = await context.chain.getBlock(hash);
|
|
89
92
|
return block ? (await block.header).toHex() : null;
|
|
90
93
|
};
|
|
@@ -105,7 +108,7 @@ const randomId = ()=>Math.random().toString(36).substring(2);
|
|
|
105
108
|
afterResponse(async ()=>{
|
|
106
109
|
const block = await context.chain.getBlock(hash);
|
|
107
110
|
if (!block) {
|
|
108
|
-
|
|
111
|
+
following.get(followSubscription)?.callback({
|
|
109
112
|
event: 'operationError',
|
|
110
113
|
operationId,
|
|
111
114
|
error: `Block ${hash} not found`
|
|
@@ -115,13 +118,13 @@ const randomId = ()=>Math.random().toString(36).substring(2);
|
|
|
115
118
|
const resp = await block.call(method, [
|
|
116
119
|
callParameters
|
|
117
120
|
]);
|
|
118
|
-
|
|
121
|
+
following.get(followSubscription)?.callback({
|
|
119
122
|
event: 'operationCallDone',
|
|
120
123
|
operationId,
|
|
121
124
|
output: resp.result
|
|
122
125
|
});
|
|
123
126
|
} catch (ex) {
|
|
124
|
-
|
|
127
|
+
following.get(followSubscription)?.callback({
|
|
125
128
|
event: 'operationError',
|
|
126
129
|
operationId,
|
|
127
130
|
error: ex.message
|
|
@@ -131,6 +134,30 @@ const randomId = ()=>Math.random().toString(36).substring(2);
|
|
|
131
134
|
});
|
|
132
135
|
return operationStarted(operationId);
|
|
133
136
|
};
|
|
137
|
+
const PAGE_SIZE = 1000;
|
|
138
|
+
async function getDescendantValues(block, params) {
|
|
139
|
+
const keys = await block.getKeysPaged({
|
|
140
|
+
...params,
|
|
141
|
+
pageSize: PAGE_SIZE
|
|
142
|
+
});
|
|
143
|
+
const items = await Promise.all(keys.map((key)=>block.get(key).then((value)=>({
|
|
144
|
+
key,
|
|
145
|
+
value
|
|
146
|
+
}))));
|
|
147
|
+
if (keys.length < PAGE_SIZE) {
|
|
148
|
+
return {
|
|
149
|
+
items,
|
|
150
|
+
next: null
|
|
151
|
+
};
|
|
152
|
+
}
|
|
153
|
+
return {
|
|
154
|
+
items,
|
|
155
|
+
next: {
|
|
156
|
+
...params,
|
|
157
|
+
startKey: keys[PAGE_SIZE - 1]
|
|
158
|
+
}
|
|
159
|
+
};
|
|
160
|
+
}
|
|
134
161
|
/**
|
|
135
162
|
* Query the storage for a given block
|
|
136
163
|
*
|
|
@@ -143,7 +170,7 @@ const randomId = ()=>Math.random().toString(36).substring(2);
|
|
|
143
170
|
afterResponse(async ()=>{
|
|
144
171
|
const block = await context.chain.getBlock(hash);
|
|
145
172
|
if (!block) {
|
|
146
|
-
|
|
173
|
+
following.get(followSubscription)?.callback({
|
|
147
174
|
event: 'operationError',
|
|
148
175
|
operationId,
|
|
149
176
|
error: 'Block not found'
|
|
@@ -156,7 +183,7 @@ const randomId = ()=>Math.random().toString(36).substring(2);
|
|
|
156
183
|
{
|
|
157
184
|
const value = await block.get(sir.key);
|
|
158
185
|
if (value) {
|
|
159
|
-
|
|
186
|
+
following.get(followSubscription)?.callback({
|
|
160
187
|
event: 'operationStorageItems',
|
|
161
188
|
operationId,
|
|
162
189
|
items: [
|
|
@@ -167,43 +194,47 @@ const randomId = ()=>Math.random().toString(36).substring(2);
|
|
|
167
194
|
]
|
|
168
195
|
});
|
|
169
196
|
}
|
|
170
|
-
|
|
197
|
+
return null;
|
|
171
198
|
}
|
|
172
199
|
case 'descendantsValues':
|
|
173
200
|
{
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
const items = await Promise.all(keys.map((key)=>block.get(key).then((value)=>({
|
|
185
|
-
key,
|
|
186
|
-
value
|
|
187
|
-
}))));
|
|
188
|
-
callbacks.get(followSubscription)?.({
|
|
189
|
-
event: 'operationStorageItems',
|
|
190
|
-
operationId,
|
|
191
|
-
items
|
|
192
|
-
});
|
|
193
|
-
break;
|
|
194
|
-
}
|
|
195
|
-
break;
|
|
201
|
+
const { items, next } = await getDescendantValues(block, {
|
|
202
|
+
prefix: sir.key,
|
|
203
|
+
startKey: '0x'
|
|
204
|
+
});
|
|
205
|
+
following.get(followSubscription)?.callback({
|
|
206
|
+
event: 'operationStorageItems',
|
|
207
|
+
operationId,
|
|
208
|
+
items
|
|
209
|
+
});
|
|
210
|
+
return next;
|
|
196
211
|
}
|
|
197
212
|
default:
|
|
198
213
|
// TODO
|
|
199
214
|
console.warn(`Storage type not implemented ${sir.type}`);
|
|
215
|
+
return null;
|
|
200
216
|
}
|
|
201
217
|
};
|
|
202
|
-
await Promise.all(items.map(handleStorageItemRequest));
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
218
|
+
const listResult = await Promise.all(items.map(handleStorageItemRequest));
|
|
219
|
+
const pending = listResult.filter((v)=>v !== null);
|
|
220
|
+
if (!pending.length) {
|
|
221
|
+
following.get(followSubscription)?.callback({
|
|
222
|
+
event: 'operationStorageDone',
|
|
223
|
+
operationId
|
|
224
|
+
});
|
|
225
|
+
} else {
|
|
226
|
+
const follower = following.get(followSubscription);
|
|
227
|
+
if (follower) {
|
|
228
|
+
follower.pendingDescendantValues.set(operationId, {
|
|
229
|
+
hash,
|
|
230
|
+
params: pending
|
|
231
|
+
});
|
|
232
|
+
follower.callback({
|
|
233
|
+
event: 'operationWaitingForContinue',
|
|
234
|
+
operationId
|
|
235
|
+
});
|
|
236
|
+
}
|
|
237
|
+
}
|
|
207
238
|
});
|
|
208
239
|
return {
|
|
209
240
|
...operationStarted(operationId),
|
|
@@ -221,7 +252,7 @@ const limitReached = {
|
|
|
221
252
|
*
|
|
222
253
|
* @return OperationStarted event with operationId to receive the result on the follow subscription
|
|
223
254
|
*/ export const chainHead_v1_body = async (context, [followSubscription, hash])=>{
|
|
224
|
-
if (!
|
|
255
|
+
if (!following.has(followSubscription)) return limitReached;
|
|
225
256
|
const block = await context.chain.getBlock(hash);
|
|
226
257
|
if (!block) {
|
|
227
258
|
throw new ResponseError(-32801, 'Block not found');
|
|
@@ -229,7 +260,7 @@ const limitReached = {
|
|
|
229
260
|
const operationId = randomId();
|
|
230
261
|
afterResponse(async ()=>{
|
|
231
262
|
const body = await block.extrinsics;
|
|
232
|
-
|
|
263
|
+
following.get(followSubscription)?.callback({
|
|
233
264
|
event: 'operationBodyDone',
|
|
234
265
|
operationId,
|
|
235
266
|
value: body
|
|
@@ -237,11 +268,54 @@ const limitReached = {
|
|
|
237
268
|
});
|
|
238
269
|
return operationStarted(operationId);
|
|
239
270
|
};
|
|
240
|
-
|
|
241
|
-
|
|
271
|
+
/**
|
|
272
|
+
* Resume an operation paused through `operationWaitingForContinue`
|
|
273
|
+
*
|
|
274
|
+
* @param context
|
|
275
|
+
* @param params - [`followSubscription`, `operationId`]
|
|
276
|
+
*/ export const chainHead_v1_continue = async (context, [followSubscription, operationId])=>{
|
|
277
|
+
const follower = following.get(followSubscription);
|
|
278
|
+
const pendingOp = follower?.pendingDescendantValues.get(operationId);
|
|
279
|
+
if (!pendingOp || !follower) {
|
|
280
|
+
throw new ResponseError(-32803, "Operation ID doesn't have anything pending");
|
|
281
|
+
}
|
|
282
|
+
const block = await context.chain.getBlock(pendingOp.hash);
|
|
283
|
+
if (!block) {
|
|
284
|
+
throw new ResponseError(-32801, 'Block not found');
|
|
285
|
+
}
|
|
286
|
+
afterResponse(async ()=>{
|
|
287
|
+
const handlePendingOperation = async (params)=>{
|
|
288
|
+
const { items, next } = await getDescendantValues(block, params);
|
|
289
|
+
follower.callback({
|
|
290
|
+
event: 'operationStorageItems',
|
|
291
|
+
operationId,
|
|
292
|
+
items
|
|
293
|
+
});
|
|
294
|
+
return next;
|
|
295
|
+
};
|
|
296
|
+
const listResult = await Promise.all(pendingOp.params.map(handlePendingOperation));
|
|
297
|
+
const pending = listResult.filter((v)=>v !== null);
|
|
298
|
+
if (!pending.length) {
|
|
299
|
+
follower.pendingDescendantValues.delete(operationId);
|
|
300
|
+
follower.callback({
|
|
301
|
+
event: 'operationStorageDone',
|
|
302
|
+
operationId
|
|
303
|
+
});
|
|
304
|
+
} else {
|
|
305
|
+
follower.pendingDescendantValues.set(operationId, {
|
|
306
|
+
hash: pendingOp.hash,
|
|
307
|
+
params: pending
|
|
308
|
+
});
|
|
309
|
+
follower.callback({
|
|
310
|
+
event: 'operationWaitingForContinue',
|
|
311
|
+
operationId
|
|
312
|
+
});
|
|
313
|
+
}
|
|
314
|
+
});
|
|
242
315
|
return null;
|
|
243
316
|
};
|
|
244
|
-
export const chainHead_v1_stopOperation = async (_context, [
|
|
317
|
+
export const chainHead_v1_stopOperation = async (_context, [followSubscription, operationId])=>{
|
|
318
|
+
following.get(followSubscription)?.pendingDescendantValues.delete(operationId);
|
|
245
319
|
return null;
|
|
246
320
|
};
|
|
247
321
|
// no-op, since there's no concept of unpinning in chopsticks
|
package/dist/esm/rpc/shared.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { z } from 'zod';
|
|
2
2
|
import { Blockchain } from '../blockchain/index.js';
|
|
3
|
-
export declare const logger: import("pino").default.Logger<never>;
|
|
3
|
+
export declare const logger: import("pino").default.Logger<never, boolean>;
|
|
4
4
|
export declare const zHex: z.ZodType<`0x${string}`, z.ZodTypeDef, `0x${string}`>;
|
|
5
5
|
export declare const zHash: z.ZodIntersection<z.ZodString, z.ZodType<`0x${string}`, z.ZodTypeDef, `0x${string}`>>;
|
|
6
6
|
export declare class ResponseError extends Error {
|
package/dist/esm/utils/index.js
CHANGED
package/dist/esm/xcm/index.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
1
|
import { Blockchain } from '../blockchain/index.js';
|
|
2
|
-
export declare const xcmLogger: import("pino").default.Logger<never>;
|
|
2
|
+
export declare const xcmLogger: import("pino").default.Logger<never, boolean>;
|
|
3
3
|
export declare const connectVertical: (relaychain: Blockchain, parachain: Blockchain) => Promise<void>;
|
|
4
4
|
export declare const connectParachains: (parachains: Blockchain[], disableAutoHrmp?: boolean) => Promise<void>;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@acala-network/chopsticks-core",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "1.0.0",
|
|
4
4
|
"author": "Acala Developers <hello@acala.network>",
|
|
5
5
|
"license": "Apache-2.0",
|
|
6
6
|
"type": "module",
|
|
@@ -11,28 +11,28 @@
|
|
|
11
11
|
"depcheck": "npx depcheck"
|
|
12
12
|
},
|
|
13
13
|
"dependencies": {
|
|
14
|
-
"@acala-network/chopsticks-executor": "0.
|
|
15
|
-
"@polkadot/rpc-provider": "^
|
|
16
|
-
"@polkadot/types": "^
|
|
17
|
-
"@polkadot/types-codec": "^
|
|
18
|
-
"@polkadot/types-known": "^
|
|
19
|
-
"@polkadot/util": "^13.
|
|
20
|
-
"@polkadot/util-crypto": "^13.
|
|
14
|
+
"@acala-network/chopsticks-executor": "1.0.0",
|
|
15
|
+
"@polkadot/rpc-provider": "^14.0.1",
|
|
16
|
+
"@polkadot/types": "^14.0.1",
|
|
17
|
+
"@polkadot/types-codec": "^14.0.1",
|
|
18
|
+
"@polkadot/types-known": "^14.0.1",
|
|
19
|
+
"@polkadot/util": "^13.2.2",
|
|
20
|
+
"@polkadot/util-crypto": "^13.2.2",
|
|
21
21
|
"comlink": "^4.4.1",
|
|
22
22
|
"eventemitter3": "^5.0.1",
|
|
23
23
|
"lodash": "^4.17.21",
|
|
24
|
-
"lru-cache": "^
|
|
25
|
-
"pino": "^
|
|
26
|
-
"pino-pretty": "^11.
|
|
24
|
+
"lru-cache": "^11.0.1",
|
|
25
|
+
"pino": "^9.5.0",
|
|
26
|
+
"pino-pretty": "^11.3.0",
|
|
27
27
|
"rxjs": "^7.8.1",
|
|
28
|
-
"zod": "^3.
|
|
28
|
+
"zod": "^3.23.8"
|
|
29
29
|
},
|
|
30
30
|
"devDependencies": {
|
|
31
|
-
"@swc/cli": "0.
|
|
32
|
-
"@swc/core": "^1.7.
|
|
33
|
-
"@types/lodash": "^4.17.
|
|
34
|
-
"typescript": "^5.
|
|
35
|
-
"vitest": "^1.4
|
|
31
|
+
"@swc/cli": "0.5.0",
|
|
32
|
+
"@swc/core": "^1.7.40",
|
|
33
|
+
"@types/lodash": "^4.17.13",
|
|
34
|
+
"typescript": "^5.6.3",
|
|
35
|
+
"vitest": "^2.1.4"
|
|
36
36
|
},
|
|
37
37
|
"files": [
|
|
38
38
|
"dist/esm/**",
|