@acala-network/chopsticks-core 1.4.2 → 1.5.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/api.d.ts +5 -0
- package/dist/cjs/api.js +9 -0
- package/dist/cjs/bridge/encode.d.ts +5 -0
- package/dist/cjs/bridge/encode.js +38 -0
- package/dist/cjs/bridge/index.d.ts +2 -0
- package/dist/cjs/bridge/index.js +28 -0
- package/dist/cjs/index.d.ts +1 -0
- package/dist/cjs/index.js +1 -0
- package/dist/cjs/rpc/dev/get-read-proof.d.ts +20 -0
- package/dist/cjs/rpc/dev/get-read-proof.js +12 -0
- package/dist/cjs/rpc/dev/index.d.ts +6 -0
- package/dist/cjs/rpc/dev/index.js +2 -0
- package/dist/cjs/rpc/read-proof.d.ts +15 -0
- package/dist/cjs/rpc/read-proof.js +62 -0
- package/dist/cjs/rpc/substrate/index.d.ts +4 -0
- package/dist/cjs/rpc/substrate/state.d.ts +18 -0
- package/dist/cjs/rpc/substrate/state.js +11 -0
- package/dist/esm/api.d.ts +5 -0
- package/dist/esm/api.js +9 -0
- package/dist/esm/bridge/encode.d.ts +5 -0
- package/dist/esm/bridge/encode.js +20 -0
- package/dist/esm/bridge/index.d.ts +2 -0
- package/dist/esm/bridge/index.js +5 -0
- package/dist/esm/index.d.ts +1 -0
- package/dist/esm/index.js +1 -0
- package/dist/esm/rpc/dev/get-read-proof.d.ts +20 -0
- package/dist/esm/rpc/dev/get-read-proof.js +11 -0
- package/dist/esm/rpc/dev/index.d.ts +6 -0
- package/dist/esm/rpc/dev/index.js +3 -0
- package/dist/esm/rpc/read-proof.d.ts +15 -0
- package/dist/esm/rpc/read-proof.js +59 -0
- package/dist/esm/rpc/substrate/index.d.ts +4 -0
- package/dist/esm/rpc/substrate/state.d.ts +18 -0
- package/dist/esm/rpc/substrate/state.js +18 -0
- package/package.json +2 -2
package/dist/cjs/api.d.ts
CHANGED
|
@@ -36,6 +36,11 @@ export declare class Api {
|
|
|
36
36
|
getStorage(key: string, hash?: string): Promise<`0x${string}` | null>;
|
|
37
37
|
getKeysPaged(prefix: string, pageSize: number, startKey: string, hash?: string): Promise<`0x${string}`[]>;
|
|
38
38
|
getStorageBatch(prefix: HexString, keys: HexString[], hash?: HexString): any;
|
|
39
|
+
/** Upstream `state_getReadProof`. Throws if upstream doesn't expose it. */
|
|
40
|
+
getReadProof(keys: HexString[], hash?: HexString): Promise<{
|
|
41
|
+
at: HexString;
|
|
42
|
+
proof: HexString[];
|
|
43
|
+
}>;
|
|
39
44
|
subscribeRemoteNewHeads(cb: ProviderInterfaceCallback): Promise<string | number>;
|
|
40
45
|
subscribeRemoteFinalizedHeads(cb: ProviderInterfaceCallback): Promise<string | number>;
|
|
41
46
|
}
|
package/dist/cjs/api.js
CHANGED
|
@@ -234,6 +234,15 @@ class Api {
|
|
|
234
234
|
if (hash) params.push(hash);
|
|
235
235
|
return _class_private_field_get(this, _provider).send('state_queryStorageAt', params, !!hash).then((result)=>result[0]?.['changes'] || []).catch(retryOnError);
|
|
236
236
|
}
|
|
237
|
+
/** Upstream `state_getReadProof`. Throws if upstream doesn't expose it. */ async getReadProof(keys, hash) {
|
|
238
|
+
const params = hash ? [
|
|
239
|
+
keys,
|
|
240
|
+
hash
|
|
241
|
+
] : [
|
|
242
|
+
keys
|
|
243
|
+
];
|
|
244
|
+
return this.send('state_getReadProof', params, !!hash);
|
|
245
|
+
}
|
|
237
246
|
async subscribeRemoteNewHeads(cb) {
|
|
238
247
|
if (!_class_private_field_get(this, _provider).hasSubscriptions) {
|
|
239
248
|
throw new Error('subscribeRemoteNewHeads only works with subscriptions');
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
import type { HexString } from '@polkadot/util/types';
|
|
2
|
+
/** `ParaInfo { best_head_hash: { at_relay_block_number: u32, head_hash: H256 }, next_imported_hash_position: u32 }` */
|
|
3
|
+
export declare const encodeParaInfo: (atRelayBlockNumber: number, headHash: Uint8Array, nextImportedHashPosition: number) => HexString;
|
|
4
|
+
/** `ParaStoredHeaderData(Vec<u8>)` wrapping SCALE-encoded `StoredHeaderData { number: u32, state_root: H256 }`. */
|
|
5
|
+
export declare const encodeParaStoredHeaderData: (blockNumber: number, stateRoot: Uint8Array) => HexString;
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
// Value encoders for `pallet_bridge_parachains` storage items. The bridge connector forges
|
|
2
|
+
// these values via `dev_setStorage`, so they're SCALE-encoded by hand — runtime metadata
|
|
3
|
+
// describes their types but can't construct them. Storage *keys*, by contrast, are derived
|
|
4
|
+
// from metadata by the callers (`api.query[pallet].item.key(...)`), never hand-hashed.
|
|
5
|
+
"use strict";
|
|
6
|
+
Object.defineProperty(exports, "__esModule", {
|
|
7
|
+
value: true
|
|
8
|
+
});
|
|
9
|
+
function _export(target, all) {
|
|
10
|
+
for(var name in all)Object.defineProperty(target, name, {
|
|
11
|
+
enumerable: true,
|
|
12
|
+
get: Object.getOwnPropertyDescriptor(all, name).get
|
|
13
|
+
});
|
|
14
|
+
}
|
|
15
|
+
_export(exports, {
|
|
16
|
+
get encodeParaInfo () {
|
|
17
|
+
return encodeParaInfo;
|
|
18
|
+
},
|
|
19
|
+
get encodeParaStoredHeaderData () {
|
|
20
|
+
return encodeParaStoredHeaderData;
|
|
21
|
+
}
|
|
22
|
+
});
|
|
23
|
+
const _util = require("@polkadot/util");
|
|
24
|
+
const u32LE = (v)=>(0, _util.nToU8a)(v, {
|
|
25
|
+
bitLength: 32,
|
|
26
|
+
isLe: true
|
|
27
|
+
});
|
|
28
|
+
const requireBytes = (label, b, len)=>{
|
|
29
|
+
if (b.length !== len) throw new Error(`${label} must be ${len} bytes, got ${b.length}`);
|
|
30
|
+
};
|
|
31
|
+
const encodeParaInfo = (atRelayBlockNumber, headHash, nextImportedHashPosition)=>{
|
|
32
|
+
requireBytes('headHash', headHash, 32);
|
|
33
|
+
return (0, _util.u8aToHex)((0, _util.u8aConcat)(u32LE(atRelayBlockNumber), headHash, u32LE(nextImportedHashPosition)));
|
|
34
|
+
};
|
|
35
|
+
const encodeParaStoredHeaderData = (blockNumber, stateRoot)=>{
|
|
36
|
+
requireBytes('stateRoot', stateRoot, 32);
|
|
37
|
+
return (0, _util.u8aToHex)((0, _util.compactAddLength)((0, _util.u8aConcat)(u32LE(blockNumber), stateRoot)));
|
|
38
|
+
};
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", {
|
|
3
|
+
value: true
|
|
4
|
+
});
|
|
5
|
+
Object.defineProperty(exports, "bridgeLogger", {
|
|
6
|
+
enumerable: true,
|
|
7
|
+
get: function() {
|
|
8
|
+
return bridgeLogger;
|
|
9
|
+
}
|
|
10
|
+
});
|
|
11
|
+
const _logger = require("../logger.js");
|
|
12
|
+
_export_star(require("./encode.js"), exports);
|
|
13
|
+
function _export_star(from, to) {
|
|
14
|
+
Object.keys(from).forEach(function(k) {
|
|
15
|
+
if (k !== "default" && !Object.prototype.hasOwnProperty.call(to, k)) {
|
|
16
|
+
Object.defineProperty(to, k, {
|
|
17
|
+
enumerable: true,
|
|
18
|
+
get: function() {
|
|
19
|
+
return from[k];
|
|
20
|
+
}
|
|
21
|
+
});
|
|
22
|
+
}
|
|
23
|
+
});
|
|
24
|
+
return from;
|
|
25
|
+
}
|
|
26
|
+
const bridgeLogger = _logger.defaultLogger.child({
|
|
27
|
+
name: 'bridge'
|
|
28
|
+
});
|
package/dist/cjs/index.d.ts
CHANGED
|
@@ -37,6 +37,7 @@ export * from './blockchain/index.js';
|
|
|
37
37
|
export * from './blockchain/inherent/index.js';
|
|
38
38
|
export * from './blockchain/storage-layer.js';
|
|
39
39
|
export * from './blockchain/txpool.js';
|
|
40
|
+
export * from './bridge/index.js';
|
|
40
41
|
export * from './chopsticks-provider.js';
|
|
41
42
|
export * from './database.js';
|
|
42
43
|
export * from './env.js';
|
package/dist/cjs/index.js
CHANGED
|
@@ -18,6 +18,7 @@ _export_star(require("./blockchain/index.js"), exports);
|
|
|
18
18
|
_export_star(require("./blockchain/inherent/index.js"), exports);
|
|
19
19
|
_export_star(require("./blockchain/storage-layer.js"), exports);
|
|
20
20
|
_export_star(require("./blockchain/txpool.js"), exports);
|
|
21
|
+
_export_star(require("./bridge/index.js"), exports);
|
|
21
22
|
_export_star(require("./chopsticks-provider.js"), exports);
|
|
22
23
|
_export_star(require("./database.js"), exports);
|
|
23
24
|
_export_star(require("./env.js"), exports);
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import type { HexString } from '@polkadot/util/types';
|
|
2
|
+
import type { Handler } from '../shared.js';
|
|
3
|
+
/**
|
|
4
|
+
* @param context
|
|
5
|
+
* @param params - [`keys`, `blockhash?`]
|
|
6
|
+
*
|
|
7
|
+
* @return `{ at, proof, stateRoot }`
|
|
8
|
+
*
|
|
9
|
+
* Chopsticks-specific variant of `state_getReadProof` that also returns `stateRoot` — the
|
|
10
|
+
* root the composed proof verifies against, which verifiers must check instead of the header
|
|
11
|
+
* state root (see `buildReadProof`). Kept out of the spec method so it stays `{ at, proof }`.
|
|
12
|
+
*/
|
|
13
|
+
export declare const dev_getReadProof: Handler<[
|
|
14
|
+
HexString[],
|
|
15
|
+
HexString | undefined
|
|
16
|
+
], {
|
|
17
|
+
at: HexString;
|
|
18
|
+
proof: HexString[];
|
|
19
|
+
stateRoot: HexString;
|
|
20
|
+
}>;
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", {
|
|
3
|
+
value: true
|
|
4
|
+
});
|
|
5
|
+
Object.defineProperty(exports, "dev_getReadProof", {
|
|
6
|
+
enumerable: true,
|
|
7
|
+
get: function() {
|
|
8
|
+
return dev_getReadProof;
|
|
9
|
+
}
|
|
10
|
+
});
|
|
11
|
+
const _readproof = require("../read-proof.js");
|
|
12
|
+
const dev_getReadProof = async (context, [keys, hash])=>(0, _readproof.buildReadProof)(context, keys, hash);
|
|
@@ -1,4 +1,9 @@
|
|
|
1
1
|
declare const handlers: {
|
|
2
|
+
dev_getReadProof: import("../shared.js").Handler<[`0x${string}`[], `0x${string}` | undefined], {
|
|
3
|
+
at: import("@polkadot/util/types").HexString;
|
|
4
|
+
proof: import("@polkadot/util/types").HexString[];
|
|
5
|
+
stateRoot: import("@polkadot/util/types").HexString;
|
|
6
|
+
}>;
|
|
2
7
|
dev_newBlock: (context: import("../shared.js").Context, [params]: [import("./new-block.js").NewBlockParams]) => Promise<`0x${string}`>;
|
|
3
8
|
dev_setBlockBuildMode: (context: import("../shared.js").Context, [mode]: [import("../../index.js").BuildBlockMode]) => Promise<void>;
|
|
4
9
|
dev_setHead: (context: import("../shared.js").Context, [params]: [number | `0x${string}`]) => Promise<`0x${string}`>;
|
|
@@ -7,6 +12,7 @@ declare const handlers: {
|
|
|
7
12
|
dev_timeTravel: (context: import("../shared.js").Context, [date]: [string | number]) => Promise<number>;
|
|
8
13
|
};
|
|
9
14
|
export default handlers;
|
|
15
|
+
export * from './get-read-proof.js';
|
|
10
16
|
export * from './new-block.js';
|
|
11
17
|
export * from './set-block-build-mode.js';
|
|
12
18
|
export * from './set-head.js';
|
|
@@ -8,6 +8,7 @@ Object.defineProperty(exports, "default", {
|
|
|
8
8
|
return _default;
|
|
9
9
|
}
|
|
10
10
|
});
|
|
11
|
+
const _getreadproof = _export_star(require("./get-read-proof.js"), exports);
|
|
11
12
|
const _newblock = _export_star(require("./new-block.js"), exports);
|
|
12
13
|
const _setblockbuildmode = _export_star(require("./set-block-build-mode.js"), exports);
|
|
13
14
|
const _sethead = _export_star(require("./set-head.js"), exports);
|
|
@@ -28,6 +29,7 @@ function _export_star(from, to) {
|
|
|
28
29
|
return from;
|
|
29
30
|
}
|
|
30
31
|
const handlers = {
|
|
32
|
+
dev_getReadProof: _getreadproof.dev_getReadProof,
|
|
31
33
|
dev_newBlock: _newblock.dev_newBlock,
|
|
32
34
|
dev_setBlockBuildMode: _setblockbuildmode.dev_setBlockBuildMode,
|
|
33
35
|
dev_setHead: _sethead.dev_setHead,
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import type { HexString } from '@polkadot/util/types';
|
|
2
|
+
import { type Context } from './shared.js';
|
|
3
|
+
/**
|
|
4
|
+
* Compose a storage read proof: chopsticks keeps no trie of its own, so it fetches a base
|
|
5
|
+
* proof from upstream (falling back to upstream head for chopsticks-only blocks) and
|
|
6
|
+
* re-applies chopsticks-side values via `createProof`. Returns the proof nodes and the
|
|
7
|
+
* recomputed trie root — which diverges from `chain_getHeader(at).state_root` once local
|
|
8
|
+
* overrides are applied. Shared by `state_getReadProof` (drops the root, spec shape) and
|
|
9
|
+
* `dev_getReadProof` (keeps it). Child-storage keys are rejected.
|
|
10
|
+
*/
|
|
11
|
+
export declare const buildReadProof: (context: Context, keys: HexString[], hash: HexString | undefined) => Promise<{
|
|
12
|
+
at: HexString;
|
|
13
|
+
proof: HexString[];
|
|
14
|
+
stateRoot: HexString;
|
|
15
|
+
}>;
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", {
|
|
3
|
+
value: true
|
|
4
|
+
});
|
|
5
|
+
Object.defineProperty(exports, "buildReadProof", {
|
|
6
|
+
enumerable: true,
|
|
7
|
+
get: function() {
|
|
8
|
+
return buildReadProof;
|
|
9
|
+
}
|
|
10
|
+
});
|
|
11
|
+
const _logger = require("../logger.js");
|
|
12
|
+
const _index = require("../utils/index.js");
|
|
13
|
+
const _index1 = require("../wasm-executor/index.js");
|
|
14
|
+
const _shared = require("./shared.js");
|
|
15
|
+
const logger = _logger.defaultLogger.child({
|
|
16
|
+
name: 'rpc-read-proof'
|
|
17
|
+
});
|
|
18
|
+
const buildReadProof = async (context, keys, hash)=>{
|
|
19
|
+
if (keys.length === 0) {
|
|
20
|
+
throw new _shared.ResponseError(-32602, 'getReadProof requires a non-empty array of keys');
|
|
21
|
+
}
|
|
22
|
+
for (const key of keys){
|
|
23
|
+
if ((0, _index.isPrefixedChildKey)(key)) {
|
|
24
|
+
throw new _shared.ResponseError(-32601, `getReadProof does not support child-storage keys (got ${key}); use state_getChildReadProof`);
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
const block = await context.chain.getBlock(hash);
|
|
28
|
+
if (!block) {
|
|
29
|
+
throw new _shared.ResponseError(1, `Block ${hash ?? 'head'} not found`);
|
|
30
|
+
}
|
|
31
|
+
// Upstream rejects chopsticks-only blocks with UnknownBlock; fall back to upstream
|
|
32
|
+
// head whose trie is guaranteed available.
|
|
33
|
+
const fetchUpstreamProof = async ()=>{
|
|
34
|
+
try {
|
|
35
|
+
return await context.chain.api.getReadProof(keys, block.hash);
|
|
36
|
+
} catch (err) {
|
|
37
|
+
logger.debug({
|
|
38
|
+
err: err.message,
|
|
39
|
+
blockHash: block.hash
|
|
40
|
+
}, 'getReadProof at block failed; retrying at head');
|
|
41
|
+
try {
|
|
42
|
+
return await context.chain.api.getReadProof(keys);
|
|
43
|
+
} catch (err2) {
|
|
44
|
+
throw new _shared.ResponseError(-32603, `getReadProof: upstream rejected at block ${block.hash} and at head (${err2.message})`);
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
};
|
|
48
|
+
// The local reads and the upstream proof are independent — overlap their round trips.
|
|
49
|
+
const [updates, upstreamProof] = await Promise.all([
|
|
50
|
+
Promise.all(keys.map(async (key)=>[
|
|
51
|
+
key,
|
|
52
|
+
await block.get(key) ?? null
|
|
53
|
+
])),
|
|
54
|
+
fetchUpstreamProof()
|
|
55
|
+
]);
|
|
56
|
+
const { trieRootHash, nodes } = await (0, _index1.createProof)(upstreamProof.proof, updates);
|
|
57
|
+
return {
|
|
58
|
+
at: block.hash,
|
|
59
|
+
proof: nodes,
|
|
60
|
+
stateRoot: trieRootHash
|
|
61
|
+
};
|
|
62
|
+
};
|
|
@@ -35,6 +35,10 @@ declare const handlers: {
|
|
|
35
35
|
changes: [string, string | null][];
|
|
36
36
|
}]>;
|
|
37
37
|
state_call: import("../shared.js").Handler<[import("@polkadot/util/types").HexString, import("@polkadot/util/types").HexString, import("@polkadot/util/types").HexString], import("@polkadot/util/types").HexString>;
|
|
38
|
+
state_getReadProof: import("../shared.js").Handler<[import("@polkadot/util/types").HexString[], import("@polkadot/util/types").HexString | undefined], {
|
|
39
|
+
at: import("@polkadot/util/types").HexString;
|
|
40
|
+
proof: import("@polkadot/util/types").HexString[];
|
|
41
|
+
}>;
|
|
38
42
|
state_subscribeRuntimeVersion: import("../shared.js").Handler<[], string>;
|
|
39
43
|
state_unsubscribeRuntimeVersion: import("../shared.js").Handler<[import("@polkadot/util/types").HexString], void>;
|
|
40
44
|
state_subscribeStorage: import("../shared.js").Handler<[string[]], string>;
|
|
@@ -51,6 +51,24 @@ export declare const state_queryStorageAt: Handler<[
|
|
|
51
51
|
* @return result in hash
|
|
52
52
|
*/
|
|
53
53
|
export declare const state_call: Handler<[HexString, HexString, HexString], HexString>;
|
|
54
|
+
/**
|
|
55
|
+
* @param context
|
|
56
|
+
* @param params - [`keys`, `blockhash?`]
|
|
57
|
+
*
|
|
58
|
+
* @return `{ at, proof }` — proof is a list of SCALE-encoded trie nodes.
|
|
59
|
+
*
|
|
60
|
+
* Spec-compatible response shape. The composed proof's root diverges from
|
|
61
|
+
* `chain_getHeader(at).state_root` once local overrides are applied (see `buildReadProof`);
|
|
62
|
+
* callers that need the recomputed root should use chopsticks's `dev_getReadProof`.
|
|
63
|
+
* Child-storage keys are rejected — use `state_getChildReadProof`.
|
|
64
|
+
*/
|
|
65
|
+
export declare const state_getReadProof: Handler<[
|
|
66
|
+
HexString[],
|
|
67
|
+
HexString | undefined
|
|
68
|
+
], {
|
|
69
|
+
at: HexString;
|
|
70
|
+
proof: HexString[];
|
|
71
|
+
}>;
|
|
54
72
|
/**
|
|
55
73
|
* @return subscription id
|
|
56
74
|
*/
|
|
@@ -24,6 +24,9 @@ _export(exports, {
|
|
|
24
24
|
get state_getMetadata () {
|
|
25
25
|
return state_getMetadata;
|
|
26
26
|
},
|
|
27
|
+
get state_getReadProof () {
|
|
28
|
+
return state_getReadProof;
|
|
29
|
+
},
|
|
27
30
|
get state_getRuntimeVersion () {
|
|
28
31
|
return state_getRuntimeVersion;
|
|
29
32
|
},
|
|
@@ -52,6 +55,7 @@ _export(exports, {
|
|
|
52
55
|
const _util = require("@polkadot/util");
|
|
53
56
|
const _logger = require("../../logger.js");
|
|
54
57
|
const _index = require("../../utils/index.js");
|
|
58
|
+
const _readproof = require("../read-proof.js");
|
|
55
59
|
const _shared = require("../shared.js");
|
|
56
60
|
const logger = _logger.defaultLogger.child({
|
|
57
61
|
name: 'rpc-state'
|
|
@@ -103,6 +107,13 @@ const state_call = async (context, [method, data, hash])=>{
|
|
|
103
107
|
]);
|
|
104
108
|
return resp.result;
|
|
105
109
|
};
|
|
110
|
+
const state_getReadProof = async (context, [keys, hash])=>{
|
|
111
|
+
const { at, proof } = await (0, _readproof.buildReadProof)(context, keys, hash);
|
|
112
|
+
return {
|
|
113
|
+
at,
|
|
114
|
+
proof
|
|
115
|
+
};
|
|
116
|
+
};
|
|
106
117
|
const state_subscribeRuntimeVersion = async (context, _params, { subscribe })=>{
|
|
107
118
|
let update = (_block)=>{};
|
|
108
119
|
const id = await context.chain.headState.subscribeStorage([
|
package/dist/esm/api.d.ts
CHANGED
|
@@ -36,6 +36,11 @@ export declare class Api {
|
|
|
36
36
|
getStorage(key: string, hash?: string): Promise<`0x${string}` | null>;
|
|
37
37
|
getKeysPaged(prefix: string, pageSize: number, startKey: string, hash?: string): Promise<`0x${string}`[]>;
|
|
38
38
|
getStorageBatch(prefix: HexString, keys: HexString[], hash?: HexString): any;
|
|
39
|
+
/** Upstream `state_getReadProof`. Throws if upstream doesn't expose it. */
|
|
40
|
+
getReadProof(keys: HexString[], hash?: HexString): Promise<{
|
|
41
|
+
at: HexString;
|
|
42
|
+
proof: HexString[];
|
|
43
|
+
}>;
|
|
39
44
|
subscribeRemoteNewHeads(cb: ProviderInterfaceCallback): Promise<string | number>;
|
|
40
45
|
subscribeRemoteFinalizedHeads(cb: ProviderInterfaceCallback): Promise<string | number>;
|
|
41
46
|
}
|
package/dist/esm/api.js
CHANGED
|
@@ -191,6 +191,15 @@ const CACHEABLE_METHODS = new Set([
|
|
|
191
191
|
if (hash) params.push(hash);
|
|
192
192
|
return this.#provider.send('state_queryStorageAt', params, !!hash).then((result)=>result[0]?.['changes'] || []).catch(retryOnError);
|
|
193
193
|
}
|
|
194
|
+
/** Upstream `state_getReadProof`. Throws if upstream doesn't expose it. */ async getReadProof(keys, hash) {
|
|
195
|
+
const params = hash ? [
|
|
196
|
+
keys,
|
|
197
|
+
hash
|
|
198
|
+
] : [
|
|
199
|
+
keys
|
|
200
|
+
];
|
|
201
|
+
return this.send('state_getReadProof', params, !!hash);
|
|
202
|
+
}
|
|
194
203
|
async subscribeRemoteNewHeads(cb) {
|
|
195
204
|
if (!this.#provider.hasSubscriptions) {
|
|
196
205
|
throw new Error('subscribeRemoteNewHeads only works with subscriptions');
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
import type { HexString } from '@polkadot/util/types';
|
|
2
|
+
/** `ParaInfo { best_head_hash: { at_relay_block_number: u32, head_hash: H256 }, next_imported_hash_position: u32 }` */
|
|
3
|
+
export declare const encodeParaInfo: (atRelayBlockNumber: number, headHash: Uint8Array, nextImportedHashPosition: number) => HexString;
|
|
4
|
+
/** `ParaStoredHeaderData(Vec<u8>)` wrapping SCALE-encoded `StoredHeaderData { number: u32, state_root: H256 }`. */
|
|
5
|
+
export declare const encodeParaStoredHeaderData: (blockNumber: number, stateRoot: Uint8Array) => HexString;
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
// Value encoders for `pallet_bridge_parachains` storage items. The bridge connector forges
|
|
2
|
+
// these values via `dev_setStorage`, so they're SCALE-encoded by hand — runtime metadata
|
|
3
|
+
// describes their types but can't construct them. Storage *keys*, by contrast, are derived
|
|
4
|
+
// from metadata by the callers (`api.query[pallet].item.key(...)`), never hand-hashed.
|
|
5
|
+
import { compactAddLength, nToU8a, u8aConcat, u8aToHex } from '@polkadot/util';
|
|
6
|
+
const u32LE = (v)=>nToU8a(v, {
|
|
7
|
+
bitLength: 32,
|
|
8
|
+
isLe: true
|
|
9
|
+
});
|
|
10
|
+
const requireBytes = (label, b, len)=>{
|
|
11
|
+
if (b.length !== len) throw new Error(`${label} must be ${len} bytes, got ${b.length}`);
|
|
12
|
+
};
|
|
13
|
+
/** `ParaInfo { best_head_hash: { at_relay_block_number: u32, head_hash: H256 }, next_imported_hash_position: u32 }` */ export const encodeParaInfo = (atRelayBlockNumber, headHash, nextImportedHashPosition)=>{
|
|
14
|
+
requireBytes('headHash', headHash, 32);
|
|
15
|
+
return u8aToHex(u8aConcat(u32LE(atRelayBlockNumber), headHash, u32LE(nextImportedHashPosition)));
|
|
16
|
+
};
|
|
17
|
+
/** `ParaStoredHeaderData(Vec<u8>)` wrapping SCALE-encoded `StoredHeaderData { number: u32, state_root: H256 }`. */ export const encodeParaStoredHeaderData = (blockNumber, stateRoot)=>{
|
|
18
|
+
requireBytes('stateRoot', stateRoot, 32);
|
|
19
|
+
return u8aToHex(compactAddLength(u8aConcat(u32LE(blockNumber), stateRoot)));
|
|
20
|
+
};
|
package/dist/esm/index.d.ts
CHANGED
|
@@ -37,6 +37,7 @@ export * from './blockchain/index.js';
|
|
|
37
37
|
export * from './blockchain/inherent/index.js';
|
|
38
38
|
export * from './blockchain/storage-layer.js';
|
|
39
39
|
export * from './blockchain/txpool.js';
|
|
40
|
+
export * from './bridge/index.js';
|
|
40
41
|
export * from './chopsticks-provider.js';
|
|
41
42
|
export * from './database.js';
|
|
42
43
|
export * from './env.js';
|
package/dist/esm/index.js
CHANGED
|
@@ -14,6 +14,7 @@ export * from './blockchain/index.js';
|
|
|
14
14
|
export * from './blockchain/inherent/index.js';
|
|
15
15
|
export * from './blockchain/storage-layer.js';
|
|
16
16
|
export * from './blockchain/txpool.js';
|
|
17
|
+
export * from './bridge/index.js';
|
|
17
18
|
export * from './chopsticks-provider.js';
|
|
18
19
|
export * from './database.js';
|
|
19
20
|
export * from './env.js';
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import type { HexString } from '@polkadot/util/types';
|
|
2
|
+
import type { Handler } from '../shared.js';
|
|
3
|
+
/**
|
|
4
|
+
* @param context
|
|
5
|
+
* @param params - [`keys`, `blockhash?`]
|
|
6
|
+
*
|
|
7
|
+
* @return `{ at, proof, stateRoot }`
|
|
8
|
+
*
|
|
9
|
+
* Chopsticks-specific variant of `state_getReadProof` that also returns `stateRoot` — the
|
|
10
|
+
* root the composed proof verifies against, which verifiers must check instead of the header
|
|
11
|
+
* state root (see `buildReadProof`). Kept out of the spec method so it stays `{ at, proof }`.
|
|
12
|
+
*/
|
|
13
|
+
export declare const dev_getReadProof: Handler<[
|
|
14
|
+
HexString[],
|
|
15
|
+
HexString | undefined
|
|
16
|
+
], {
|
|
17
|
+
at: HexString;
|
|
18
|
+
proof: HexString[];
|
|
19
|
+
stateRoot: HexString;
|
|
20
|
+
}>;
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { buildReadProof } from '../read-proof.js';
|
|
2
|
+
/**
|
|
3
|
+
* @param context
|
|
4
|
+
* @param params - [`keys`, `blockhash?`]
|
|
5
|
+
*
|
|
6
|
+
* @return `{ at, proof, stateRoot }`
|
|
7
|
+
*
|
|
8
|
+
* Chopsticks-specific variant of `state_getReadProof` that also returns `stateRoot` — the
|
|
9
|
+
* root the composed proof verifies against, which verifiers must check instead of the header
|
|
10
|
+
* state root (see `buildReadProof`). Kept out of the spec method so it stays `{ at, proof }`.
|
|
11
|
+
*/ export const dev_getReadProof = async (context, [keys, hash])=>buildReadProof(context, keys, hash);
|
|
@@ -1,4 +1,9 @@
|
|
|
1
1
|
declare const handlers: {
|
|
2
|
+
dev_getReadProof: import("../shared.js").Handler<[`0x${string}`[], `0x${string}` | undefined], {
|
|
3
|
+
at: import("@polkadot/util/types").HexString;
|
|
4
|
+
proof: import("@polkadot/util/types").HexString[];
|
|
5
|
+
stateRoot: import("@polkadot/util/types").HexString;
|
|
6
|
+
}>;
|
|
2
7
|
dev_newBlock: (context: import("../shared.js").Context, [params]: [import("./new-block.js").NewBlockParams]) => Promise<`0x${string}`>;
|
|
3
8
|
dev_setBlockBuildMode: (context: import("../shared.js").Context, [mode]: [import("../../index.js").BuildBlockMode]) => Promise<void>;
|
|
4
9
|
dev_setHead: (context: import("../shared.js").Context, [params]: [number | `0x${string}`]) => Promise<`0x${string}`>;
|
|
@@ -7,6 +12,7 @@ declare const handlers: {
|
|
|
7
12
|
dev_timeTravel: (context: import("../shared.js").Context, [date]: [string | number]) => Promise<number>;
|
|
8
13
|
};
|
|
9
14
|
export default handlers;
|
|
15
|
+
export * from './get-read-proof.js';
|
|
10
16
|
export * from './new-block.js';
|
|
11
17
|
export * from './set-block-build-mode.js';
|
|
12
18
|
export * from './set-head.js';
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { dev_getReadProof } from './get-read-proof.js';
|
|
1
2
|
import { dev_newBlock } from './new-block.js';
|
|
2
3
|
import { dev_setBlockBuildMode } from './set-block-build-mode.js';
|
|
3
4
|
import { dev_setHead } from './set-head.js';
|
|
@@ -5,6 +6,7 @@ import { dev_setRuntimeLogLevel } from './set-runtime-log-level.js';
|
|
|
5
6
|
import { dev_setStorage } from './set-storage.js';
|
|
6
7
|
import { dev_timeTravel } from './time-travel.js';
|
|
7
8
|
const handlers = {
|
|
9
|
+
dev_getReadProof,
|
|
8
10
|
dev_newBlock,
|
|
9
11
|
dev_setBlockBuildMode,
|
|
10
12
|
dev_setHead,
|
|
@@ -13,6 +15,7 @@ const handlers = {
|
|
|
13
15
|
dev_timeTravel
|
|
14
16
|
};
|
|
15
17
|
export default handlers;
|
|
18
|
+
export * from './get-read-proof.js';
|
|
16
19
|
export * from './new-block.js';
|
|
17
20
|
export * from './set-block-build-mode.js';
|
|
18
21
|
export * from './set-head.js';
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import type { HexString } from '@polkadot/util/types';
|
|
2
|
+
import { type Context } from './shared.js';
|
|
3
|
+
/**
|
|
4
|
+
* Compose a storage read proof: chopsticks keeps no trie of its own, so it fetches a base
|
|
5
|
+
* proof from upstream (falling back to upstream head for chopsticks-only blocks) and
|
|
6
|
+
* re-applies chopsticks-side values via `createProof`. Returns the proof nodes and the
|
|
7
|
+
* recomputed trie root — which diverges from `chain_getHeader(at).state_root` once local
|
|
8
|
+
* overrides are applied. Shared by `state_getReadProof` (drops the root, spec shape) and
|
|
9
|
+
* `dev_getReadProof` (keeps it). Child-storage keys are rejected.
|
|
10
|
+
*/
|
|
11
|
+
export declare const buildReadProof: (context: Context, keys: HexString[], hash: HexString | undefined) => Promise<{
|
|
12
|
+
at: HexString;
|
|
13
|
+
proof: HexString[];
|
|
14
|
+
stateRoot: HexString;
|
|
15
|
+
}>;
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
import { defaultLogger } from '../logger.js';
|
|
2
|
+
import { isPrefixedChildKey } from '../utils/index.js';
|
|
3
|
+
import { createProof } from '../wasm-executor/index.js';
|
|
4
|
+
import { ResponseError } from './shared.js';
|
|
5
|
+
const logger = defaultLogger.child({
|
|
6
|
+
name: 'rpc-read-proof'
|
|
7
|
+
});
|
|
8
|
+
/**
|
|
9
|
+
* Compose a storage read proof: chopsticks keeps no trie of its own, so it fetches a base
|
|
10
|
+
* proof from upstream (falling back to upstream head for chopsticks-only blocks) and
|
|
11
|
+
* re-applies chopsticks-side values via `createProof`. Returns the proof nodes and the
|
|
12
|
+
* recomputed trie root — which diverges from `chain_getHeader(at).state_root` once local
|
|
13
|
+
* overrides are applied. Shared by `state_getReadProof` (drops the root, spec shape) and
|
|
14
|
+
* `dev_getReadProof` (keeps it). Child-storage keys are rejected.
|
|
15
|
+
*/ export const buildReadProof = async (context, keys, hash)=>{
|
|
16
|
+
if (keys.length === 0) {
|
|
17
|
+
throw new ResponseError(-32602, 'getReadProof requires a non-empty array of keys');
|
|
18
|
+
}
|
|
19
|
+
for (const key of keys){
|
|
20
|
+
if (isPrefixedChildKey(key)) {
|
|
21
|
+
throw new ResponseError(-32601, `getReadProof does not support child-storage keys (got ${key}); use state_getChildReadProof`);
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
const block = await context.chain.getBlock(hash);
|
|
25
|
+
if (!block) {
|
|
26
|
+
throw new ResponseError(1, `Block ${hash ?? 'head'} not found`);
|
|
27
|
+
}
|
|
28
|
+
// Upstream rejects chopsticks-only blocks with UnknownBlock; fall back to upstream
|
|
29
|
+
// head whose trie is guaranteed available.
|
|
30
|
+
const fetchUpstreamProof = async ()=>{
|
|
31
|
+
try {
|
|
32
|
+
return await context.chain.api.getReadProof(keys, block.hash);
|
|
33
|
+
} catch (err) {
|
|
34
|
+
logger.debug({
|
|
35
|
+
err: err.message,
|
|
36
|
+
blockHash: block.hash
|
|
37
|
+
}, 'getReadProof at block failed; retrying at head');
|
|
38
|
+
try {
|
|
39
|
+
return await context.chain.api.getReadProof(keys);
|
|
40
|
+
} catch (err2) {
|
|
41
|
+
throw new ResponseError(-32603, `getReadProof: upstream rejected at block ${block.hash} and at head (${err2.message})`);
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
};
|
|
45
|
+
// The local reads and the upstream proof are independent — overlap their round trips.
|
|
46
|
+
const [updates, upstreamProof] = await Promise.all([
|
|
47
|
+
Promise.all(keys.map(async (key)=>[
|
|
48
|
+
key,
|
|
49
|
+
await block.get(key) ?? null
|
|
50
|
+
])),
|
|
51
|
+
fetchUpstreamProof()
|
|
52
|
+
]);
|
|
53
|
+
const { trieRootHash, nodes } = await createProof(upstreamProof.proof, updates);
|
|
54
|
+
return {
|
|
55
|
+
at: block.hash,
|
|
56
|
+
proof: nodes,
|
|
57
|
+
stateRoot: trieRootHash
|
|
58
|
+
};
|
|
59
|
+
};
|
|
@@ -35,6 +35,10 @@ declare const handlers: {
|
|
|
35
35
|
changes: [string, string | null][];
|
|
36
36
|
}]>;
|
|
37
37
|
state_call: import("../shared.js").Handler<[import("@polkadot/util/types").HexString, import("@polkadot/util/types").HexString, import("@polkadot/util/types").HexString], import("@polkadot/util/types").HexString>;
|
|
38
|
+
state_getReadProof: import("../shared.js").Handler<[import("@polkadot/util/types").HexString[], import("@polkadot/util/types").HexString | undefined], {
|
|
39
|
+
at: import("@polkadot/util/types").HexString;
|
|
40
|
+
proof: import("@polkadot/util/types").HexString[];
|
|
41
|
+
}>;
|
|
38
42
|
state_subscribeRuntimeVersion: import("../shared.js").Handler<[], string>;
|
|
39
43
|
state_unsubscribeRuntimeVersion: import("../shared.js").Handler<[import("@polkadot/util/types").HexString], void>;
|
|
40
44
|
state_subscribeStorage: import("../shared.js").Handler<[string[]], string>;
|
|
@@ -51,6 +51,24 @@ export declare const state_queryStorageAt: Handler<[
|
|
|
51
51
|
* @return result in hash
|
|
52
52
|
*/
|
|
53
53
|
export declare const state_call: Handler<[HexString, HexString, HexString], HexString>;
|
|
54
|
+
/**
|
|
55
|
+
* @param context
|
|
56
|
+
* @param params - [`keys`, `blockhash?`]
|
|
57
|
+
*
|
|
58
|
+
* @return `{ at, proof }` — proof is a list of SCALE-encoded trie nodes.
|
|
59
|
+
*
|
|
60
|
+
* Spec-compatible response shape. The composed proof's root diverges from
|
|
61
|
+
* `chain_getHeader(at).state_root` once local overrides are applied (see `buildReadProof`);
|
|
62
|
+
* callers that need the recomputed root should use chopsticks's `dev_getReadProof`.
|
|
63
|
+
* Child-storage keys are rejected — use `state_getChildReadProof`.
|
|
64
|
+
*/
|
|
65
|
+
export declare const state_getReadProof: Handler<[
|
|
66
|
+
HexString[],
|
|
67
|
+
HexString | undefined
|
|
68
|
+
], {
|
|
69
|
+
at: HexString;
|
|
70
|
+
proof: HexString[];
|
|
71
|
+
}>;
|
|
54
72
|
/**
|
|
55
73
|
* @return subscription id
|
|
56
74
|
*/
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { stringToHex } from '@polkadot/util';
|
|
2
2
|
import { defaultLogger } from '../../logger.js';
|
|
3
3
|
import { isPrefixedChildKey, prefixedChildKey, stripChildPrefix } from '../../utils/index.js';
|
|
4
|
+
import { buildReadProof } from '../read-proof.js';
|
|
4
5
|
import { ResponseError } from '../shared.js';
|
|
5
6
|
const logger = defaultLogger.child({
|
|
6
7
|
name: 'rpc-state'
|
|
@@ -82,6 +83,23 @@ const logger = defaultLogger.child({
|
|
|
82
83
|
]);
|
|
83
84
|
return resp.result;
|
|
84
85
|
};
|
|
86
|
+
/**
|
|
87
|
+
* @param context
|
|
88
|
+
* @param params - [`keys`, `blockhash?`]
|
|
89
|
+
*
|
|
90
|
+
* @return `{ at, proof }` — proof is a list of SCALE-encoded trie nodes.
|
|
91
|
+
*
|
|
92
|
+
* Spec-compatible response shape. The composed proof's root diverges from
|
|
93
|
+
* `chain_getHeader(at).state_root` once local overrides are applied (see `buildReadProof`);
|
|
94
|
+
* callers that need the recomputed root should use chopsticks's `dev_getReadProof`.
|
|
95
|
+
* Child-storage keys are rejected — use `state_getChildReadProof`.
|
|
96
|
+
*/ export const state_getReadProof = async (context, [keys, hash])=>{
|
|
97
|
+
const { at, proof } = await buildReadProof(context, keys, hash);
|
|
98
|
+
return {
|
|
99
|
+
at,
|
|
100
|
+
proof
|
|
101
|
+
};
|
|
102
|
+
};
|
|
85
103
|
/**
|
|
86
104
|
* @return subscription id
|
|
87
105
|
*/ export const state_subscribeRuntimeVersion = async (context, _params, { subscribe })=>{
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@acala-network/chopsticks-core",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.5.0",
|
|
4
4
|
"author": "Acala Developers <hello@acala.network>",
|
|
5
5
|
"license": "Apache-2.0",
|
|
6
6
|
"type": "module",
|
|
@@ -14,7 +14,7 @@
|
|
|
14
14
|
"depcheck": "npx depcheck"
|
|
15
15
|
},
|
|
16
16
|
"dependencies": {
|
|
17
|
-
"@acala-network/chopsticks-executor": "1.
|
|
17
|
+
"@acala-network/chopsticks-executor": "1.5.0",
|
|
18
18
|
"@polkadot/rpc-provider": "^16.4.1",
|
|
19
19
|
"@polkadot/types": "^16.4.1",
|
|
20
20
|
"@polkadot/types-codec": "^16.4.1",
|