fix converting stack

pull/3316/head
yann300 2 years ago committed by Aniket
parent 484aa46fb9
commit f5e5147b1b
  1. 7
      apps/debugger/src/app/debugger-api.ts
  2. 16
      libs/remix-debug/src/trace/traceAnalyser.ts
  3. 5
      libs/remix-debug/src/trace/traceCache.ts
  4. 5
      libs/remix-debug/src/trace/traceHelper.ts
  5. 18
      libs/remix-debug/src/trace/traceManager.ts
  6. 21
      libs/remix-lib/src/util.ts
  7. 30
      libs/remix-simulator/src/VmProxy.ts

@ -137,7 +137,12 @@ export const DebuggerApiMixin = (Base) => class extends Base {
},
debugWithGeneratedSources: false
})
return await debug.debugger.traceManager.getTrace(hash)
const trace = await debug.debugger.traceManager.getTrace(hash)
trace.structLogs = trace.structLogs.map((step) => {
step.stack = []
return step
})
return trace
}
debug (hash, web3?) {

@ -1,4 +1,6 @@
'use strict'
import { util } from '@remix-project/remix-lib'
const { toHexPaddedString } = util
import * as traceHelper from './traceHelper'
export class TraceAnalyser {
@ -36,8 +38,8 @@ export class TraceAnalyser {
buildReturnValues (index, step) {
if (traceHelper.isReturnInstruction(step)) {
let offset = 2 * parseInt(step.stack[step.stack.length - 1], 16)
const size = 2 * parseInt(step.stack[step.stack.length - 2], 16)
let offset = 2 * parseInt(toHexPaddedString(step.stack[step.stack.length - 1]), 16)
const size = 2 * parseInt(toHexPaddedString(step.stack[step.stack.length - 2]), 16)
const memory = this.trace[this.traceCache.memoryChanges[this.traceCache.memoryChanges.length - 1]].memory
const noOfReturnParams = size / 64
const memoryInString = memory.join('')
@ -77,11 +79,11 @@ export class TraceAnalyser {
let offset = 0
let size = 0
if (callStep.op === 'DELEGATECALL') {
offset = 2 * parseInt(stack[stack.length - 3], 16)
size = 2 * parseInt(stack[stack.length - 4], 16)
offset = 2 * parseInt(toHexPaddedString(stack[stack.length - 3]), 16)
size = 2 * parseInt(toHexPaddedString(stack[stack.length - 4]), 16)
} else {
offset = 2 * parseInt(stack[stack.length - 4], 16)
size = 2 * parseInt(stack[stack.length - 5], 16)
offset = 2 * parseInt(toHexPaddedString(stack[stack.length - 4]), 16)
size = 2 * parseInt(toHexPaddedString(stack[stack.length - 5]), 16)
}
calldata = '0x' + memory.join('').substr(offset, size)
this.traceCache.pushCallDataChanges(index + 1, calldata)
@ -104,7 +106,7 @@ export class TraceAnalyser {
}
this.traceCache.pushStoreChanges(index + 1, context.storageContext[context.storageContext.length - 1])
} else if (traceHelper.isSSTOREInstruction(step)) {
this.traceCache.pushStoreChanges(index + 1, context.storageContext[context.storageContext.length - 1], step.stack[step.stack.length - 1], step.stack[step.stack.length - 2])
this.traceCache.pushStoreChanges(index + 1, context.storageContext[context.storageContext.length - 1], toHexPaddedString(step.stack[step.stack.length - 1]), toHexPaddedString(step.stack[step.stack.length - 2]))
} else if (traceHelper.isReturnInstruction(step) || traceHelper.isStopInstruction(step)) {
context.storageContext.pop()
this.traceCache.pushStoreChanges(index + 1, context.storageContext[context.storageContext.length - 1])

@ -1,5 +1,6 @@
'use strict'
import { util } from '@remix-project/remix-lib'
const { toHexPaddedString } = util
// eslint-disable-next-line camelcase
const { sha3_256 } = util
@ -103,8 +104,8 @@ export class TraceCache {
pushContractCreationFromMemory (index, token, trace, lastMemoryChange) {
const memory = trace[lastMemoryChange].memory
const stack = trace[index].stack
const offset = 2 * parseInt(stack[stack.length - 2], 16)
const size = 2 * parseInt(stack[stack.length - 3], 16)
const offset = 2 * parseInt(toHexPaddedString(stack[stack.length - 2]), 16)
const size = 2 * parseInt(toHexPaddedString(stack[stack.length - 3]), 16)
this.contractCreation[token] = '0x' + memory.join('').substr(offset, size)
}

@ -1,5 +1,6 @@
'use strict'
import { helpers } from '@remix-project/remix-lib'
import { helpers, util } from '@remix-project/remix-lib'
const { toHexPaddedString } = util
const { ui } = helpers
// vmTraceIndex has to point to a CALL, CODECALL, ...
@ -9,7 +10,7 @@ export function resolveCalledAddress (vmTraceIndex, trace) {
return contractCreationToken(vmTraceIndex)
} else if (isCallInstruction(step)) {
const stack = step.stack // callcode, delegatecall, ...
return ui.normalizeHexAddress(stack[stack.length - 2])
return ui.normalizeHexAddress(toHexPaddedString(stack[stack.length - 2]))
}
return undefined
}

@ -1,5 +1,6 @@
'use strict'
import { util, execution } from '@remix-project/remix-lib'
const { toHexPaddedString } = util
import { TraceAnalyser } from './traceAnalyser'
import { TraceCache } from './traceCache'
import { TraceStepManager } from './traceStepManager'
@ -148,9 +149,24 @@ export class TraceManager {
getStackAt (stepIndex) {
this.checkRequestedStep(stepIndex)
if (this.trace[stepIndex] && this.trace[stepIndex].stack) { // there's always a stack
if (Array.isArray(this.trace[stepIndex].stack)) {
const stack = this.trace[stepIndex].stack.slice(0)
stack.reverse()
return stack.map(el => el.startsWith('0x') ? el : '0x' + el)
return stack.map(el => toHexPaddedString(el))
} else {
// it's an object coming from the VM.
// for performance reasons,
// we don't turn the stack coming from the VM into an array when the tx is executed
// but now when the app needs it.
const stack = []
for (const prop in this.trace[stepIndex].stack) {
if (prop !== 'length') {
stack.push(toHexPaddedString(this.trace[stepIndex].stack[prop]))
}
}
stack.reverse()
return stack
}
} else {
throw new Error('no stack found')
}

@ -1,5 +1,6 @@
'use strict'
import { BN, bufferToHex, keccak, setLengthLeft, toBuffer, addHexPrefix } from 'ethereumjs-util'
import { bufferToHex, keccak, setLengthLeft, toBuffer, addHexPrefix } from 'ethereumjs-util'
import { bigIntToHex } from '@ethereumjs/util'
import stringSimilarity from 'string-similarity'
/*
@ -35,14 +36,22 @@ export function hexToIntArray (hexString) {
export function hexListFromBNs (bnList) {
const ret = []
for (const k in bnList) {
const v = bnList[k]
if (BN.isBN(v)) {
ret.push('0x' + v.toString('hex', 64))
const v = bnList[k].toString(16)
ret.push('0x' + v.padStart(64, '0'))
}
return ret
}
export function toHexPaddedString(v: bigint | string): string {
if (v) {
if (typeof v === 'string') {
return v.startsWith('0x') ? v : '0x' + v
} else {
ret.push('0x' + (new BN(v)).toString('hex', 64)) // TEMP FIX TO REMOVE ONCE https://github.com/ethereumjs/ethereumjs-vm/pull/293 is released
return '0x' + v.toString(16).padStart(64, '0')
}
}
return ret
else
return '0x' + '0'.padStart(64, '0')
}
/*

@ -1,5 +1,5 @@
import { util } from '@remix-project/remix-lib'
const { hexListFromBNs, formatMemory } = util
const { toHexPaddedString, formatMemory } = util
import { helpers } from '@remix-project/remix-lib'
const { normalizeHexAddress } = helpers.ui
import { ConsoleLogs } from '@remix-project/remix-lib'
@ -240,7 +240,7 @@ export class VmProxy {
previousOpcode.invalidDepthChange = previousOpcode.op !== 'RETURN' && previousOpcode.op !== 'STOP'
}
const step = {
stack: hexListFromBNs(data.stack),
stack: { ...data.stack },
storage: {},
memory: null,
op: data.opcode.name,
@ -249,6 +249,7 @@ export class VmProxy {
gas: data.gasLeft.toString(),
depth: depth
}
step.stack.length = Object.keys(data.stack).length
if (previousOpcode && (previousOpcode.op === 'CALLDATACOPY' || previousOpcode.op === 'CODECOPY' || previousOpcode.op === 'EXTCODECOPY' || previousOpcode.op === 'RETURNDATACOPY' || previousOpcode.op === 'MSTORE' || previousOpcode.op === 'MSTORE8')) {
step.memory = data.memory
@ -256,9 +257,8 @@ export class VmProxy {
}
this.vmTraces[this.processingHash].structLogs.push(step)
// Track hardhat console.log call
if (step.op === 'STATICCALL' && step.stack[step.stack.length - 2] === '0x000000000000000000000000000000000000000000636f6e736f6c652e6c6f67') {
const stackLength = step.stack.length
const payloadStart = parseInt(step.stack[stackLength - 3], 16)
if (step.op === 'STATICCALL' && toHexPaddedString(step.stack[step.stack.length - 2]) === '0x000000000000000000000000000000000000000000636f6e736f6c652e6c6f67') {
const payloadStart = parseInt(toHexPaddedString(step.stack[step.stack.length - 3]), 16)
const memory = formatMemory(data.memory)
const memoryStr = memory.join('')
let payload = memoryStr.substring(payloadStart * 2, memoryStr.length)
@ -290,7 +290,7 @@ export class VmProxy {
this.processingAddress = '(Contract Creation - Step ' + this.processingIndex + ')'
this.storageCache[this.processingHash][this.processingAddress] = {}
} else {
this.processingAddress = normalizeHexAddress(step.stack[step.stack.length - 2])
this.processingAddress = normalizeHexAddress(toHexPaddedString(step.stack[step.stack.length - 2]))
this.processingAddress = toChecksumAddress(this.processingAddress)
if (!this.storageCache[this.processingHash][this.processingAddress]) {
(async (processingHash, processingAddress, self) => {
@ -307,7 +307,7 @@ export class VmProxy {
}
if (previousOpcode && previousOpcode.op === 'SHA3') {
const preimage = this.getSha3Input(previousOpcode.stack, formatMemory(this.lastMemoryUpdate))
const imageHash = step.stack[step.stack.length - 1].replace('0x', '')
const imageHash = toHexPaddedString(step.stack[step.stack.length - 1]).replace('0x', '')
this.sha3Preimages[imageHash] = {
preimage: preimage
}
@ -421,26 +421,26 @@ export class VmProxy {
}
getSha3Input (stack, memory) {
let memoryStart = stack[stack.length - 1]
let memoryLength = stack[stack.length - 2]
const memoryStart = toHexPaddedString(stack[stack.length - 1])
const memoryLength = toHexPaddedString(stack[stack.length - 2])
const memStartDec = (new BN(memoryStart.replace('0x', ''), 16)).toString(10)
memoryStart = parseInt(memStartDec) * 2
const memoryStartInt = parseInt(memStartDec) * 2
const memLengthDec = (new BN(memoryLength.replace('0x', ''), 16).toString(10))
memoryLength = parseInt(memLengthDec) * 2
const memoryLengthInt = parseInt(memLengthDec) * 2
let i = Math.floor(memoryStart / 32)
const maxIndex = Math.floor(memoryLength / 32) + i
let i = Math.floor(memoryStartInt / 32)
const maxIndex = Math.floor(memoryLengthInt / 32) + i
if (!memory[i]) {
return this.emptyFill(memoryLength)
}
let sha3Input = memory[i].slice(memoryStart - 32 * i)
let sha3Input = memory[i].slice(memoryStartInt - 32 * i)
i++
while (i < maxIndex) {
sha3Input += memory[i] ? memory[i] : this.emptyFill(32)
i++
}
if (sha3Input.length < memoryLength) {
const leftSize = memoryLength - sha3Input.length
const leftSize = memoryLengthInt - sha3Input.length
sha3Input += memory[i] ? memory[i].slice(0, leftSize) : this.emptyFill(leftSize)
}
return sha3Input

Loading…
Cancel
Save