UNPKG

ton-assembly

Version:
129 lines 5.39 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.findInstructionInfo = exports.createTraceInfoPerTransaction = exports.createTraceInfo = void 0; const logs_1 = require("./logs"); /** * Creates a trace from the logs and mapping. */ const createTraceInfo = (logs, mapping, sourceMap) => { const stepLogInfo = (0, logs_1.parseLogs)(logs).flat(); const steps = stepLogInfo.flatMap((stepInfo) => { // TODO: handle JMPREF and first ref instruction with offset 0 const res = (0, exports.findInstructionInfo)(mapping, stepInfo); if (!res) { // skip for simplicity for now return []; } const [instructions, index] = res; const instr = instructions[index]; if (!instr) return []; const sourceMapEntries = sourceMap ? instr.debugSections.map(it => sourceMap.locations[it]).filter(it => it !== undefined) : []; return [ { loc: instr.loc, instructionName: instr.name, stack: stepInfo.stack, gas: stepInfo.gas, gasCost: stepInfo.gasCost, sourceMapEntries, }, ]; }); return { steps }; }; exports.createTraceInfo = createTraceInfo; const createTraceInfoPerTransaction = (logs, mapping, sourceMap) => { const transactionLogs = (0, logs_1.parseLogs)(logs); return transactionLogs.map((transactionLog) => { const steps = []; // handle cases where we have two instructions with offset 0 // like JMPREF and the first instruction in the ref let offsetZeroCount = 0; for (const stepInfo of transactionLog) { const res = (0, exports.findInstructionInfo)(mapping, stepInfo); if (!res) { // skip for simplicity for now continue; } if (stepInfo.offset !== 0 && offsetZeroCount !== 0) { // if we found an instruction with a non-zero offset, // we reset the offsetZeroCount to correctly handle it offsetZeroCount = 0; } const [instructions, index] = res; const instr = instructions[index + offsetZeroCount]; if (!instr) continue; if (stepInfo.offset === 0 && offsetZeroCount === 0) { // if we handled the first instruction with offset 0, // on the next step we will handle the second one offsetZeroCount = 1; } const sourceMapEntries = sourceMap ? instr.debugSections .map(it => sourceMap.locations[it]) .filter(it => it !== undefined) : []; if (stepInfo.implicit) { const actualInstr = index === -1 && instructions.at(-1)?.name === "RET" ? (instructions.at(-1) ?? instr) : instructions.length > index + 1 && instructions[index + 1]?.name === "RET" ? (instructions[index + 1] ?? instr) : instr; const actualSourceMapEntries = sourceMap ? actualInstr.debugSections .map(it => sourceMap.locations[it]) .filter(it => it !== undefined) : []; steps.push({ loc: actualInstr === instr ? undefined : actualInstr.loc, instructionName: "implicit RET", stack: stepInfo.stack, gas: stepInfo.gas, gasCost: stepInfo.gasCost, sourceMapEntries: actualSourceMapEntries, }); continue; } steps.push({ loc: instr.loc, instructionName: instr.name, stack: stepInfo.stack, gas: stepInfo.gas, gasCost: stepInfo.gasCost, sourceMapEntries, }); } return { steps }; }); }; exports.createTraceInfoPerTransaction = createTraceInfoPerTransaction; /** * Finds the instruction in the mapping. */ const findInstructionInfo = (info, stepInfo) => { // Cell hash can be both Dictionary Cell hash or just a regular code Cell hash const hash = stepInfo.hash; // We try to find the Dictionary Cell in the mapping const dictCell = info.dictionaryCells.find(it => it.cell === hash); // And if we found it, we use not Dictionary Cell hash, // but the data Cell hash that we stored in the mapping const [targetCellHash, offset] = dictCell ? [dictCell.dataCell, dictCell.offset] : [hash, 0]; const cell = info.cells[targetCellHash]; if (!cell) { // no luck, we don't have this cell in the mapping return undefined; } // Important note that we need to shift the step offset that we have in the log // since in the code Cell we start from the 0, while in logs it starts from the offset // of the code Cell in the Dictionary Cell return [ cell.instructions, cell.instructions.findIndex(it => it.offset === stepInfo.offset - offset), ]; }; exports.findInstructionInfo = findInstructionInfo; //# sourceMappingURL=trace.js.map