@acala-network/chopsticks-core 1.0.2 → 1.0.4

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 CHANGED
@@ -29,9 +29,10 @@ export declare class Api {
29
29
  getSystemChain(): Promise<string>;
30
30
  getBlockHash(blockNumber?: number): Promise<`0x${string}` | null>;
31
31
  getHeader(hash?: string): Promise<Header | null>;
32
+ getFinalizedHead(): Promise<string>;
32
33
  getBlock(hash?: string): Promise<SignedBlock | null>;
33
34
  getStorage(key: string, hash?: string): Promise<`0x${string}` | null>;
34
- getKeysPaged(prefix: string, pageSize: number, startKey: string, hash?: string): Promise<string[]>;
35
+ getKeysPaged(prefix: string, pageSize: number, startKey: string, hash?: string): Promise<`0x${string}`[]>;
35
36
  getStorageBatch(prefix: HexString, keys: HexString[], hash?: HexString): Promise<[`0x${string}`, `0x${string}` | null][]>;
36
37
  subscribeRemoteNewHeads(cb: ProviderInterfaceCallback): Promise<string | number>;
37
38
  subscribeRemoteFinalizedHeads(cb: ProviderInterfaceCallback): Promise<string | number>;
package/dist/cjs/api.js CHANGED
@@ -129,6 +129,9 @@ class Api {
129
129
  hash
130
130
  ] : [], !!hash);
131
131
  }
