-
Notifications
You must be signed in to change notification settings - Fork 21
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
7c94726
commit 0629d48
Showing
6 changed files
with
332 additions
and
28 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,264 @@ | ||
import { ApiPromise } from '@polkadot/api'; | ||
import { Extrinsic } from '@polkadot/types/interfaces'; | ||
import { HexString } from '@polkadot/util/types'; | ||
import { IExtrinsic } from '@polkadot/types/types'; | ||
|
||
export type CallTrace = { | ||
type: 'CALL' | 'CALLCODE' | 'STATICCALL' | 'DELEGATECALL' | 'CREATE' | 'SUICIDE'; | ||
from: HexString; | ||
to: HexString; | ||
input: HexString; | ||
value: HexString; | ||
gas: number; | ||
gasUsed: number; | ||
output: HexString | null; | ||
error: string | null; | ||
revertReason: string | null; | ||
depth: number; | ||
calls: CallTrace[]; | ||
} | ||
|
||
export interface StepBase { | ||
pc: number; | ||
depth: number; | ||
gas: number; | ||
stack: HexString[]; | ||
memory: string[] | null; | ||
} | ||
|
||
export interface StepRaw extends StepBase { | ||
op: number; | ||
} | ||
|
||
export interface Step extends StepBase { | ||
op: string; | ||
} | ||
|
||
export enum TracerType { | ||
CallTracer = 'callTracer', | ||
OpcodeTracer = 'opcodeTracer' | ||
} | ||
|
||
export const OPNAME_TABLE = { | ||
'0x00': 'STOP', | ||
'0x01': 'ADD', | ||
'0x02': 'MUL', | ||
'0x03': 'SUB', | ||
'0x04': 'DIV', | ||
'0x05': 'SDIV', | ||
'0x06': 'MOD', | ||
'0x07': 'SMOD', | ||
'0x08': 'ADDMOD', | ||
'0x09': 'MULMOD', | ||
'0x0a': 'EXP', | ||
'0x0b': 'SIGNEXTEND', | ||
'0x10': 'LT', | ||
'0x11': 'GT', | ||
'0x12': 'SLT', | ||
'0x13': 'SGT', | ||
'0x14': 'EQ', | ||
'0x15': 'ISZERO', | ||
'0x16': 'AND', | ||
'0x17': 'OR', | ||
'0x18': 'XOR', | ||
'0x19': 'NOT', | ||
'0x1a': 'BYTE', | ||
'0x35': 'CALLDATALOAD', | ||
'0x36': 'CALLDATASIZE', | ||
'0x37': 'CALLDATACOPY', | ||
'0x38': 'CODESIZE', | ||
'0x39': 'CODECOPY', | ||
'0x1b': 'SHL', | ||
'0x1c': 'SHR', | ||
'0x1d': 'SAR', | ||
'0x50': 'POP', | ||
'0x51': 'MLOAD', | ||
'0x52': 'MSTORE', | ||
'0x53': 'MSTORE8', | ||
'0x56': 'JUMP', | ||
'0x57': 'JUMPI', | ||
'0x58': 'PC', | ||
'0x59': 'MSIZE', | ||
'0x5b': 'JUMPDEST', | ||
'0x5f': 'PUSH0', | ||
'0x60': 'PUSH1', | ||
'0x61': 'PUSH2', | ||
'0x62': 'PUSH3', | ||
'0x63': 'PUSH4', | ||
'0x64': 'PUSH5', | ||
'0x65': 'PUSH6', | ||
'0x66': 'PUSH7', | ||
'0x67': 'PUSH8', | ||
'0x68': 'PUSH9', | ||
'0x69': 'PUSH10', | ||
'0x6a': 'PUSH11', | ||
'0x6b': 'PUSH12', | ||
'0x6c': 'PUSH13', | ||
'0x6d': 'PUSH14', | ||
'0x6e': 'PUSH15', | ||
'0x6f': 'PUSH16', | ||
'0x70': 'PUSH17', | ||
'0x71': 'PUSH18', | ||
'0x72': 'PUSH19', | ||
'0x73': 'PUSH20', | ||
'0x74': 'PUSH21', | ||
'0x75': 'PUSH22', | ||
'0x76': 'PUSH23', | ||
'0x77': 'PUSH24', | ||
'0x78': 'PUSH25', | ||
'0x79': 'PUSH26', | ||
'0x7a': 'PUSH27', | ||
'0x7b': 'PUSH28', | ||
'0x7c': 'PUSH29', | ||
'0x7d': 'PUSH30', | ||
'0x7e': 'PUSH31', | ||
'0x7f': 'PUSH32', | ||
'0x80': 'DUP1', | ||
'0x81': 'DUP2', | ||
'0x82': 'DUP3', | ||
'0x83': 'DUP4', | ||
'0x84': 'DUP5', | ||
'0x85': 'DUP6', | ||
'0x86': 'DUP7', | ||
'0x87': 'DUP8', | ||
'0x88': 'DUP9', | ||
'0x89': 'DUP10', | ||
'0x8a': 'DUP11', | ||
'0x8b': 'DUP12', | ||
'0x8c': 'DUP13', | ||
'0x8d': 'DUP14', | ||
'0x8e': 'DUP15', | ||
'0x8f': 'DUP16', | ||
'0x90': 'SWAP1', | ||
'0x91': 'SWAP2', | ||
'0x92': 'SWAP3', | ||
'0x93': 'SWAP4', | ||
'0x94': 'SWAP5', | ||
'0x95': 'SWAP6', | ||
'0x96': 'SWAP7', | ||
'0x97': 'SWAP8', | ||
'0x98': 'SWAP9', | ||
'0x99': 'SWAP10', | ||
'0x9a': 'SWAP11', | ||
'0x9b': 'SWAP12', | ||
'0x9c': 'SWAP13', | ||
'0x9d': 'SWAP14', | ||
'0x9e': 'SWAP15', | ||
'0x9f': 'SWAP16', | ||
'0xf3': 'RETURN', | ||
'0xfd': 'REVERT', | ||
'0xfe': 'INVALID', | ||
'0xef': 'EOFMAGIC', | ||
'0x20': 'SHA3', | ||
'0x30': 'ADDRESS', | ||
'0x31': 'BALANCE', | ||
'0x47': 'SELFBALANCE', | ||
'0x48': 'BASEFEE', | ||
'0x32': 'ORIGIN', | ||
'0x33': 'CALLER', | ||
'0x34': 'CALLVALUE', | ||
'0x3a': 'GASPRICE', | ||
'0x3b': 'EXTCODESIZE', | ||
'0x3c': 'EXTCODECOPY', | ||
'0x3f': 'EXTCODEHASH', | ||
'0x3d': 'RETURNDATASIZE', | ||
'0x3e': 'RETURNDATACOPY', | ||
'0x40': 'BLOCKHASH', | ||
'0x41': 'COINBASE', | ||
'0x42': 'TIMESTAMP', | ||
'0x43': 'NUMBER', | ||
'0x44': 'DIFFICULTY', | ||
'0x45': 'GASLIMIT', | ||
'0x54': 'SLOAD', | ||
'0x55': 'SSTORE', | ||
'0x5a': 'GAS', | ||
'0xa0': 'LOG0', | ||
'0xa1': 'LOG1', | ||
'0xa2': 'LOG2', | ||
'0xa3': 'LOG3', | ||
'0xa4': 'LOG4', | ||
'0xf0': 'CREATE', | ||
'0xf5': 'CREATE2', | ||
'0xf1': 'CALL', | ||
'0xf2': 'CALLCODE', | ||
'0xf4': 'DELEGATECALL', | ||
'0xfa': 'STATICCALL', | ||
'0xff': 'SUICIDE', | ||
'0x46': 'CHAINID', | ||
}; | ||
|
||
export const opName = (opCode: number): string => { | ||
const opCodeHex = `0x${opCode.toString(16).padStart(2, '0')}`; | ||
return OPNAME_TABLE[opCodeHex] ?? opCodeHex; | ||
}; | ||
|
||
export const traceVM = async ( | ||
api: ApiPromise, | ||
extrinsic: Extrinsic | IExtrinsic | string | Uint8Array, | ||
) => { | ||
const pageSize = 10000; | ||
const traceConf = { | ||
page: 0, | ||
pageSize, | ||
disableStack: false, | ||
enableMemory: true, | ||
}; | ||
|
||
let traceNextPage = true; | ||
let steps: Step[] = []; | ||
while (traceNextPage) { | ||
const res = await api.call.evmTraceApi.traceExtrinsic(extrinsic, { OpcodeTracer: traceConf }); | ||
|
||
if (!res.isOk) { | ||
throw new Error(`traceVM: trace failed. Err: ${res.asErr.toString()}`); | ||
} | ||
|
||
const okRes = res.asOk; | ||
if (!okRes.isSteps) { | ||
throw new Error('traceVM: invalid outcome'); | ||
} | ||
|
||
const curSteps = okRes.asSteps.toJSON() as StepRaw[]; | ||
Check failure on line 221 in packages/eth-providers/src/utils/trace.ts
|
||
|
||
steps = steps.concat( | ||
curSteps.map(step => ({ | ||
...step, | ||
op: opName(step.op), | ||
// transform memory to 64 bytes chunks | ||
memory: step.memory | ||
? step.memory.map((chunk, idx) => { | ||
// remove 0x prefix | ||
const slice = chunk.slice(2); | ||
// make sure each chunk is 64 bytes | ||
return slice.length < 64 && idx + 1 < step.memory!.length | ||
? slice.padStart(64, '0') | ||
: slice; | ||
}) | ||
: null, | ||
})), | ||
); | ||
|
||
traceConf.page++; | ||
traceNextPage = curSteps.length == pageSize; | ||
} | ||
|
||
return steps; | ||
}; | ||
|
||
export const traceCall = async ( | ||
api: ApiPromise, | ||
extrinsic: Extrinsic | IExtrinsic | string | Uint8Array, | ||
): Promise<CallTrace[]> => { | ||
const traceConf = { CallTracer: null }; | ||
const res = await api.call.evmTraceApi.traceExtrinsic(extrinsic, traceConf); | ||
if (!res.isOk) { | ||
throw new Error(`traceCall: trace failed. Err: ${res.asErr.toString()}`); | ||
} | ||
|
||
const okRes = res.asOk; | ||
if (!okRes.isCalls) { | ||
throw new Error('traceVM: invalid outcome'); | ||
} | ||
|
||
return okRes.asCalls.toJSON() as CallTrace[]; | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.