|
|
|
@ -28,7 +28,6 @@ export class VmProxy { |
|
|
|
|
providers |
|
|
|
|
currentProvider |
|
|
|
|
storageCache |
|
|
|
|
lastProcessedStorageTxHash |
|
|
|
|
sha3Preimages |
|
|
|
|
sha3 |
|
|
|
|
toHex |
|
|
|
@ -69,7 +68,6 @@ export class VmProxy { |
|
|
|
|
this.providers = { HttpProvider: function (url) {} } |
|
|
|
|
this.currentProvider = { host: 'vm provider' } |
|
|
|
|
this.storageCache = {} |
|
|
|
|
this.lastProcessedStorageTxHash = {} |
|
|
|
|
this.sha3Preimages = {} |
|
|
|
|
// util
|
|
|
|
|
this.sha3 = (...args) => utils.sha3.apply(this, args) |
|
|
|
@ -136,7 +134,6 @@ export class VmProxy { |
|
|
|
|
try { |
|
|
|
|
const storage = await this.vm.stateManager.dumpStorage(data.to) |
|
|
|
|
this.storageCache[this.processingHash][tx['to']] = storage |
|
|
|
|
this.lastProcessedStorageTxHash[tx['to']] = this.processingHash |
|
|
|
|
} catch (e) { |
|
|
|
|
console.log(e) |
|
|
|
|
} |
|
|
|
@ -201,84 +198,82 @@ export class VmProxy { |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
async pushTrace (data: InterpreterStep) { |
|
|
|
|
const depth = data.depth + 1 // geth starts the depth from 1
|
|
|
|
|
if (!this.processingHash) { |
|
|
|
|
console.log('no tx processing') |
|
|
|
|
return |
|
|
|
|
} |
|
|
|
|
let previousopcode |
|
|
|
|
if (this.vmTraces[this.processingHash] && this.vmTraces[this.processingHash].structLogs[this.processingIndex - 1]) { |
|
|
|
|
previousopcode = this.vmTraces[this.processingHash].structLogs[this.processingIndex - 1] |
|
|
|
|
} |
|
|
|
|
try { |
|
|
|
|
const depth = data.depth + 1 // geth starts the depth from 1
|
|
|
|
|
if (!this.processingHash) { |
|
|
|
|
console.log('no tx processing') |
|
|
|
|
return |
|
|
|
|
} |
|
|
|
|
let previousopcode |
|
|
|
|
if (this.vmTraces[this.processingHash] && this.vmTraces[this.processingHash].structLogs[this.processingIndex - 1]) { |
|
|
|
|
previousopcode = this.vmTraces[this.processingHash].structLogs[this.processingIndex - 1] |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
if (this.previousDepth > depth && previousopcode) { |
|
|
|
|
// returning from context, set error it is not STOP, RETURN
|
|
|
|
|
previousopcode.invalidDepthChange = previousopcode.op !== 'RETURN' && previousopcode.op !== 'STOP' |
|
|
|
|
} |
|
|
|
|
const step = { |
|
|
|
|
stack: hexListFromBNs(data.stack), |
|
|
|
|
memory: formatMemory(data.memory), |
|
|
|
|
storage: {}, |
|
|
|
|
op: data.opcode.name, |
|
|
|
|
pc: data.pc, |
|
|
|
|
gasCost: data.opcode.fee.toString(), |
|
|
|
|
gas: data.gasLeft.toString(), |
|
|
|
|
depth: depth |
|
|
|
|
} |
|
|
|
|
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) |
|
|
|
|
const memory = step.memory.join('') |
|
|
|
|
let payload = memory.substring(payloadStart * 2, memory.length) |
|
|
|
|
const fnselectorStr = payload.substring(0, 8) |
|
|
|
|
const fnselectorStrInHex = '0x' + fnselectorStr |
|
|
|
|
const fnselector = parseInt(fnselectorStrInHex) |
|
|
|
|
const fnArgs = ConsoleLogs[fnselector] |
|
|
|
|
const iface = new ethers.utils.Interface([`function log${fnArgs} view`]) |
|
|
|
|
const functionDesc = iface.getFunction(`log${fnArgs}`) |
|
|
|
|
const sigHash = iface.getSighash(`log${fnArgs}`) |
|
|
|
|
if (fnArgs.includes('uint') && sigHash !== fnselectorStrInHex) { |
|
|
|
|
payload = payload.replace(fnselectorStr, sigHash) |
|
|
|
|
} else { |
|
|
|
|
payload = '0x' + payload |
|
|
|
|
if (this.previousDepth > depth && previousopcode) { |
|
|
|
|
// returning from context, set error it is not STOP, RETURN
|
|
|
|
|
previousopcode.invalidDepthChange = previousopcode.op !== 'RETURN' && previousopcode.op !== 'STOP' |
|
|
|
|
} |
|
|
|
|
const step = { |
|
|
|
|
stack: hexListFromBNs(data.stack), |
|
|
|
|
memory: formatMemory(data.memory), |
|
|
|
|
storage: {}, |
|
|
|
|
op: data.opcode.name, |
|
|
|
|
pc: data.pc, |
|
|
|
|
gasCost: data.opcode.fee.toString(), |
|
|
|
|
gas: data.gasLeft.toString(), |
|
|
|
|
depth: depth |
|
|
|
|
} |
|
|
|
|
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) |
|
|
|
|
const memory = step.memory.join('') |
|
|
|
|
let payload = memory.substring(payloadStart * 2, memory.length) |
|
|
|
|
const fnselectorStr = payload.substring(0, 8) |
|
|
|
|
const fnselectorStrInHex = '0x' + fnselectorStr |
|
|
|
|
const fnselector = parseInt(fnselectorStrInHex) |
|
|
|
|
const fnArgs = ConsoleLogs[fnselector] |
|
|
|
|
const iface = new ethers.utils.Interface([`function log${fnArgs} view`]) |
|
|
|
|
const functionDesc = iface.getFunction(`log${fnArgs}`) |
|
|
|
|
const sigHash = iface.getSighash(`log${fnArgs}`) |
|
|
|
|
if (fnArgs.includes('uint') && sigHash !== fnselectorStrInHex) { |
|
|
|
|
payload = payload.replace(fnselectorStr, sigHash) |
|
|
|
|
} else { |
|
|
|
|
payload = '0x' + payload |
|
|
|
|
} |
|
|
|
|
const consoleArgs = iface.decodeFunctionData(functionDesc, payload) |
|
|
|
|
this.hhLogs[this.processingHash] = this.hhLogs[this.processingHash] ? this.hhLogs[this.processingHash] : [] |
|
|
|
|
this.hhLogs[this.processingHash].push(consoleArgs) |
|
|
|
|
} |
|
|
|
|
const consoleArgs = iface.decodeFunctionData(functionDesc, payload) |
|
|
|
|
this.hhLogs[this.processingHash] = this.hhLogs[this.processingHash] ? this.hhLogs[this.processingHash] : [] |
|
|
|
|
this.hhLogs[this.processingHash].push(consoleArgs) |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
if (step.op === 'CREATE' || step.op === 'CALL') { |
|
|
|
|
if (step.op === 'CREATE') { |
|
|
|
|
this.processingAddress = '(Contract Creation - Step ' + this.processingIndex + ')' |
|
|
|
|
this.storageCache[this.processingHash][this.processingAddress] = {} |
|
|
|
|
this.lastProcessedStorageTxHash[this.processingAddress] = this.processingHash |
|
|
|
|
} else { |
|
|
|
|
this.processingAddress = normalizeHexAddress(step.stack[step.stack.length - 2]) |
|
|
|
|
this.processingAddress = toChecksumAddress(this.processingAddress) |
|
|
|
|
if (!this.storageCache[this.processingHash][this.processingAddress]) { |
|
|
|
|
const account = Address.fromString(this.processingAddress) |
|
|
|
|
try { |
|
|
|
|
const storage = await this.vm.stateManager.dumpStorage(account) |
|
|
|
|
this.storageCache[this.processingHash][this.processingAddress] = storage |
|
|
|
|
this.lastProcessedStorageTxHash[this.processingAddress] = this.processingHash |
|
|
|
|
} catch (e) { |
|
|
|
|
console.log(e) |
|
|
|
|
if (step.op === 'CREATE' || step.op === 'CALL') { |
|
|
|
|
if (step.op === 'CREATE') { |
|
|
|
|
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 = toChecksumAddress(this.processingAddress) |
|
|
|
|
if (!this.storageCache[this.processingHash][this.processingAddress]) { |
|
|
|
|
const account = Address.fromString(this.processingAddress) |
|
|
|
|
this.vm.stateManager.dumpStorage(account).then((storage) => { |
|
|
|
|
this.storageCache[this.processingHash][this.processingAddress] = storage |
|
|
|
|
}).catch(console.log)
|
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
if (previousopcode && previousopcode.op === 'SHA3') { |
|
|
|
|
const preimage = this.getSha3Input(previousopcode.stack, previousopcode.memory) |
|
|
|
|
const imageHash = step.stack[step.stack.length - 1].replace('0x', '') |
|
|
|
|
this.sha3Preimages[imageHash] = { |
|
|
|
|
preimage: preimage |
|
|
|
|
if (previousopcode && previousopcode.op === 'SHA3') { |
|
|
|
|
const preimage = this.getSha3Input(previousopcode.stack, previousopcode.memory) |
|
|
|
|
const imageHash = step.stack[step.stack.length - 1].replace('0x', '') |
|
|
|
|
this.sha3Preimages[imageHash] = { |
|
|
|
|
preimage: preimage |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
this.processingIndex++ |
|
|
|
|
this.previousDepth = depth |
|
|
|
|
} catch (e) { |
|
|
|
|
console.log(e) |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
this.processingIndex++ |
|
|
|
|
this.previousDepth = depth |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
getCode (address, cb) { |
|
|
|
|