@acala-network/chopsticks 0.9.13 → 0.10.0-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/cli.js +4 -4
- package/dist/cjs/plugins/index.js +2 -1
- package/dist/cjs/plugins/trace-transaction/README.md +12 -0
- package/dist/cjs/plugins/trace-transaction/__tests__/__snapshots__/trace-call.test.ts.snap +365 -0
- package/dist/cjs/plugins/trace-transaction/index.d.ts +2 -0
- package/dist/cjs/plugins/trace-transaction/index.js +66 -0
- package/dist/cjs/plugins/trace-transaction/table.d.ts +148 -0
- package/dist/cjs/plugins/trace-transaction/table.js +168 -0
- package/dist/cjs/plugins/trace-transaction/types.d.ts +30 -0
- package/dist/cjs/plugins/trace-transaction/types.js +64 -0
- package/dist/cjs/plugins/trace-transaction/utils.d.ts +40 -0
- package/dist/cjs/plugins/trace-transaction/utils.js +207 -0
- package/dist/cjs/utils/tunnel.js +2 -1
- package/dist/esm/cli.js +5 -5
- package/dist/esm/plugins/index.js +2 -1
- package/dist/esm/plugins/trace-transaction/README.md +12 -0
- package/dist/esm/plugins/trace-transaction/__tests__/__snapshots__/trace-call.test.ts.snap +365 -0
- package/dist/esm/plugins/trace-transaction/index.d.ts +2 -0
- package/dist/esm/plugins/trace-transaction/index.js +56 -0
- package/dist/esm/plugins/trace-transaction/table.d.ts +148 -0
- package/dist/esm/plugins/trace-transaction/table.js +150 -0
- package/dist/esm/plugins/trace-transaction/types.d.ts +30 -0
- package/dist/esm/plugins/trace-transaction/types.js +54 -0
- package/dist/esm/plugins/trace-transaction/utils.d.ts +40 -0
- package/dist/esm/plugins/trace-transaction/utils.js +199 -0
- package/dist/esm/utils/tunnel.js +2 -1
- package/package.json +3 -3
|
@@ -0,0 +1,150 @@
|
|
|
1
|
+
export const TABLE = {
|
|
2
|
+
'0x00': 'STOP',
|
|
3
|
+
'0x01': 'ADD',
|
|
4
|
+
'0x02': 'MUL',
|
|
5
|
+
'0x03': 'SUB',
|
|
6
|
+
'0x04': 'DIV',
|
|
7
|
+
'0x05': 'SDIV',
|
|
8
|
+
'0x06': 'MOD',
|
|
9
|
+
'0x07': 'SMOD',
|
|
10
|
+
'0x08': 'ADDMOD',
|
|
11
|
+
'0x09': 'MULMOD',
|
|
12
|
+
'0x0a': 'EXP',
|
|
13
|
+
'0x0b': 'SIGNEXTEND',
|
|
14
|
+
'0x10': 'LT',
|
|
15
|
+
'0x11': 'GT',
|
|
16
|
+
'0x12': 'SLT',
|
|
17
|
+
'0x13': 'SGT',
|
|
18
|
+
'0x14': 'EQ',
|
|
19
|
+
'0x15': 'ISZERO',
|
|
20
|
+
'0x16': 'AND',
|
|
21
|
+
'0x17': 'OR',
|
|
22
|
+
'0x18': 'XOR',
|
|
23
|
+
'0x19': 'NOT',
|
|
24
|
+
'0x1a': 'BYTE',
|
|
25
|
+
'0x35': 'CALLDATALOAD',
|
|
26
|
+
'0x36': 'CALLDATASIZE',
|
|
27
|
+
'0x37': 'CALLDATACOPY',
|
|
28
|
+
'0x38': 'CODESIZE',
|
|
29
|
+
'0x39': 'CODECOPY',
|
|
30
|
+
'0x1b': 'SHL',
|
|
31
|
+
'0x1c': 'SHR',
|
|
32
|
+
'0x1d': 'SAR',
|
|
33
|
+
'0x50': 'POP',
|
|
34
|
+
'0x51': 'MLOAD',
|
|
35
|
+
'0x52': 'MSTORE',
|
|
36
|
+
'0x53': 'MSTORE8',
|
|
37
|
+
'0x56': 'JUMP',
|
|
38
|
+
'0x57': 'JUMPI',
|
|
39
|
+
'0x58': 'PC',
|
|
40
|
+
'0x59': 'MSIZE',
|
|
41
|
+
'0x5b': 'JUMPDEST',
|
|
42
|
+
'0x5f': 'PUSH0',
|
|
43
|
+
'0x60': 'PUSH1',
|
|
44
|
+
'0x61': 'PUSH2',
|
|
45
|
+
'0x62': 'PUSH3',
|
|
46
|
+
'0x63': 'PUSH4',
|
|
47
|
+
'0x64': 'PUSH5',
|
|
48
|
+
'0x65': 'PUSH6',
|
|
49
|
+
'0x66': 'PUSH7',
|
|
50
|
+
'0x67': 'PUSH8',
|
|
51
|
+
'0x68': 'PUSH9',
|
|
52
|
+
'0x69': 'PUSH10',
|
|
53
|
+
'0x6a': 'PUSH11',
|
|
54
|
+
'0x6b': 'PUSH12',
|
|
55
|
+
'0x6c': 'PUSH13',
|
|
56
|
+
'0x6d': 'PUSH14',
|
|
57
|
+
'0x6e': 'PUSH15',
|
|
58
|
+
'0x6f': 'PUSH16',
|
|
59
|
+
'0x70': 'PUSH17',
|
|
60
|
+
'0x71': 'PUSH18',
|
|
61
|
+
'0x72': 'PUSH19',
|
|
62
|
+
'0x73': 'PUSH20',
|
|
63
|
+
'0x74': 'PUSH21',
|
|
64
|
+
'0x75': 'PUSH22',
|
|
65
|
+
'0x76': 'PUSH23',
|
|
66
|
+
'0x77': 'PUSH24',
|
|
67
|
+
'0x78': 'PUSH25',
|
|
68
|
+
'0x79': 'PUSH26',
|
|
69
|
+
'0x7a': 'PUSH27',
|
|
70
|
+
'0x7b': 'PUSH28',
|
|
71
|
+
'0x7c': 'PUSH29',
|
|
72
|
+
'0x7d': 'PUSH30',
|
|
73
|
+
'0x7e': 'PUSH31',
|
|
74
|
+
'0x7f': 'PUSH32',
|
|
75
|
+
'0x80': 'DUP1',
|
|
76
|
+
'0x81': 'DUP2',
|
|
77
|
+
'0x82': 'DUP3',
|
|
78
|
+
'0x83': 'DUP4',
|
|
79
|
+
'0x84': 'DUP5',
|
|
80
|
+
'0x85': 'DUP6',
|
|
81
|
+
'0x86': 'DUP7',
|
|
82
|
+
'0x87': 'DUP8',
|
|
83
|
+
'0x88': 'DUP9',
|
|
84
|
+
'0x89': 'DUP10',
|
|
85
|
+
'0x8a': 'DUP11',
|
|
86
|
+
'0x8b': 'DUP12',
|
|
87
|
+
'0x8c': 'DUP13',
|
|
88
|
+
'0x8d': 'DUP14',
|
|
89
|
+
'0x8e': 'DUP15',
|
|
90
|
+
'0x8f': 'DUP16',
|
|
91
|
+
'0x90': 'SWAP1',
|
|
92
|
+
'0x91': 'SWAP2',
|
|
93
|
+
'0x92': 'SWAP3',
|
|
94
|
+
'0x93': 'SWAP4',
|
|
95
|
+
'0x94': 'SWAP5',
|
|
96
|
+
'0x95': 'SWAP6',
|
|
97
|
+
'0x96': 'SWAP7',
|
|
98
|
+
'0x97': 'SWAP8',
|
|
99
|
+
'0x98': 'SWAP9',
|
|
100
|
+
'0x99': 'SWAP10',
|
|
101
|
+
'0x9a': 'SWAP11',
|
|
102
|
+
'0x9b': 'SWAP12',
|
|
103
|
+
'0x9c': 'SWAP13',
|
|
104
|
+
'0x9d': 'SWAP14',
|
|
105
|
+
'0x9e': 'SWAP15',
|
|
106
|
+
'0x9f': 'SWAP16',
|
|
107
|
+
'0xf3': 'RETURN',
|
|
108
|
+
'0xfd': 'REVERT',
|
|
109
|
+
'0xfe': 'INVALID',
|
|
110
|
+
'0xef': 'EOFMAGIC',
|
|
111
|
+
'0x20': 'SHA3',
|
|
112
|
+
'0x30': 'ADDRESS',
|
|
113
|
+
'0x31': 'BALANCE',
|
|
114
|
+
'0x47': 'SELFBALANCE',
|
|
115
|
+
'0x48': 'BASEFEE',
|
|
116
|
+
'0x32': 'ORIGIN',
|
|
117
|
+
'0x33': 'CALLER',
|
|
118
|
+
'0x34': 'CALLVALUE',
|
|
119
|
+
'0x3a': 'GASPRICE',
|
|
120
|
+
'0x3b': 'EXTCODESIZE',
|
|
121
|
+
'0x3c': 'EXTCODECOPY',
|
|
122
|
+
'0x3f': 'EXTCODEHASH',
|
|
123
|
+
'0x3d': 'RETURNDATASIZE',
|
|
124
|
+
'0x3e': 'RETURNDATACOPY',
|
|
125
|
+
'0x40': 'BLOCKHASH',
|
|
126
|
+
'0x41': 'COINBASE',
|
|
127
|
+
'0x42': 'TIMESTAMP',
|
|
128
|
+
'0x43': 'NUMBER',
|
|
129
|
+
'0x44': 'DIFFICULTY',
|
|
130
|
+
'0x45': 'GASLIMIT',
|
|
131
|
+
'0x54': 'SLOAD',
|
|
132
|
+
'0x55': 'SSTORE',
|
|
133
|
+
'0x5a': 'GAS',
|
|
134
|
+
'0xa0': 'LOG0',
|
|
135
|
+
'0xa1': 'LOG1',
|
|
136
|
+
'0xa2': 'LOG2',
|
|
137
|
+
'0xa3': 'LOG3',
|
|
138
|
+
'0xa4': 'LOG4',
|
|
139
|
+
'0xf0': 'CREATE',
|
|
140
|
+
'0xf5': 'CREATE2',
|
|
141
|
+
'0xf1': 'CALL',
|
|
142
|
+
'0xf2': 'CALLCODE',
|
|
143
|
+
'0xf4': 'DELEGATECALL',
|
|
144
|
+
'0xfa': 'STATICCALL',
|
|
145
|
+
'0xff': 'SUICIDE',
|
|
146
|
+
'0x46': 'CHAINID'
|
|
147
|
+
};
|
|
148
|
+
export const opName = (op)=>{
|
|
149
|
+
return TABLE[`0x${op.toString(16).padStart(2, '0')}`] || `0x${op.toString(16).padStart(2, '0')}`;
|
|
150
|
+
};
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import { HexString } from '@polkadot/util/types';
|
|
2
|
+
import { Registry } from '@polkadot/types/types';
|
|
3
|
+
export type CallTrace = {
|
|
4
|
+
type: 'CALL' | 'CALLCODE' | 'STATICCALL' | 'DELEGATECALL' | 'CREATE' | 'SUICIDE';
|
|
5
|
+
from: HexString;
|
|
6
|
+
to: HexString;
|
|
7
|
+
input: HexString;
|
|
8
|
+
value: HexString;
|
|
9
|
+
gas: number;
|
|
10
|
+
gasUsed: number;
|
|
11
|
+
output: HexString | null;
|
|
12
|
+
error: string | null;
|
|
13
|
+
revertReason: string | null;
|
|
14
|
+
depth: number;
|
|
15
|
+
calls: CallTrace[];
|
|
16
|
+
};
|
|
17
|
+
export type Step = {
|
|
18
|
+
op: number;
|
|
19
|
+
pc: number;
|
|
20
|
+
depth: number;
|
|
21
|
+
gas: number;
|
|
22
|
+
stack: HexString[];
|
|
23
|
+
memory: string[] | null;
|
|
24
|
+
};
|
|
25
|
+
export type TraceOutcome = {
|
|
26
|
+
steps: Step[];
|
|
27
|
+
} | {
|
|
28
|
+
calls: CallTrace[];
|
|
29
|
+
};
|
|
30
|
+
export declare const registerTypes: (registry: Registry) => void;
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
export const registerTypes = (registry)=>{
|
|
2
|
+
registry.register({
|
|
3
|
+
Step: {
|
|
4
|
+
op: 'u8',
|
|
5
|
+
pc: 'Compact<u32>',
|
|
6
|
+
depth: 'Compact<u32>',
|
|
7
|
+
gas: 'Compact<u64>',
|
|
8
|
+
stack: 'Vec<Bytes>',
|
|
9
|
+
memory: 'Option<Vec<Bytes>>'
|
|
10
|
+
},
|
|
11
|
+
CallType: {
|
|
12
|
+
_enum: {
|
|
13
|
+
CALL: null,
|
|
14
|
+
CALLCODE: null,
|
|
15
|
+
STATICCALL: null,
|
|
16
|
+
DELEGATECALL: null,
|
|
17
|
+
CREATE: null,
|
|
18
|
+
SUICIDE: null
|
|
19
|
+
}
|
|
20
|
+
},
|
|
21
|
+
CallTrace: {
|
|
22
|
+
type: 'CallType',
|
|
23
|
+
from: 'H160',
|
|
24
|
+
to: 'H160',
|
|
25
|
+
input: 'Bytes',
|
|
26
|
+
value: 'U256',
|
|
27
|
+
gas: 'Compact<u64>',
|
|
28
|
+
gasUsed: 'Compact<u64>',
|
|
29
|
+
output: 'Option<Bytes>',
|
|
30
|
+
error: 'Option<String>',
|
|
31
|
+
revertReason: 'Option<String>',
|
|
32
|
+
depth: 'Compact<u32>',
|
|
33
|
+
calls: 'Vec<CallTrace>'
|
|
34
|
+
},
|
|
35
|
+
TraceOutcome: {
|
|
36
|
+
_enum: {
|
|
37
|
+
Calls: 'Vec<CallTrace>',
|
|
38
|
+
Steps: 'Vec<Step>'
|
|
39
|
+
}
|
|
40
|
+
},
|
|
41
|
+
OpcodeConfig: {
|
|
42
|
+
page: 'u32',
|
|
43
|
+
pageSize: 'u32',
|
|
44
|
+
disableStack: 'bool',
|
|
45
|
+
enableMemory: 'bool'
|
|
46
|
+
},
|
|
47
|
+
TracerConfig: {
|
|
48
|
+
_enum: {
|
|
49
|
+
CallTracer: null,
|
|
50
|
+
OpcodeTracer: 'OpcodeConfig'
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
});
|
|
54
|
+
};
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
/// <reference types="node" resolution-mode="require"/>
|
|
2
|
+
import { Block, Blockchain, RuntimeVersion } from '@acala-network/chopsticks-core';
|
|
3
|
+
import { HexString } from '@polkadot/util/types';
|
|
4
|
+
import { Step } from './types.js';
|
|
5
|
+
/**
|
|
6
|
+
* Fetches the runtime with tracing feature from Github releases.
|
|
7
|
+
* @param runtimeVersion - The version of the runtime.
|
|
8
|
+
* @returns A Promise that resolves to the fetched runtime as a Buffer.
|
|
9
|
+
*/
|
|
10
|
+
export declare const fetchRuntime: (runtimeVersion: RuntimeVersion) => Promise<Buffer | undefined>;
|
|
11
|
+
export declare const fetchEVMTransaction: (runtimeVersion: RuntimeVersion, txHash: string) => Promise<any>;
|
|
12
|
+
/**
|
|
13
|
+
* Traces the execution of a transaction in the VM.
|
|
14
|
+
* @param block - The block to trace the extrinsic in.
|
|
15
|
+
* @param extrinsic - The extrinsic to trace.
|
|
16
|
+
* @returns An array of VM steps.
|
|
17
|
+
* @throws Error if the trace outcome is invalid.
|
|
18
|
+
*/
|
|
19
|
+
export declare const traceVM: (block: Block, extrinsic: HexString, pageSize?: number, disableStack?: boolean, enableMemory?: boolean) => Promise<Step[]>;
|
|
20
|
+
/**
|
|
21
|
+
* Traces the calls made by an extrinsic in a block.
|
|
22
|
+
* @param block - The block to trace the extrinsic in.
|
|
23
|
+
* @param extrinsic - The extrinsic to trace.
|
|
24
|
+
* @returns An array of calls made by the extrinsic.
|
|
25
|
+
* @throws Error if the trace outcome is invalid.
|
|
26
|
+
*/
|
|
27
|
+
export declare const traceCalls: (block: Block, extrinsic: HexString) => Promise<import("./types.js").CallTrace[]>;
|
|
28
|
+
/**
|
|
29
|
+
* Prepares a block for tracing a transaction.
|
|
30
|
+
* @param chain The blockchain instance.
|
|
31
|
+
* @param blockHashNumber The block hash or block number.
|
|
32
|
+
* @param txHash The transaction hash.
|
|
33
|
+
* @param wasmPath The path to the runtime wasm file.
|
|
34
|
+
* @returns An object containing the tracing block and the transaction extrinsic.
|
|
35
|
+
* @throws Error if the block or parent block is not found, or if the runtime wasm with tracing feature cannot be found.
|
|
36
|
+
*/
|
|
37
|
+
export declare const prepareBlock: (chain: Blockchain, blockHashNumber: HexString | number, txHash: string, wasmPath?: string) => Promise<{
|
|
38
|
+
tracingBlock: Block;
|
|
39
|
+
extrinsic: `0x${string}`;
|
|
40
|
+
}>;
|
|
@@ -0,0 +1,199 @@
|
|
|
1
|
+
import { Block, pinoLogger } from '@acala-network/chopsticks-core';
|
|
2
|
+
import { blake2AsHex } from '@polkadot/util-crypto';
|
|
3
|
+
import _ from 'lodash';
|
|
4
|
+
import { registerTypes } from './types.js';
|
|
5
|
+
import { opName } from './table.js';
|
|
6
|
+
import { overrideWasm } from '../../utils/override.js';
|
|
7
|
+
/**
|
|
8
|
+
* Fetches the runtime with tracing feature from Github releases.
|
|
9
|
+
* @param runtimeVersion - The version of the runtime.
|
|
10
|
+
* @returns A Promise that resolves to the fetched runtime as a Buffer.
|
|
11
|
+
*/ export const fetchRuntime = async (runtimeVersion)=>{
|
|
12
|
+
const GIHTUB_RELEASES_API = 'https://api.github.com/repos/AcalaNetwork/Acala/releases';
|
|
13
|
+
const assetName = `${runtimeVersion.specName}_runtime_tracing_${runtimeVersion.specVersion}.compact.compressed.wasm`;
|
|
14
|
+
pinoLogger.info({
|
|
15
|
+
assetName
|
|
16
|
+
}, 'Search for runtime with tracing feature from Github releases ...');
|
|
17
|
+
const releases = await fetch(GIHTUB_RELEASES_API).then((res)=>res.json());
|
|
18
|
+
for (const release of releases){
|
|
19
|
+
if (release.assets) {
|
|
20
|
+
for (const asset of release.assets){
|
|
21
|
+
if (asset.name === assetName) {
|
|
22
|
+
pinoLogger.info({
|
|
23
|
+
url: asset.browser_download_url
|
|
24
|
+
}, 'Downloading ...');
|
|
25
|
+
const runtime = await fetch(asset.browser_download_url).then((x)=>x.arrayBuffer());
|
|
26
|
+
return Buffer.from(runtime);
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
};
|
|
32
|
+
export const fetchEVMTransaction = async (runtimeVersion, txHash)=>{
|
|
33
|
+
const ACALA_ETH_RPC = 'https://eth-rpc-acala.aca-api.network';
|
|
34
|
+
const KARURA_ETH_RPC = 'https://eth-rpc-karura.aca-api.network';
|
|
35
|
+
let ethRpc;
|
|
36
|
+
if (runtimeVersion.specName.includes('acala')) {
|
|
37
|
+
ethRpc = ACALA_ETH_RPC;
|
|
38
|
+
} else if (runtimeVersion.specName.includes('karura')) {
|
|
39
|
+
ethRpc = KARURA_ETH_RPC;
|
|
40
|
+
} else {
|
|
41
|
+
throw new Error(`Unsupported chain. Only Acala and Karura are supported`);
|
|
42
|
+
}
|
|
43
|
+
pinoLogger.info(`Fetching EVM transaction ...`);
|
|
44
|
+
const response = await fetch(ethRpc, {
|
|
45
|
+
headers: [
|
|
46
|
+
[
|
|
47
|
+
'Content-Type',
|
|
48
|
+
'application/json'
|
|
49
|
+
],
|
|
50
|
+
[
|
|
51
|
+
'Accept',
|
|
52
|
+
'application/json'
|
|
53
|
+
]
|
|
54
|
+
],
|
|
55
|
+
method: 'POST',
|
|
56
|
+
body: JSON.stringify({
|
|
57
|
+
jsonrpc: '2.0',
|
|
58
|
+
id: 1,
|
|
59
|
+
method: 'eth_getTransactionByHash',
|
|
60
|
+
params: [
|
|
61
|
+
txHash
|
|
62
|
+
]
|
|
63
|
+
})
|
|
64
|
+
});
|
|
65
|
+
const data = await response.json();
|
|
66
|
+
if (data.error) {
|
|
67
|
+
throw new Error(data.error.message);
|
|
68
|
+
}
|
|
69
|
+
return data.result;
|
|
70
|
+
};
|
|
71
|
+
/**
|
|
72
|
+
* Traces the execution of a transaction in the VM.
|
|
73
|
+
* @param block - The block to trace the extrinsic in.
|
|
74
|
+
* @param extrinsic - The extrinsic to trace.
|
|
75
|
+
* @returns An array of VM steps.
|
|
76
|
+
* @throws Error if the trace outcome is invalid.
|
|
77
|
+
*/ export const traceVM = async (block, extrinsic, pageSize = 50_000, disableStack = false, enableMemory = true)=>{
|
|
78
|
+
const meta = await block.meta;
|
|
79
|
+
registerTypes(meta.registry);
|
|
80
|
+
let page = 0;
|
|
81
|
+
let traceNextPage = true;
|
|
82
|
+
let steps = [];
|
|
83
|
+
while(traceNextPage){
|
|
84
|
+
pinoLogger.info(`VM trace page ${page} ...`);
|
|
85
|
+
const tracerConfig = meta.registry.createType('TracerConfig', {
|
|
86
|
+
OpcodeTracer: {
|
|
87
|
+
page,
|
|
88
|
+
pageSize,
|
|
89
|
+
disableStack,
|
|
90
|
+
enableMemory
|
|
91
|
+
}
|
|
92
|
+
}).toHex();
|
|
93
|
+
const taskResponse = await block.call('EVMTraceApi_trace_extrinsic', [
|
|
94
|
+
extrinsic,
|
|
95
|
+
tracerConfig
|
|
96
|
+
]);
|
|
97
|
+
const outcome = meta.registry.createType('Result<TraceOutcome, TransactionValidityError>', taskResponse.result).asOk.toJSON();
|
|
98
|
+
if (!('steps' in outcome)) {
|
|
99
|
+
throw new Error('Invalid trace outcome');
|
|
100
|
+
}
|
|
101
|
+
steps = steps.concat(outcome.steps.map((step)=>({
|
|
102
|
+
...step,
|
|
103
|
+
op: opName(step.op),
|
|
104
|
+
// transform memory to 64 bytes chunks
|
|
105
|
+
memory: step.memory ? step.memory.map((chunk, idx)=>{
|
|
106
|
+
// remove 0x prefix
|
|
107
|
+
const slice = chunk.slice(2);
|
|
108
|
+
// make sure each chunk is 64 bytes
|
|
109
|
+
if (slice.length < 64 && idx + 1 < step.memory.length) {
|
|
110
|
+
return slice.padStart(64, '0');
|
|
111
|
+
}
|
|
112
|
+
return slice;
|
|
113
|
+
}) : null
|
|
114
|
+
})));
|
|
115
|
+
page += 1;
|
|
116
|
+
traceNextPage = outcome.steps.length == pageSize;
|
|
117
|
+
}
|
|
118
|
+
return steps;
|
|
119
|
+
};
|
|
120
|
+
/**
|
|
121
|
+
* Traces the calls made by an extrinsic in a block.
|
|
122
|
+
* @param block - The block to trace the extrinsic in.
|
|
123
|
+
* @param extrinsic - The extrinsic to trace.
|
|
124
|
+
* @returns An array of calls made by the extrinsic.
|
|
125
|
+
* @throws Error if the trace outcome is invalid.
|
|
126
|
+
*/ export const traceCalls = async (block, extrinsic)=>{
|
|
127
|
+
const meta = await block.meta;
|
|
128
|
+
registerTypes(meta.registry);
|
|
129
|
+
const tracerConfig = meta.registry.createType('TracerConfig', {
|
|
130
|
+
CallTracer: null
|
|
131
|
+
}).toHex();
|
|
132
|
+
const taskResponse = await block.call('EVMTraceApi_trace_extrinsic', [
|
|
133
|
+
extrinsic,
|
|
134
|
+
tracerConfig
|
|
135
|
+
]);
|
|
136
|
+
const outcome = meta.registry.createType('Result<TraceOutcome, TransactionValidityError>', taskResponse.result).asOk.toJSON();
|
|
137
|
+
if (!('calls' in outcome)) {
|
|
138
|
+
throw new Error('Invalid trace outcome');
|
|
139
|
+
}
|
|
140
|
+
return outcome.calls;
|
|
141
|
+
};
|
|
142
|
+
/**
|
|
143
|
+
* Prepares a block for tracing a transaction.
|
|
144
|
+
* @param chain The blockchain instance.
|
|
145
|
+
* @param blockHashNumber The block hash or block number.
|
|
146
|
+
* @param txHash The transaction hash.
|
|
147
|
+
* @param wasmPath The path to the runtime wasm file.
|
|
148
|
+
* @returns An object containing the tracing block and the transaction extrinsic.
|
|
149
|
+
* @throws Error if the block or parent block is not found, or if the runtime wasm with tracing feature cannot be found.
|
|
150
|
+
*/ export const prepareBlock = async (chain, blockHashNumber, txHash, wasmPath)=>{
|
|
151
|
+
let wasm = wasmPath;
|
|
152
|
+
const block = typeof blockHashNumber == 'number' ? await chain.getBlockAt(blockHashNumber) : await chain.getBlock(blockHashNumber);
|
|
153
|
+
if (!block) {
|
|
154
|
+
throw new Error(`Block not found ${blockHashNumber}`);
|
|
155
|
+
}
|
|
156
|
+
const header = await block.header;
|
|
157
|
+
const parent = await chain.getBlock(header.parentHash.toHex());
|
|
158
|
+
if (!parent) {
|
|
159
|
+
throw new Error(`Block not found ${blockHashNumber}`);
|
|
160
|
+
}
|
|
161
|
+
await chain.setHead(parent);
|
|
162
|
+
// override wasm with tracing feature
|
|
163
|
+
if (typeof wasm === 'string') {
|
|
164
|
+
await overrideWasm(chain, wasm);
|
|
165
|
+
} else {
|
|
166
|
+
// Fetch runtime wasm with tracing feature from Github releases
|
|
167
|
+
if (!wasm) {
|
|
168
|
+
wasm = await fetchRuntime(await chain.head.runtimeVersion);
|
|
169
|
+
if (!wasm) {
|
|
170
|
+
throw new Error('Could not find runtime with tracing feature from Github releasesw. Make sure to manually override runtime wasm built with `tracing` feature enabled.');
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
chain.head.setWasm(`0x${wasm.toString('hex')}`);
|
|
174
|
+
}
|
|
175
|
+
const runtimeVersion = await chain.head.runtimeVersion;
|
|
176
|
+
pinoLogger.info(`${_.capitalize(runtimeVersion.specName)} specVersion: ${runtimeVersion.specVersion}`);
|
|
177
|
+
const extrinsics = await block.extrinsics;
|
|
178
|
+
const txIndex = extrinsics.findIndex((tx)=>blake2AsHex(tx) === txHash);
|
|
179
|
+
const tracingBlock = new Block(chain, block.number, block.hash, parent, {
|
|
180
|
+
header,
|
|
181
|
+
extrinsics: [],
|
|
182
|
+
storage: parent.storage
|
|
183
|
+
});
|
|
184
|
+
pinoLogger.info(`Preparing block ${chain.head.number + 1} ...`);
|
|
185
|
+
const { storageDiff } = await tracingBlock.call('Core_initialize_block', [
|
|
186
|
+
header.toHex()
|
|
187
|
+
]);
|
|
188
|
+
tracingBlock.pushStorageLayer().setAll(storageDiff);
|
|
189
|
+
for (const extrinsic of extrinsics.slice(0, txIndex)){
|
|
190
|
+
const { storageDiff } = await tracingBlock.call('BlockBuilder_apply_extrinsic', [
|
|
191
|
+
extrinsic
|
|
192
|
+
]);
|
|
193
|
+
tracingBlock.pushStorageLayer().setAll(storageDiff);
|
|
194
|
+
}
|
|
195
|
+
return {
|
|
196
|
+
tracingBlock,
|
|
197
|
+
extrinsic: extrinsics[txIndex]
|
|
198
|
+
};
|
|
199
|
+
};
|
package/dist/esm/utils/tunnel.js
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { bootstrap } from 'global-agent';
|
|
2
2
|
bootstrap();
|
|
3
|
+
import { environment } from '@acala-network/chopsticks-core';
|
|
3
4
|
import npmConf from '@pnpm/npm-conf';
|
|
4
5
|
const npmConfig = npmConf().config;
|
|
5
|
-
global.GLOBAL_AGENT.HTTP_PROXY =
|
|
6
|
+
global.GLOBAL_AGENT.HTTP_PROXY = environment.HTTP_PROXY || environment.http_proxy || environment.HTTPS_PROXY || environment.https_proxy || npmConfig.get('proxy') || npmConfig.get('https-proxy') || global.GLOBAL_AGENT.HTTP_PROXY;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@acala-network/chopsticks",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.10.0-2",
|
|
4
4
|
"author": "Acala Developers <hello@acala.network>",
|
|
5
5
|
"license": "Apache-2.0",
|
|
6
6
|
"bin": "./chopsticks.cjs",
|
|
@@ -13,8 +13,8 @@
|
|
|
13
13
|
"docs:prep": "typedoc"
|
|
14
14
|
},
|
|
15
15
|
"dependencies": {
|
|
16
|
-
"@acala-network/chopsticks-core": "0.
|
|
17
|
-
"@acala-network/chopsticks-db": "0.
|
|
16
|
+
"@acala-network/chopsticks-core": "0.10.0-2",
|
|
17
|
+
"@acala-network/chopsticks-db": "0.10.0-2",
|
|
18
18
|
"@pnpm/npm-conf": "^2.2.2",
|
|
19
19
|
"@polkadot/api-augment": "^10.11.2",
|
|
20
20
|
"@polkadot/types": "^10.11.2",
|