Unverified Commit 627bef0b authored by yann300's avatar yann300 Committed by GitHub

Merge pull request #63 from ethereum/refactor_remix_debug4

Refactor remix debug4
parents f2b46943 f8f965ec
'use strict' '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 remixLib = require('@remix-project/remix-lib')
const TraceManager = remixLib.trace.TraceManager const TraceManager = remixLib.trace.TraceManager
const CodeManager = remixLib.code.CodeManager const CodeManager = remixLib.code.CodeManager
const traceHelper = remixLib.helpers.trace const traceHelper = remixLib.helpers.trace
const EventManager = remixLib.EventManager 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 * Ethdebugger is a wrapper around a few classes that helps debugging a transaction
* *
...@@ -58,23 +54,15 @@ Ethdebugger.prototype.resolveStep = function (index) { ...@@ -58,23 +54,15 @@ Ethdebugger.prototype.resolveStep = function (index) {
} }
Ethdebugger.prototype.setCompilationResult = function (compilationResult) { Ethdebugger.prototype.setCompilationResult = function (compilationResult) {
if (compilationResult && compilationResult.data) { this.solidityProxy.reset((compilationResult && compilationResult.data) || {})
this.solidityProxy.reset(compilationResult.data)
} else {
this.solidityProxy.reset({})
}
} }
Ethdebugger.prototype.sourceLocationFromVMTraceIndex = function (address, stepIndex, callback) { Ethdebugger.prototype.sourceLocationFromVMTraceIndex = async function (address, stepIndex) {
this.callTree.sourceLocationTracker.getSourceLocationFromVMTraceIndex(address, stepIndex, this.solidityProxy.contracts).then((rawLocation) => { return this.callTree.sourceLocationTracker.getSourceLocationFromVMTraceIndex(address, stepIndex, this.solidityProxy.contracts)
callback(null, rawLocation)
}).catch(callback)
} }
Ethdebugger.prototype.sourceLocationFromInstructionIndex = function (address, instIndex, callback) { Ethdebugger.prototype.sourceLocationFromInstructionIndex = async function (address, instIndex, callback) {
this.callTree.sourceLocationTracker.getSourceLocationFromInstructionIndex(address, instIndex, this.solidityProxy.contracts).then((rawLocation) => { return this.callTree.sourceLocationTracker.getSourceLocationFromInstructionIndex(address, instIndex, this.solidityProxy.contracts)
callback(null, rawLocation)
}).catch(callback)
} }
/* breakpoint */ /* breakpoint */
...@@ -83,98 +71,48 @@ Ethdebugger.prototype.setBreakpointManager = function (breakpointManager) { ...@@ -83,98 +71,48 @@ Ethdebugger.prototype.setBreakpointManager = function (breakpointManager) {
} }
/* decode locals */ /* decode locals */
Ethdebugger.prototype.extractLocalsAt = function (step, callback) { Ethdebugger.prototype.extractLocalsAt = function (step) {
callback(null, this.callTree.findScope(step)) return this.callTree.findScope(step)
} }
Ethdebugger.prototype.decodeLocalsAt = function (step, sourceLocation, callback) { Ethdebugger.prototype.decodeLocalsAt = async function (step, sourceLocation, callback) {
const self = this try {
this.traceManager.waterfall([ const stack = this.traceManager.getStackAt(step)
function getStackAt (stepIndex, callback) { const memory = this.traceManager.getMemoryAt(step)
try { const address = this.traceManager.getCurrentCalledAddressAt(step)
const result = self.traceManager.getStackAt(stepIndex) try {
callback(null, result) const storageViewer = new StorageViewer({ stepIndex: step, tx: this.tx, address: address }, this.storageResolver, this.traceManager)
} catch (error) { const locals = await localDecoder.solidityLocals(step, this.callTree, stack, memory, storageViewer, sourceLocation)
callback(error) if (locals.error) {
} return callback(locals.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)
} }
}) return callback(null, locals)
} catch (e) {
callback(e.message)
}
} catch (error) {
callback(error)
}
} }
/* decode state */ /* decode state */
Ethdebugger.prototype.extractStateAt = function (step, callback) { Ethdebugger.prototype.extractStateAt = async function (step) {
this.solidityProxy.extractStateVariablesAt(step).then((stateVars) => { return this.solidityProxy.extractStateVariablesAt(step)
callback(null, stateVars)
}).catch(callback)
} }
Ethdebugger.prototype.decodeStateAt = function (step, stateVars, callback) { Ethdebugger.prototype.decodeStateAt = async function (step, stateVars, callback) {
try { try {
const address = this.traceManager.getCurrentCalledAddressAt(step) const address = this.traceManager.getCurrentCalledAddressAt(step)
const storageViewer = new StorageViewer({ const storageViewer = new StorageViewer({stepIndex: step, tx: this.tx, address: address}, this.storageResolver, this.traceManager)
stepIndex: step, const result = await stateDecoder.decodeState(stateVars, storageViewer)
tx: this.tx, return result
address: address
}, this.storageResolver, this.traceManager)
stateDecoder.decodeState(stateVars, storageViewer).then((result) => {
if (!result.error) {
callback(null, result)
} else {
callback(result.error)
}
})
} catch (error) { } catch (error) {
callback(error) callback(error)
} }
} }
Ethdebugger.prototype.storageViewAt = function (step, address) { Ethdebugger.prototype.storageViewAt = function (step, address) {
return new StorageViewer({ return new StorageViewer({stepIndex: step, tx: this.tx, address: address}, this.storageResolver, this.traceManager)
stepIndex: step,
tx: this.tx,
address: address
}, this.storageResolver, this.traceManager)
} }
Ethdebugger.prototype.updateWeb3 = function (web3) { Ethdebugger.prototype.updateWeb3 = function (web3) {
...@@ -192,21 +130,18 @@ Ethdebugger.prototype.debug = function (tx) { ...@@ -192,21 +130,18 @@ Ethdebugger.prototype.debug = function (tx) {
if (this.traceManager.isLoading) { if (this.traceManager.isLoading) {
return return
} }
if (!tx.to) { tx.to = tx.to || traceHelper.contractCreationToken('0')
tx.to = traceHelper.contractCreationToken('0')
}
this.tx = tx this.tx = tx
this.traceManager.resolveTrace(tx, async (error, result) => {
if (result) { this.traceManager.resolveTrace(tx).then(async (result) => {
this.setCompilationResult(await this.compilationResult(tx.to)) this.setCompilationResult(await this.compilationResult(tx.to))
this.event.trigger('newTraceLoaded', [this.traceManager.trace]) this.event.trigger('newTraceLoaded', [this.traceManager.trace])
if (this.breakpointManager && this.breakpointManager.hasBreakpoint()) { if (this.breakpointManager && this.breakpointManager.hasBreakpoint()) {
this.breakpointManager.jumpNextBreakpoint(false) this.breakpointManager.jumpNextBreakpoint(false)
}
this.storageResolver = new StorageResolver({web3: this.traceManager.web3})
} else {
this.statusMessage = error ? error.message : 'Trace not loaded'
} }
this.storageResolver = new StorageResolver({web3: this.traceManager.web3})
}).catch((error) => {
this.statusMessage = error ? error.message : 'Trace not loaded'
}) })
} }
......
...@@ -124,23 +124,15 @@ class InternalCallTree { ...@@ -124,23 +124,15 @@ class InternalCallTree {
return functions return functions
} }
extractSourceLocation (step) { async extractSourceLocation (step) {
return new Promise((resolve, reject) => { try {
try { const address = this.traceManager.getCurrentCalledAddressAt(step)
const address = this.traceManager.getCurrentCalledAddressAt(step) const location = await this.sourceLocationTracker.getSourceLocationFromVMTraceIndex(address, step, this.solidityProxy.contracts)
try { return location
this.sourceLocationTracker.getSourceLocationFromVMTraceIndex(address, step, this.solidityProxy.contracts).then(resolve).catch((error) => { } catch (error) {
return reject('InternalCallTree - Cannot retrieve sourcelocation for step ' + step + ' ' + error) throw new Error('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 function buildTree (tree, step, scopeId, isExternalCall) { async function buildTree (tree, step, scopeId, isExternalCall) {
......
...@@ -39,25 +39,15 @@ class SolidityProxy { ...@@ -39,25 +39,15 @@ class SolidityProxy {
* @param {Int} vmTraceIndex - index in the vm trave where to resolve the executed contract name * @param {Int} vmTraceIndex - index in the vm trave where to resolve the executed contract name
* @param {Function} cb - callback returns (error, contractName) * @param {Function} cb - callback returns (error, contractName)
*/ */
contractNameAt (vmTraceIndex) { async contractNameAt (vmTraceIndex) {
return new Promise((resolve, reject) => { const address = this.traceManager.getCurrentCalledAddressAt(vmTraceIndex)
try { if (this.cache.contractNameByAddress[address]) {
const address = this.traceManager.getCurrentCalledAddressAt(vmTraceIndex) return this.cache.contractNameByAddress[address]
if (this.cache.contractNameByAddress[address]) { }
return resolve(this.cache.contractNameByAddress[address]) const code = await this.codeManager.getCode(address)
} const contractName = contractNameFromCode(this.contracts, code.bytecode, address)
this.codeManager.getCode(address, (error, code) => { this.cache.contractNameByAddress[address] = contractName
if (error) { return contractName
return reject(error)
}
const contractName = contractNameFromCode(this.contracts, code.bytecode, address)
this.cache.contractNameByAddress[address] = contractName
resolve(contractName)
})
} catch (error) {
reject(error)
}
})
} }
/** /**
...@@ -95,12 +85,9 @@ class SolidityProxy { ...@@ -95,12 +85,9 @@ class SolidityProxy {
* @param {Int} vmTraceIndex - index in the vm trave where to resolve the state variables * @param {Int} vmTraceIndex - index in the vm trave where to resolve the state variables
* @return {Object} - returns state variables of @args vmTraceIndex * @return {Object} - returns state variables of @args vmTraceIndex
*/ */
extractStateVariablesAt (vmtraceIndex) { async extractStateVariablesAt (vmtraceIndex) {
return new Promise((resolve, reject) => { const contractName = await this.contractNameAt(vmtraceIndex)
this.contractNameAt(vmtraceIndex).then((contractName) => { return this.extractStateVariables(contractName)
resolve(this.extractStateVariables(contractName))
}).catch(reject)
})
} }
/** /**
...@@ -113,10 +100,8 @@ class SolidityProxy { ...@@ -113,10 +100,8 @@ class SolidityProxy {
const file = this.fileNameFromIndex(sourceLocation.file) const file = this.fileNameFromIndex(sourceLocation.file)
if (this.sources[file]) { if (this.sources[file]) {
return this.sources[file].legacyAST return this.sources[file].legacyAST
} else {
// console.log('AST not found for file id ' + sourceLocation.file)
return null
} }
return null
} }
/** /**
......
...@@ -39,17 +39,14 @@ class StorageResolver { ...@@ -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). * @param {Array} corrections - used in case the calculated sha3 has been modifyed before SSTORE (notably used for struct in mapping).
* @return {Function} - callback * @return {Function} - callback
*/ */
initialPreimagesMappings (tx, stepIndex, address, corrections) { async initialPreimagesMappings (tx, stepIndex, address, corrections) {
return new Promise((resolve, reject) => { if (this.preimagesMappingByAddress[address]) {
if (this.preimagesMappingByAddress[address]) { return this.preimagesMappingByAddress[address]
return resolve(this.preimagesMappingByAddress[address]) }
} const storage = await this.storageRange(tx, stepIndex, address)
this.storageRange(tx, stepIndex, address).then((storage) => { const mappings = mappingPreimages.decodeMappingsKeys(this.web3, storage, corrections)
const mappings = mappingPreimages.decodeMappingsKeys(this.web3, storage, corrections) this.preimagesMappingByAddress[address] = mappings
this.preimagesMappingByAddress[address] = mappings return mappings
resolve(mappings)
}).catch(reject)
})
} }
/** /**
...@@ -61,12 +58,9 @@ class StorageResolver { ...@@ -61,12 +58,9 @@ class StorageResolver {
* @param {String} - address - lookup address * @param {String} - address - lookup address
* @param {Function} - callback - {key, hashedKey, value} - * @param {Function} - callback - {key, hashedKey, value} -
*/ */
storageSlot (slot, tx, stepIndex, address) { async storageSlot (slot, tx, stepIndex, address) {
return new Promise((resolve, reject) => { const storage = await this.storageRangeInternal(this, slot, tx, stepIndex, address)
this.storageRangeInternal(this, slot, tx, stepIndex, address).then((storage) => { return (storage[slot] !== undefined ? storage[slot] : null)
resolve(storage[slot] !== undefined ? storage[slot] : null)
}).catch(reject)
})
} }
/** /**
...@@ -85,27 +79,21 @@ class StorageResolver { ...@@ -85,27 +79,21 @@ class StorageResolver {
* even if the next 1000 items are not in the cache. * 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. * - If @arg slot is not cached, the corresponding value will be resolved and the next 1000 slots.
*/ */
storageRangeInternal (self, slotKey, tx, stepIndex, address) { async storageRangeInternal (self, slotKey, tx, stepIndex, address) {
return new Promise((resolve, reject) => { var cached = this.fromCache(self, 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...
if (cached && cached.storage[slotKey]) { // we have the current slot in the cache and maybe the next 1000... return cached.storage
return resolve(cached.storage) }
} const result = await this.storageRangeWeb3Call(tx, address, slotKey, self.maxSize)
this.storageRangeWeb3Call(tx, address, slotKey, self.maxSize).then((result) => { const [storage, nextKey] = result
const [storage, nextKey] = result if (!storage[slotKey] && slotKey !== self.zeroSlot) { // we don't cache the zero slot (could lead to inconsistency)
if (!storage[slotKey] && slotKey !== self.zeroSlot) { // we don't cache the zero slot (could lead to inconsistency) storage[slotKey] = {key: slotKey, value: self.zeroSlot}
storage[slotKey] = { }
key: slotKey, self.toCache(self, address, storage)
value: self.zeroSlot if (slotKey === self.zeroSlot && !nextKey) { // only working if keys are sorted !!
} self.storageByAddress[address].complete = true
} }
self.toCache(self, address, storage) return storage
if (slotKey === self.zeroSlot && !nextKey) { // only working if keys are sorted !!
self.storageByAddress[address].complete = true
}
return resolve(storage)
}).catch(reject)
})
} }
/** /**
......
...@@ -77,13 +77,8 @@ class StorageViewer { ...@@ -77,13 +77,8 @@ class StorageViewer {
async mappingsLocation (corrections) { async mappingsLocation (corrections) {
if (!this.currentMappingsLocationPromise) { if (!this.currentMappingsLocationPromise) {
this.currentMappingsLocationPromise = new Promise((resolve, reject) => { this.currentMappingsLocationPromise = new Promise((resolve, reject) => {
this.extractMappingsLocationChanges(this.storageChanges, corrections, (error, mappingsLocationChanges) => { const mappingsLocationChanges = this.extractMappingsLocationChanges(this.storageChanges, corrections)
if (error) { return resolve(mappingsLocationChanges)
reject(error)
} else {
resolve(mappingsLocationChanges)
}
})
}) })
} }
return this.currentMappingsLocationPromise return this.currentMappingsLocationPromise
...@@ -94,13 +89,13 @@ class StorageViewer { ...@@ -94,13 +89,13 @@ class StorageViewer {
* @param {Map} storageChanges * @param {Map} storageChanges
* @param {Array} corrections - used in case the calculated sha3 has been modifyed before SSTORE (notably used for struct in mapping). * @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) { if (this.mappingsLocationChanges) {
return callback(null, this.mappingsLocationChanges) return this.mappingsLocationChanges
} }
const mappings = mappingPreimages.decodeMappingsKeys(this.web3, storageChanges, corrections) const mappings = mappingPreimages.decodeMappingsKeys(this.web3, storageChanges, corrections)
this.mappingsLocationChanges = mappings this.mappingsLocationChanges = mappings
return callback(null, this.mappingsLocationChanges) return this.mappingsLocationChanges
} }
} }
......
...@@ -235,37 +235,34 @@ function testDebugging (debugManager) { ...@@ -235,37 +235,34 @@ function testDebugging (debugManager) {
} }
}) })
tape('traceManager.decodeStateAt', (t) => { tape('traceManager.decodeStateAt', async (t) => {
t.plan(7) 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) 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) 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[]"}}') 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 { try {
const address = debugManager.traceManager.getCurrentCalledAddressAt(330) 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) if (error) return t.end(error)
debugManager.decodeLocalsAt(330, location, (error, decodedlocals) => { t.equal(JSON.stringify(decodedlocals), JSON.stringify(tested))
if (error) return t.end(error)
t.equal(JSON.stringify(decodedlocals), JSON.stringify(tested))
})
}) })
// })
} catch (error) { } catch (error) {
return t.end(error) return t.end(error)
} }
......
...@@ -119,12 +119,10 @@ module.exports = function (st, vm, privateKey, contractBytecode, compilationResu ...@@ -119,12 +119,10 @@ module.exports = function (st, vm, privateKey, contractBytecode, compilationResu
cb() cb()
}) })
}) })
traceManager.resolveTrace(tx, (error, result) => { traceManager.resolveTrace(tx).then(() => {
if (error) { debuggerEvent.trigger('newTraceLoaded', [traceManager.trace])
st.fail(error) }).catch((error) => {
} else { st.fail(error)
debuggerEvent.trigger('newTraceLoaded', [traceManager.trace])
}
}) })
} }
}) })
......
...@@ -65,12 +65,10 @@ module.exports = function (st, vm, privateKey, contractBytecode, compilationResu ...@@ -65,12 +65,10 @@ module.exports = function (st, vm, privateKey, contractBytecode, compilationResu
cb() cb()
}) })
}) })
traceManager.resolveTrace(tx, (error, result) => { traceManager.resolveTrace(tx).then(() => {
if (error) { debuggerEvent.trigger('newTraceLoaded', [traceManager.trace])
st.fail(error) }).catch((error) => {
} else { st.fail(error)
debuggerEvent.trigger('newTraceLoaded', [traceManager.trace])
}
}) })
} }
}) })
......
...@@ -51,12 +51,10 @@ module.exports = function (st, vm, privateKey, contractBytecode, compilationResu ...@@ -51,12 +51,10 @@ module.exports = function (st, vm, privateKey, contractBytecode, compilationResu
cb() cb()
}) })
}) })
traceManager.resolveTrace(tx, (error, result) => { traceManager.resolveTrace(tx).then(() => {
if (error) { debuggerEvent.trigger('newTraceLoaded', [traceManager.trace])
st.fail(error) }).catch((error) => {
} else { st.fail(error)
debuggerEvent.trigger('newTraceLoaded', [traceManager.trace])
}
}) })
} }
}) })
......
...@@ -109,12 +109,10 @@ module.exports = function (st, vm, privateKey, contractBytecode, compilationResu ...@@ -109,12 +109,10 @@ module.exports = function (st, vm, privateKey, contractBytecode, compilationResu
cb() cb()
}) })
}) })
traceManager.resolveTrace(tx, (error, result) => { traceManager.resolveTrace(tx).then(() => {
if (error) { debuggerEvent.trigger('newTraceLoaded', [traceManager.trace])
st.fail(error) }).catch((error) => {
} else { st.fail(error)
debuggerEvent.trigger('newTraceLoaded', [traceManager.trace])
}
}) })
} }
}) })
......
...@@ -46,7 +46,8 @@ function testMapping (st, vm, privateKey, contractAddress, output, cb) { ...@@ -46,7 +46,8 @@ function testMapping (st, vm, privateKey, contractAddress, output, cb) {
st.end(error) st.end(error)
} else { } else {
var traceManager = new TraceManager({web3: vm.web3}) var traceManager = new TraceManager({web3: vm.web3})
traceManager.resolveTrace(tx, () => {
traceManager.resolveTrace(tx).then(() => {
var storageViewer = new StorageViewer({ var storageViewer = new StorageViewer({
stepIndex: 268, stepIndex: 268,
tx: tx, tx: tx,
......
...@@ -53,19 +53,18 @@ CodeManager.prototype.resolveStep = function (stepIndex, tx) { ...@@ -53,19 +53,18 @@ CodeManager.prototype.resolveStep = function (stepIndex, tx) {
* @param {String} address - address of the contract to get the code from * @param {String} address - address of the contract to get the code from
* @param {Function} cb - callback function, return the bytecode * @param {Function} cb - callback function, return the bytecode
*/ */
CodeManager.prototype.getCode = function (address, cb) { CodeManager.prototype.getCode = async function (address) {
if (!traceHelper.isContractCreation(address)) { if (!traceHelper.isContractCreation(address)) {
return this.codeResolver.resolveCode(address).then((code) => { const code = await this.codeResolver.resolveCode(address)
cb(null, code) return code
})
} }
var codes = this.codeResolver.getExecutingCodeFromCache(address) var codes = this.codeResolver.getExecutingCodeFromCache(address)
if (codes) { if (codes) {
return cb(null, codes) return codes
} }
const hexCode = this.traceManager.getContractCreationCode(address) const hexCode = this.traceManager.getContractCreationCode(address)
codes = this.codeResolver.cacheExecutingCode(address, hexCode) codes = this.codeResolver.cacheExecutingCode(address, hexCode)
cb(null, codes) return codes
} }
/** /**
...@@ -94,14 +93,14 @@ CodeManager.prototype.getFunctionFromStep = function (stepIndex, sourceMap, ast) ...@@ -94,14 +93,14 @@ CodeManager.prototype.getFunctionFromStep = function (stepIndex, sourceMap, ast)
* @param {String} step - vm trace step * @param {String} step - vm trace step
* @param {Function} callback - instruction index * @param {Function} callback - instruction index
*/ */
CodeManager.prototype.getInstructionIndex = function (address, step, callback) { CodeManager.prototype.getInstructionIndex = function (address, step) {
try { try {
const pc = this.traceManager.getCurrentPC(step) const pc = this.traceManager.getCurrentPC(step)
const itemIndex = this.codeResolver.getInstructionIndex(address, pc) const itemIndex = this.codeResolver.getInstructionIndex(address, pc)
callback(null, itemIndex) return itemIndex
} catch (error) { } catch (error) {
console.log(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) ...@@ -120,21 +119,21 @@ CodeManager.prototype.getFunctionFromPC = function (address, pc, sourceMap, ast)
} }
function retrieveCodeAndTrigger (codeMananger, address, stepIndex, tx) { function retrieveCodeAndTrigger (codeMananger, address, stepIndex, tx) {
codeMananger.getCode(address, (error, result) => { codeMananger.getCode(address).then((result) => {
if (error) {
return console.log(error)
}
retrieveIndexAndTrigger(codeMananger, address, stepIndex, result.instructions) retrieveIndexAndTrigger(codeMananger, address, stepIndex, result.instructions)
}).catch((error) => {
return console.log(error)
}) })
} }
function retrieveIndexAndTrigger (codeMananger, address, step, code) { function retrieveIndexAndTrigger (codeMananger, address, step, code) {
codeMananger.getInstructionIndex(address, step, (error, result) => { let result
if (error) { try {
return console.log(error) result = codeMananger.getInstructionIndex(address, step)
} } catch (error) {
codeMananger.event.trigger('changed', [code, address, result]) return console.log(error)
}) }
codeMananger.event.trigger('changed', [code, address, result])
} }
module.exports = CodeManager module.exports = CodeManager
...@@ -22,12 +22,9 @@ function SourceLocationTracker (_codeManager) { ...@@ -22,12 +22,9 @@ function SourceLocationTracker (_codeManager) {
* @param {Object} contractDetails - AST of compiled contracts * @param {Object} contractDetails - AST of compiled contracts
* @param {Function} cb - callback function * @param {Function} cb - callback function
*/ */
SourceLocationTracker.prototype.getSourceLocationFromInstructionIndex = function (address, index, contracts) { SourceLocationTracker.prototype.getSourceLocationFromInstructionIndex = async function (address, index, contracts) {
return new Promise((resolve, reject) => { const sourceMap = await extractSourceMap(this, this.codeManager, address, contracts)
extractSourceMap(this, this.codeManager, address, contracts).then((sourceMap) => { return this.sourceMappingDecoder.atIndex(index, sourceMap)
resolve(this.sourceMappingDecoder.atIndex(index, sourceMap))
}).catch(reject)
})
} }
/** /**
...@@ -38,18 +35,10 @@ SourceLocationTracker.prototype.getSourceLocationFromInstructionIndex = function ...@@ -38,18 +35,10 @@ SourceLocationTracker.prototype.getSourceLocationFromInstructionIndex = function
* @param {Object} contractDetails - AST of compiled contracts * @param {Object} contractDetails - AST of compiled contracts
* @param {Function} cb - callback function * @param {Function} cb - callback function
*/ */
SourceLocationTracker.prototype.getSourceLocationFromVMTraceIndex = function (address, vmtraceStepIndex, contracts) { SourceLocationTracker.prototype.getSourceLocationFromVMTraceIndex = async function (address, vmtraceStepIndex, contracts) {
return new Promise((resolve, reject) => { const sourceMap = await extractSourceMap(this, this.codeManager, address, contracts)
extractSourceMap(this, this.codeManager, address, contracts).then((sourceMap) => { const index = this.codeManager.getInstructionIndex(address, vmtraceStepIndex)
this.codeManager.getInstructionIndex(address, vmtraceStepIndex, (error, index) => { return this.sourceMappingDecoder.atIndex(index, sourceMap)
if (error) {
reject(error)
} else {
resolve(this.sourceMappingDecoder.atIndex(index, sourceMap))
}
})
}).catch(reject)
})
} }
SourceLocationTracker.prototype.clearCache = function () { SourceLocationTracker.prototype.clearCache = function () {
...@@ -78,19 +67,15 @@ function extractSourceMap (self, codeManager, address, contracts) { ...@@ -78,19 +67,15 @@ function extractSourceMap (self, codeManager, address, contracts) {
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
if (self.sourceMapByAddress[address]) return resolve(self.sourceMapByAddress[address]) if (self.sourceMapByAddress[address]) return resolve(self.sourceMapByAddress[address])
codeManager.getCode(address, (error, result) => { codeManager.getCode(address).then((result) => {
if (!error) { const sourceMap = getSourceMap(address, result.bytecode, contracts)
const sourceMap = getSourceMap(address, result.bytecode, contracts) if (sourceMap) {
if (sourceMap) { if (!helper.isContractCreation(address)) self.sourceMapByAddress[address] = sourceMap
if (!helper.isContractCreation(address)) self.sourceMapByAddress[address] = sourceMap resolve(sourceMap)
resolve(sourceMap)
} else {
reject('no sourcemap associated with the code ' + address)
}
} else { } else {
reject(error) reject('no sourcemap associated with the code ' + address)
} }
}) }).catch(reject)
}) })
} }
......
...@@ -17,10 +17,10 @@ function TraceManager (options) { ...@@ -17,10 +17,10 @@ function TraceManager (options) {
} }
// init section // init section
TraceManager.prototype.resolveTrace = async function (tx, callback) { TraceManager.prototype.resolveTrace = async function (tx) {
this.tx = tx this.tx = tx
this.init() this.init()
if (!this.web3) callback('web3 not loaded', false) if (!this.web3) throw new Error('web3 not loaded')
this.isLoading = true this.isLoading = true
try { try {
const result = await this.getTrace(tx.hash) const result = await this.getTrace(tx.hash)
...@@ -30,16 +30,16 @@ TraceManager.prototype.resolveTrace = async function (tx, callback) { ...@@ -30,16 +30,16 @@ TraceManager.prototype.resolveTrace = async function (tx, callback) {
this.traceAnalyser.analyse(result.structLogs, tx) this.traceAnalyser.analyse(result.structLogs, tx)
this.isLoading = false this.isLoading = false
return callback(null, true) return true
} }
var mes = tx.hash + ' is not a contract invocation or contract creation.' var mes = tx.hash + ' is not a contract invocation or contract creation.'
console.log(mes) console.log(mes)
this.isLoading = false this.isLoading = false
callback(mes, false) throw new Error(mes)
} catch (error) { } catch (error) {
console.log(error) console.log(error)
this.isLoading = false this.isLoading = false
callback(error, false) throw new Error(error)
} }
} }
......
...@@ -23,12 +23,10 @@ tape('CodeManager', function (t) { ...@@ -23,12 +23,10 @@ tape('CodeManager', function (t) {
const contractCode = web3.eth.getCode('0x0d3a18d64dfe4f927832ab58d6451cecc4e517c5') const contractCode = web3.eth.getCode('0x0d3a18d64dfe4f927832ab58d6451cecc4e517c5')
codeManager.codeResolver.cacheExecutingCode('0x0d3a18d64dfe4f927832ab58d6451cecc4e517c5', contractCode) // so a call to web3 is not necessary codeManager.codeResolver.cacheExecutingCode('0x0d3a18d64dfe4f927832ab58d6451cecc4e517c5', contractCode) // so a call to web3 is not necessary
const tx = web3.eth.getTransaction('0x20ef65b8b186ca942fcccd634f37074dde49b541c27994fc7596740ef44cfd51') const tx = web3.eth.getTransaction('0x20ef65b8b186ca942fcccd634f37074dde49b541c27994fc7596740ef44cfd51')
traceManager.resolveTrace(tx, function (error, result) { traceManager.resolveTrace(tx).then(() => {
if (error) { continueTesting(t, codeManager)
t.fail(' - traceManager.resolveTrace - failed ' + result) }).catch(() => {
} else { t.fail(' - traceManager.resolveTrace - failed ')
continueTesting(t, codeManager)
}
}) })
} }
}) })
...@@ -70,22 +68,20 @@ function continueTesting (t, codeManager) { ...@@ -70,22 +68,20 @@ function continueTesting (t, codeManager) {
t.test('CodeManager.getInstructionIndex', function (st) { t.test('CodeManager.getInstructionIndex', function (st) {
st.plan(2) st.plan(2)
codeManager.getInstructionIndex('0x0d3a18d64dfe4f927832ab58d6451cecc4e517c5', 16, function (error, result) { try {
const result = codeManager.getInstructionIndex('0x0d3a18d64dfe4f927832ab58d6451cecc4e517c5', 16)
console.log(result) console.log(result)
if (error) { st.ok(result === 25)
st.fail(error) } catch (error) {
} else { st.fail(error)
st.ok(result === 25) }
}
})
codeManager.getInstructionIndex('(Contract Creation - Step 63)', 70, function (error, result) { try {
const result = codeManager.getInstructionIndex('(Contract Creation - Step 63)', 70)
console.log(result) console.log(result)
if (error) { st.ok(result === 6)
st.fail(error) } catch (error) {
} else { st.fail(error)
st.ok(result === 6) }
}
})
}) })
} }
...@@ -27,12 +27,10 @@ tape('TraceManager', function (t) { ...@@ -27,12 +27,10 @@ tape('TraceManager', function (t) {
t.test('TraceManager.resolveTrace', function (st) { t.test('TraceManager.resolveTrace', function (st) {
const tx = web3.eth.getTransaction('0x20ef65b8b186ca942fcccd634f37074dde49b541c27994fc7596740ef44cfd51') const tx = web3.eth.getTransaction('0x20ef65b8b186ca942fcccd634f37074dde49b541c27994fc7596740ef44cfd51')
traceManager.resolveTrace(tx, function (error, result) { traceManager.resolveTrace(tx).then(() => {
if (error) { st.end()
st.fail(' - traceManager.resolveTrace - failed ' + result) }).catch(() => {
} else { st.fail(' - traceManager.resolveTrace - failed ')
st.end()
}
}) })
}) })
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment