@dedot/api 0.17.1-next.9d03d21b.3 → 0.18.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.
@@ -186,24 +186,42 @@ class DedotClient// prettier-end-here
186
186
  const cached = this._apiAtCache.get(hash);
187
187
  if (cached)
188
188
  return cached;
189
- let targetVersion;
189
+ let parentVersion;
190
+ let parentHash;
190
191
  // Try to get block info from ChainHead first (for pinned blocks)
191
192
  const targetBlock = this.chainHead.findBlock(hash);
192
193
  if (targetBlock) {
193
- targetVersion = targetBlock.runtime;
194
- if (!targetVersion) {
195
- // fallback to fetching on-chain runtime if we can't find it in the block
196
- targetVersion = this.toSubstrateRuntimeVersion(await this.callAt(hash).core.version());
194
+ if (hash === this.genesisHash) {
195
+ parentHash = hash;
196
+ parentVersion = targetBlock.runtime;
197
+ }
198
+ else {
199
+ parentHash = targetBlock.parent;
200
+ const parentBlock = this.chainHead.findBlock(parentHash);
201
+ parentVersion = parentBlock?.runtime;
202
+ }
203
+ // fallback to fetching on-chain runtime if we can't find it in the block
204
+ if (!parentVersion) {
205
+ parentVersion = this.toSubstrateRuntimeVersion(await this.callAt(parentHash).core.version());
197
206
  }
198
207
  }
199
208
  else {
200
209
  // Block not pinned, try via Archive fallback if supported
201
210
  if (this._archive && (await this._archive.supported())) {
202
211
  try {
212
+ if (hash === this.genesisHash) {
213
+ parentHash = hash;
214
+ }
215
+ else {
216
+ const rawHeader = await this._archive.header(hash);
217
+ (0, utils_1.assert)(rawHeader, `Header for block ${hash} not found`);
218
+ const header = codecs_1.$Header.tryDecode(rawHeader);
219
+ parentHash = header.parentHash;
220
+ }
203
221
  // Fetch runtime version via Archive
204
- const runtimeRaw = await this._archive.call('Core_version', '0x', hash);
222
+ const runtimeRaw = await this._archive.call('Core_version', '0x', parentHash);
205
223
  (0, utils_1.assert)(runtimeRaw, 'Runtime Version Not Found');
206
- targetVersion = this.toSubstrateRuntimeVersion(codecs_1.$RuntimeVersion.tryDecode(runtimeRaw));
224
+ parentVersion = this.toSubstrateRuntimeVersion(codecs_1.$RuntimeVersion.tryDecode(runtimeRaw));
207
225
  }
208
226
  catch (error) {
209
227
  throw new utils_1.DedotError(`Unable to fetch runtime version for block ${hash}: ${error}`);
@@ -215,8 +233,8 @@ class DedotClient// prettier-end-here
215
233
  }
216
234
  let metadata = this.metadata;
217
235
  let registry = this.registry;
218
- if (targetVersion && targetVersion.specVersion !== this.runtimeVersion.specVersion) {
219
- metadata = await this.fetchMetadata(hash, targetVersion);
236
+ if (parentVersion && parentVersion.specVersion !== this.runtimeVersion.specVersion) {
237
+ metadata = await this.fetchMetadata(parentHash, parentVersion);
220
238
  registry = new codecs_1.PortableRegistry(metadata.latest, this.options.hasher);
221
239
  }
222
240
  const api = {
@@ -224,7 +242,7 @@ class DedotClient// prettier-end-here
224
242
  atBlockHash: hash,
225
243
  options: this.options,
226
244
  genesisHash: this.genesisHash,
227
- runtimeVersion: targetVersion,
245
+ runtimeVersion: parentVersion,
228
246
  metadata,
229
247
  registry,
230
248
  rpc: this.rpc,
@@ -2,6 +2,7 @@
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.LegacyClient = void 0;
4
4
  const codecs_1 = require("@dedot/codecs");
5
+ const utils_1 = require("@dedot/utils");
5
6
  const index_js_1 = require("../executor/index.js");
6
7
  const proxychain_js_1 = require("../proxychain.js");
7
8
  const index_js_2 = require("../storage/index.js");
@@ -233,11 +234,12 @@ class LegacyClient// prettier-end-here
233
234
  const cached = this._apiAtCache.get(hash);
234
235
  if (cached)
235
236
  return cached;
236
- const targetVersion = await this.#getRuntimeVersion(hash);
237
+ const parentHash = await this.#findParentHash(hash);
238
+ const targetVersion = await this.#getRuntimeVersion(parentHash);
237
239
  let metadata = this.metadata;
238
240
  let registry = this.registry;
239
241
  if (targetVersion.specVersion !== this.runtimeVersion.specVersion) {
240
- metadata = await this.fetchMetadata(hash, targetVersion);
242
+ metadata = await this.fetchMetadata(parentHash, targetVersion);
241
243
  registry = new codecs_1.PortableRegistry(metadata.latest, this.options.hasher);
242
244
  }
243
245
  const api = {
@@ -265,5 +267,15 @@ class LegacyClient// prettier-end-here
265
267
  getStorageQuery() {
266
268
  return new index_js_2.LegacyStorageQuery(this);
267
269
  }
270
+ async #findParentHash(hash) {
271
+ if (hash === this.genesisHash) {
272
+ return this.genesisHash;
273
+ }
274
+ else {
275
+ const header = await this.rpc.chain_getHeader(hash);
276
+ (0, utils_1.assert)(header, `Header for ${hash} not found`);
277
+ return header.parentHash;
278
+ }
279
+ }
268
280
  }
269
281
  exports.LegacyClient = LegacyClient;
@@ -22,6 +22,15 @@ class SubmittableExtrinsicV2 extends BaseSubmittableExtrinsic_js_1.BaseSubmittab
22
22
  const txHash = this.hash;
23
23
  // validate the transaction
24
24
  // https://github.com/paritytech/json-rpc-interface-spec/issues/55#issuecomment-1609011150
25
+ // ensure at least 2 finalized blocks, this is to make sure the api.at can find the parent hash & block to fetch runtime
26
+ while (true) {
27
+ const block = await this.client.chainHead.finalizedBlock();
28
+ const parentBlock = this.client.chainHead.findBlock(block.parent);
29
+ if (parentBlock) {
30
+ break;
31
+ }
32
+ await (0, utils_1.waitFor)(100);
33
+ }
25
34
  const finalizedHash = await this.client.chainHead.finalizedHash();
26
35
  const validateTx = async (hash) => {
27
36
  const apiAt = await api.at(hash);
@@ -1,4 +1,4 @@
1
- import { $H256, $RuntimeVersion, PortableRegistry } from '@dedot/codecs';
1
+ import { $H256, $Header, $RuntimeVersion, PortableRegistry } from '@dedot/codecs';
2
2
  import { u32 } from '@dedot/shape';
3
3
  import { assert, concatU8a, DedotError, noop, twox64Concat, u8aToHex, xxhashAsU8a } from '@dedot/utils';
4
4
  import { ConstantExecutor, ErrorExecutor, EventExecutor, RuntimeApiExecutorV2, StorageQueryExecutorV2, TxExecutorV2, ViewFunctionExecutorV2, } from '../executor/index.js';
@@ -183,24 +183,42 @@ export class DedotClient// prettier-end-here
183
183
  const cached = this._apiAtCache.get(hash);
184
184
  if (cached)
185
185
  return cached;
186
- let targetVersion;
186
+ let parentVersion;
187
+ let parentHash;
187
188
  // Try to get block info from ChainHead first (for pinned blocks)
188
189
  const targetBlock = this.chainHead.findBlock(hash);
189
190
  if (targetBlock) {
190
- targetVersion = targetBlock.runtime;
191
- if (!targetVersion) {
192
- // fallback to fetching on-chain runtime if we can't find it in the block
193
- targetVersion = this.toSubstrateRuntimeVersion(await this.callAt(hash).core.version());
191
+ if (hash === this.genesisHash) {
192
+ parentHash = hash;
193
+ parentVersion = targetBlock.runtime;
194
+ }
195
+ else {
196
+ parentHash = targetBlock.parent;
197
+ const parentBlock = this.chainHead.findBlock(parentHash);
198
+ parentVersion = parentBlock?.runtime;
199
+ }
200
+ // fallback to fetching on-chain runtime if we can't find it in the block
201
+ if (!parentVersion) {
202
+ parentVersion = this.toSubstrateRuntimeVersion(await this.callAt(parentHash).core.version());
194
203
  }
195
204
  }
196
205
  else {
197
206
  // Block not pinned, try via Archive fallback if supported
198
207
  if (this._archive && (await this._archive.supported())) {
199
208
  try {
209
+ if (hash === this.genesisHash) {
210
+ parentHash = hash;
211
+ }
212
+ else {
213
+ const rawHeader = await this._archive.header(hash);
214
+ assert(rawHeader, `Header for block ${hash} not found`);
215
+ const header = $Header.tryDecode(rawHeader);
216
+ parentHash = header.parentHash;
217
+ }
200
218
  // Fetch runtime version via Archive
201
- const runtimeRaw = await this._archive.call('Core_version', '0x', hash);
219
+ const runtimeRaw = await this._archive.call('Core_version', '0x', parentHash);
202
220
  assert(runtimeRaw, 'Runtime Version Not Found');
203
- targetVersion = this.toSubstrateRuntimeVersion($RuntimeVersion.tryDecode(runtimeRaw));
221
+ parentVersion = this.toSubstrateRuntimeVersion($RuntimeVersion.tryDecode(runtimeRaw));
204
222
  }
205
223
  catch (error) {
206
224
  throw new DedotError(`Unable to fetch runtime version for block ${hash}: ${error}`);
@@ -212,8 +230,8 @@ export class DedotClient// prettier-end-here
212
230
  }
213
231
  let metadata = this.metadata;
214
232
  let registry = this.registry;
215
- if (targetVersion && targetVersion.specVersion !== this.runtimeVersion.specVersion) {
216
- metadata = await this.fetchMetadata(hash, targetVersion);
233
+ if (parentVersion && parentVersion.specVersion !== this.runtimeVersion.specVersion) {
234
+ metadata = await this.fetchMetadata(parentHash, parentVersion);
217
235
  registry = new PortableRegistry(metadata.latest, this.options.hasher);
218
236
  }
219
237
  const api = {
@@ -221,7 +239,7 @@ export class DedotClient// prettier-end-here
221
239
  atBlockHash: hash,
222
240
  options: this.options,
223
241
  genesisHash: this.genesisHash,
224
- runtimeVersion: targetVersion,
242
+ runtimeVersion: parentVersion,
225
243
  metadata,
226
244
  registry,
227
245
  rpc: this.rpc,
@@ -1,4 +1,5 @@
1
1
  import { PortableRegistry } from '@dedot/codecs';
2
+ import { assert } from '@dedot/utils';
2
3
  import { ConstantExecutor, ErrorExecutor, EventExecutor, RuntimeApiExecutor, StorageQueryExecutor, TxExecutor, ViewFunctionExecutor, } from '../executor/index.js';
3
4
  import { newProxyChain } from '../proxychain.js';
4
5
  import { LegacyStorageQuery } from '../storage/index.js';
@@ -230,11 +231,12 @@ export class LegacyClient// prettier-end-here
230
231
  const cached = this._apiAtCache.get(hash);
231
232
  if (cached)
232
233
  return cached;
233
- const targetVersion = await this.#getRuntimeVersion(hash);
234
+ const parentHash = await this.#findParentHash(hash);
235
+ const targetVersion = await this.#getRuntimeVersion(parentHash);
234
236
  let metadata = this.metadata;
235
237
  let registry = this.registry;
236
238
  if (targetVersion.specVersion !== this.runtimeVersion.specVersion) {
237
- metadata = await this.fetchMetadata(hash, targetVersion);
239
+ metadata = await this.fetchMetadata(parentHash, targetVersion);
238
240
  registry = new PortableRegistry(metadata.latest, this.options.hasher);
239
241
  }
240
242
  const api = {
@@ -262,4 +264,14 @@ export class LegacyClient// prettier-end-here
262
264
  getStorageQuery() {
263
265
  return new LegacyStorageQuery(this);
264
266
  }
267
+ async #findParentHash(hash) {
268
+ if (hash === this.genesisHash) {
269
+ return this.genesisHash;
270
+ }
271
+ else {
272
+ const header = await this.rpc.chain_getHeader(hash);
273
+ assert(header, `Header for ${hash} not found`);
274
+ return header.parentHash;
275
+ }
276
+ }
265
277
  }
@@ -1,4 +1,4 @@
1
- import { AsyncQueue, noop } from '@dedot/utils';
1
+ import { AsyncQueue, noop, waitFor } from '@dedot/utils';
2
2
  import { BaseSubmittableExtrinsic } from './BaseSubmittableExtrinsic.js';
3
3
  import { SubmittableResult } from './SubmittableResult.js';
4
4
  import { InvalidTxError } from './errors.js';
@@ -19,6 +19,15 @@ export class SubmittableExtrinsicV2 extends BaseSubmittableExtrinsic {
19
19
  const txHash = this.hash;
20
20
  // validate the transaction
21
21
  // https://github.com/paritytech/json-rpc-interface-spec/issues/55#issuecomment-1609011150
22
+ // ensure at least 2 finalized blocks, this is to make sure the api.at can find the parent hash & block to fetch runtime
23
+ while (true) {
24
+ const block = await this.client.chainHead.finalizedBlock();
25
+ const parentBlock = this.client.chainHead.findBlock(block.parent);
26
+ if (parentBlock) {
27
+ break;
28
+ }
29
+ await waitFor(100);
30
+ }
22
31
  const finalizedHash = await this.client.chainHead.finalizedHash();
23
32
  const validateTx = async (hash) => {
24
33
  const apiAt = await api.at(hash);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@dedot/api",
3
- "version": "0.17.1-next.9d03d21b.3+9d03d21b",
3
+ "version": "0.18.0",
4
4
  "description": "A delightful JavaScript/TypeScript client for Polkadot & Substrate",
5
5
  "author": "Thang X. Vu <thang@dedot.dev>",
6
6
  "homepage": "https://dedot.dev",
@@ -13,13 +13,13 @@
13
13
  "type": "module",
14
14
  "sideEffects": false,
15
15
  "dependencies": {
16
- "@dedot/codecs": "0.17.1-next.9d03d21b.3+9d03d21b",
17
- "@dedot/providers": "0.17.1-next.9d03d21b.3+9d03d21b",
18
- "@dedot/runtime-specs": "0.17.1-next.9d03d21b.3+9d03d21b",
19
- "@dedot/shape": "0.17.1-next.9d03d21b.3+9d03d21b",
20
- "@dedot/storage": "0.17.1-next.9d03d21b.3+9d03d21b",
21
- "@dedot/types": "0.17.1-next.9d03d21b.3+9d03d21b",
22
- "@dedot/utils": "0.17.1-next.9d03d21b.3+9d03d21b"
16
+ "@dedot/codecs": "0.18.0",
17
+ "@dedot/providers": "0.18.0",
18
+ "@dedot/runtime-specs": "0.18.0",
19
+ "@dedot/shape": "0.18.0",
20
+ "@dedot/storage": "0.18.0",
21
+ "@dedot/types": "0.18.0",
22
+ "@dedot/utils": "0.18.0"
23
23
  },
24
24
  "scripts": {
25
25
  "build": "tsc --project tsconfig.build.json && tsc --project tsconfig.build.cjs.json",
@@ -48,7 +48,7 @@
48
48
  "node": ">=18"
49
49
  },
50
50
  "license": "Apache-2.0",
51
- "gitHead": "9d03d21b0b652b14222301b64682940047514172",
51
+ "gitHead": "32395b356a4febaac0d52506742947c916ac9895",
52
52
  "module": "./index.js",
53
53
  "types": "./index.d.ts"
54
54
  }