132
+ async getFinalizedHead() {
133
+ return this.send('chain_getFinalizedHead', []);
134
+ }
132
135
  async getBlock(hash) {
133
136
  return this.send('chain_getBlock', hash ? [
134
137
  hash
@@ -1,3 +1,4 @@
1
+ import type { HexString } from '@polkadot/util/types';
1
2
  import type { Api } from '../api.js';
2
3
  import type { Database } from '../database.js';
3
4
  export declare enum StorageValueKind {
@@ -21,7 +22,7 @@ export interface StorageLayerProvider {
21
22
  }
22
23
  export declare class RemoteStorageLayer implements StorageLayerProvider {
23
24
  #private;
24
- constructor(api: Api, at: string, db: Database | undefined);
25
+ constructor(api: Api, at: HexString, db: Database | undefined);
25
26
  get(key: string, _cache: boolean): Promise<StorageValue>;
26
27
  findNextKey(prefix: string, startKey: string, _knownBest?: string): Promise<string | undefined>;
27
28
  getKeysPaged(prefix: string, pageSize: number, startKey: string): Promise<string[]>;
@@ -156,12 +156,23 @@ class RemoteStorageLayer {
156
156
  break;
157
157
  }
158
158
  if (_class_private_field_get(this, _db)) {
159
- // batch fetch storage values and save to db, they may be used later
160
- _class_private_field_get(this, _api).getStorageBatch(prefix, batch, _class_private_field_get(this, _at)).then((storage)=>{
161
- for (const [key, value] of storage){
162
- _class_private_field_get(this, _db)?.saveStorage(_class_private_field_get(this, _at), key, value);
159
+ // filter out keys that are not in the db]
160
+ const newBatch = [];
161
+ for (const key of batch){
162
+ const res = await _class_private_field_get(this, _db).queryStorage(_class_private_field_get(this, _at), key);
163
+ if (res) {
164
+ continue;
163
165
  }
164
- });
166
+ newBatch.push(key);
167
+ }
168
+ if (newBatch.length > 0) {
169
+ // batch fetch storage values and save to db, they may be used later
170
+ _class_private_field_get(this, _api).getStorageBatch(prefix, newBatch, _class_private_field_get(this, _at)).then((storage)=>{
171
+ for (const [key, value] of storage){
172
+ _class_private_field_get(this, _db)?.saveStorage(_class_private_field_get(this, _at), key, value);
173
+ }
174
+ });
175
+ }
165
176
  }
166
177
  }
167
178
  return keysPaged;
@@ -326,6 +326,14 @@ async function buildBlockIfNeeded() {
326
326
  _class_private_field_set(this, _isBuilding, true);
327
327
  try {
328
328
  await _class_private_method_get(this, _buildBlock, buildBlock).call(this);
329
+ } catch (error) {
330
+ logger.error({
331
+ error
332
+ }, 'build block failed');
333
+ for (const { deferred } of _class_private_field_get(this, _pendingBlocks)){
334
+ deferred.reject(error);
335
+ }
336
+ _class_private_field_get(this, _pendingBlocks).length = 0;
329
337
  } finally{
330
338
  _class_private_field_set(this, _isBuilding, false);
331
339
  }
@@ -191,6 +191,7 @@ class GenesisProvider {
191
191
  case 'chain_getBlock':
192
192
  return this.getBlock();
193
193
  case 'chain_getBlockHash':
194
+ case 'chain_getFinalizedHead':
194
195
  return this.blockHash;
195
196
  case 'state_getKeysPaged':
196
197
  case 'state_getKeysPagedAt':
@@ -45,10 +45,13 @@ const innerTruncate = (level = 0)=>(val)=>{
45
45
  }
46
46
  switch(typeof val){
47
47
  case 'string':
48
- if (val.length > 66 && !verboseLog) {
49
- return `${val.slice(0, 34)}…${val.slice(-32)}`;
48
+ {
49
+ const maxLength = verboseLog ? 10 * 1024 : 66;
50
+ if (val.length > maxLength) {
51
+ return `${val.slice(0, 34)}…${val.slice(-32)}`;
52
+ }
53
+ return val;
50
54
  }
51
- return val;
52
55
  case 'object':
53
56
  if (Array.isArray(val)) {
54
57
  return val.map(innerTruncate(level + 1));
@@ -18,6 +18,7 @@ export type SetupOptions = {
18
18
  offchainWorker?: boolean;
19
19
  maxMemoryBlockCount?: number;
20
20
  processQueuedMessages?: boolean;
21
+ rpcTimeout?: number;
21
22
  hooks?: {
22
23
  apiFetching?: () => void;
23
24
  };
@@ -37,6 +38,7 @@ export declare const processOptions: (options: SetupOptions) => Promise<{
37
38
  offchainWorker?: boolean;
38
39
  maxMemoryBlockCount?: number;
39
40
  processQueuedMessages?: boolean;
41
+ rpcTimeout?: number;
40
42
  hooks?: {
41
43
  apiFetching?: () => void;
42
44
  };
package/dist/cjs/setup.js CHANGED
@@ -30,7 +30,7 @@ const processOptions = async (options)=>{
30
30
  } else if (typeof options.endpoint === 'string' && /^(https|http):\/\//.test(options.endpoint || '')) {
31
31
  provider = new _rpcprovider.HttpProvider(options.endpoint);
32
32
  } else {
33
- provider = new _rpcprovider.WsProvider(options.endpoint, 3_000);
33
+ provider = new _rpcprovider.WsProvider(options.endpoint, 3_000, undefined, options.rpcTimeout);
34
34
  }
35
35
  const api = new _api.Api(provider);
36
36
  // setup api hooks
@@ -38,7 +38,7 @@ const processOptions = async (options)=>{
38
38
  await api.isReady;
39
39
  let blockHash;
40
40
  if (options.block == null) {
41
- blockHash = await api.getBlockHash().then((hash)=>{
41
+ blockHash = await api.getFinalizedHead().then((hash)=>{
42
42
  if (!hash) {
43
43
  // should not happen, but just in case
44
44
  throw new Error('Cannot find block hash');
@@ -20,7 +20,7 @@ export type Deferred<T> = {
20
20
  export declare function defer<T>(): Deferred<T>;
21
21
  export declare const CHILD_PREFIX_LENGTH: number;
22
22
  export declare const PREFIX_LENGTH = 66;
23
- export declare const prefixedChildKey: (prefix: HexString, key: HexString) => string;
23
+ export declare const prefixedChildKey: (prefix: HexString, key: HexString) => HexString;
24
24
  export declare const isPrefixedChildKey: (key: HexString) => boolean;
25
25
  export declare const splitChildKey: (key: HexString) => [`0x${string}`, `0x${string}`] | never[];
26
26
  export declare const stripChildPrefix: (key: HexString) => `0x${string}`;
package/dist/esm/api.d.ts CHANGED
@@ -29,9 +29,10 @@ export declare class Api {
29
29
  getSystemChain(): Promise<string>;
30
30
  getBlockHash(blockNumber?: number): Promise<`0x${string}` | null>;
31
31
  getHeader(hash?: string): Promise<Header | null>;
32
+ getFinalizedHead(): Promise<string>;
32
33
  getBlock(hash?: string): Promise<SignedBlock | null>;
33
34
  getStorage(key: string, hash?: string): Promise<`0x${string}` | null>;
34
- getKeysPaged(prefix: string, pageSize: number, startKey: string, hash?: string): Promise<string[]>;
35
+ getKeysPaged(prefix: string, pageSize: number, startKey: string, hash?: string): Promise<`0x${string}`[]>;
35
36
  getStorageBatch(prefix: HexString, keys: HexString[], hash?: HexString): Promise<[`0x${string}`, `0x${string}` | null][]>;
36
37
  subscribeRemoteNewHeads(cb: ProviderInterfaceCallback): Promise<string | number>;
37
38
  subscribeRemoteFinalizedHeads(cb: ProviderInterfaceCallback): Promise<string | number>;
package/dist/esm/api.js CHANGED
@@ -81,6 +81,9 @@ import { prefixedChildKey, splitChildKey, stripChildPrefix } from './utils/index
81
81
  hash
82
82
  ] : [], !!hash);
83
83
  }
84
+ async getFinalizedHead() {
85
+ return this.send('chain_getFinalizedHead', []);
86
+ }
84
87
  async getBlock(hash) {
85
88
  return this.send('chain_getBlock', hash ? [
86
89
  hash
@@ -1,3 +1,4 @@
1
+ import type { HexString } from '@polkadot/util/types';
1
2
  import type { Api } from '../api.js';
2
3
  import type { Database } from '../database.js';
3
4
  export declare enum StorageValueKind {
@@ -21,7 +22,7 @@ export interface StorageLayerProvider {
21
22
  }
22
23
  export declare class RemoteStorageLayer implements StorageLayerProvider {
23
24
  #private;
24
- constructor(api: Api, at: string, db: Database | undefined);
25
+ constructor(api: Api, at: HexString, db: Database | undefined);
25
26
  get(key: string, _cache: boolean): Promise<StorageValue>;
26
27
  findNextKey(prefix: string, startKey: string, _knownBest?: string): Promise<string | undefined>;
27
28
  getKeysPaged(prefix: string, pageSize: number, startKey: string): Promise<string[]>;
@@ -89,12 +89,23 @@ export class RemoteStorageLayer {
89
89
  break;
90
90
  }
91
91
  if (this.#db) {
92
- // batch fetch storage values and save to db, they may be used later
93
- this.#api.getStorageBatch(prefix, batch, this.#at).then((storage)=>{
94
- for (const [key, value] of storage){
95
- this.#db?.saveStorage(this.#at, key, value);
92
+ // filter out keys that are not in the db]
93
+ const newBatch = [];
94
+ for (const key of batch){
95
+ const res = await this.#db.queryStorage(this.#at, key);
96
+ if (res) {
97
+ continue;
96
98
  }
97
- });
99
+ newBatch.push(key);
100
+ }
101
+ if (newBatch.length > 0) {
102
+ // batch fetch storage values and save to db, they may be used later
103
+ this.#api.getStorageBatch(prefix, newBatch, this.#at).then((storage)=>{
104
+ for (const [key, value] of storage){
105
+ this.#db?.saveStorage(this.#at, key, value);
106
+ }
107
+ });
108
+ }
98
109
  }
99
110
  }
100
111
  return keysPaged;
@@ -201,6 +201,14 @@ export class TxPool {
201
201
  this.#isBuilding = true;
202
202
  try {
203
203
  await this.#buildBlock();
204
+ } catch (error) {
205
+ logger.error({
206
+ error
207
+ }, 'build block failed');
208
+ for (const { deferred } of this.#pendingBlocks){
209
+ deferred.reject(error);
210
+ }
211
+ this.#pendingBlocks.length = 0;
204
212
  } finally{
205
213
  this.#isBuilding = false;
206
214
  }
@@ -127,6 +127,7 @@ import { calculateStateRoot, emptyTaskHandler } from './wasm-executor/index.js';
127
127
  case 'chain_getBlock':
128
128
  return this.getBlock();
129
129
  case 'chain_getBlockHash':
130
+ case 'chain_getFinalizedHead':
130
131
  return this.blockHash;
131
132
  case 'state_getKeysPaged':
132
133
  case 'state_getKeysPagedAt':
@@ -24,10 +24,13 @@ const innerTruncate = (level = 0)=>(val)=>{
24
24
  }
25
25
  switch(typeof val){
26
26
  case 'string':
27
- if (val.length > 66 && !verboseLog) {
28
- return `${val.slice(0, 34)}…${val.slice(-32)}`;
27
+ {
28
+ const maxLength = verboseLog ? 10 * 1024 : 66;
29
+ if (val.length > maxLength) {
30
+ return `${val.slice(0, 34)}…${val.slice(-32)}`;
31
+ }
32
+ return val;
29
33
  }
30
- return val;
31
34
  case 'object':
32
35
  if (Array.isArray(val)) {
33
36
  return val.map(innerTruncate(level + 1));
@@ -18,6 +18,7 @@ export type SetupOptions = {
18
18
  offchainWorker?: boolean;
19
19
  maxMemoryBlockCount?: number;
20
20
  processQueuedMessages?: boolean;
21
+ rpcTimeout?: number;
21
22
  hooks?: {
22
23
  apiFetching?: () => void;
23
24
  };
@@ -37,6 +38,7 @@ export declare const processOptions: (options: SetupOptions) => Promise<{
37
38
  offchainWorker?: boolean;
38
39
  maxMemoryBlockCount?: number;
39
40
  processQueuedMessages?: boolean;
41
+ rpcTimeout?: number;
40
42
  hooks?: {
41
43
  apiFetching?: () => void;
42
44
  };
package/dist/esm/setup.js CHANGED
@@ -12,7 +12,7 @@ export const processOptions = async (options)=>{
12
12
  } else if (typeof options.endpoint === 'string' && /^(https|http):\/\//.test(options.endpoint || '')) {
13
13
  provider = new HttpProvider(options.endpoint);
14
14
  } else {
15
- provider = new WsProvider(options.endpoint, 3_000);
15
+ provider = new WsProvider(options.endpoint, 3_000, undefined, options.rpcTimeout);
16
16
  }
17
17
  const api = new Api(provider);
18
18
  // setup api hooks
@@ -20,7 +20,7 @@ export const processOptions = async (options)=>{
20
20
  await api.isReady;
21
21
  let blockHash;
22
22
  if (options.block == null) {
23
- blockHash = await api.getBlockHash().then((hash)=>{
23
+ blockHash = await api.getFinalizedHead().then((hash)=>{
24
24
  if (!hash) {
25
25
  // should not happen, but just in case
26
26
  throw new Error('Cannot find block hash');
@@ -20,7 +20,7 @@ export type Deferred<T> = {
20
20
  export declare function defer<T>(): Deferred<T>;
21
21
  export declare const CHILD_PREFIX_LENGTH: number;
22
22
  export declare const PREFIX_LENGTH = 66;
23
- export declare const prefixedChildKey: (prefix: HexString, key: HexString) => string;
23
+ export declare const prefixedChildKey: (prefix: HexString, key: HexString) => HexString;
24
24
  export declare const isPrefixedChildKey: (key: HexString) => boolean;
25
25
  export declare const splitChildKey: (key: HexString) => [`0x${string}`, `0x${string}`] | never[];
26
26
  export declare const stripChildPrefix: (key: HexString) => `0x${string}`;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@acala-network/chopsticks-core",
3
- "version": "1.0.2",
3
+ "version": "1.0.4",
4
4
  "author": "Acala Developers <hello@acala.network>",
5
5
  "license": "Apache-2.0",
6
6
  "type": "module",
@@ -14,28 +14,28 @@
14
14
  "depcheck": "npx depcheck"
15
15
  },
16
16
  "dependencies": {
17
- "@acala-network/chopsticks-executor": "1.0.2",
18
- "@polkadot/rpc-provider": "^15.0",
19
- "@polkadot/types": "^15.0",
20
- "@polkadot/types-codec": "^15.0",
21
- "@polkadot/types-known": "^15.0",
22
- "@polkadot/util": "^13.2",
23
- "@polkadot/util-crypto": "^13.2",
17
+ "@acala-network/chopsticks-executor": "1.0.4",
18
+ "@polkadot/rpc-provider": "^15.7.1",
19
+ "@polkadot/types": "^15.7.1",
20
+ "@polkadot/types-codec": "^15.7.1",
21
+ "@polkadot/types-known": "^15.7.1",
22
+ "@polkadot/util": "^13.4.3",
23
+ "@polkadot/util-crypto": "^13.4.3",
24
24
  "comlink": "^4.4.2",
25
25
  "eventemitter3": "^5.0.1",
26
26
  "lodash": "^4.17.21",
27
27
  "lru-cache": "^11.0.2",
28
- "pino": "^9.5.0",
28
+ "pino": "^9.6.0",
29
29
  "pino-pretty": "^13.0.0",
30
- "rxjs": "^7.8.1",
31
- "zod": "^3.24.1"
30
+ "rxjs": "^7.8.2",
31
+ "zod": "^3.24.2"
32
32
  },
33
33
  "devDependencies": {
34
- "@swc/cli": "0.5.2",
35
- "@swc/core": "^1.10.1",
36
- "@types/lodash": "^4.17.13",
37
- "typescript": "^5.7.2",
38
- "vitest": "^2.1.8"
34
+ "@swc/cli": "0.6.0",
35
+ "@swc/core": "^1.11.1",
36
+ "@types/lodash": "^4.17.15",
37
+ "typescript": "^5.7.3",
38
+ "vitest": "^3.0.7"
39
39
  },
40
40
  "files": [
41
41
  "dist/esm/**",