diff --git a/packages/sol-profiler/src/cost_utils.ts b/packages/sol-profiler/src/cost_utils.ts index 2672540fc9..be1d959d80 100644 --- a/packages/sol-profiler/src/cost_utils.ts +++ b/packages/sol-profiler/src/cost_utils.ts @@ -1,4 +1,4 @@ -import { TraceInfo } from '@0x/sol-tracing-utils'; +import { TraceInfo, constants } from '@0x/sol-tracing-utils'; import { logUtils } from '@0x/utils'; import { OpCode } from 'ethereum-types'; import { stripHexPrefix } from 'ethereumjs-util'; @@ -47,11 +47,17 @@ export const costUtils = { ); const memoryLocationsAccessed = _.map(memoryLogs, structLog => { if (_.includes(CALL_DATA_OPCODES, structLog.op)) { - const memOffset = parseInt(structLog.stack[0], HEX_BASE); - const length = parseInt(structLog.stack[2], HEX_BASE); + const memoryOffsetStackOffset = constants.opCodeToParamToStackOffset[structLog.op as any].memoryOffset; + const lengthStackOffset = constants.opCodeToParamToStackOffset[structLog.op as any].length; + const memOffset = parseInt( + structLog.stack[structLog.stack.length - memoryOffsetStackOffset - 1], + HEX_BASE, + ); + const length = parseInt(structLog.stack[structLog.stack.length - lengthStackOffset - 1], HEX_BASE); return memOffset + length; } else { - return parseInt(structLog.stack[structLog.stack.length - 1], HEX_BASE); + const memoryLocationStackOffset = constants.opCodeToParamToStackOffset[structLog.op].offset; + return parseInt(structLog.stack[structLog.stack.length - memoryLocationStackOffset - 1], HEX_BASE); } }); const highestMemoryLocationAccessed = _.max(memoryLocationsAccessed); @@ -62,7 +68,8 @@ export const costUtils = { const COPY_OPCODES = [OpCode.CallDataCopy]; const copyLogs = _.filter(structLogs, structLog => _.includes(COPY_OPCODES, structLog.op)); const copyCosts = _.map(copyLogs, structLog => { - const length = parseInt(structLog.stack[2], HEX_BASE); + const lengthStackOffset = constants.opCodeToParamToStackOffset[structLog.op as any].length; + const length = parseInt(structLog.stack[structLog.stack.length - lengthStackOffset - 1], HEX_BASE); return Math.ceil(length / WORD_SIZE) * G_COPY; }); return _.sum(copyCosts); diff --git a/packages/sol-profiler/src/profiler_subprovider.ts b/packages/sol-profiler/src/profiler_subprovider.ts index 0bea3aa7ba..8d16e3b6ee 100644 --- a/packages/sol-profiler/src/profiler_subprovider.ts +++ b/packages/sol-profiler/src/profiler_subprovider.ts @@ -65,7 +65,7 @@ export class ProfilerSubprovider extends TraceInfoSubprovider { const transactionBaseCost = BASE_COST; let totalCost = callDataCost + opcodesCost + BASE_COST; logUtils.header('Final breakdown', '-'); - if (!_.isNull(receipt.contractAddress)) { + if (_.isString(receipt.contractAddress)) { const code = await this._web3Wrapper.getContractCodeAsync(receipt.contractAddress); const codeBuff = Buffer.from(stripHexPrefix(code), 'hex'); const codeLength = codeBuff.length; diff --git a/packages/sol-tracing-utils/src/revert_trace.ts b/packages/sol-tracing-utils/src/revert_trace.ts index b40bca41d3..4ebb8a672a 100644 --- a/packages/sol-tracing-utils/src/revert_trace.ts +++ b/packages/sol-tracing-utils/src/revert_trace.ts @@ -3,6 +3,7 @@ import { OpCode, StructLog } from 'ethereum-types'; import * as _ from 'lodash'; +import { constants } from './constants'; import { EvmCallStack } from './types'; import { utils } from './utils'; @@ -29,9 +30,8 @@ export function getRevertTrace(structLogs: StructLog[], startAddress: string): E if (utils.isCallLike(structLog.op)) { const currentAddress = _.last(addressStack) as string; - const jumpAddressOffset = 1; const newAddress = utils.getAddressFromStackEntry( - structLog.stack[structLog.stack.length - jumpAddressOffset - 1], + structLog.stack[structLog.stack.length - constants.opCodeToParamToStackOffset[OpCode.Call].to - 1], ); // Sometimes calls don't change the execution context (current address). When we do a transfer to an diff --git a/packages/sol-tracing-utils/src/trace.ts b/packages/sol-tracing-utils/src/trace.ts index 1f5235455a..b96846d82c 100644 --- a/packages/sol-tracing-utils/src/trace.ts +++ b/packages/sol-tracing-utils/src/trace.ts @@ -3,6 +3,7 @@ import { OpCode, StructLog } from 'ethereum-types'; import * as _ from 'lodash'; import { utils } from './utils'; +import { constants } from './constants'; export interface ContractAddressToTraces { [contractAddress: string]: StructLog[]; @@ -33,9 +34,8 @@ export function getContractAddressToTraces(structLogs: StructLog[], startAddress if (utils.isCallLike(structLog.op)) { const currentAddress = _.last(addressStack) as string; - const jumpAddressOffset = 1; const newAddress = utils.getAddressFromStackEntry( - structLog.stack[structLog.stack.length - jumpAddressOffset - 1], + structLog.stack[structLog.stack.length - constants.opCodeToParamToStackOffset[OpCode.Call].to - 1], ); // Sometimes calls don't change the execution context (current address). When we do a transfer to an diff --git a/packages/sol-tracing-utils/src/trace_info_subprovider.ts b/packages/sol-tracing-utils/src/trace_info_subprovider.ts index f7b8af25c3..18e73aaf19 100644 --- a/packages/sol-tracing-utils/src/trace_info_subprovider.ts +++ b/packages/sol-tracing-utils/src/trace_info_subprovider.ts @@ -52,11 +52,11 @@ export abstract class TraceInfoSubprovider extends TraceCollectionSubprovider { const isCallDataAccess = opn == 0x37; var stack; if (isCall) { - stack = [null, '0x'+log.stack.peek(1).toString(16)]; + stack = ['0x'+log.stack.peek(1).toString(16), null]; } else if (isMemoryAccess) { stack = ['0x'+log.stack.peek(0).toString(16)]; } else if (isCallDataAccess) { - stack = ['0x'+log.stack.peek(0).toString(16), '0x'+log.stack.peek(1).toString(16), '0x'+log.stack.peek(2).toString(16)]; + stack = ['0x'+log.stack.peek(2).toString(16), '0x'+log.stack.peek(1).toString(16), '0x'+log.stack.peek(0).toString(16)]; } this.data.push({ pc, gasCost, depth, op, stack, gas }); }, diff --git a/packages/sol-tracing-utils/src/utils.ts b/packages/sol-tracing-utils/src/utils.ts index 7dccd36472..eeae51b5c5 100644 --- a/packages/sol-tracing-utils/src/utils.ts +++ b/packages/sol-tracing-utils/src/utils.ts @@ -3,11 +3,9 @@ import { OpCode, StructLog } from 'ethereum-types'; import { addHexPrefix } from 'ethereumjs-util'; import * as _ from 'lodash'; +import { constants } from './constants'; import { ContractData, LineColumn, SingleFileSourceRange } from './types'; -const STATICCALL_GAS_COST = 40; -const CALL_GAS_COST = 700; - const bytecodeToContractDataIfExists: { [bytecode: string]: ContractData | undefined } = {}; export const utils = { @@ -95,14 +93,16 @@ export const utils = { structLog.op === OpCode.StaticCall ? { ...structLog, - gasCost: STATICCALL_GAS_COST, + gasCost: constants.opCodeToGasCost[structLog.op], } : structLog; // HACK(leo): Geth traces sometimes returns those gas costs incorrectly as very big numbers so we manually fix them. const normalizeCallCost = (structLog: StructLog, index: number) => { if (structLog.op === OpCode.Call) { - const HEX_BASE = 16; - const callAddress = parseInt(structLog.stack[0], HEX_BASE); + const callAddress = parseInt( + structLog.stack[structLog.stack.length - constants.opCodeToParamToStackOffset[OpCode.Call].to - 1], + constants.HEX_BASE, + ); const MAX_REASONABLE_PRECOMPILE_ADDRESS = 100; if (callAddress < MAX_REASONABLE_PRECOMPILE_ADDRESS) { const nextStructLog = normalizedStructLogs[index + 1]; @@ -114,7 +114,7 @@ export const utils = { } else { return { ...structLog, - gasCost: CALL_GAS_COST, + gasCost: constants.opCodeToGasCost[structLog.op], }; } } else {