You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
190 lines
6.3 KiB
190 lines
6.3 KiB
7 years ago
|
'use strict'
|
||
7 years ago
|
|
||
5 years ago
|
const StorageViewer = require('./storage/storageViewer')
|
||
|
const StorageResolver = require('./storage/storageResolver')
|
||
7 years ago
|
|
||
5 years ago
|
const SolidityDecoder = require('./solidity-decoder')
|
||
|
const SolidityProxy = SolidityDecoder.SolidityProxy
|
||
|
const stateDecoder = SolidityDecoder.stateDecoder
|
||
|
const localDecoder = SolidityDecoder.localDecoder
|
||
|
const InternalCallTree = SolidityDecoder.InternalCallTree
|
||
7 years ago
|
|
||
5 years ago
|
const remixLib = require('remix-lib')
|
||
|
const TraceManager = remixLib.trace.TraceManager
|
||
|
const CodeManager = remixLib.code.CodeManager
|
||
|
const traceHelper = remixLib.helpers.trace
|
||
|
const EventManager = remixLib.EventManager
|
||
7 years ago
|
|
||
|
/**
|
||
|
* Ethdebugger is a wrapper around a few classes that helps debugging a transaction
|
||
|
*
|
||
|
* - Web3Providers - define which environment (web3) the transaction will be retrieved from
|
||
|
* - TraceManager - Load / Analyze the trace and retrieve details of specific test
|
||
|
* - CodeManager - Retrieve loaded byte code and help to resolve AST item from vmtrace index
|
||
|
* - SolidityProxy - Basically used to extract state variable from AST
|
||
|
* - Breakpoint Manager - Used to add / remove / jumpto breakpoint
|
||
|
* - InternalCallTree - Used to retrieved local variables
|
||
7 years ago
|
* - StorageResolver - Help resolving the storage accross different steps
|
||
7 years ago
|
*
|
||
|
* @param {Map} opts - { function compilationResult } //
|
||
|
*/
|
||
|
function Ethdebugger (opts) {
|
||
5 years ago
|
this.compilationResult = opts.compilationResult || function (contractAddress) { return null }
|
||
6 years ago
|
this.web3 = opts.web3
|
||
7 years ago
|
|
||
7 years ago
|
this.event = new EventManager()
|
||
|
|
||
|
this.tx
|
||
|
|
||
7 years ago
|
this.traceManager = new TraceManager({web3: this.web3})
|
||
|
this.codeManager = new CodeManager(this.traceManager)
|
||
|
this.solidityProxy = new SolidityProxy(this.traceManager, this.codeManager)
|
||
|
this.storageResolver = null
|
||
|
|
||
|
this.callTree = new InternalCallTree(this.event, this.traceManager, this.solidityProxy, this.codeManager, { includeLocalVariables: true })
|
||
|
}
|
||
|
|
||
|
Ethdebugger.prototype.setManagers = function () {
|
||
|
this.traceManager = new TraceManager({web3: this.web3})
|
||
7 years ago
|
this.codeManager = new CodeManager(this.traceManager)
|
||
|
this.solidityProxy = new SolidityProxy(this.traceManager, this.codeManager)
|
||
7 years ago
|
this.storageResolver = null
|
||
7 years ago
|
|
||
|
this.callTree = new InternalCallTree(this.event, this.traceManager, this.solidityProxy, this.codeManager, { includeLocalVariables: true })
|
||
7 years ago
|
}
|
||
7 years ago
|
|
||
7 years ago
|
Ethdebugger.prototype.resolveStep = function (index) {
|
||
|
this.codeManager.resolveStep(index, this.tx)
|
||
7 years ago
|
}
|
||
|
|
||
7 years ago
|
Ethdebugger.prototype.setCompilationResult = function (compilationResult) {
|
||
5 years ago
|
if (compilationResult && compilationResult.data) {
|
||
|
this.solidityProxy.reset(compilationResult.data)
|
||
7 years ago
|
} else {
|
||
|
this.solidityProxy.reset({})
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/* resolve source location */
|
||
7 years ago
|
Ethdebugger.prototype.sourceLocationFromVMTraceIndex = function (address, stepIndex, callback) {
|
||
|
this.callTree.sourceLocationTracker.getSourceLocationFromVMTraceIndex(address, stepIndex, this.solidityProxy.contracts, (error, rawLocation) => {
|
||
|
callback(error, rawLocation)
|
||
|
})
|
||
|
}
|
||
|
|
||
|
Ethdebugger.prototype.sourceLocationFromInstructionIndex = function (address, instIndex, callback) {
|
||
5 years ago
|
this.callTree.sourceLocationTracker.getSourceLocationFromInstructionIndex(address, instIndex, this.solidityProxy.contracts, (error, rawLocation) => {
|
||
7 years ago
|
callback(error, rawLocation)
|
||
|
})
|
||
|
}
|
||
|
|
||
7 years ago
|
/* breakpoint */
|
||
7 years ago
|
Ethdebugger.prototype.setBreakpointManager = function (breakpointManager) {
|
||
|
this.breakpointManager = breakpointManager
|
||
|
}
|
||
|
|
||
7 years ago
|
/* decode locals */
|
||
|
Ethdebugger.prototype.extractLocalsAt = function (step, callback) {
|
||
|
callback(null, this.callTree.findScope(step))
|
||
|
}
|
||
|
|
||
|
Ethdebugger.prototype.decodeLocalsAt = function (step, sourceLocation, callback) {
|
||
|
this.traceManager.waterfall([
|
||
|
this.traceManager.getStackAt,
|
||
|
this.traceManager.getMemoryAt,
|
||
|
this.traceManager.getCurrentCalledAddressAt],
|
||
|
step,
|
||
|
(error, result) => {
|
||
|
if (!error) {
|
||
5 years ago
|
const stack = result[0].value
|
||
|
const memory = result[1].value
|
||
7 years ago
|
try {
|
||
5 years ago
|
const storageViewer = new StorageViewer({
|
||
7 years ago
|
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)
|
||
|
}
|
||
|
})
|
||
7 years ago
|
}
|
||
|
|
||
7 years ago
|
/* decode state */
|
||
|
Ethdebugger.prototype.extractStateAt = function (step, callback) {
|
||
5 years ago
|
this.solidityProxy.extractStateVariablesAt(step, (error, stateVars) => {
|
||
7 years ago
|
callback(error, stateVars)
|
||
|
})
|
||
|
}
|
||
|
|
||
|
Ethdebugger.prototype.decodeStateAt = function (step, stateVars, callback) {
|
||
|
this.traceManager.getCurrentCalledAddressAt(step, (error, address) => {
|
||
|
if (error) return callback(error)
|
||
5 years ago
|
const storageViewer = new StorageViewer({
|
||
7 years ago
|
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)
|
||
|
}
|
||
|
})
|
||
|
})
|
||
|
}
|
||
|
|
||
|
Ethdebugger.prototype.storageViewAt = function (step, address) {
|
||
|
return new StorageViewer({
|
||
|
stepIndex: step,
|
||
|
tx: this.tx,
|
||
|
address: address
|
||
|
}, this.storageResolver, this.traceManager)
|
||
|
}
|
||
7 years ago
|
|
||
6 years ago
|
Ethdebugger.prototype.updateWeb3 = function (web3) {
|
||
|
this.web3 = web3
|
||
6 years ago
|
this.setManagers()
|
||
7 years ago
|
}
|
||
|
|
||
|
Ethdebugger.prototype.unLoad = function () {
|
||
|
this.traceManager.init()
|
||
|
this.codeManager.clear()
|
||
|
this.event.trigger('traceUnloaded')
|
||
|
}
|
||
|
|
||
7 years ago
|
Ethdebugger.prototype.debug = function (tx) {
|
||
7 years ago
|
if (this.traceManager.isLoading) {
|
||
|
return
|
||
|
}
|
||
7 years ago
|
if (!tx.to) {
|
||
|
tx.to = traceHelper.contractCreationToken('0')
|
||
|
}
|
||
7 years ago
|
this.tx = tx
|
||
5 years ago
|
this.traceManager.resolveTrace(tx, async (error, result) => {
|
||
7 years ago
|
if (result) {
|
||
5 years ago
|
this.setCompilationResult(await this.compilationResult(tx.to))
|
||
5 years ago
|
this.event.trigger('newTraceLoaded', [this.traceManager.trace])
|
||
|
if (this.breakpointManager && this.breakpointManager.hasBreakpoint()) {
|
||
|
this.breakpointManager.jumpNextBreakpoint(false)
|
||
7 years ago
|
}
|
||
5 years ago
|
this.storageResolver = new StorageResolver({web3: this.traceManager.web3})
|
||
7 years ago
|
} else {
|
||
5 years ago
|
this.statusMessage = error ? error.message : 'Trace not loaded'
|
||
7 years ago
|
}
|
||
|
})
|
||
|
}
|
||
|
|
||
|
module.exports = Ethdebugger
|