diff --git a/libs/remix-debug/src/trace/traceCache.ts b/libs/remix-debug/src/trace/traceCache.ts index cf23de75cb..2b2e0fc45c 100644 --- a/libs/remix-debug/src/trace/traceCache.ts +++ b/libs/remix-debug/src/trace/traceCache.ts @@ -17,6 +17,7 @@ export class TraceCache { memoryChanges storageChanges sstore + formattedMemory constructor () { this.init() @@ -36,6 +37,7 @@ export class TraceCache { this.addresses = [] this.callDataChanges = [] this.memoryChanges = [] + this.formattedMemory = {} this.storageChanges = [] this.sstore = {} // all sstore occurence in the trace } @@ -53,6 +55,10 @@ export class TraceCache { this.memoryChanges.push(value) } + setFormattedMemory (stepIndex, memory) { + this.formattedMemory[stepIndex] = memory + } + // outOfGas has been removed because gas left logging is apparently made differently // in the vm/geth/eth. TODO add the error property (with about the error in all clients) pushCall (step, index, address, callStack, reverted) { diff --git a/libs/remix-debug/src/trace/traceManager.ts b/libs/remix-debug/src/trace/traceManager.ts index 408bfd8ceb..82f0716b66 100644 --- a/libs/remix-debug/src/trace/traceManager.ts +++ b/libs/remix-debug/src/trace/traceManager.ts @@ -190,13 +190,21 @@ export class TraceManager { return this.traceCache.contractCreation[token] } - getMemoryAt (stepIndex) { + getMemoryAt (stepIndex, format = true) { this.checkRequestedStep(stepIndex) const lastChanges = util.findLowerBoundValue(stepIndex, this.traceCache.memoryChanges) if (lastChanges === null) { throw new Error('no memory found') } - return this.trace[lastChanges].memory + if (!format) { + return this.trace[lastChanges].memory + } + if (this.traceCache.formattedMemory[lastChanges]) { + return this.traceCache.formattedMemory[lastChanges] + } + const memory = util.formatMemory(this.trace[lastChanges].memory) + this.traceCache.setFormattedMemory(lastChanges, memory) + return memory } getCurrentPC (stepIndex) { diff --git a/libs/remix-debug/test/traceManager.ts b/libs/remix-debug/test/traceManager.ts index 3269bceb4a..8128e21ac8 100644 --- a/libs/remix-debug/test/traceManager.ts +++ b/libs/remix-debug/test/traceManager.ts @@ -164,7 +164,7 @@ tape('TraceManager', function (t) { t.test('TraceManager.getMemoryAt', function (st) { st.plan(3) try { - const result = traceManager.getMemoryAt(0) + const result = traceManager.getMemoryAt(0, false) console.log(result) st.ok(result.length === 0) } catch (error) { @@ -172,7 +172,7 @@ tape('TraceManager', function (t) { } try { - const result = traceManager.getMemoryAt(34) + const result = traceManager.getMemoryAt(34, false) console.log(result) st.ok(result.length === 3) st.ok(result[2] === '0000000000000000000000000000000000000000000000000000000000000060') diff --git a/libs/remix-lib/src/execution/txRunnerWeb3.ts b/libs/remix-lib/src/execution/txRunnerWeb3.ts index 465960a753..4319b8be92 100644 --- a/libs/remix-lib/src/execution/txRunnerWeb3.ts +++ b/libs/remix-lib/src/execution/txRunnerWeb3.ts @@ -61,7 +61,7 @@ export class TxRunnerWeb3 { tx = await tryTillTxAvailable(resp, this.getWeb3()) currentDateTime = new Date(); const end = currentDateTime.getTime() / 1000 - console.log('stopwatch', end - start) + console.log('tx duration', end - start) resolve({ receipt, tx, diff --git a/libs/remix-simulator/src/VmProxy.ts b/libs/remix-simulator/src/VmProxy.ts index afd840147c..a7c6ae323a 100644 --- a/libs/remix-simulator/src/VmProxy.ts +++ b/libs/remix-simulator/src/VmProxy.ts @@ -43,7 +43,9 @@ export class VmProxy { txsMapBlock blocks stateCopy: StateManager - + flagDoNotRecordEVMSteps: boolean + lastMemoryUpdate: Array + constructor (vmContext: VMContext) { this.vmContext = vmContext this.stateCopy @@ -85,6 +87,7 @@ export class VmProxy { this.utils = utils this.txsMapBlock = {} this.blocks = {} + this.lastMemoryUpdate = [] } setVM (vm) { @@ -109,7 +112,13 @@ export class VmProxy { return ret } + flagNextAsDoNotRecordEvmSteps () { + this.flagDoNotRecordEVMSteps = true + } + async txWillProcess (data: TypedTransaction) { + if (this.flagDoNotRecordEVMSteps) return + this.lastMemoryUpdate = [] this.stateCopy = await this.vm.stateManager.copy() this.incr++ this.processingHash = bufferToHex(data.hash()) @@ -142,12 +151,16 @@ export class VmProxy { } catch (e) { console.log(e) } - })(this.processingHash, data.to, tx['to'], this) + })(this.processingHash, data.to, tx['to'], this) } this.processingIndex = 0 } async txProcessed (data: AfterTxEvent) { + if (this.flagDoNotRecordEVMSteps) { + this.flagDoNotRecordEVMSteps = false + return + } const lastOp = this.vmTraces[this.processingHash].structLogs[this.processingIndex - 1] if (lastOp) { lastOp.error = lastOp.op !== 'RETURN' && lastOp.op !== 'STOP' && lastOp.op !== 'DESTRUCT' @@ -181,9 +194,15 @@ export class VmProxy { const to = this.txs[this.processingHash].to if (to) { try { - const account = Address.fromString(to) - const storage = await this.vm.stateManager.dumpStorage(account) - this.storageCache['after_' + this.processingHash][to] = storage + await (async (processingHash, processingAddress, self) => { + try { + const account = Address.fromString(processingAddress) + const storage = await self.vm.stateManager.dumpStorage(account) + self.storageCache['after_' + processingHash][processingAddress] = storage + } catch (e) { + console.log(e) + } + })(this.processingHash, to, this) } catch (e) { console.log(e) } @@ -191,8 +210,9 @@ export class VmProxy { if (data.createdAddress) { const address = data.createdAddress.toString() - this.vmTraces[this.processingHash].return = toChecksumAddress(address) - this.txsReceipt[this.processingHash].contractAddress = toChecksumAddress(address) + const checksumedAddress = toChecksumAddress(address) + this.vmTraces[this.processingHash].return = checksumedAddress + this.txsReceipt[this.processingHash].contractAddress = checksumedAddress } else if (data.execResult.returnValue) { this.vmTraces[this.processingHash].return = '0x' + data.execResult.returnValue.toString('hex') } else { @@ -205,6 +225,7 @@ export class VmProxy { } async pushTrace (data: InterpreterStep) { + if (this.flagDoNotRecordEVMSteps) return try { const depth = data.depth + 1 // geth starts the depth from 1 if (!this.processingHash) { @@ -220,21 +241,27 @@ export class VmProxy { } const step = { stack: hexListFromBNs(data.stack), - memory: formatMemory(data.memory), storage: {}, + memory: null, op: data.opcode.name, pc: data.pc, gasCost: data.opcode.fee.toString(), gas: data.gasLeft.toString(), depth: depth } + + if (previousOpcode && (previousOpcode.op === 'CALLDATACOPY' || previousOpcode.op === 'CODECOPY' || previousOpcode.op === 'EXTCODECOPY' || previousOpcode.op === 'RETURNDATACOPY' || previousOpcode.op === 'MSTORE' || previousOpcode.op === 'MSTORE8')) { + step.memory = data.memory + this.lastMemoryUpdate = step.memory + } 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 memory = formatMemory(data.memory) + const memoryStr = memory.join('') + let payload = memoryStr.substring(payloadStart * 2, memoryStr.length) const fnselectorStr = payload.substring(0, 8) const fnselectorStrInHex = '0x' + fnselectorStr const fnselector = parseInt(fnselectorStrInHex) @@ -279,7 +306,7 @@ export class VmProxy { } } if (previousOpcode && previousOpcode.op === 'SHA3') { - const preimage = this.getSha3Input(previousOpcode.stack, previousOpcode.memory) + const preimage = this.getSha3Input(previousOpcode.stack, formatMemory(this.lastMemoryUpdate)) const imageHash = step.stack[step.stack.length - 1].replace('0x', '') this.sha3Preimages[imageHash] = { preimage: preimage diff --git a/libs/remix-simulator/src/methods/transactions.ts b/libs/remix-simulator/src/methods/transactions.ts index 28cedbedf4..7dc4dd5dc7 100644 --- a/libs/remix-simulator/src/methods/transactions.ts +++ b/libs/remix-simulator/src/methods/transactions.ts @@ -155,6 +155,7 @@ export class Transactions { payload.params[0].gas = 10000000 * 10 + this.vmContext.web3().flagNextAsDoNotRecordEvmSteps() processTx(this.txRunnerInstance, payload, true, (error, value: VMexecutionResult) => { const result: RunTxResult = value.result if (error) return cb(error) diff --git a/libs/remix-simulator/src/vm-context.ts b/libs/remix-simulator/src/vm-context.ts index a10e32b0bb..a07a4c25c0 100644 --- a/libs/remix-simulator/src/vm-context.ts +++ b/libs/remix-simulator/src/vm-context.ts @@ -79,21 +79,6 @@ class StateManagerCommonStorageDump extends DefaultStateManager { }) }) } - - async setStateRoot (stateRoot) { - await this._cache.flush() - - if (!stateRoot.equals(this._trie.EMPTY_TRIE_ROOT)) { - const hasRoot = await this._trie.checkRoot(stateRoot) - if (!hasRoot) { - throw new Error('State trie does not contain state root') - } - } - - this._trie.root = stateRoot - this._cache.clear() - this._storageTries = {} - } } export type CurrentVm = {