@acala-network/chopsticks-core 1.2.0 → 1.2.2
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/block.d.ts +4 -0
- package/dist/cjs/blockchain/block.js +13 -0
- package/dist/cjs/blockchain/inherent/parachain/validation-data.js +43 -10
- package/dist/cjs/blockchain/storage-layer.d.ts +12 -0
- package/dist/cjs/blockchain/storage-layer.js +85 -1
- package/dist/cjs/rpc/rpc-spec/archive_v1.d.ts +74 -0
- package/dist/cjs/rpc/rpc-spec/archive_v1.js +201 -0
- package/dist/cjs/rpc/rpc-spec/chainHead_v1.js +9 -36
- package/dist/cjs/rpc/rpc-spec/index.d.ts +9 -0
- package/dist/cjs/rpc/rpc-spec/index.js +2 -0
- package/dist/cjs/rpc/rpc-spec/storage-common.d.ts +16 -0
- package/dist/cjs/rpc/rpc-spec/storage-common.js +49 -0
- package/dist/esm/blockchain/block.d.ts +4 -0
- package/dist/esm/blockchain/block.js +13 -0
- package/dist/esm/blockchain/inherent/parachain/validation-data.js +43 -10
- package/dist/esm/blockchain/storage-layer.d.ts +12 -0
- package/dist/esm/blockchain/storage-layer.js +85 -1
- package/dist/esm/rpc/rpc-spec/archive_v1.d.ts +74 -0
- package/dist/esm/rpc/rpc-spec/archive_v1.js +215 -0
- package/dist/esm/rpc/rpc-spec/chainHead_v1.js +1 -28
- package/dist/esm/rpc/rpc-spec/index.d.ts +9 -0
- package/dist/esm/rpc/rpc-spec/index.js +2 -0
- package/dist/esm/rpc/rpc-spec/storage-common.d.ts +16 -0
- package/dist/esm/rpc/rpc-spec/storage-common.js +28 -0
- package/package.json +3 -3
|
@@ -48,6 +48,10 @@ export declare class Block {
|
|
|
48
48
|
* Get the block storage by key.
|
|
49
49
|
*/
|
|
50
50
|
get(key: string): Promise<HexString | undefined>;
|
|
51
|
+
/**
|
|
52
|
+
* Get the block storage by key.
|
|
53
|
+
*/
|
|
54
|
+
getMany(keys: string[]): Promise<Array<HexString | undefined>>;
|
|
51
55
|
read<T extends string>(type: T, query: StorageEntry, ...args: any[]): Promise<import("@polkadot/types/types").DetectCodec<import("@polkadot/types-codec/types").Codec, T> | undefined>;
|
|
52
56
|
/**
|
|
53
57
|
* Get paged storage keys.
|
|
@@ -127,6 +127,19 @@ class Block {
|
|
|
127
127
|
return val;
|
|
128
128
|
}
|
|
129
129
|
}
|
|
130
|
+
/**
|
|
131
|
+
* Get the block storage by key.
|
|
132
|
+
*/ async getMany(keys) {
|
|
133
|
+
const vals = await this.storage.getMany(keys, true);
|
|
134
|
+
return vals.map((val)=>{
|
|
135
|
+
switch(val){
|
|
136
|
+
case _storagelayer.StorageValueKind.Deleted:
|
|
137
|
+
return undefined;
|
|
138
|
+
default:
|
|
139
|
+
return val;
|
|
140
|
+
}
|
|
141
|
+
});
|
|
142
|
+
}
|
|
130
143
|
async read(type, query, ...args) {
|
|
131
144
|
const key = (0, _index.compactHex)(query(...args));
|
|
132
145
|
const value = await this.get(key);
|
|
@@ -12,6 +12,7 @@ const _types = require("@polkadot/types");
|
|
|
12
12
|
const _util = require("@polkadot/util");
|
|
13
13
|
const _utilcrypto = require("@polkadot/util-crypto");
|
|
14
14
|
const _lodash = /*#__PURE__*/ _interop_require_default(require("lodash"));
|
|
15
|
+
const _logger = require("../../../logger.js");
|
|
15
16
|
const _index = require("../../../utils/index.js");
|
|
16
17
|
const _proof = require("../../../utils/proof.js");
|
|
17
18
|
const _index1 = require("../../../wasm-executor/index.js");
|
|
@@ -20,6 +21,9 @@ function _interop_require_default(obj) {
|
|
|
20
21
|
default: obj
|
|
21
22
|
};
|
|
22
23
|
}
|
|
24
|
+
const logger = _logger.defaultLogger.child({
|
|
25
|
+
name: 'parachain-validation-data'
|
|
26
|
+
});
|
|
23
27
|
const MOCK_VALIDATION_DATA = {
|
|
24
28
|
validationData: {
|
|
25
29
|
relayParentNumber: 1000,
|
|
@@ -46,7 +50,7 @@ const MOCK_VALIDATION_DATA = {
|
|
|
46
50
|
horizontalMessages: [],
|
|
47
51
|
downwardMessages: []
|
|
48
52
|
};
|
|
49
|
-
const getValidationData = async (parent)=>{
|
|
53
|
+
const getValidationData = async (parent, fallback = true)=>{
|
|
50
54
|
const meta = await parent.meta;
|
|
51
55
|
if (parent.number === 0) {
|
|
52
56
|
const { trieRootHash, nodes } = await (0, _index1.createProof)(MOCK_VALIDATION_DATA.relayChainState.trieNodes, []);
|
|
@@ -61,15 +65,39 @@ const getValidationData = async (parent)=>{
|
|
|
61
65
|
}
|
|
62
66
|
};
|
|
63
67
|
}
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
const
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
68
|
+
try {
|
|
69
|
+
const extrinsics = await parent.extrinsics;
|
|
70
|
+
const validationDataExtrinsic = extrinsics.find((extrinsic)=>{
|
|
71
|
+
const firstArg = meta.registry.createType('GenericExtrinsic', extrinsic)?.args?.[0];
|
|
72
|
+
return firstArg && 'validationData' in firstArg;
|
|
73
|
+
});
|
|
74
|
+
if (!validationDataExtrinsic) {
|
|
75
|
+
throw new Error('Missing validation data from block');
|
|
76
|
+
}
|
|
77
|
+
return meta.registry.createType('GenericExtrinsic', validationDataExtrinsic).args[0].toJSON();
|
|
78
|
+
} catch (e) {
|
|
79
|
+
logger.warn('Failed to get validation data from block %d %s', parent.number, e);
|
|
80
|
+
if (fallback) {
|
|
81
|
+
// this could fail due to wasm override that breaks the validation data format
|
|
82
|
+
// so we will try parent's parent
|
|
83
|
+
const grandParent = await parent.parentBlock;
|
|
84
|
+
if (grandParent) {
|
|
85
|
+
const data = await getValidationData(grandParent, false);
|
|
86
|
+
return {
|
|
87
|
+
...data,
|
|
88
|
+
validationData: {
|
|
89
|
+
...data.validationData,
|
|
90
|
+
relayParentNumber: data.validationData.relayParentNumber + 2
|
|
91
|
+
}
|
|
92
|
+
};
|
|
93
|
+
} else {
|
|
94
|
+
throw e;
|
|
95
|
+
}
|
|
96
|
+
} else {
|
|
97
|
+
// fallback failed, throw error
|
|
98
|
+
throw e;
|
|
99
|
+
}
|
|
71
100
|
}
|
|
72
|
-
return meta.registry.createType('GenericExtrinsic', validationDataExtrinsic).args[0].toJSON();
|
|
73
101
|
};
|
|
74
102
|
class SetValidationData {
|
|
75
103
|
async createInherents(newBlock, params) {
|
|
@@ -97,7 +125,12 @@ class SetValidationData {
|
|
|
97
125
|
if (key === _proof.WELL_KNOWN_KEYS.CURRENT_SLOT) {
|
|
98
126
|
// increment current slot
|
|
99
127
|
const relayCurrentSlot = decoded[key] ? meta.registry.createType('Slot', (0, _util.hexToU8a)(decoded[key])).toNumber() : await (0, _index.getCurrentSlot)(parent) * relaySlotIncrease;
|
|
100
|
-
const newSlot = meta.registry.createType('Slot', relayCurrentSlot + relaySlotIncrease)
|
|
128
|
+
const newSlot = meta.registry.createType('Slot', relayCurrentSlot + relaySlotIncrease + 1) // +1 to be safe
|
|
129
|
+
;
|
|
130
|
+
logger.debug({
|
|
131
|
+
relayCurrentSlot,
|
|
132
|
+
newSlot: newSlot.toNumber()
|
|
133
|
+
}, 'Updating relay current slot');
|
|
101
134
|
newEntries.push([
|
|
102
135
|
key,
|
|
103
136
|
(0, _util.u8aToHex)(newSlot.toU8a())
|
|
@@ -7,10 +7,18 @@ export declare enum StorageValueKind {
|
|
|
7
7
|
}
|
|
8
8
|
export type StorageValue = string | StorageValueKind | undefined;
|
|
9
9
|
export interface StorageLayerProvider {
|
|
10
|
+
/**
|
|
11
|
+
* Returns true if key is deleted
|
|
12
|
+
*/
|
|
13
|
+
deleted(key: string): boolean;
|
|
10
14
|
/**
|
|
11
15
|
* Get the value of a storage key.
|
|
12
16
|
*/
|
|
13
17
|
get(key: string, cache: boolean): Promise<StorageValue>;
|
|
18
|
+
/**
|
|
19
|
+
* Get the value of many storage keys.
|
|
20
|
+
*/
|
|
21
|
+
getMany(keys: string[], _cache: boolean): Promise<StorageValue[]>;
|
|
14
22
|
/**
|
|
15
23
|
* Get paged storage keys.
|
|
16
24
|
*/
|
|
@@ -23,14 +31,18 @@ export interface StorageLayerProvider {
|
|
|
23
31
|
export declare class RemoteStorageLayer implements StorageLayerProvider {
|
|
24
32
|
#private;
|
|
25
33
|
constructor(api: Api, at: HexString, db: Database | undefined);
|
|
34
|
+
deleted(_key: string): boolean;
|
|
26
35
|
get(key: string, _cache: boolean): Promise<StorageValue>;
|
|
36
|
+
getMany(keys: string[], _cache: boolean): Promise<StorageValue[]>;
|
|
27
37
|
findNextKey(prefix: string, startKey: string, _knownBest?: string): Promise<string | undefined>;
|
|
28
38
|
getKeysPaged(prefix: string, pageSize: number, startKey: string): Promise<string[]>;
|
|
29
39
|
}
|
|
30
40
|
export declare class StorageLayer implements StorageLayerProvider {
|
|
31
41
|
#private;
|
|
32
42
|
constructor(parent?: StorageLayerProvider);
|
|
43
|
+
deleted(key: string): boolean;
|
|
33
44
|
get(key: string, cache: boolean): Promise<StorageValue | undefined>;
|
|
45
|
+
getMany(keys: string[], cache: boolean): Promise<StorageValue[]>;
|
|
34
46
|
set(key: string, value: StorageValue): void;
|
|
35
47
|
setAll(values: Record<string, StorageValue | null> | [string, StorageValue | null][]): void;
|
|
36
48
|
findNextKey(prefix: string, startKey: string, knownBest?: string): Promise<string | undefined>;
|
|
@@ -89,6 +89,9 @@ var StorageValueKind = /*#__PURE__*/ function(StorageValueKind) {
|
|
|
89
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
|
+
deleted(_key) {
|
|
93
|
+
return false;
|
|
94
|
+
}
|
|
92
95
|
async get(key, _cache) {
|
|
93
96
|
if (_class_private_field_get(this, _db)) {
|
|
94
97
|
const res = await _class_private_field_get(this, _db).queryStorage(_class_private_field_get(this, _at), key);
|
|
@@ -104,6 +107,48 @@ class RemoteStorageLayer {
|
|
|
104
107
|
_class_private_field_get(this, _db)?.saveStorage(_class_private_field_get(this, _at), key, data);
|
|
105
108
|
return data ?? undefined;
|
|
106
109
|
}
|
|
110
|
+
async getMany(keys, _cache) {
|
|
111
|
+
const result = [];
|
|
112
|
+
let pending = keys.map((key, idx)=>({
|
|
113
|
+
key,
|
|
114
|
+
idx
|
|
115
|
+
}));
|
|
116
|
+
if (_class_private_field_get(this, _db)) {
|
|
117
|
+
const results = await Promise.all(pending.map(({ key })=>_class_private_field_get(this, _db).queryStorage(_class_private_field_get(this, _at), key)));
|
|
118
|
+
const oldPending = pending;
|
|
119
|
+
pending = [];
|
|
120
|
+
results.forEach((res, idx)=>{
|
|
121
|
+
if (res) {
|
|
122
|
+
result[idx] = res.value ?? undefined;
|
|
123
|
+
} else {
|
|
124
|
+
pending.push({
|
|
125
|
+
key: oldPending[idx].key,
|
|
126
|
+
idx
|
|
127
|
+
});
|
|
128
|
+
}
|
|
129
|
+
});
|
|
130
|
+
}
|
|
131
|
+
if (pending.length) {
|
|
132
|
+
logger.trace({
|
|
133
|
+
at: _class_private_field_get(this, _at),
|
|
134
|
+
keys
|
|
135
|
+
}, 'RemoteStorageLayer getMany');
|
|
136
|
+
const data = await _class_private_field_get(this, _api).getStorageBatch('0x', pending.map(({ key })=>key), _class_private_field_get(this, _at));
|
|
137
|
+
data.forEach(([, res], idx)=>{
|
|
138
|
+
result[pending[idx].idx] = res ?? undefined;
|
|
139
|
+
});
|
|
140
|
+
if (_class_private_field_get(this, _db)?.saveStorageBatch) {
|
|
141
|
+
_class_private_field_get(this, _db)?.saveStorageBatch(data.map(([key, value])=>({
|
|
142
|
+
key,
|
|
143
|
+
value,
|
|
144
|
+
blockHash: _class_private_field_get(this, _at)
|
|
145
|
+
})));
|
|
146
|
+
} else if (_class_private_field_get(this, _db)) {
|
|
147
|
+
data.forEach(([key, value])=>_class_private_field_get(this, _db)?.saveStorage(_class_private_field_get(this, _at), key, value));
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
return result;
|
|
151
|
+
}
|
|
107
152
|
async findNextKey(prefix, startKey, _knownBest) {
|
|
108
153
|
const keys = await this.getKeysPaged(prefix, 1, startKey);
|
|
109
154
|
return keys[0];
|
|
@@ -205,6 +250,18 @@ class RemoteStorageLayer {
|
|
|
205
250
|
}
|
|
206
251
|
var _store = /*#__PURE__*/ new WeakMap(), _keys = /*#__PURE__*/ new WeakMap(), _deletedPrefix = /*#__PURE__*/ new WeakMap(), _parent = /*#__PURE__*/ new WeakMap(), _addKey = /*#__PURE__*/ new WeakSet(), _removeKey = /*#__PURE__*/ new WeakSet();
|
|
207
252
|
class StorageLayer {
|
|
253
|
+
deleted(key) {
|
|
254
|
+
if (_class_private_field_get(this, _store).has(key)) {
|
|
255
|
+
return _class_private_field_get(this, _store).get(key) === "Deleted";
|
|
256
|
+
}
|
|
257
|
+
if (_class_private_field_get(this, _deletedPrefix).some((dp)=>key.startsWith(dp))) {
|
|
258
|
+
return true;
|
|
259
|
+
}
|
|
260
|
+
if (_class_private_field_get(this, _parent)) {
|
|
261
|
+
return _class_private_field_get(this, _parent).deleted(key);
|
|
262
|
+
}
|
|
263
|
+
return false;
|
|
264
|
+
}
|
|
208
265
|
async get(key, cache) {
|
|
209
266
|
if (_class_private_field_get(this, _store).has(key)) {
|
|
210
267
|
return _class_private_field_get(this, _store).get(key);
|
|
@@ -221,6 +278,33 @@ class StorageLayer {
|
|
|
221
278
|
}
|
|
222
279
|
return undefined;
|
|
223
280
|
}
|
|
281
|
+
async getMany(keys, cache) {
|
|
282
|
+
const result = [];
|
|
283
|
+
const pending = [];
|
|
284
|
+
const preloadedPromises = keys.map(async (key, idx)=>{
|
|
285
|
+
if (_class_private_field_get(this, _store).has(key)) {
|
|
286
|
+
result[idx] = await _class_private_field_get(this, _store).get(key);
|
|
287
|
+
} else if (_class_private_field_get(this, _deletedPrefix).some((dp)=>key.startsWith(dp))) {
|
|
288
|
+
result[idx] = "Deleted";
|
|
289
|
+
} else {
|
|
290
|
+
pending.push({
|
|
291
|
+
key,
|
|
292
|
+
idx
|
|
293
|
+
});
|
|
294
|
+
}
|
|
295
|
+
});
|
|
296
|
+
if (pending.length && _class_private_field_get(this, _parent)) {
|
|
297
|
+
const vals = await _class_private_field_get(this, _parent).getMany(pending.map((p)=>p.key), false);
|
|
298
|
+
vals.forEach((val, idx)=>{
|
|
299
|
+
if (cache) {
|
|
300
|
+
_class_private_field_get(this, _store).set(pending[idx].key, val);
|
|
301
|
+
}
|
|
302
|
+
result[pending[idx].idx] = val;
|
|
303
|
+
});
|
|
304
|
+
}
|
|
305
|
+
await Promise.all(preloadedPromises);
|
|
306
|
+
return result;
|
|
307
|
+
}
|
|
224
308
|
set(key, value) {
|
|
225
309
|
switch(value){
|
|
226
310
|
case "Deleted":
|
|
@@ -283,7 +367,7 @@ class StorageLayer {
|
|
|
283
367
|
const next = await this.findNextKey(prefix, startKey, undefined);
|
|
284
368
|
if (!next) break;
|
|
285
369
|
startKey = next;
|
|
286
|
-
if (
|
|
370
|
+
if (this.deleted(next)) continue;
|
|
287
371
|
keys.push(next);
|
|
288
372
|
}
|
|
289
373
|
return keys;
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
import type { HexString } from '@polkadot/util/types';
|
|
2
|
+
import { type Handler } from '../shared.js';
|
|
3
|
+
import type { StorageItemRequest } from './chainHead_v1.js';
|
|
4
|
+
/**
|
|
5
|
+
* Retrieve the body of a specific block
|
|
6
|
+
*
|
|
7
|
+
* @param context
|
|
8
|
+
* @param params - [`hash`]
|
|
9
|
+
*
|
|
10
|
+
* @return An array of the SCALE-encoded transactions of a block, or `null` if the block is not found.
|
|
11
|
+
*/
|
|
12
|
+
export declare const archive_v1_body: Handler<[HexString], HexString[] | null>;
|
|
13
|
+
export type CallResult = {
|
|
14
|
+
success: true;
|
|
15
|
+
value: HexString;
|
|
16
|
+
} | {
|
|
17
|
+
success: false;
|
|
18
|
+
error: any;
|
|
19
|
+
};
|
|
20
|
+
export declare const archive_v1_call: Handler<[HexString, string, HexString], CallResult | null>;
|
|
21
|
+
/**
|
|
22
|
+
* Retrieve the height of the finalized block.
|
|
23
|
+
*
|
|
24
|
+
* @param context
|
|
25
|
+
*
|
|
26
|
+
* @return The `number` of the height of the head (a.k.a. finalized) block.
|
|
27
|
+
*/
|
|
28
|
+
export declare const archive_v1_finalizedHeight: Handler<undefined, number>;
|
|
29
|
+
/**
|
|
30
|
+
* Retrieve the genesis hash
|
|
31
|
+
*
|
|
32
|
+
* @param context
|
|
33
|
+
*
|
|
34
|
+
* @return An {@link HexString} with the hash of the genesis block.
|
|
35
|
+
*/
|
|
36
|
+
export declare const archive_v1_genesisHash: Handler<undefined, HexString>;
|
|
37
|
+
/**
|
|
38
|
+
* Retrieve the hash of a specific height
|
|
39
|
+
*
|
|
40
|
+
* @param context
|
|
41
|
+
* @param params - [`height`]
|
|
42
|
+
*
|
|
43
|
+
* @return An array of {@link HexString} with the hashes of the blocks associated to the
|
|
44
|
+
* given height.
|
|
45
|
+
*/
|
|
46
|
+
export declare const archive_v1_hashByHeight: Handler<[number], HexString[]>;
|
|
47
|
+
/**
|
|
48
|
+
* Retrieve the header for a specific block
|
|
49
|
+
*
|
|
50
|
+
* @param context
|
|
51
|
+
* @param params - [`hash`]
|
|
52
|
+
*
|
|
53
|
+
* @return SCALE-encoded header, or `null` if the block is not found.
|
|
54
|
+
*/
|
|
55
|
+
export declare const archive_v1_header: Handler<[HexString], HexString | null>;
|
|
56
|
+
/**
|
|
57
|
+
* Query the storage for a given block
|
|
58
|
+
*
|
|
59
|
+
* @param context
|
|
60
|
+
* @param params - [`hash`, `items`, `childTrie`]
|
|
61
|
+
*
|
|
62
|
+
* @return the operationId to capture the notifications where to receive the result
|
|
63
|
+
*
|
|
64
|
+
* The query type `closestDescendantMerkleValue` is not up to spec.
|
|
65
|
+
* According to the spec, the result should be the Merkle value of the key or
|
|
66
|
+
* the closest descendant of the key.
|
|
67
|
+
* As chopsticks doesn't have direct access to the Merkle tree, it will return
|
|
68
|
+
* a string that will change every time that one of the descendant changes, but
|
|
69
|
+
* it won't be the actual Merkle value.
|
|
70
|
+
* This should be enough for applications that don't rely on the actual Merkle
|
|
71
|
+
* value, but just use it to detect for storage changes.
|
|
72
|
+
*/
|
|
73
|
+
export declare const archive_v1_storage: Handler<[HexString, StorageItemRequest[], HexString | null], string>;
|
|
74
|
+
export declare const archive_v1_stopStorage: Handler<[string], null>;
|
|
@@ -0,0 +1,201 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", {
|
|
3
|
+
value: true
|
|
4
|
+
});
|
|
5
|
+
function _export(target, all) {
|
|
6
|
+
for(var name in all)Object.defineProperty(target, name, {
|
|
7
|
+
enumerable: true,
|
|
8
|
+
get: Object.getOwnPropertyDescriptor(all, name).get
|
|
9
|
+
});
|
|
10
|
+
}
|
|
11
|
+
_export(exports, {
|
|
12
|
+
get archive_v1_body () {
|
|
13
|
+
return archive_v1_body;
|
|
14
|
+
},
|
|
15
|
+
get archive_v1_call () {
|
|
16
|
+
return archive_v1_call;
|
|
17
|
+
},
|
|
18
|
+
get archive_v1_finalizedHeight () {
|
|
19
|
+
return archive_v1_finalizedHeight;
|
|
20
|
+
},
|
|
21
|
+
get archive_v1_genesisHash () {
|
|
22
|
+
return archive_v1_genesisHash;
|
|
23
|
+
},
|
|
24
|
+
get archive_v1_hashByHeight () {
|
|
25
|
+
return archive_v1_hashByHeight;
|
|
26
|
+
},
|
|
27
|
+
get archive_v1_header () {
|
|
28
|
+
return archive_v1_header;
|
|
29
|
+
},
|
|
30
|
+
get archive_v1_stopStorage () {
|
|
31
|
+
return archive_v1_stopStorage;
|
|
32
|
+
},
|
|
33
|
+
get archive_v1_storage () {
|
|
34
|
+
return archive_v1_storage;
|
|
35
|
+
}
|
|
36
|
+
});
|
|
37
|
+
const _utilcrypto = require("@polkadot/util-crypto");
|
|
38
|
+
const _headstate = require("../../blockchain/head-state.js");
|
|
39
|
+
const _shared = require("../shared.js");
|
|
40
|
+
const _archive = require("../substrate/archive.js");
|
|
41
|
+
const _storagecommon = require("./storage-common.js");
|
|
42
|
+
const archive_v1_body = async (...args)=>(0, _archive.archive_unstable_body)(...args).catch(()=>null);
|
|
43
|
+
/**
|
|
44
|
+
* Perform a runtime call for a block
|
|
45
|
+
*
|
|
46
|
+
* @param context
|
|
47
|
+
* @param params - [`hash`, `function`, `callParameters`]
|
|
48
|
+
*
|
|
49
|
+
* @return A {@link CallResult} with the result of the runtime call, or `null` if the block
|
|
50
|
+
* is not found.
|
|
51
|
+
*/ function isBlockNotFound(error) {
|
|
52
|
+
return error instanceof _shared.ResponseError && error.code === 1;
|
|
53
|
+
}
|
|
54
|
+
const archive_v1_call = async (...args)=>_archive.archive_unstable_call.call(undefined, ...args).then(({ value })=>({
|
|
55
|
+
success: true,
|
|
56
|
+
value
|
|
57
|
+
}), (error)=>isBlockNotFound(error) ? null : {
|
|
58
|
+
success: false,
|
|
59
|
+
error
|
|
60
|
+
});
|
|
61
|
+
const archive_v1_finalizedHeight = (context)=>{
|
|
62
|
+
return Promise.resolve(context.chain.head.number);
|
|
63
|
+
};
|
|
64
|
+
const archive_v1_genesisHash = async (context)=>{
|
|
65
|
+
const genesisBlock = await context.chain.getBlockAt(0);
|
|
66
|
+
return genesisBlock.hash;
|
|
67
|
+
};
|
|
68
|
+
const archive_v1_hashByHeight = async (context, [height])=>{
|
|
69
|
+
const block = await context.chain.getBlockAt(height);
|
|
70
|
+
return block ? [
|
|
71
|
+
block.hash
|
|
72
|
+
] : [];
|
|
73
|
+
};
|
|
74
|
+
const archive_v1_header = async (context, [hash])=>{
|
|
75
|
+
const block = await context.chain.getBlock(hash);
|
|
76
|
+
return block ? (await block.header).toHex() : null;
|
|
77
|
+
};
|
|
78
|
+
/**
|
|
79
|
+
* Contains the storage operations.
|
|
80
|
+
*/ const storageOperations = new Map();
|
|
81
|
+
const archive_v1_storage = async (context, [hash, items, _childTrie], { subscribe })=>{
|
|
82
|
+
const operationId = (0, _headstate.randomId)();
|
|
83
|
+
const callback = subscribe('chainHead_v1_storageEvent', operationId, ()=>storageOperations.delete(operationId));
|
|
84
|
+
storageOperations.set(operationId, {
|
|
85
|
+
callback,
|
|
86
|
+
hash,
|
|
87
|
+
params: [],
|
|
88
|
+
storageDiffs: new Map()
|
|
89
|
+
});
|
|
90
|
+
(0, _storagecommon.afterResponse)(async ()=>{
|
|
91
|
+
const block = await context.chain.getBlock(hash);
|
|
92
|
+
if (!block) {
|
|
93
|
+
storageOperations.get(operationId)?.callback({
|
|
94
|
+
event: 'storageError',
|
|
95
|
+
operationId,
|
|
96
|
+
error: 'Block not found'
|
|
97
|
+
});
|
|
98
|
+
return;
|
|
99
|
+
}
|
|
100
|
+
const handleStorageItemRequest = async (sir)=>{
|
|
101
|
+
switch(sir.type){
|
|
102
|
+
case 'value':
|
|
103
|
+
{
|
|
104
|
+
const value = await block.get(sir.key);
|
|
105
|
+
if (value) {
|
|
106
|
+
storageOperations.get(operationId)?.callback({
|
|
107
|
+
event: 'storage',
|
|
108
|
+
key: sir.key,
|
|
109
|
+
value
|
|
110
|
+
});
|
|
111
|
+
}
|
|
112
|
+
return null;
|
|
113
|
+
}
|
|
114
|
+
case 'hash':
|
|
115
|
+
{
|
|
116
|
+
const value = await block.get(sir.key);
|
|
117
|
+
if (value) {
|
|
118
|
+
storageOperations.get(operationId)?.callback({
|
|
119
|
+
event: 'storage',
|
|
120
|
+
key: sir.key,
|
|
121
|
+
hash
|
|
122
|
+
});
|
|
123
|
+
}
|
|
124
|
+
return null;
|
|
125
|
+
}
|
|
126
|
+
case 'descendantsValues':
|
|
127
|
+
{
|
|
128
|
+
let items;
|
|
129
|
+
let next = {
|
|
130
|
+
prefix: sir.key,
|
|
131
|
+
startKey: '0x'
|
|
132
|
+
};
|
|
133
|
+
do {
|
|
134
|
+
;
|
|
135
|
+
({ items, next } = await (0, _storagecommon.getDescendantValues)(block, next));
|
|
136
|
+
for (const { key, value } of items){
|
|
137
|
+
storageOperations.get(operationId)?.callback({
|
|
138
|
+
event: 'storage',
|
|
139
|
+
key,
|
|
140
|
+
value
|
|
141
|
+
});
|
|
142
|
+
}
|
|
143
|
+
}while (next !== null)
|
|
144
|
+
return null;
|
|
145
|
+
}
|
|
146
|
+
case 'descendantsHashes':
|
|
147
|
+
{
|
|
148
|
+
let items;
|
|
149
|
+
let next = {
|
|
150
|
+
prefix: sir.key,
|
|
151
|
+
startKey: '0x'
|
|
152
|
+
};
|
|
153
|
+
do {
|
|
154
|
+
;
|
|
155
|
+
({ items, next } = await (0, _storagecommon.getDescendantValues)(block, next));
|
|
156
|
+
for (const { key, value } of items){
|
|
157
|
+
if (value === undefined) {
|
|
158
|
+
continue;
|
|
159
|
+
}
|
|
160
|
+
storageOperations.get(operationId)?.callback({
|
|
161
|
+
event: 'storage',
|
|
162
|
+
key,
|
|
163
|
+
hash: (0, _utilcrypto.blake2AsHex)(value)
|
|
164
|
+
});
|
|
165
|
+
}
|
|
166
|
+
}while (next !== null)
|
|
167
|
+
return null;
|
|
168
|
+
}
|
|
169
|
+
case 'closestDescendantMerkleValue':
|
|
170
|
+
{
|
|
171
|
+
const subscription = storageOperations.get(operationId);
|
|
172
|
+
if (!subscription) return null;
|
|
173
|
+
if (!subscription.storageDiffs.has(sir.key)) {
|
|
174
|
+
// Set up a diff watch for this key
|
|
175
|
+
subscription.storageDiffs.set(sir.key, 0);
|
|
176
|
+
}
|
|
177
|
+
subscription.callback({
|
|
178
|
+
event: 'storage',
|
|
179
|
+
operationId,
|
|
180
|
+
items: [
|
|
181
|
+
{
|
|
182
|
+
key: sir.key,
|
|
183
|
+
closestDescendantMerkleValue: String(subscription.storageDiffs.get(sir.key))
|
|
184
|
+
}
|
|
185
|
+
]
|
|
186
|
+
});
|
|
187
|
+
return null;
|
|
188
|
+
}
|
|
189
|
+
}
|
|
190
|
+
};
|
|
191
|
+
await Promise.all(items.map(handleStorageItemRequest));
|
|
192
|
+
storageOperations.get(operationId)?.callback({
|
|
193
|
+
event: 'storageDone'
|
|
194
|
+
});
|
|
195
|
+
});
|
|
196
|
+
return operationId;
|
|
197
|
+
};
|
|
198
|
+
const archive_v1_stopStorage = async (_, [operationId], { unsubscribe })=>{
|
|
199
|
+
unsubscribe(operationId);
|
|
200
|
+
return null;
|
|
201
|
+
};
|
|
@@ -40,14 +40,11 @@ _export(exports, {
|
|
|
40
40
|
const _utilcrypto = require("@polkadot/util-crypto");
|
|
41
41
|
const _logger = require("../../logger.js");
|
|
42
42
|
const _shared = require("../shared.js");
|
|
43
|
+
const _storagecommon = require("./storage-common.js");
|
|
43
44
|
const logger = _logger.defaultLogger.child({
|
|
44
45
|
name: 'rpc-chainHead_v1'
|
|
45
46
|
});
|
|
46
47
|
const following = new Map();
|
|
47
|
-
async function afterResponse(fn) {
|
|
48
|
-
await new Promise((resolve)=>setTimeout(resolve, 0));
|
|
49
|
-
fn();
|
|
50
|
-
}
|
|
51
48
|
const chainHead_v1_follow = async (context, [withRuntime], { subscribe })=>{
|
|
52
49
|
const update = async (block)=>{
|
|
53
50
|
logger.trace({
|
|
@@ -101,7 +98,7 @@ const chainHead_v1_follow = async (context, [withRuntime], { subscribe })=>{
|
|
|
101
98
|
pendingDescendantValues: new Map(),
|
|
102
99
|
storageDiffs: new Map()
|
|
103
100
|
});
|
|
104
|
-
afterResponse(async ()=>{
|
|
101
|
+
(0, _storagecommon.afterResponse)(async ()=>{
|
|
105
102
|
callback({
|
|
106
103
|
event: 'initialized',
|
|
107
104
|
finalizedBlockHashes: [
|
|
@@ -128,7 +125,7 @@ const operationStarted = (operationId)=>({
|
|
|
128
125
|
const randomId = ()=>Math.random().toString(36).substring(2);
|
|
129
126
|
const chainHead_v1_call = async (context, [followSubscription, hash, method, callParameters])=>{
|
|
130
127
|
const operationId = randomId();
|
|
131
|
-
afterResponse(async ()=>{
|
|
128
|
+
(0, _storagecommon.afterResponse)(async ()=>{
|
|
132
129
|
const block = await context.chain.getBlock(hash);
|
|
133
130
|
if (!block) {
|
|
134
131
|
following.get(followSubscription)?.callback({
|
|
@@ -157,33 +154,9 @@ const chainHead_v1_call = async (context, [followSubscription, hash, method, cal
|
|
|
157
154
|
});
|
|
158
155
|
return operationStarted(operationId);
|
|
159
156
|
};
|
|
160
|
-
const PAGE_SIZE = 1000;
|
|
161
|
-
async function getDescendantValues(block, params) {
|
|
162
|
-
const keys = await block.getKeysPaged({
|
|
163
|
-
...params,
|
|
164
|
-
pageSize: PAGE_SIZE
|
|
165
|
-
});
|
|
166
|
-
const items = await Promise.all(keys.map((key)=>block.get(key).then((value)=>({
|
|
167
|
-
key,
|
|
168
|
-
value
|
|
169
|
-
}))));
|
|
170
|
-
if (keys.length < PAGE_SIZE) {
|
|
171
|
-
return {
|
|
172
|
-
items,
|
|
173
|
-
next: null
|
|
174
|
-
};
|
|
175
|
-
}
|
|
176
|
-
return {
|
|
177
|
-
items,
|
|
178
|
-
next: {
|
|
179
|
-
...params,
|
|
180
|
-
startKey: keys[PAGE_SIZE - 1]
|
|
181
|
-
}
|
|
182
|
-
};
|
|
183
|
-
}
|
|
184
157
|
const chainHead_v1_storage = async (context, [followSubscription, hash, items, _childTrie])=>{
|
|
185
158
|
const operationId = randomId();
|
|
186
|
-
afterResponse(async ()=>{
|
|
159
|
+
(0, _storagecommon.afterResponse)(async ()=>{
|
|
187
160
|
const block = await context.chain.getBlock(hash);
|
|
188
161
|
if (!block) {
|
|
189
162
|
following.get(followSubscription)?.callback({
|
|
@@ -231,7 +204,7 @@ const chainHead_v1_storage = async (context, [followSubscription, hash, items, _
|
|
|
231
204
|
}
|
|
232
205
|
case 'descendantsValues':
|
|
233
206
|
{
|
|
234
|
-
const { items, next } = await getDescendantValues(block, {
|
|
207
|
+
const { items, next } = await (0, _storagecommon.getDescendantValues)(block, {
|
|
235
208
|
prefix: sir.key,
|
|
236
209
|
startKey: '0x'
|
|
237
210
|
});
|
|
@@ -244,7 +217,7 @@ const chainHead_v1_storage = async (context, [followSubscription, hash, items, _
|
|
|
244
217
|
}
|
|
245
218
|
case 'descendantsHashes':
|
|
246
219
|
{
|
|
247
|
-
const { items, next } = await getDescendantValues(block, {
|
|
220
|
+
const { items, next } = await (0, _storagecommon.getDescendantValues)(block, {
|
|
248
221
|
prefix: sir.key,
|
|
249
222
|
startKey: '0x'
|
|
250
223
|
});
|
|
@@ -319,7 +292,7 @@ const chainHead_v1_body = async (context, [followSubscription, hash])=>{
|
|
|
319
292
|
throw new _shared.ResponseError(-32801, 'Block not found');
|
|
320
293
|
}
|
|
321
294
|
const operationId = randomId();
|
|
322
|
-
afterResponse(async ()=>{
|
|
295
|
+
(0, _storagecommon.afterResponse)(async ()=>{
|
|
323
296
|
const body = await block.extrinsics;
|
|
324
297
|
following.get(followSubscription)?.callback({
|
|
325
298
|
event: 'operationBodyDone',
|
|
@@ -339,9 +312,9 @@ const chainHead_v1_continue = async (context, [followSubscription, operationId])
|
|
|
339
312
|
if (!block) {
|
|
340
313
|
throw new _shared.ResponseError(-32801, 'Block not found');
|
|
341
314
|
}
|
|
342
|
-
afterResponse(async ()=>{
|
|
315
|
+
(0, _storagecommon.afterResponse)(async ()=>{
|
|
343
316
|
const handlePendingOperation = async (params)=>{
|
|
344
|
-
const { items, next } = await getDescendantValues(block, params);
|
|
317
|
+
const { items, next } = await (0, _storagecommon.getDescendantValues)(block, params);
|
|
345
318
|
follower.callback({
|
|
346
319
|
event: 'operationStorageItems',
|
|
347
320
|
operationId,
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import * as ArchiveV1RPC from './archive_v1.js';
|
|
1
2
|
import * as ChainHeadV1RPC from './chainHead_v1.js';
|
|
2
3
|
import * as ChainSpecV1RPC from './chainSpec_v1.js';
|
|
3
4
|
import * as TransactionV1RPC from './transaction_v1.js';
|
|
@@ -23,5 +24,13 @@ declare const handlers: {
|
|
|
23
24
|
chainHead_v1_continue: import("../shared.js").Handler<[string, import("@polkadot/util/types").HexString], null>;
|
|
24
25
|
chainHead_v1_stopOperation: import("../shared.js").Handler<[string, import("@polkadot/util/types").HexString], null>;
|
|
25
26
|
chainHead_v1_unpin: import("../shared.js").Handler<[string, import("@polkadot/util/types").HexString | import("@polkadot/util/types").HexString[]], null>;
|
|
27
|
+
archive_v1_body: import("../shared.js").Handler<[import("@polkadot/util/types").HexString], import("@polkadot/util/types").HexString[] | null>;
|
|
28
|
+
archive_v1_call: import("../shared.js").Handler<[import("@polkadot/util/types").HexString, string, import("@polkadot/util/types").HexString], ArchiveV1RPC.CallResult | null>;
|
|
29
|
+
archive_v1_finalizedHeight: import("../shared.js").Handler<undefined, number>;
|
|
30
|
+
archive_v1_genesisHash: import("../shared.js").Handler<undefined, import("@polkadot/util/types").HexString>;
|
|
31
|
+
archive_v1_hashByHeight: import("../shared.js").Handler<[number], import("@polkadot/util/types").HexString[]>;
|
|
32
|
+
archive_v1_header: import("../shared.js").Handler<[import("@polkadot/util/types").HexString], import("@polkadot/util/types").HexString | null>;
|
|
33
|
+
archive_v1_storage: import("../shared.js").Handler<[import("@polkadot/util/types").HexString, ChainHeadV1RPC.StorageItemRequest[], import("@polkadot/util/types").HexString | null], string>;
|
|
34
|
+
archive_v1_stopStorage: import("../shared.js").Handler<[string], null>;
|
|
26
35
|
};
|
|
27
36
|
export default handlers;
|