@acala-network/chopsticks 0.1.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.
Files changed (61) hide show
  1. package/README.md +52 -0
  2. package/chopsticks.js +2 -0
  3. package/dist/api.d.ts +43 -0
  4. package/dist/api.js +78 -0
  5. package/dist/blockchain/block.d.ts +38 -0
  6. package/dist/blockchain/block.js +178 -0
  7. package/dist/blockchain/head-state.d.ts +13 -0
  8. package/dist/blockchain/head-state.js +57 -0
  9. package/dist/blockchain/index.d.ts +35 -0
  10. package/dist/blockchain/index.js +115 -0
  11. package/dist/blockchain/inherents.d.ts +26 -0
  12. package/dist/blockchain/inherents.js +96 -0
  13. package/dist/blockchain/storage-layer.d.ts +32 -0
  14. package/dist/blockchain/storage-layer.js +168 -0
  15. package/dist/blockchain/txpool.d.ts +13 -0
  16. package/dist/blockchain/txpool.js +165 -0
  17. package/dist/db/entities.d.ts +5 -0
  18. package/dist/db/entities.js +34 -0
  19. package/dist/db/index.d.ts +3 -0
  20. package/dist/db/index.js +41 -0
  21. package/dist/executor.d.ts +16 -0
  22. package/dist/executor.js +25 -0
  23. package/dist/executor.test.d.ts +1 -0
  24. package/dist/executor.test.js +58 -0
  25. package/dist/genesis-provider.d.ts +42 -0
  26. package/dist/genesis-provider.js +141 -0
  27. package/dist/index.d.ts +13 -0
  28. package/dist/index.js +208 -0
  29. package/dist/logger.d.ts +7 -0
  30. package/dist/logger.js +25 -0
  31. package/dist/rpc/dev.d.ts +3 -0
  32. package/dist/rpc/dev.js +33 -0
  33. package/dist/rpc/exec.d.ts +3 -0
  34. package/dist/rpc/exec.js +44 -0
  35. package/dist/rpc/index.d.ts +5 -0
  36. package/dist/rpc/index.js +25 -0
  37. package/dist/rpc/shared.d.ts +30 -0
  38. package/dist/rpc/shared.js +20 -0
  39. package/dist/rpc/substrate/author.d.ts +3 -0
  40. package/dist/rpc/substrate/author.js +42 -0
  41. package/dist/rpc/substrate/chain.d.ts +5 -0
  42. package/dist/rpc/substrate/chain.js +62 -0
  43. package/dist/rpc/substrate/index.d.ts +3 -0
  44. package/dist/rpc/substrate/index.js +20 -0
  45. package/dist/rpc/substrate/state.d.ts +3 -0
  46. package/dist/rpc/substrate/state.js +80 -0
  47. package/dist/rpc/substrate/system.d.ts +3 -0
  48. package/dist/rpc/substrate/system.js +27 -0
  49. package/dist/schema/index.d.ts +183 -0
  50. package/dist/schema/index.js +29 -0
  51. package/dist/server.d.ts +9 -0
  52. package/dist/server.js +148 -0
  53. package/dist/task.d.ts +38 -0
  54. package/dist/task.js +66 -0
  55. package/dist/utils/import-storage.d.ts +4 -0
  56. package/dist/utils/import-storage.js +43 -0
  57. package/dist/utils/index.d.ts +7 -0
  58. package/dist/utils/index.js +32 -0
  59. package/dist/utils/set-storage.d.ts +6 -0
  60. package/dist/utils/set-storage.js +57 -0
  61. package/package.json +91 -0
