diff --git a/libs/remix-debug/src/Ethdebugger.js b/libs/remix-debug/src/Ethdebugger.js index 2cebaeb149..a2b61fd8f5 100644 --- a/libs/remix-debug/src/Ethdebugger.js +++ b/libs/remix-debug/src/Ethdebugger.js @@ -1,20 +1,16 @@ 'use strict' -const StorageViewer = require('./storage/storageViewer') -const StorageResolver = require('./storage/storageResolver') - -const SolidityDecoder = require('./solidity-decoder') -const SolidityProxy = SolidityDecoder.SolidityProxy -const stateDecoder = SolidityDecoder.stateDecoder -const localDecoder = SolidityDecoder.localDecoder -const InternalCallTree = SolidityDecoder.InternalCallTree - const remixLib = require('@remix-project/remix-lib') const TraceManager = remixLib.trace.TraceManager const CodeManager = remixLib.code.CodeManager const traceHelper = remixLib.helpers.trace const EventManager = remixLib.EventManager +const {SolidityProxy, stateDecoder, localDecoder, InternalCallTree} = require('./solidity-decoder') + +const StorageViewer = require('./storage/storageViewer') +const StorageResolver = require('./storage/storageResolver') + /** * Ethdebugger is a wrapper around a few classes that helps debugging a transaction * @@ -58,23 +54,15 @@ Ethdebugger.prototype.resolveStep = function (index) { } Ethdebugger.prototype.setCompilationResult = function (compilationResult) { - if (compilationResult && compilationResult.data) { - this.solidityProxy.reset(compilationResult.data) - } else { - this.solidityProxy.reset({}) - } + this.solidityProxy.reset((compilationResult && compilationResult.data) || {}) } -Ethdebugger.prototype.sourceLocationFromVMTraceIndex = function (address, stepIndex, callback) { - this.callTree.sourceLocationTracker.getSourceLocationFromVMTraceIndex(address, stepIndex, this.solidityProxy.contracts).then((rawLocation) => { - callback(null, rawLocation) - }).catch(callback) +Ethdebugger.prototype.sourceLocationFromVMTraceIndex = async function (address, stepIndex) { + return this.callTree.sourceLocationTracker.getSourceLocationFromVMTraceIndex(address, stepIndex, this.solidityProxy.contracts) } -Ethdebugger.prototype.sourceLocationFromInstructionIndex = function (address, instIndex, callback) { - this.callTree.sourceLocationTracker.getSourceLocationFromInstructionIndex(address, instIndex, this.solidityProxy.contracts).then((rawLocation) => { - callback(null, rawLocation) - }).catch(callback) +Ethdebugger.prototype.sourceLocationFromInstructionIndex = async function (address, instIndex, callback) { + return this.callTree.sourceLocationTracker.getSourceLocationFromInstructionIndex(address, instIndex, this.solidityProxy.contracts) } /* breakpoint */ @@ -83,98 +71,48 @@ Ethdebugger.prototype.setBreakpointManager = function (breakpointManager) { } /* decode locals */ -Ethdebugger.prototype.extractLocalsAt = function (step, callback) { - callback(null, this.callTree.findScope(step)) +Ethdebugger.prototype.extractLocalsAt = function (step) { + return this.callTree.findScope(step) } -Ethdebugger.prototype.decodeLocalsAt = function (step, sourceLocation, callback) { - const self = this - this.traceManager.waterfall([ - function getStackAt (stepIndex, callback) { - try { - const result = self.traceManager.getStackAt(stepIndex) - callback(null, result) - } catch (error) { - callback(error) - } - }, - function getMemoryAt (stepIndex, callback) { - try { - const result = self.traceManager.getMemoryAt(stepIndex) - callback(null, result) - } catch (error) { - callback(error) - } - }, - - function getCurrentCalledAddressAt (stepIndex, next) { - try { - const address = self.traceManager.getCurrentCalledAddressAt(stepIndex) - next(null, address) - } catch (error) { - next(error) - } - }], - step, - (error, result) => { - if (!error) { - const stack = result[0].value - const memory = result[1].value - try { - const storageViewer = new StorageViewer({ - stepIndex: step, - tx: this.tx, - address: result[2].value - }, this.storageResolver, this.traceManager) - localDecoder.solidityLocals(step, this.callTree, stack, memory, storageViewer, sourceLocation).then((locals) => { - if (!locals.error) { - callback(null, locals) - } else { - callback(locals.error) - } - }) - } catch (e) { - callback(e.message) - } - } else { - callback(error) +Ethdebugger.prototype.decodeLocalsAt = async function (step, sourceLocation, callback) { + try { + const stack = this.traceManager.getStackAt(step) + const memory = this.traceManager.getMemoryAt(step) + const address = this.traceManager.getCurrentCalledAddressAt(step) + try { + const storageViewer = new StorageViewer({ stepIndex: step, tx: this.tx, address: address }, this.storageResolver, this.traceManager) + const locals = await localDecoder.solidityLocals(step, this.callTree, stack, memory, storageViewer, sourceLocation) + if (locals.error) { + return callback(locals.error) } - }) + return callback(null, locals) + } catch (e) { + callback(e.message) + } + } catch (error) { + callback(error) + } } /* decode state */ -Ethdebugger.prototype.extractStateAt = function (step, callback) { - this.solidityProxy.extractStateVariablesAt(step).then((stateVars) => { - callback(null, stateVars) - }).catch(callback) +Ethdebugger.prototype.extractStateAt = async function (step) { + return this.solidityProxy.extractStateVariablesAt(step) } -Ethdebugger.prototype.decodeStateAt = function (step, stateVars, callback) { +Ethdebugger.prototype.decodeStateAt = async function (step, stateVars, callback) { try { const address = this.traceManager.getCurrentCalledAddressAt(step) - const storageViewer = new StorageViewer({ - stepIndex: step, - tx: this.tx, - address: address - }, this.storageResolver, this.traceManager) - stateDecoder.decodeState(stateVars, storageViewer).then((result) => { - if (!result.error) { - callback(null, result) - } else { - callback(result.error) - } - }) + const storageViewer = new StorageViewer({stepIndex: step, tx: this.tx, address: address}, this.storageResolver, this.traceManager) + const result = await stateDecoder.decodeState(stateVars, storageViewer) + return result } catch (error) { callback(error) } } Ethdebugger.prototype.storageViewAt = function (step, address) { - return new StorageViewer({ - stepIndex: step, - tx: this.tx, - address: address - }, this.storageResolver, this.traceManager) + return new StorageViewer({stepIndex: step, tx: this.tx, address: address}, this.storageResolver, this.traceManager) } Ethdebugger.prototype.updateWeb3 = function (web3) { @@ -192,21 +130,18 @@ Ethdebugger.prototype.debug = function (tx) { if (this.traceManager.isLoading) { return } - if (!tx.to) { - tx.to = traceHelper.contractCreationToken('0') - } + tx.to = tx.to || traceHelper.contractCreationToken('0') this.tx = tx - this.traceManager.resolveTrace(tx, async (error, result) => { - if (result) { - this.setCompilationResult(await this.compilationResult(tx.to)) - this.event.trigger('newTraceLoaded', [this.traceManager.trace]) - if (this.breakpointManager && this.breakpointManager.hasBreakpoint()) { - this.breakpointManager.jumpNextBreakpoint(false) - } - this.storageResolver = new StorageResolver({web3: this.traceManager.web3}) - } else { - this.statusMessage = error ? error.message : 'Trace not loaded' + + this.traceManager.resolveTrace(tx).then(async (result) => { + this.setCompilationResult(await this.compilationResult(tx.to)) + this.event.trigger('newTraceLoaded', [this.traceManager.trace]) + if (this.breakpointManager && this.breakpointManager.hasBreakpoint()) { + this.breakpointManager.jumpNextBreakpoint(false) } + this.storageResolver = new StorageResolver({web3: this.traceManager.web3}) + }).catch((error) => { + this.statusMessage = error ? error.message : 'Trace not loaded' }) } diff --git a/libs/remix-debug/src/solidity-decoder/internalCallTree.js b/libs/remix-debug/src/solidity-decoder/internalCallTree.js index b9c6872b45..56d41d4faa 100644 --- a/libs/remix-debug/src/solidity-decoder/internalCallTree.js +++ b/libs/remix-debug/src/solidity-decoder/internalCallTree.js @@ -124,23 +124,15 @@ class InternalCallTree { return functions } - extractSourceLocation (step) { - return new Promise((resolve, reject) => { - try { - const address = this.traceManager.getCurrentCalledAddressAt(step) - try { - this.sourceLocationTracker.getSourceLocationFromVMTraceIndex(address, step, this.solidityProxy.contracts).then(resolve).catch((error) => { - return reject('InternalCallTree - Cannot retrieve sourcelocation for step ' + step + ' ' + error) - }) - } catch (error) { - return reject('InternalCallTree - Cannot retrieve address for step ' + step + ' ' + error) - } - } catch (error) { - return reject('InternalCallTree - Cannot retrieve address for step ' + step + ' ' + error) - } - }) + async extractSourceLocation (step) { + try { + const address = this.traceManager.getCurrentCalledAddressAt(step) + const location = await this.sourceLocationTracker.getSourceLocationFromVMTraceIndex(address, step, this.solidityProxy.contracts) + return location + } catch (error) { + throw new Error('InternalCallTree - Cannot retrieve sourcelocation for step ' + step + ' ' + error) + } } - } async function buildTree (tree, step, scopeId, isExternalCall) { diff --git a/libs/remix-debug/src/solidity-decoder/solidityProxy.js b/libs/remix-debug/src/solidity-decoder/solidityProxy.js index ee3fd5beac..e4f10a53e6 100644 --- a/libs/remix-debug/src/solidity-decoder/solidityProxy.js +++ b/libs/remix-debug/src/solidity-decoder/solidityProxy.js @@ -39,25 +39,15 @@ class SolidityProxy { * @param {Int} vmTraceIndex - index in the vm trave where to resolve the executed contract name * @param {Function} cb - callback returns (error, contractName) */ - contractNameAt (vmTraceIndex) { - return new Promise((resolve, reject) => { - try { - const address = this.traceManager.getCurrentCalledAddressAt(vmTraceIndex) - if (this.cache.contractNameByAddress[address]) { - return resolve(this.cache.contractNameByAddress[address]) - } - this.codeManager.getCode(address, (error, code) => { - if (error) { - return reject(error) - } - const contractName = contractNameFromCode(this.contracts, code.bytecode, address) - this.cache.contractNameByAddress[address] = contractName - resolve(contractName) - }) - } catch (error) { - reject(error) - } - }) + async contractNameAt (vmTraceIndex) { + const address = this.traceManager.getCurrentCalledAddressAt(vmTraceIndex) + if (this.cache.contractNameByAddress[address]) { + return this.cache.contractNameByAddress[address] + } + const code = await this.codeManager.getCode(address) + const contractName = contractNameFromCode(this.contracts, code.bytecode, address) + this.cache.contractNameByAddress[address] = contractName + return contractName } /** @@ -95,12 +85,9 @@ class SolidityProxy { * @param {Int} vmTraceIndex - index in the vm trave where to resolve the state variables * @return {Object} - returns state variables of @args vmTraceIndex */ - extractStateVariablesAt (vmtraceIndex) { - return new Promise((resolve, reject) => { - this.contractNameAt(vmtraceIndex).then((contractName) => { - resolve(this.extractStateVariables(contractName)) - }).catch(reject) - }) + async extractStateVariablesAt (vmtraceIndex) { + const contractName = await this.contractNameAt(vmtraceIndex) + return this.extractStateVariables(contractName) } /** @@ -113,10 +100,8 @@ class SolidityProxy { const file = this.fileNameFromIndex(sourceLocation.file) if (this.sources[file]) { return this.sources[file].legacyAST - } else { - // console.log('AST not found for file id ' + sourceLocation.file) - return null } + return null } /** diff --git a/libs/remix-debug/src/storage/storageResolver.js b/libs/remix-debug/src/storage/storageResolver.js index 0de8fbd161..8186e87368 100644 --- a/libs/remix-debug/src/storage/storageResolver.js +++ b/libs/remix-debug/src/storage/storageResolver.js @@ -39,17 +39,14 @@ class StorageResolver { * @param {Array} corrections - used in case the calculated sha3 has been modifyed before SSTORE (notably used for struct in mapping). * @return {Function} - callback */ - initialPreimagesMappings (tx, stepIndex, address, corrections) { - return new Promise((resolve, reject) => { - if (this.preimagesMappingByAddress[address]) { - return resolve(this.preimagesMappingByAddress[address]) - } - this.storageRange(tx, stepIndex, address).then((storage) => { - const mappings = mappingPreimages.decodeMappingsKeys(this.web3, storage, corrections) - this.preimagesMappingByAddress[address] = mappings - resolve(mappings) - }).catch(reject) - }) + async initialPreimagesMappings (tx, stepIndex, address, corrections) { + if (this.preimagesMappingByAddress[address]) { + return this.preimagesMappingByAddress[address] + } + const storage = await this.storageRange(tx, stepIndex, address) + const mappings = mappingPreimages.decodeMappingsKeys(this.web3, storage, corrections) + this.preimagesMappingByAddress[address] = mappings + return mappings } /** @@ -61,12 +58,9 @@ class StorageResolver { * @param {String} - address - lookup address * @param {Function} - callback - {key, hashedKey, value} - */ - storageSlot (slot, tx, stepIndex, address) { - return new Promise((resolve, reject) => { - this.storageRangeInternal(this, slot, tx, stepIndex, address).then((storage) => { - resolve(storage[slot] !== undefined ? storage[slot] : null) - }).catch(reject) - }) + async storageSlot (slot, tx, stepIndex, address) { + const storage = await this.storageRangeInternal(this, slot, tx, stepIndex, address) + return (storage[slot] !== undefined ? storage[slot] : null) } /** @@ -85,27 +79,21 @@ class StorageResolver { * even if the next 1000 items are not in the cache. * - If @arg slot is not cached, the corresponding value will be resolved and the next 1000 slots. */ - storageRangeInternal (self, slotKey, tx, stepIndex, address) { - return new Promise((resolve, reject) => { - var cached = this.fromCache(self, address) - if (cached && cached.storage[slotKey]) { // we have the current slot in the cache and maybe the next 1000... - return resolve(cached.storage) - } - this.storageRangeWeb3Call(tx, address, slotKey, self.maxSize).then((result) => { - const [storage, nextKey] = result - if (!storage[slotKey] && slotKey !== self.zeroSlot) { // we don't cache the zero slot (could lead to inconsistency) - storage[slotKey] = { - key: slotKey, - value: self.zeroSlot - } - } - self.toCache(self, address, storage) - if (slotKey === self.zeroSlot && !nextKey) { // only working if keys are sorted !! - self.storageByAddress[address].complete = true - } - return resolve(storage) - }).catch(reject) - }) + async storageRangeInternal (self, slotKey, tx, stepIndex, address) { + var cached = this.fromCache(self, address) + if (cached && cached.storage[slotKey]) { // we have the current slot in the cache and maybe the next 1000... + return cached.storage + } + const result = await this.storageRangeWeb3Call(tx, address, slotKey, self.maxSize) + const [storage, nextKey] = result + if (!storage[slotKey] && slotKey !== self.zeroSlot) { // we don't cache the zero slot (could lead to inconsistency) + storage[slotKey] = {key: slotKey, value: self.zeroSlot} + } + self.toCache(self, address, storage) + if (slotKey === self.zeroSlot && !nextKey) { // only working if keys are sorted !! + self.storageByAddress[address].complete = true + } + return storage } /** diff --git a/libs/remix-debug/src/storage/storageViewer.js b/libs/remix-debug/src/storage/storageViewer.js index 206701a637..0661dd3f9c 100644 --- a/libs/remix-debug/src/storage/storageViewer.js +++ b/libs/remix-debug/src/storage/storageViewer.js @@ -77,13 +77,8 @@ class StorageViewer { async mappingsLocation (corrections) { if (!this.currentMappingsLocationPromise) { this.currentMappingsLocationPromise = new Promise((resolve, reject) => { - this.extractMappingsLocationChanges(this.storageChanges, corrections, (error, mappingsLocationChanges) => { - if (error) { - reject(error) - } else { - resolve(mappingsLocationChanges) - } - }) + const mappingsLocationChanges = this.extractMappingsLocationChanges(this.storageChanges, corrections) + return resolve(mappingsLocationChanges) }) } return this.currentMappingsLocationPromise @@ -94,13 +89,13 @@ class StorageViewer { * @param {Map} storageChanges * @param {Array} corrections - used in case the calculated sha3 has been modifyed before SSTORE (notably used for struct in mapping). */ - extractMappingsLocationChanges (storageChanges, corrections, callback) { + extractMappingsLocationChanges (storageChanges, corrections) { if (this.mappingsLocationChanges) { - return callback(null, this.mappingsLocationChanges) + return this.mappingsLocationChanges } const mappings = mappingPreimages.decodeMappingsKeys(this.web3, storageChanges, corrections) this.mappingsLocationChanges = mappings - return callback(null, this.mappingsLocationChanges) + return this.mappingsLocationChanges } } diff --git a/libs/remix-debug/test/debugger.js b/libs/remix-debug/test/debugger.js index 81a800ee09..5526e03f3e 100644 --- a/libs/remix-debug/test/debugger.js +++ b/libs/remix-debug/test/debugger.js @@ -235,37 +235,34 @@ function testDebugging (debugManager) { } }) - tape('traceManager.decodeStateAt', (t) => { + tape('traceManager.decodeStateAt', async (t) => { t.plan(7) - debugManager.extractStateAt(312, (error, state) => { + try { + const state = await debugManager.extractStateAt(312) + const decodedState = await debugManager.decodeStateAt(312, state) + console.log(decodedState) + t.equal(decodedState['chairperson'].value, '0x4B0897B0513FDC7C541B6D9D7E929C4E5364D2DB') + t.equal(decodedState['chairperson'].type, 'address') + t.equal(decodedState['proposals'].value[0].value.voteCount.value, '0') + t.equal(decodedState['proposals'].value[0].value.voteCount.type, 'uint256') + t.equal(decodedState['proposals'].value[0].type, 'struct Ballot.Proposal') + t.equal(decodedState['proposals'].length, '0x1') + t.equal(decodedState['proposals'].type, 'struct Ballot.Proposal[]') + } catch (error) { if (error) return t.end(error) - debugManager.decodeStateAt(312, state, (error, decodedState) => { - if (error) return t.end(error) - console.log(decodedState) - t.equal(decodedState['chairperson'].value, '0x4B0897B0513FDC7C541B6D9D7E929C4E5364D2DB') - t.equal(decodedState['chairperson'].type, 'address') - t.equal(decodedState['proposals'].value[0].value.voteCount.value, '0') - t.equal(decodedState['proposals'].value[0].value.voteCount.type, 'uint256') - t.equal(decodedState['proposals'].value[0].type, 'struct Ballot.Proposal') - t.equal(decodedState['proposals'].length, '0x1') - t.equal(decodedState['proposals'].type, 'struct Ballot.Proposal[]') - }) - }) + } }) - tape('traceManager.decodeLocalsAt', (t) => { + tape('traceManager.decodeLocalsAt', async (t) => { t.plan(1) const tested = JSON.parse('{"proposalNames":{"value":[{"value":"0x48656C6C6F20576F726C64210000000000000000000000000000000000000000","type":"bytes32"}],"length":"0x1","type":"bytes32[]"},"p":{"value":"45","type":"uint256"},"addressLocal":{"value":"0x4B0897B0513FDC7C541B6D9D7E929C4E5364D2DB","type":"address"},"i":{"value":"2","type":"uint256"},"proposalsLocals":{"value":[{"value":{"name":{"value":"0x48656C6C6F20576F726C64210000000000000000000000000000000000000000","type":"bytes32"},"voteCount":{"value":"0","type":"uint256"}},"type":"struct Ballot.Proposal"}],"length":"0x1","type":"struct Ballot.Proposal[]"}}') try { const address = debugManager.traceManager.getCurrentCalledAddressAt(330) - debugManager.sourceLocationFromVMTraceIndex(address, 330, (error, location) => { + const location = await debugManager.sourceLocationFromVMTraceIndex(address, 330) + debugManager.decodeLocalsAt(330, location, (error, decodedlocals) => { if (error) return t.end(error) - debugManager.decodeLocalsAt(330, location, (error, decodedlocals) => { - if (error) return t.end(error) - t.equal(JSON.stringify(decodedlocals), JSON.stringify(tested)) - }) + t.equal(JSON.stringify(decodedlocals), JSON.stringify(tested)) }) - // }) } catch (error) { return t.end(error) } diff --git a/libs/remix-debug/test/decoder/localsTests/int.js b/libs/remix-debug/test/decoder/localsTests/int.js index dc1cd74375..2e7f5036e3 100644 --- a/libs/remix-debug/test/decoder/localsTests/int.js +++ b/libs/remix-debug/test/decoder/localsTests/int.js @@ -119,12 +119,10 @@ module.exports = function (st, vm, privateKey, contractBytecode, compilationResu cb() }) }) - traceManager.resolveTrace(tx, (error, result) => { - if (error) { - st.fail(error) - } else { - debuggerEvent.trigger('newTraceLoaded', [traceManager.trace]) - } + traceManager.resolveTrace(tx).then(() => { + debuggerEvent.trigger('newTraceLoaded', [traceManager.trace]) + }).catch((error) => { + st.fail(error) }) } }) diff --git a/libs/remix-debug/test/decoder/localsTests/misc.js b/libs/remix-debug/test/decoder/localsTests/misc.js index 48c727689a..be40d3de6e 100644 --- a/libs/remix-debug/test/decoder/localsTests/misc.js +++ b/libs/remix-debug/test/decoder/localsTests/misc.js @@ -65,12 +65,10 @@ module.exports = function (st, vm, privateKey, contractBytecode, compilationResu cb() }) }) - traceManager.resolveTrace(tx, (error, result) => { - if (error) { - st.fail(error) - } else { - debuggerEvent.trigger('newTraceLoaded', [traceManager.trace]) - } + traceManager.resolveTrace(tx).then(() => { + debuggerEvent.trigger('newTraceLoaded', [traceManager.trace]) + }).catch((error) => { + st.fail(error) }) } }) diff --git a/libs/remix-debug/test/decoder/localsTests/misc2.js b/libs/remix-debug/test/decoder/localsTests/misc2.js index e9ca0a4d74..3bdff3a259 100644 --- a/libs/remix-debug/test/decoder/localsTests/misc2.js +++ b/libs/remix-debug/test/decoder/localsTests/misc2.js @@ -51,12 +51,10 @@ module.exports = function (st, vm, privateKey, contractBytecode, compilationResu cb() }) }) - traceManager.resolveTrace(tx, (error, result) => { - if (error) { - st.fail(error) - } else { - debuggerEvent.trigger('newTraceLoaded', [traceManager.trace]) - } + traceManager.resolveTrace(tx).then(() => { + debuggerEvent.trigger('newTraceLoaded', [traceManager.trace]) + }).catch((error) => { + st.fail(error) }) } }) diff --git a/libs/remix-debug/test/decoder/localsTests/structArray.js b/libs/remix-debug/test/decoder/localsTests/structArray.js index c424727138..16235d9453 100644 --- a/libs/remix-debug/test/decoder/localsTests/structArray.js +++ b/libs/remix-debug/test/decoder/localsTests/structArray.js @@ -109,12 +109,10 @@ module.exports = function (st, vm, privateKey, contractBytecode, compilationResu cb() }) }) - traceManager.resolveTrace(tx, (error, result) => { - if (error) { - st.fail(error) - } else { - debuggerEvent.trigger('newTraceLoaded', [traceManager.trace]) - } + traceManager.resolveTrace(tx).then(() => { + debuggerEvent.trigger('newTraceLoaded', [traceManager.trace]) + }).catch((error) => { + st.fail(error) }) } }) diff --git a/libs/remix-debug/test/decoder/stateTests/mapping.js b/libs/remix-debug/test/decoder/stateTests/mapping.js index 97520367df..2fa355f7f8 100644 --- a/libs/remix-debug/test/decoder/stateTests/mapping.js +++ b/libs/remix-debug/test/decoder/stateTests/mapping.js @@ -46,7 +46,8 @@ function testMapping (st, vm, privateKey, contractAddress, output, cb) { st.end(error) } else { var traceManager = new TraceManager({web3: vm.web3}) - traceManager.resolveTrace(tx, () => { + + traceManager.resolveTrace(tx).then(() => { var storageViewer = new StorageViewer({ stepIndex: 268, tx: tx, diff --git a/libs/remix-lib/src/code/codeManager.js b/libs/remix-lib/src/code/codeManager.js index d665192a28..3f4df37b6f 100644 --- a/libs/remix-lib/src/code/codeManager.js +++ b/libs/remix-lib/src/code/codeManager.js @@ -53,19 +53,18 @@ CodeManager.prototype.resolveStep = function (stepIndex, tx) { * @param {String} address - address of the contract to get the code from * @param {Function} cb - callback function, return the bytecode */ -CodeManager.prototype.getCode = function (address, cb) { +CodeManager.prototype.getCode = async function (address) { if (!traceHelper.isContractCreation(address)) { - return this.codeResolver.resolveCode(address).then((code) => { - cb(null, code) - }) + const code = await this.codeResolver.resolveCode(address) + return code } var codes = this.codeResolver.getExecutingCodeFromCache(address) if (codes) { - return cb(null, codes) + return codes } const hexCode = this.traceManager.getContractCreationCode(address) codes = this.codeResolver.cacheExecutingCode(address, hexCode) - cb(null, codes) + return codes } /** @@ -94,14 +93,14 @@ CodeManager.prototype.getFunctionFromStep = function (stepIndex, sourceMap, ast) * @param {String} step - vm trace step * @param {Function} callback - instruction index */ -CodeManager.prototype.getInstructionIndex = function (address, step, callback) { +CodeManager.prototype.getInstructionIndex = function (address, step) { try { const pc = this.traceManager.getCurrentPC(step) const itemIndex = this.codeResolver.getInstructionIndex(address, pc) - callback(null, itemIndex) + return itemIndex } catch (error) { console.log(error) - return callback('Cannot retrieve current PC for ' + step, null) + throw new Error('Cannot retrieve current PC for ' + step) } } @@ -120,21 +119,21 @@ CodeManager.prototype.getFunctionFromPC = function (address, pc, sourceMap, ast) } function retrieveCodeAndTrigger (codeMananger, address, stepIndex, tx) { - codeMananger.getCode(address, (error, result) => { - if (error) { - return console.log(error) - } + codeMananger.getCode(address).then((result) => { retrieveIndexAndTrigger(codeMananger, address, stepIndex, result.instructions) + }).catch((error) => { + return console.log(error) }) } function retrieveIndexAndTrigger (codeMananger, address, step, code) { - codeMananger.getInstructionIndex(address, step, (error, result) => { - if (error) { - return console.log(error) - } - codeMananger.event.trigger('changed', [code, address, result]) - }) + let result + try { + result = codeMananger.getInstructionIndex(address, step) + } catch (error) { + return console.log(error) + } + codeMananger.event.trigger('changed', [code, address, result]) } module.exports = CodeManager diff --git a/libs/remix-lib/src/sourceLocationTracker.js b/libs/remix-lib/src/sourceLocationTracker.js index 79c5a82357..2ce73865c2 100644 --- a/libs/remix-lib/src/sourceLocationTracker.js +++ b/libs/remix-lib/src/sourceLocationTracker.js @@ -22,12 +22,9 @@ function SourceLocationTracker (_codeManager) { * @param {Object} contractDetails - AST of compiled contracts * @param {Function} cb - callback function */ -SourceLocationTracker.prototype.getSourceLocationFromInstructionIndex = function (address, index, contracts) { - return new Promise((resolve, reject) => { - extractSourceMap(this, this.codeManager, address, contracts).then((sourceMap) => { - resolve(this.sourceMappingDecoder.atIndex(index, sourceMap)) - }).catch(reject) - }) +SourceLocationTracker.prototype.getSourceLocationFromInstructionIndex = async function (address, index, contracts) { + const sourceMap = await extractSourceMap(this, this.codeManager, address, contracts) + return this.sourceMappingDecoder.atIndex(index, sourceMap) } /** @@ -38,18 +35,10 @@ SourceLocationTracker.prototype.getSourceLocationFromInstructionIndex = function * @param {Object} contractDetails - AST of compiled contracts * @param {Function} cb - callback function */ -SourceLocationTracker.prototype.getSourceLocationFromVMTraceIndex = function (address, vmtraceStepIndex, contracts) { - return new Promise((resolve, reject) => { - extractSourceMap(this, this.codeManager, address, contracts).then((sourceMap) => { - this.codeManager.getInstructionIndex(address, vmtraceStepIndex, (error, index) => { - if (error) { - reject(error) - } else { - resolve(this.sourceMappingDecoder.atIndex(index, sourceMap)) - } - }) - }).catch(reject) - }) +SourceLocationTracker.prototype.getSourceLocationFromVMTraceIndex = async function (address, vmtraceStepIndex, contracts) { + const sourceMap = await extractSourceMap(this, this.codeManager, address, contracts) + const index = this.codeManager.getInstructionIndex(address, vmtraceStepIndex) + return this.sourceMappingDecoder.atIndex(index, sourceMap) } SourceLocationTracker.prototype.clearCache = function () { @@ -78,19 +67,15 @@ function extractSourceMap (self, codeManager, address, contracts) { return new Promise((resolve, reject) => { if (self.sourceMapByAddress[address]) return resolve(self.sourceMapByAddress[address]) - codeManager.getCode(address, (error, result) => { - if (!error) { - const sourceMap = getSourceMap(address, result.bytecode, contracts) - if (sourceMap) { - if (!helper.isContractCreation(address)) self.sourceMapByAddress[address] = sourceMap - resolve(sourceMap) - } else { - reject('no sourcemap associated with the code ' + address) - } + codeManager.getCode(address).then((result) => { + const sourceMap = getSourceMap(address, result.bytecode, contracts) + if (sourceMap) { + if (!helper.isContractCreation(address)) self.sourceMapByAddress[address] = sourceMap + resolve(sourceMap) } else { - reject(error) + reject('no sourcemap associated with the code ' + address) } - }) + }).catch(reject) }) } diff --git a/libs/remix-lib/src/trace/traceManager.js b/libs/remix-lib/src/trace/traceManager.js index 386ec78e25..7109c5c744 100644 --- a/libs/remix-lib/src/trace/traceManager.js +++ b/libs/remix-lib/src/trace/traceManager.js @@ -17,10 +17,10 @@ function TraceManager (options) { } // init section -TraceManager.prototype.resolveTrace = async function (tx, callback) { +TraceManager.prototype.resolveTrace = async function (tx) { this.tx = tx this.init() - if (!this.web3) callback('web3 not loaded', false) + if (!this.web3) throw new Error('web3 not loaded') this.isLoading = true try { const result = await this.getTrace(tx.hash) @@ -30,16 +30,16 @@ TraceManager.prototype.resolveTrace = async function (tx, callback) { this.traceAnalyser.analyse(result.structLogs, tx) this.isLoading = false - return callback(null, true) + return true } var mes = tx.hash + ' is not a contract invocation or contract creation.' console.log(mes) this.isLoading = false - callback(mes, false) + throw new Error(mes) } catch (error) { console.log(error) this.isLoading = false - callback(error, false) + throw new Error(error) } } diff --git a/libs/remix-lib/test/codeManager.js b/libs/remix-lib/test/codeManager.js index 52f0ea3768..5ced6c6a74 100644 --- a/libs/remix-lib/test/codeManager.js +++ b/libs/remix-lib/test/codeManager.js @@ -23,12 +23,10 @@ tape('CodeManager', function (t) { const contractCode = web3.eth.getCode('0x0d3a18d64dfe4f927832ab58d6451cecc4e517c5') codeManager.codeResolver.cacheExecutingCode('0x0d3a18d64dfe4f927832ab58d6451cecc4e517c5', contractCode) // so a call to web3 is not necessary const tx = web3.eth.getTransaction('0x20ef65b8b186ca942fcccd634f37074dde49b541c27994fc7596740ef44cfd51') - traceManager.resolveTrace(tx, function (error, result) { - if (error) { - t.fail(' - traceManager.resolveTrace - failed ' + result) - } else { - continueTesting(t, codeManager) - } + traceManager.resolveTrace(tx).then(() => { + continueTesting(t, codeManager) + }).catch(() => { + t.fail(' - traceManager.resolveTrace - failed ') }) } }) @@ -70,22 +68,20 @@ function continueTesting (t, codeManager) { t.test('CodeManager.getInstructionIndex', function (st) { st.plan(2) - codeManager.getInstructionIndex('0x0d3a18d64dfe4f927832ab58d6451cecc4e517c5', 16, function (error, result) { + try { + const result = codeManager.getInstructionIndex('0x0d3a18d64dfe4f927832ab58d6451cecc4e517c5', 16) console.log(result) - if (error) { - st.fail(error) - } else { - st.ok(result === 25) - } - }) + st.ok(result === 25) + } catch (error) { + st.fail(error) + } - codeManager.getInstructionIndex('(Contract Creation - Step 63)', 70, function (error, result) { + try { + const result = codeManager.getInstructionIndex('(Contract Creation - Step 63)', 70) console.log(result) - if (error) { - st.fail(error) - } else { - st.ok(result === 6) - } - }) + st.ok(result === 6) + } catch (error) { + st.fail(error) + } }) } diff --git a/libs/remix-lib/test/traceManager.js b/libs/remix-lib/test/traceManager.js index 83f12b31d6..ee65b82ab9 100644 --- a/libs/remix-lib/test/traceManager.js +++ b/libs/remix-lib/test/traceManager.js @@ -27,12 +27,10 @@ tape('TraceManager', function (t) { t.test('TraceManager.resolveTrace', function (st) { const tx = web3.eth.getTransaction('0x20ef65b8b186ca942fcccd634f37074dde49b541c27994fc7596740ef44cfd51') - traceManager.resolveTrace(tx, function (error, result) { - if (error) { - st.fail(' - traceManager.resolveTrace - failed ' + result) - } else { - st.end() - } + traceManager.resolveTrace(tx).then(() => { + st.end() + }).catch(() => { + st.fail(' - traceManager.resolveTrace - failed ') }) })