@@ -0,0 +1,42 @@
1
+ import { HexString } from '@polkadot/util/types';
2
+ import { ProviderInterface, ProviderInterfaceCallback, ProviderInterfaceEmitCb, ProviderInterfaceEmitted, ProviderStats } from '@polkadot/rpc-provider/types';
3
+ import { Genesis } from './schema';
4
+ export declare class GenesisProvider implements ProviderInterface {
5
+ #private;
6
+ readonly stats?: ProviderStats;
7
+ constructor(genesis: Genesis);
8
+ static fromUrl: (url: string) => Promise<GenesisProvider>;
9
+ get isClonable(): boolean;
10
+ clone: () => ProviderInterface;
11
+ get hasSubscriptions(): boolean;
12
+ get isConnected(): boolean;
13
+ get isReady(): Promise<GenesisProvider>;
14
+ connect: () => Promise<void>;
15
+ disconnect: () => Promise<void>;
16
+ on: (type: ProviderInterfaceEmitted, sub: ProviderInterfaceEmitCb) => (() => void);
17
+ get blockHash(): HexString;
18
+ getHeader: () => Promise<{
19
+ blockHash: `0x${string}`;
20
+ number: number;
21
+ stateRoot: `0x${string}`;
22
+ digest: {
23
+ logs: never[];
24
+ };
25
+ }>;
26
+ getBlock: () => Promise<{
27
+ block: {
28
+ header: {
29
+ blockHash: `0x${string}`;
30
+ number: number;
31
+ stateRoot: `0x${string}`;
32
+ digest: {
33
+ logs: never[];
34
+ };
35
+ };
36
+ extrinsics: never[];
37
+ };
38
+ }>;
39
+ send: (method: string, params: unknown[], _isCacheable?: boolean) => Promise<any>;
40
+ subscribe: (_type: string, _method: string, _params: unknown[], _cb: ProviderInterfaceCallback) => Promise<number | string>;
41
+ unsubscribe: (_type: string, _method: string, _id: number | string) => Promise<boolean>;
42
+ }
@@ -0,0 +1,141 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.GenesisProvider = void 0;
7
+ const node_events_1 = require("node:events");
8
+ const node_fs_1 = require("node:fs");
9
+ const util_1 = require("@polkadot/util");
10
+ const axios_1 = __importDefault(require("axios"));
11
+ const schema_1 = require("./schema");
12
+ const executor_1 = require("./executor");
13
+ class GenesisProvider {
14
+ #isConnected = false;
15
+ stats;
16
+ #eventemitter;
17
+ #isReadyPromise;
18
+ #genesis;
19
+ #stateRoot;
20
+ constructor(genesis) {
21
+ this.#genesis = genesis;
22
+ this.#stateRoot = (0, executor_1.calculateStateRoot)(Object.entries(this.#genesis.genesis.raw.top).reduce((accu, item) => {
23
+ accu.push(item);
24
+ return accu;
25
+ }, []));
26
+ this.#eventemitter = new node_events_1.EventEmitter();
27
+ this.#isReadyPromise = new Promise((resolve, reject) => {
28
+ this.#eventemitter.once('connected', () => {
29
+ resolve(this);
30
+ });
31
+ this.#eventemitter.once('error', reject);
32
+ });
33
+ this.connect();
34
+ }
35
+ static fromUrl = async (url) => {
36
+ let isUrl = false;
37
+ try {
38
+ new URL(url);
39
+ isUrl = true;
40
+ }
41
+ catch (e) {
42
+ void e;
43
+ }
44
+ let file;
45
+ if (isUrl) {
46
+ file = await axios_1.default.get(url).then((x) => x.data);
47
+ }
48
+ else if ((0, node_fs_1.lstatSync)(url).isFile()) {
49
+ file = JSON.parse(String((0, node_fs_1.readFileSync)(url)));
50
+ }
51
+ else {
52
+ throw Error(`invalid genesis path or url ${url}`);
53
+ }
54
+ return new GenesisProvider(schema_1.genesisSchema.parse(file));
55
+ };
56
+ get isClonable() {
57
+ return true;
58
+ }
59
+ clone = () => {
60
+ return new GenesisProvider(this.#genesis);
61
+ };
62
+ get hasSubscriptions() {
63
+ return false;
64
+ }
65
+ get isConnected() {
66
+ return this.#isConnected;
67
+ }
68
+ get isReady() {
69
+ return this.#isReadyPromise;
70
+ }
71
+ connect = async () => {
72
+ this.#isConnected = true;
73
+ this.#eventemitter.emit('connected');
74
+ };
75
+ disconnect = async () => {
76
+ this.#isConnected = false;
77
+ this.#eventemitter.emit('disconnected');
78
+ };
79
+ on = (type, sub) => {
80
+ this.#eventemitter.on(type, sub);
81
+ return () => {
82
+ this.#eventemitter.removeListener(type, sub);
83
+ };
84
+ };
85
+ get blockHash() {
86
+ return '0x91b171bb158e2d3848fa23a9f1c25182fb8e20313b2c1eb49219da7a70ce90c3';
87
+ }
88
+ getHeader = async () => {
89
+ return {
90
+ blockHash: this.blockHash,
91
+ number: 0,
92
+ stateRoot: await this.#stateRoot,
93
+ digest: {
94
+ logs: [],
95
+ },
96
+ };
97
+ };
98
+ getBlock = async () => {
99
+ return {
100
+ block: {
101
+ header: await this.getHeader(),
102
+ extrinsics: [],
103
+ },
104
+ };
105
+ };
106
+ send = async (method, params, _isCacheable) => {
107
+ await this.isReady;
108
+ switch (method) {
109
+ case 'system_properties':
110
+ return this.#genesis.properties;
111
+ case 'system_chain':
112
+ return this.#genesis.id;
113
+ case 'system_name':
114
+ return this.#genesis.name;
115
+ case 'state_getMetadata': {
116
+ const code = this.#genesis.genesis.raw.top[(0, util_1.stringToHex)(':code')];
117
+ return (0, executor_1.getMetadata)(code);
118
+ }
119
+ case 'chain_getHeader':
120
+ return this.getHeader();
121
+ case 'chain_getBlock':
122
+ return this.getBlock();
123
+ case 'chain_getBlockHash':
124
+ return this.blockHash;
125
+ case 'state_getKeysPagedAt':
126
+ return [];
127
+ case 'state_getStorage':
128
+ case 'state_getStorageAt':
129
+ return this.#genesis.genesis.raw.top[params[0]];
130
+ default:
131
+ throw Error(`${method} not implemented`);
132
+ }
133
+ };
134
+ subscribe = async (_type, _method, _params, _cb) => {
135
+ throw Error('unimplemented');
136
+ };
137
+ unsubscribe = async (_type, _method, _id) => {
138
+ throw Error('unimplemented');
139
+ };
140
+ }
141
+ exports.GenesisProvider = GenesisProvider;
@@ -0,0 +1,13 @@
1
+ import '@polkadot/types-codec';
2
+ import { Api } from './api';
3
+ import { Blockchain } from './blockchain';
4
+ import { Config } from './schema';
5
+ import { ProviderInterface } from '@polkadot/rpc-provider/types';
6
+ import { TaskManager } from './task';
7
+ export declare const setup: (argv: Config) => Promise<{
8
+ chain: Blockchain;
9
+ api: Api;
10
+ ws: ProviderInterface;
11
+ tasks: TaskManager;
12
+ }>;
13
+ export declare const runBlock: (argv: any) => Promise<void>;
package/dist/index.js ADDED
@@ -0,0 +1,208 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.runBlock = exports.setup = void 0;
7
+ require("@polkadot/types-codec");
8
+ const api_1 = require("./api");
9
+ const blockchain_1 = require("./blockchain");
10
+ const txpool_1 = require("./blockchain/txpool");
11
+ const schema_1 = require("./schema");
12
+ const genesis_provider_1 = require("./genesis-provider");
13
+ const inherents_1 = require("./blockchain/inherents");
14
+ const task_1 = require("./task");
15
+ const api_2 = require("@polkadot/api");
16
+ const server_1 = require("./server");
17
+ const logger_1 = require("./logger");
18
+ const rpc_1 = require("./rpc");
19
+ const helpers_1 = require("yargs/helpers");
20
+ const import_storage_1 = require("./utils/import-storage");
21
+ const db_1 = require("./db");
22
+ const node_fs_1 = require("node:fs");
23
+ const js_yaml_1 = __importDefault(require("js-yaml"));
24
+ const yargs_1 = __importDefault(require("yargs"));
25
+ const setup = async (argv) => {
26
+ const port = argv.port || Number(process.env.PORT) || 8000;
27
+ let wsProvider;
28
+ if (argv.genesis) {
29
+ if (typeof argv.genesis === 'string') {
30
+ wsProvider = await genesis_provider_1.GenesisProvider.fromUrl(argv.genesis);
31
+ }
32
+ else {
33
+ wsProvider = new genesis_provider_1.GenesisProvider(argv.genesis);
34
+ }
35
+ }
36
+ else {
37
+ wsProvider = new api_2.WsProvider(argv.endpoint);
38
+ }
39
+ const api = new api_1.Api(wsProvider);
40
+ await api.isReady;
41
+ let blockHash;
42
+ if (argv.block == null) {
43
+ blockHash = await api.getBlockHash();
44
+ }
45
+ else if (Number.isInteger(argv.block)) {
46
+ blockHash = await api.getBlockHash(Number(argv.block));
47
+ }
48
+ else {
49
+ blockHash = argv.block;
50
+ }
51
+ logger_1.defaultLogger.info({ ...argv, blockHash }, 'Args');
52
+ let db;
53
+ if (argv.db) {
54
+ db = await (0, db_1.openDb)(argv.db);
55
+ }
56
+ const header = await api.getHeader(blockHash);
57
+ const tasks = new task_1.TaskManager(port, argv['mock-signature-host'], argv['executor-cmd']);
58
+ const setTimestamp = new inherents_1.SetTimestamp();
59
+ const inherents = new inherents_1.InherentProviders(setTimestamp, [new inherents_1.SetValidationData(tasks, 1)]);
60
+ const chain = new blockchain_1.Blockchain({
61
+ api,
62
+ tasks,
63
+ buildBlockMode: argv['build-block-mode'],
64
+ inherentProvider: inherents,
65
+ db,
66
+ header: {
67
+ hash: blockHash,
68
+ number: Number(header.number),
69
+ },
70
+ });
71
+ const context = { chain, api, ws: wsProvider, tasks };
72
+ const listeningPort = await (0, server_1.createServer)(port, (0, rpc_1.handler)(context)).port;
73
+ tasks.updateListeningPort(listeningPort);
74
+ await (0, import_storage_1.importStorage)(chain, argv['import-storage']);
75
+ await (0, import_storage_1.overrideWasm)(chain, argv['wasm-override']);
76
+ if (argv.genesis) {
77
+ // mine 1st block when starting from genesis to set some mock validation data
78
+ await chain.newBlock();
79
+ }
80
+ return context;
81
+ };
82
+ exports.setup = setup;
83
+ const runBlock = async (argv) => {
84
+ const context = await (0, exports.setup)(argv);
85
+ const header = await context.chain.head.header;
86
+ const parent = header.parentHash.toHex();
87
+ const wasm = await context.chain.head.wasm;
88
+ const block = context.chain.head;
89
+ const calls = [['Core_initialize_block', header.toHex()]];
90
+ for (const extrinsic of await block.extrinsics) {
91
+ calls.push(['BlockBuilder_apply_extrinsic', extrinsic]);
92
+ }
93
+ calls.push(['BlockBuilder_finalize_block', '0x']);
94
+ await context.tasks.addAndRunTask({
95
+ Call: {
96
+ blockHash: parent,
97
+ wasm,
98
+ calls,
99
+ },
100
+ }, (output) => {
101
+ if (argv['output-path']) {
102
+ (0, node_fs_1.writeFileSync)(argv['output-path'], JSON.stringify(output, null, 2));
103
+ }
104
+ else {
105
+ console.dir(output, { depth: null, colors: false });
106
+ }
107
+ });
108
+ setTimeout(() => process.exit(0), 50);
109
+ };
110
+ exports.runBlock = runBlock;
111
+ const processConfig = (argv) => {
112
+ if (argv.config) {
113
+ const configFile = (0, node_fs_1.readFileSync)(argv.config, 'utf8');
114
+ const config = js_yaml_1.default.load(configFile);
115
+ const parsed = schema_1.configSchema.parse(config);
116
+ return { ...parsed, ...argv };
117
+ }
118
+ return argv;
119
+ };
120
+ (0, yargs_1.default)((0, helpers_1.hideBin)(process.argv))
121
+ .command('run-block', 'Replay a block', (yargs) => yargs.options({
122
+ port: {
123
+ desc: 'Port to listen on',
124
+ number: true,
125
+ },
126
+ endpoint: {
127
+ desc: 'Endpoint to connect to',
128
+ string: true,
129
+ },
130
+ block: {
131
+ desc: 'Block hash or block number. Default to latest block',
132
+ string: true,
133
+ },
134
+ 'executor-cmd': {
135
+ desc: 'Command to execute the executor',
136
+ string: true,
137
+ },
138
+ 'output-path': {
139
+ desc: 'File path to print output',
140
+ string: true,
141
+ },
142
+ db: {
143
+ desc: 'Path to database',
144
+ string: true,
145
+ },
146
+ 'wasm-override': {
147
+ desc: 'Path to wasm override',
148
+ string: true,
149
+ },
150
+ config: {
151
+ desc: 'Path to config file',
152
+ string: true,
153
+ },
154
+ }), (argv) => {
155
+ (0, exports.runBlock)(processConfig(argv)).catch((err) => {
156
+ console.error(err);
157
+ process.exit(1);
158
+ });
159
+ })
160
+ .command('dev', 'Dev mode', (yargs) => yargs.options({
161
+ port: {
162
+ desc: 'Port to listen on',
163
+ number: true,
164
+ },
165
+ endpoint: {
166
+ desc: 'Endpoint to connect to',
167
+ string: true,
168
+ },
169
+ block: {
170
+ desc: 'Block hash or block number. Default to latest block',
171
+ string: true,
172
+ },
173
+ 'executor-cmd': {
174
+ desc: 'Command to execute the executor',
175
+ string: true,
176
+ },
177
+ 'build-block-mode': {
178
+ desc: 'Build block mode. Default to Batch',
179
+ enum: [txpool_1.BuildBlockMode.Batch, txpool_1.BuildBlockMode.Manual, txpool_1.BuildBlockMode.Instant],
180
+ },
181
+ 'import-storage': {
182
+ desc: 'Pre-defined JSON/YAML storage file path',
183
+ string: true,
184
+ },
185
+ 'mock-signature-host': {
186
+ desc: 'Mock signature host so any signature starts with 0xdeadbeef and filled by 0xcd is considered valid',
187
+ boolean: true,
188
+ },
189
+ db: {
190
+ desc: 'Path to database',
191
+ string: true,
192
+ },
193
+ 'wasm-override': {
194
+ desc: 'Path to wasm override',
195
+ string: true,
196
+ },
197
+ config: {
198
+ desc: 'Path to config file',
199
+ string: true,
200
+ },
201
+ }), (argv) => {
202
+ (0, exports.setup)(processConfig(argv)).catch((err) => {
203
+ console.error(err);
204
+ process.exit(1);
205
+ });
206
+ })
207
+ .strict()
208
+ .help().argv;
@@ -0,0 +1,7 @@
1
+ export declare const defaultLogger: import("pino").Logger<{
2
+ level: string;
3
+ transport: {
4
+ target: string;
5
+ };
6
+ }>;
7
+ export declare const truncate: (str?: string) => string | undefined;
package/dist/logger.js ADDED
@@ -0,0 +1,25 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.truncate = exports.defaultLogger = void 0;
7
+ const pino_1 = __importDefault(require("pino"));
8
+ exports.defaultLogger = (0, pino_1.default)({
9
+ level: process.env.LOG_LEVEL || 'info',
10
+ transport: {
11
+ target: 'pino-pretty',
12
+ },
13
+ });
14
+ const truncate = (str) => {
15
+ if (str == null) {
16
+ return str;
17
+ }
18
+ if (str.length > 66) {
19
+ return str.slice(0, 34) + '…' + str.slice(-32);
20
+ }
21
+ else {
22
+ return str;
23
+ }
24
+ };
25
+ exports.truncate = truncate;
@@ -0,0 +1,3 @@
1
+ import { Handlers } from './shared';
2
+ declare const handlers: Handlers;
3
+ export default handlers;
@@ -0,0 +1,33 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ const shared_1 = require("./shared");
4
+ const set_storage_1 = require("../utils/set-storage");
5
+ const logger_1 = require("../logger");
6
+ const logger = logger_1.defaultLogger.child({ name: 'rpc-dev' });
7
+ const handlers = {
8
+ dev_newBlock: async (context, [param]) => {
9
+ const { count, to } = param || {};
10
+ const now = context.chain.head.number;
11
+ const diff = to ? to - now : count;
12
+ const finalCount = diff > 0 ? diff : 1;
13
+ let finalHash;
14
+ for (let i = 0; i < finalCount; i++) {
15
+ const block = await context.chain.newBlock();
16
+ logger.debug({ hash: block.hash }, 'dev_newBlock');
17
+ finalHash = block.hash;
18
+ }
19
+ return finalHash;
20
+ },
21
+ dev_setStorages: async (context, params) => {
22
+ const [values, blockHash] = params;
23
+ const hash = await (0, set_storage_1.setStorage)(context.chain, values, blockHash).catch((error) => {
24
+ throw new shared_1.ResponseError(1, error.toString());
25
+ });
26
+ logger.debug({
27
+ hash,
28
+ values,
29
+ }, 'dev_setStorages');
30
+ return hash;
31
+ },
32
+ };
33
+ exports.default = handlers;
@@ -0,0 +1,3 @@
1
+ import { Handlers } from './shared';
2
+ declare const handlers: Handlers;
3
+ export default handlers;
@@ -0,0 +1,44 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ const shared_1 = require("./shared");
4
+ const logger_1 = require("../logger");
5
+ const logger = logger_1.defaultLogger.child({ name: 'rpc-exec' });
6
+ const handlers = {
7
+ exec_storageGet: async (context, [_taskId, blockHash, key]) => {
8
+ const block = await context.chain.getBlock(blockHash);
9
+ if (!block) {
10
+ throw new shared_1.ResponseError(1, `Block not found ${blockHash}`);
11
+ }
12
+ const value = await block.get(key);
13
+ logger.trace({ blockHash, key, value: (0, logger_1.truncate)(value) }, 'exec_storageGet');
14
+ return value;
15
+ },
16
+ exec_prefixKeys: async (context, [_taskId, blockHash, key]) => {
17
+ const block = await context.chain.getBlock(blockHash);
18
+ if (!block) {
19
+ throw new shared_1.ResponseError(1, `Block not found ${blockHash}`);
20
+ }
21
+ return block.getKeysPaged({ prefix: key, pageSize: 1000, startKey: key });
22
+ },
23
+ exec_nextKey: async (context, [_taskId, blockHash, key]) => {
24
+ const block = await context.chain.getBlock(blockHash);
25
+ if (!block) {
26
+ throw new shared_1.ResponseError(1, `Block not found ${blockHash}`);
27
+ }
28
+ const res = await block.getKeysPaged({ prefix: key, pageSize: 1, startKey: key });
29
+ return res[0] || null;
30
+ },
31
+ exec_getTask: async (context, [taskId]) => {
32
+ logger.trace({ taskId }, 'exec_getTask');
33
+ const task = context.tasks.getTask(Number(taskId));
34
+ if (!task) {
35
+ throw new shared_1.ResponseError(1, `Task not found ${taskId}`);
36
+ }
37
+ return task.task;
38
+ },
39
+ exec_taskResult: async (context, [taskId, resp]) => {
40
+ logger.trace({ taskId }, 'exec_taskResult');
41
+ context.tasks.getTask(Number(taskId))?.callback(resp);
42
+ },
43
+ };
44
+ exports.default = handlers;
@@ -0,0 +1,5 @@
1
+ import { Context, SubscriptionManager } from './shared';
2
+ export declare const handler: (context: Context) => ({ method, params }: {
3
+ method: string;
4
+ params: string[];
5
+ }, subscriptionManager: SubscriptionManager) => Promise<string | number | void | object | null | undefined>;
@@ -0,0 +1,25 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.handler = void 0;
7
+ const shared_1 = require("./shared");
8
+ const dev_1 = __importDefault(require("./dev"));
9
+ const exec_1 = __importDefault(require("./exec"));
10
+ const substrate_1 = __importDefault(require("./substrate"));
11
+ const allHandlers = {
12
+ ...exec_1.default,
13
+ ...substrate_1.default,
14
+ ...dev_1.default,
15
+ };
16
+ const handler = (context) => ({ method, params }, subscriptionManager) => {
17
+ shared_1.logger.trace('Handling %s', method);
18
+ const handler = allHandlers[method];
19
+ if (!handler) {
20
+ shared_1.logger.warn('Method not found %s', method);
21
+ throw new shared_1.ResponseError(-32601, `Method not found: ${method}`);
22
+ }
23
+ return handler(context, params, subscriptionManager);
24
+ };
25
+ exports.handler = handler;
@@ -0,0 +1,30 @@
1
+ import { ProviderInterface } from '@polkadot/rpc-provider/types';
2
+ import { Api } from '../api';
3
+ import { Blockchain } from '../blockchain';
4
+ import { TaskManager } from '../task';
5
+ export declare const logger: import("pino").default.Logger<{
6
+ level: string;
7
+ transport: {
8
+ target: string;
9
+ };
10
+ } & import("pino").default.ChildLoggerOptions>;
11
+ export declare class ResponseError extends Error {
12
+ code: number;
13
+ constructor(code: number, message: string);
14
+ toJSON(): {
15
+ code: number;
16
+ message: string;
17
+ };
18
+ }
19
+ export interface Context {
20
+ chain: Blockchain;
21
+ api: Api;
22
+ ws: ProviderInterface;
23
+ tasks: TaskManager;
24
+ }
25
+ export interface SubscriptionManager {
26
+ subscribe: (method: string, subid: string, onCancel?: () => void) => (data: any) => void;
27
+ unsubscribe: (subid: string) => void;
28
+ }
29
+ export type Handler = (context: Context, params: any[], subscriptionManager: SubscriptionManager) => Promise<object | string | number | void | undefined | null>;
30
+ export type Handlers = Record<string, Handler>;
@@ -0,0 +1,20 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.ResponseError = exports.logger = void 0;
4
+ const logger_1 = require("../logger");
5
+ exports.logger = logger_1.defaultLogger.child({ name: 'rpc' });
6
+ class ResponseError extends Error {
7
+ code;
8
+ constructor(code, message) {
9
+ super(message);
10
+ this.code = code;
11
+ this.message = message;
12
+ }
13
+ toJSON() {
14
+ return {
15
+ code: this.code,
16
+ message: this.message,
17
+ };
18
+ }
19
+ }
20
+ exports.ResponseError = ResponseError;
@@ -0,0 +1,3 @@
1
+ import { Handlers } from '../shared';
2
+ declare const handlers: Handlers;
3
+ export default handlers;
@@ -0,0 +1,42 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ const logger_1 = require("../../logger");
4
+ const logger = logger_1.defaultLogger.child({ name: 'rpc-author' });
5
+ const handlers = {
6
+ author_submitExtrinsic: async (context, [extrinsic]) => {
7
+ return context.chain.submitExtrinsic(extrinsic);
8
+ },
9
+ author_submitAndWatchExtrinsic: async (context, [extrinsic], { subscribe, unsubscribe }) => {
10
+ let update = (_block) => { };
11
+ const id = context.chain.headState.subscribeHead((block) => update(block));
12
+ const callback = subscribe('author_extrinsicUpdate', id, () => context.chain.headState.unsubscribeHead(id));
13
+ update = async (block) => {
14
+ logger.debug({ block: block.hash }, 'author_extrinsicUpdate');
15
+ // for now just assume tx is always included on next block
16
+ callback({
17
+ InBlock: block.hash,
18
+ });
19
+ callback({
20
+ Finalized: block.hash,
21
+ });
22
+ unsubscribe(id);
23
+ };
24
+ context.chain
25
+ .submitExtrinsic(extrinsic)
26
+ .then(() => {
27
+ callback({
28
+ Ready: null,
29
+ });
30
+ })
31
+ .catch((error) => {
32
+ logger.error({ error }, 'ExtrinsicFailed');
33
+ callback({ Invalid: null });
34
+ unsubscribe(id);
35
+ });
36
+ return id;
37
+ },
38
+ author_unwatchExtrinsic: async (_context, [subid], { unsubscribe }) => {
39
+ unsubscribe(subid);
40
+ },
41
+ };
42
+ exports.default = handlers;
@@ -0,0 +1,5 @@
1
+ declare const _default: {
2
+ chain_subscribeNewHeads: import("../shared").Handler;
3
+ chain_unsubscribeNewHeads: import("../shared").Handler;
4
+ };
5
+ export default _default;