Merge pull request #1543 from ethereum/refactor_debugger
Refactor debugger - extract logic from views, move to separate modulepull/1/head
commit
783ac30c6e
@ -1,133 +0,0 @@ |
||||
'use strict' |
||||
var EthdebuggerUI = require('./remix-debugger/src/ui/EthdebuggerUI') |
||||
var Ethdebugger = require('remix-debug').EthDebugger |
||||
var remixLib = require('remix-lib') |
||||
var executionContext = require('../../execution-context') |
||||
var globlalRegistry = require('../../global/registry') |
||||
|
||||
/** |
||||
* Manage remix and source highlighting |
||||
*/ |
||||
function Debugger (container, sourceHighlighter, localRegistry) { |
||||
this._components = { |
||||
sourceHighlighter: sourceHighlighter |
||||
} |
||||
this._components.registry = localRegistry || globlalRegistry |
||||
// dependencies
|
||||
this._deps = { |
||||
offsetToLineColumnConverter: this._components.registry.get('offsettolinecolumnconverter').api, |
||||
editor: this._components.registry.get('editor').api, |
||||
compiler: this._components.registry.get('compiler').api, |
||||
compilersArtefacts: this._components.registry.get('compilersartefacts').api |
||||
} |
||||
this.debugger = new Ethdebugger( |
||||
{ |
||||
executionContext: executionContext, |
||||
compilationResult: () => { |
||||
if (this._deps.compilersArtefacts['__last']) return this._deps.compilersArtefacts['__last'].getData() |
||||
return null |
||||
} |
||||
}) |
||||
this.debugger_ui = new EthdebuggerUI({debugger: this.debugger}) |
||||
this.sourceMappingDecoder = new remixLib.SourceMappingDecoder() |
||||
//
|
||||
// TODO: render doesn't exist anymore
|
||||
container.appendChild(this.debugger_ui.render()) |
||||
//
|
||||
this.isActive = false |
||||
|
||||
this.breakPointManager = new remixLib.code.BreakpointManager(this.debugger, (sourceLocation) => { |
||||
return self._deps.offsetToLineColumnConverter.offsetToLineColumn(sourceLocation, sourceLocation.file, this._deps.compiler.lastCompilationResult.source.sources, this._deps.compiler.lastCompilationResult.data.sources) |
||||
}, (step) => { |
||||
this.debugger_ui.stepManager.jumpTo(step) |
||||
}) |
||||
|
||||
this.debugger.setBreakpointManager(this.breakPointManager) |
||||
|
||||
var self = this |
||||
self._deps.editor.event.register('breakpointCleared', (fileName, row) => { |
||||
this.breakPointManager.remove({fileName: fileName, row: row}) |
||||
}) |
||||
|
||||
self._deps.editor.event.register('breakpointAdded', (fileName, row) => { |
||||
this.breakPointManager.add({fileName: fileName, row: row}) |
||||
}) |
||||
|
||||
executionContext.event.register('contextChanged', this, function (context) { |
||||
self.switchProvider(context) |
||||
}) |
||||
|
||||
this.debugger.event.register('newTraceLoaded', this, function () { |
||||
self.isActive = true |
||||
}) |
||||
|
||||
this.debugger.event.register('traceUnloaded', this, function () { |
||||
self._components.sourceHighlighter.currentSourceLocation(null) |
||||
self.isActive = false |
||||
}) |
||||
|
||||
// unload if a file has changed (but not if tabs were switched)
|
||||
self._deps.editor.event.register('contentChanged', function () { |
||||
self.debugger.unLoad() |
||||
}) |
||||
|
||||
// register selected code item, highlight the corresponding source location
|
||||
this.debugger_ui.event.register('indexChanged', function (index) { |
||||
if (self._deps.compiler.lastCompilationResult) { |
||||
self.debugger.traceManager.getCurrentCalledAddressAt(index, (error, address) => { |
||||
if (error) return console.log(error) |
||||
self.debugger.callTree.sourceLocationTracker.getSourceLocationFromVMTraceIndex(address, index, self._deps.compiler.lastCompilationResult.data.contracts, function (error, rawLocation) { |
||||
if (!error && self._deps.compiler.lastCompilationResult && self._deps.compiler.lastCompilationResult.data) { |
||||
var lineColumnPos = self._deps.offsetToLineColumnConverter.offsetToLineColumn(rawLocation, rawLocation.file, self._deps.compiler.lastCompilationResult.source.sources, self._deps.compiler.lastCompilationResult.data.sources) |
||||
self._components.sourceHighlighter.currentSourceLocation(lineColumnPos, rawLocation) |
||||
} else { |
||||
self._components.sourceHighlighter.currentSourceLocation(null) |
||||
} |
||||
}) |
||||
}) |
||||
} |
||||
}) |
||||
} |
||||
|
||||
/** |
||||
* Start debugging using Remix |
||||
* |
||||
* @param {String} txHash - hash of the transaction |
||||
*/ |
||||
Debugger.prototype.debug = function (txHash) { |
||||
var self = this |
||||
|
||||
this.debugger.web3.eth.getTransaction(txHash, function (error, tx) { |
||||
if (!error) { |
||||
self.debugger_ui.debug(tx) |
||||
} |
||||
}) |
||||
} |
||||
|
||||
/** |
||||
* add a new web3 provider to remix |
||||
* |
||||
* @param {String} type - type/name of the provider to add |
||||
* @param {Object} obj - provider |
||||
*/ |
||||
Debugger.prototype.addProvider = function (type, obj) { |
||||
this.debugger.addProvider(type, obj) |
||||
} |
||||
|
||||
/** |
||||
* switch the provider |
||||
* |
||||
* @param {String} type - type/name of the provider to use |
||||
*/ |
||||
Debugger.prototype.switchProvider = function (type) { |
||||
this.debugger.switchProvider(type) |
||||
} |
||||
|
||||
/** |
||||
* get the current provider |
||||
*/ |
||||
Debugger.prototype.web3 = function (type) { |
||||
return this.debugger.web3 |
||||
} |
||||
|
||||
module.exports = Debugger |
@ -0,0 +1,240 @@ |
||||
var remixDebug = require('remix-debug') |
||||
var remixLib = require('remix-lib') |
||||
var EventManager = remixLib.EventManager |
||||
var ui = remixLib.helpers.ui |
||||
var StorageResolver = remixDebug.storage.StorageResolver |
||||
var StorageViewer = remixDebug.storage.StorageViewer |
||||
|
||||
var DebuggerSolidityState = require('./solidityState') |
||||
var DebuggerSolidityLocals = require('./solidityLocals') |
||||
|
||||
class VmDebuggerLogic { |
||||
|
||||
constructor (_debugger, tx, _stepManager, _traceManager, _codeManager, _solidityProxy, _callTree) { |
||||
this.event = new EventManager() |
||||
this.debugger = _debugger |
||||
this.stepManager = _stepManager |
||||
this._traceManager = _traceManager |
||||
this._codeManager = _codeManager |
||||
this._solidityProxy = _solidityProxy |
||||
this._callTree = _callTree |
||||
this.storageResolver = null |
||||
this.tx = tx |
||||
|
||||
this.debuggerSolidityState = new DebuggerSolidityState(tx, _stepManager, _traceManager, _codeManager, _solidityProxy) |
||||
this.debuggerSolidityLocals = new DebuggerSolidityLocals(tx, _stepManager, _traceManager, _callTree) |
||||
} |
||||
|
||||
start () { |
||||
this.listenToEvents() |
||||
this.listenToCodeManagerEvents() |
||||
this.listenToTraceManagerEvents() |
||||
this.listenToFullStorageChanges() |
||||
this.listenToNewChanges() |
||||
|
||||
this.listenToSolidityStateEvents() |
||||
this.listenToSolidityLocalsEvents() |
||||
} |
||||
|
||||
listenToEvents () { |
||||
const self = this |
||||
this.debugger.event.register('traceUnloaded', function () { |
||||
self.event.trigger('traceUnloaded') |
||||
}) |
||||
|
||||
this.debugger.event.register('newTraceLoaded', function () { |
||||
self.event.trigger('newTraceLoaded') |
||||
}) |
||||
} |
||||
|
||||
listenToCodeManagerEvents () { |
||||
const self = this |
||||
this._codeManager.event.register('changed', function (code, address, index) { |
||||
self.event.trigger('codeManagerChanged', [code, address, index]) |
||||
}) |
||||
} |
||||
|
||||
listenToTraceManagerEvents () { |
||||
const self = this |
||||
|
||||
this.event.register('indexChanged', this, function (index) { |
||||
if (index < 0) return |
||||
if (self.stepManager.currentStepIndex !== index) return |
||||
|
||||
self.event.trigger('indexUpdate', [index]) |
||||
|
||||
self._traceManager.getCallDataAt(index, function (error, calldata) { |
||||
if (error) { |
||||
console.log(error) |
||||
self.event.trigger('traceManagerCallDataUpdate', [{}]) |
||||
} else if (self.stepManager.currentStepIndex === index) { |
||||
self.event.trigger('traceManagerCallDataUpdate', [calldata]) |
||||
} |
||||
}) |
||||
|
||||
self._traceManager.getMemoryAt(index, function (error, memory) { |
||||
if (error) { |
||||
console.log(error) |
||||
self.event.trigger('traceManagerMemoryUpdate', [{}]) |
||||
} else if (self.stepManager.currentStepIndex === index) { |
||||
self.event.trigger('traceManagerMemoryUpdate', [ui.formatMemory(memory, 16)]) |
||||
} |
||||
}) |
||||
|
||||
self._traceManager.getCallStackAt(index, function (error, callstack) { |
||||
if (error) { |
||||
console.log(error) |
||||
self.event.trigger('traceManagerCallStackUpdate', [{}]) |
||||
} else if (self.stepManager.currentStepIndex === index) { |
||||
self.event.trigger('traceManagerCallStackUpdate', [callstack]) |
||||
} |
||||
}) |
||||
|
||||
self._traceManager.getStackAt(index, function (error, callstack) { |
||||
if (error) { |
||||
console.log(error) |
||||
self.event.trigger('traceManagerStackUpdate', [{}]) |
||||
} else if (self.stepManager.currentStepIndex === index) { |
||||
self.event.trigger('traceManagerStackUpdate', [callstack]) |
||||
} |
||||
}) |
||||
|
||||
self._traceManager.getCurrentCalledAddressAt(index, (error, address) => { |
||||
if (error) return |
||||
if (!self.storageResolver) return |
||||
|
||||
var storageViewer = new StorageViewer({ stepIndex: self.stepManager.currentStepIndex, tx: self.tx, address: address }, self.storageResolver, self._traceManager) |
||||
|
||||
storageViewer.storageRange((error, storage) => { |
||||
if (error) { |
||||
console.log(error) |
||||
self.event.trigger('traceManagerStorageUpdate', [{}]) |
||||
} else if (self.stepManager.currentStepIndex === index) { |
||||
var header = storageViewer.isComplete(address) ? 'completely loaded' : 'partially loaded...' |
||||
self.event.trigger('traceManagerStorageUpdate', [storage, header]) |
||||
} |
||||
}) |
||||
}) |
||||
|
||||
self._traceManager.getCurrentStep(index, function (error, step) { |
||||
self.event.trigger('traceCurrentStepUpdate', [error, step]) |
||||
}) |
||||
|
||||
self._traceManager.getMemExpand(index, function (error, addmem) { |
||||
self.event.trigger('traceMemExpandUpdate', [error, addmem]) |
||||
}) |
||||
|
||||
self._traceManager.getStepCost(index, function (error, gas) { |
||||
self.event.trigger('traceStepCostUpdate', [error, gas]) |
||||
}) |
||||
|
||||
self._traceManager.getCurrentCalledAddressAt(index, function (error, address) { |
||||
self.event.trigger('traceCurrentCalledAddressAtUpdate', [error, address]) |
||||
}) |
||||
|
||||
self._traceManager.getRemainingGas(index, function (error, remaining) { |
||||
self.event.trigger('traceRemainingGasUpdate', [error, remaining]) |
||||
}) |
||||
|
||||
self._traceManager.getReturnValue(index, function (error, returnValue) { |
||||
if (error) { |
||||
self.event.trigger('traceReturnValueUpdate', [[error]]) |
||||
} else if (self.stepManager.currentStepIndex === index) { |
||||
self.event.trigger('traceReturnValueUpdate', [[returnValue]]) |
||||
} |
||||
}) |
||||
}) |
||||
} |
||||
|
||||
listenToFullStorageChanges () { |
||||
const self = this |
||||
|
||||
this.address = [] |
||||
this.traceLength = 0 |
||||
|
||||
self.debugger.event.register('newTraceLoaded', function (length) { |
||||
self._traceManager.getAddresses(function (error, addresses) { |
||||
if (error) return |
||||
self.event.trigger('traceAddressesUpdate', [addresses]) |
||||
self.addresses = addresses |
||||
}) |
||||
|
||||
self._traceManager.getLength(function (error, length) { |
||||
if (error) return |
||||
self.event.trigger('traceLengthUpdate', [length]) |
||||
self.traceLength = length |
||||
}) |
||||
}) |
||||
|
||||
self.event.register('indexChanged', this, function (index) { |
||||
if (index < 0) return |
||||
if (self.stepManager.currentStepIndex !== index) return |
||||
if (!self.storageResolver) return |
||||
|
||||
// Full storage changes are queried for each step (not only at the end of the trace as it was before)
|
||||
let storageJSON = {} |
||||
for (var k in self.addresses) { |
||||
let address = self.addresses[k] |
||||
let storage = {} |
||||
self._traceManager.accumulateStorageChanges(self.stepManager.currentStepIndex, address, storage, (error, result) => { |
||||
if (!error) { |
||||
storageJSON[address] = result |
||||
self.event.trigger('traceStorageUpdate', [storageJSON]) |
||||
} |
||||
}) |
||||
} |
||||
}) |
||||
} |
||||
|
||||
listenToNewChanges () { |
||||
const self = this |
||||
self.debugger.event.register('newTraceLoaded', this, function () { |
||||
self.storageResolver = new StorageResolver({web3: self.debugger.web3}) |
||||
self.debuggerSolidityState.storageResolver = self.storageResolver |
||||
self.debuggerSolidityLocals.storageResolver = self.storageResolver |
||||
self.event.trigger('newTrace', []) |
||||
}) |
||||
|
||||
self.debugger.event.register('callTreeReady', function () { |
||||
if (self.debugger.callTree.reducedTrace.length) { |
||||
return self.event.trigger('newCallTree', []) |
||||
} |
||||
}) |
||||
} |
||||
|
||||
listenToSolidityStateEvents () { |
||||
const self = this |
||||
this.event.register('indexChanged', this.debuggerSolidityState.init.bind(this.debuggerSolidityState)) |
||||
this.debuggerSolidityState.event.register('solidityState', function (state) { |
||||
self.event.trigger('solidityState', [state]) |
||||
}) |
||||
this.debuggerSolidityState.event.register('solidityStateMessage', function (message) { |
||||
self.event.trigger('solidityStateMessage', [message]) |
||||
}) |
||||
this.debuggerSolidityState.event.register('solidityStateUpdating', function () { |
||||
self.event.trigger('solidityStateUpdating', []) |
||||
}) |
||||
this.event.register('traceUnloaded', this.debuggerSolidityState.reset.bind(this.debuggerSolidityState)) |
||||
this.event.register('newTraceLoaded', this.debuggerSolidityState.reset.bind(this.debuggerSolidityState)) |
||||
} |
||||
|
||||
listenToSolidityLocalsEvents () { |
||||
const self = this |
||||
this.event.register('sourceLocationChanged', this.debuggerSolidityLocals.init.bind(this.debuggerSolidityLocals)) |
||||
this.debuggerSolidityLocals.event.register('solidityLocals', function (state) { |
||||
self.event.trigger('solidityLocals', [state]) |
||||
}) |
||||
this.debuggerSolidityLocals.event.register('solidityLocalsMessage', function (message) { |
||||
self.event.trigger('solidityLocalsMessage', [message]) |
||||
}) |
||||
this.debuggerSolidityLocals.event.register('solidityLocalsUpdating', function () { |
||||
self.event.trigger('solidityLocalsUpdating', []) |
||||
}) |
||||
this.debuggerSolidityLocals.event.register('traceReturnValueUpdate', function (data, header) { |
||||
self.event.trigger('traceReturnValueUpdate', [data, header]) |
||||
}) |
||||
} |
||||
|
||||
} |
||||
|
||||
module.exports = VmDebuggerLogic |
@ -0,0 +1,144 @@ |
||||
'use strict' |
||||
var Ethdebugger = require('remix-debug').EthDebugger |
||||
var remixLib = require('remix-lib') |
||||
var EventManager = remixLib.EventManager |
||||
var traceHelper = remixLib.helpers.trace |
||||
|
||||
var StepManager = require('./stepManager') |
||||
var VmDebuggerLogic = require('./VmDebugger') |
||||
|
||||
function Debugger (options) { |
||||
var self = this |
||||
this.event = new EventManager() |
||||
|
||||
this.executionContext = options.executionContext |
||||
// dependencies
|
||||
this.offsetToLineColumnConverter = options.offsetToLineColumnConverter |
||||
this.compilersArtefacts = options.compilersArtefacts |
||||
|
||||
this.debugger = new Ethdebugger({ |
||||
executionContext: options.executionContext, |
||||
compilationResult: () => { |
||||
if (this.compilersArtefacts['__last']) return this.compilersArtefacts['__last'].getData() |
||||
return null |
||||
} |
||||
}) |
||||
|
||||
this.breakPointManager = new remixLib.code.BreakpointManager(this.debugger, (sourceLocation) => { |
||||
if (!this.compilersArtefacts['__last']) return null |
||||
let compilationData = this.compilersArtefacts['__last'].getData() |
||||
if (!compilationData) return null |
||||
return self.offsetToLineColumnConverter.offsetToLineColumn(sourceLocation, sourceLocation.file, compilationData.sources, compilationData.sources) |
||||
}, (step) => { |
||||
self.event.trigger('breakpointStep', [step]) |
||||
}) |
||||
|
||||
this.debugger.setBreakpointManager(this.breakPointManager) |
||||
|
||||
this.executionContext.event.register('contextChanged', this, function (context) { |
||||
self.debugger.switchProvider(context) |
||||
}) |
||||
|
||||
this.debugger.event.register('newTraceLoaded', this, function () { |
||||
self.event.trigger('debuggerStatus', [true]) |
||||
}) |
||||
|
||||
this.debugger.event.register('traceUnloaded', this, function () { |
||||
self.event.trigger('debuggerStatus', [false]) |
||||
}) |
||||
|
||||
this.event.register('breakpointStep', function (step) { |
||||
self.step_manager.jumpTo(step) |
||||
}) |
||||
|
||||
this.debugger.addProvider('vm', this.executionContext.vm()) |
||||
this.debugger.addProvider('injected', this.executionContext.internalWeb3()) |
||||
this.debugger.addProvider('web3', this.executionContext.internalWeb3()) |
||||
this.debugger.switchProvider(this.executionContext.getProvider()) |
||||
} |
||||
|
||||
Debugger.prototype.registerAndHighlightCodeItem = function (index) { |
||||
const self = this |
||||
// register selected code item, highlight the corresponding source location
|
||||
if (!self.compilersArtefacts['__last']) { |
||||
self.event.trigger('newSourceLocation', [null]) |
||||
return |
||||
} |
||||
var compilerData = self.compilersArtefacts['__last'].getData() |
||||
self.debugger.traceManager.getCurrentCalledAddressAt(index, (error, address) => { |
||||
if (error) return console.log(error) |
||||
self.debugger.callTree.sourceLocationTracker.getSourceLocationFromVMTraceIndex(address, index, compilerData.contracts, function (error, rawLocation) { |
||||
if (!error) { |
||||
var lineColumnPos = self.offsetToLineColumnConverter.offsetToLineColumn(rawLocation, rawLocation.file, compilerData.sources, compilerData.sources) |
||||
self.event.trigger('newSourceLocation', [lineColumnPos, rawLocation]) |
||||
} else { |
||||
self.event.trigger('newSourceLocation', [null]) |
||||
} |
||||
}) |
||||
}) |
||||
} |
||||
|
||||
Debugger.prototype.debug = function (blockNumber, txNumber, tx, loadingCb) { |
||||
const self = this |
||||
let web3 = this.executionContext.web3() |
||||
|
||||
if (this.debugger.traceManager.isLoading) { |
||||
return |
||||
} |
||||
|
||||
self.debugger.solidityProxy.reset({}) |
||||
|
||||
if (tx) { |
||||
if (!tx.to) { |
||||
tx.to = traceHelper.contractCreationToken('0') |
||||
} |
||||
return self.debugTx(tx, loadingCb) |
||||
} |
||||
|
||||
try { |
||||
if (txNumber.indexOf('0x') !== -1) { |
||||
return web3.eth.getTransaction(txNumber, function (_error, result) { |
||||
let tx = result |
||||
self.debugTx(tx, loadingCb) |
||||
}) |
||||
} |
||||
web3.eth.getTransactionFromBlock(blockNumber, txNumber, function (_error, result) { |
||||
let tx = result |
||||
self.debugTx(tx, loadingCb) |
||||
}) |
||||
} catch (e) { |
||||
console.error(e.message) |
||||
} |
||||
} |
||||
|
||||
Debugger.prototype.debugTx = function (tx, loadingCb) { |
||||
const self = this |
||||
this.step_manager = new StepManager(this.debugger, this.debugger.traceManager) |
||||
|
||||
this.debugger.codeManager.event.register('changed', this, (code, address, instIndex) => { |
||||
self.debugger.callTree.sourceLocationTracker.getSourceLocationFromVMTraceIndex(address, this.step_manager.currentStepIndex, this.debugger.solidityProxy.contracts, (error, sourceLocation) => { |
||||
if (!error) { |
||||
self.vmDebuggerLogic.event.trigger('sourceLocationChanged', [sourceLocation]) |
||||
} |
||||
}) |
||||
}) |
||||
|
||||
this.vmDebuggerLogic = new VmDebuggerLogic(this.debugger, tx, this.step_manager, this.debugger.traceManager, this.debugger.codeManager, this.debugger.solidityProxy, this.debugger.callTree) |
||||
|
||||
this.step_manager.event.register('stepChanged', this, function (stepIndex) { |
||||
self.debugger.codeManager.resolveStep(stepIndex, tx) |
||||
self.step_manager.event.trigger('indexChanged', [stepIndex]) |
||||
self.vmDebuggerLogic.event.trigger('indexChanged', [stepIndex]) |
||||
self.registerAndHighlightCodeItem(stepIndex) |
||||
}) |
||||
|
||||
loadingCb() |
||||
this.debugger.debug(tx) |
||||
} |
||||
|
||||
Debugger.prototype.unload = function () { |
||||
this.debugger.unLoad() |
||||
this.event.trigger('debuggerUnloaded') |
||||
} |
||||
|
||||
module.exports = Debugger |
@ -0,0 +1,65 @@ |
||||
var remixLib = require('remix-lib') |
||||
var EventManager = remixLib.EventManager |
||||
var remixDebug = require('remix-debug') |
||||
var localDecoder = remixDebug.SolidityDecoder.localDecoder |
||||
var StorageViewer = remixDebug.storage.StorageViewer |
||||
|
||||
class DebuggerSolidityLocals { |
||||
|
||||
constructor (tx, _stepManager, _traceManager, _internalTreeCall) { |
||||
this.event = new EventManager() |
||||
this.stepManager = _stepManager |
||||
this.internalTreeCall = _internalTreeCall |
||||
this.storageResolver = null |
||||
this.traceManager = _traceManager |
||||
this.tx = tx |
||||
} |
||||
|
||||
init (sourceLocation) { |
||||
const self = this |
||||
var decodeTimeout = null |
||||
if (!this.storageResolver) { |
||||
return self.event.trigger('solidityLocalsMessage', ['storage not ready']) |
||||
} |
||||
if (decodeTimeout) { |
||||
window.clearTimeout(decodeTimeout) |
||||
} |
||||
self.event.trigger('solidityLocalsUpdating') |
||||
decodeTimeout = setTimeout(function () { |
||||
self.decode(sourceLocation) |
||||
}, 500) |
||||
} |
||||
|
||||
decode (sourceLocation) { |
||||
const self = this |
||||
self.event.trigger('solidityLocalsMessage', ['']) |
||||
self.traceManager.waterfall([ |
||||
self.traceManager.getStackAt, |
||||
self.traceManager.getMemoryAt, |
||||
self.traceManager.getCurrentCalledAddressAt], |
||||
self.stepManager.currentStepIndex, |
||||
(error, result) => { |
||||
if (error) { |
||||
return console.log(error) |
||||
} |
||||
var stack = result[0].value |
||||
var memory = result[1].value |
||||
try { |
||||
var storageViewer = new StorageViewer({ stepIndex: self.stepManager.currentStepIndex, tx: self.tx, address: result[2].value }, self.storageResolver, self.traceManager) |
||||
localDecoder.solidityLocals(self.stepManager.currentStepIndex, self.internalTreeCall, stack, memory, storageViewer, sourceLocation).then((locals) => { |
||||
if (!locals.error) { |
||||
self.event.trigger('solidityLocals', [locals]) |
||||
} |
||||
if (!Object.keys(locals).length) { |
||||
self.event.trigger('solidityLocalsMessage', ['no locals']) |
||||
} |
||||
}) |
||||
} catch (e) { |
||||
self.event.trigger('solidityLocalsMessage', [e.message]) |
||||
} |
||||
}) |
||||
} |
||||
|
||||
} |
||||
|
||||
module.exports = DebuggerSolidityLocals |
@ -0,0 +1,81 @@ |
||||
var remixLib = require('remix-lib') |
||||
var EventManager = remixLib.EventManager |
||||
var remixDebug = require('remix-debug') |
||||
var stateDecoder = remixDebug.SolidityDecoder.stateDecoder |
||||
var StorageViewer = remixDebug.storage.StorageViewer |
||||
|
||||
class DebuggerSolidityState { |
||||
|
||||
constructor (tx, _stepManager, _traceManager, _codeManager, _solidityProxy) { |
||||
this.event = new EventManager() |
||||
this.storageResolver = null |
||||
this.stepManager = _stepManager |
||||
this.traceManager = _traceManager |
||||
this.codeManager = _codeManager |
||||
this.solidityProxy = _solidityProxy |
||||
this.stateVariablesByAddresses = {} |
||||
this.tx = tx |
||||
} |
||||
|
||||
init (index) { |
||||
var self = this |
||||
var decodeTimeout = null |
||||
if (index < 0) { |
||||
return self.event.trigger('solidityStateMessage', ['invalid step index']) |
||||
} |
||||
|
||||
if (self.stepManager.currentStepIndex !== index) return |
||||
if (!self.solidityProxy.loaded()) { |
||||
return self.event.trigger('solidityStateMessage', ['invalid step index']) |
||||
} |
||||
|
||||
if (!self.storageResolver) { |
||||
return |
||||
} |
||||
if (decodeTimeout) { |
||||
window.clearTimeout(decodeTimeout) |
||||
} |
||||
self.event.trigger('solidityStateUpdating') |
||||
decodeTimeout = setTimeout(function () { |
||||
self.decode(index) |
||||
}, 500) |
||||
} |
||||
|
||||
reset () { |
||||
this.stateVariablesByAddresses = {} |
||||
} |
||||
|
||||
decode (index) { |
||||
const self = this |
||||
self.traceManager.getCurrentCalledAddressAt(self.stepManager.currentStepIndex, function (error, address) { |
||||
if (error) { |
||||
return self.event.trigger('solidityState', [{}]) |
||||
} |
||||
if (self.stateVariablesByAddresses[address]) { |
||||
return self.extractStateVariables(self.stateVariablesByAddresses[address], address) |
||||
} |
||||
self.solidityProxy.extractStateVariablesAt(index, function (error, stateVars) { |
||||
if (error) { |
||||
return self.event.trigger('solidityState', [{}]) |
||||
} |
||||
self.stateVariablesByAddresses[address] = stateVars |
||||
self.extractStateVariables(stateVars, address) |
||||
}) |
||||
}) |
||||
} |
||||
|
||||
extractStateVariables (stateVars, address) { |
||||
const self = this |
||||
var storageViewer = new StorageViewer({ stepIndex: self.stepManager.currentStepIndex, tx: self.tx, address: address }, self.storageResolver, self.traceManager) |
||||
stateDecoder.decodeState(stateVars, storageViewer).then((result) => { |
||||
self.event.trigger('solidityStateMessage', ['']) |
||||
if (result.error) { |
||||
return self.event.trigger('solidityStateMessage', [result.error]) |
||||
} |
||||
self.event.trigger('solidityState', [result]) |
||||
}) |
||||
} |
||||
|
||||
} |
||||
|
||||
module.exports = DebuggerSolidityState |
@ -0,0 +1,145 @@ |
||||
var remixLib = require('remix-lib') |
||||
var EventManager = remixLib.EventManager |
||||
|
||||
class DebuggerStepManager { |
||||
|
||||
constructor (_debugger, traceManager) { |
||||
this.event = new EventManager() |
||||
this.debugger = _debugger |
||||
this.traceManager = traceManager |
||||
this.currentStepIndex = 0 |
||||
this.traceLength = 0 |
||||
this.revertionPoint = null |
||||
|
||||
this.listenToEvents() |
||||
} |
||||
|
||||
listenToEvents () { |
||||
const self = this |
||||
|
||||
this.debugger.event.register('newTraceLoaded', this, function () { |
||||
self.traceManager.getLength(function (error, newLength) { |
||||
if (error) { |
||||
return console.log(error) |
||||
} |
||||
if (self.traceLength !== newLength) { |
||||
self.event.trigger('traceLengthChanged', [newLength]) |
||||
self.traceLength = newLength |
||||
} |
||||
self.jumpTo(0) |
||||
}) |
||||
}) |
||||
|
||||
this.debugger.callTree.event.register('callTreeReady', () => { |
||||
if (self.debugger.callTree.functionCallStack.length) { |
||||
self.jumpTo(self.debugger.callTree.functionCallStack[0]) |
||||
} |
||||
}) |
||||
|
||||
this.event.register('indexChanged', this, (index) => { |
||||
if (index < 0) return |
||||
if (self.currentStepIndex !== index) return |
||||
|
||||
self.traceManager.buildCallPath(index, (error, callsPath) => { |
||||
if (error) { |
||||
console.log(error) |
||||
return self.event.trigger('revertWarning', ['']) |
||||
} |
||||
self.currentCall = callsPath[callsPath.length - 1] |
||||
if (self.currentCall.reverted) { |
||||
let revertedReason = self.currentCall.outofgas ? 'outofgas' : '' |
||||
self.revertionPoint = self.currentCall.return |
||||
return self.event.trigger('revertWarning', [revertedReason]) |
||||
} |
||||
for (var k = callsPath.length - 2; k >= 0; k--) { |
||||
var parent = callsPath[k] |
||||
if (!parent.reverted) continue |
||||
self.revertionPoint = parent.return |
||||
self.event.trigger('revertWarning', ['parenthasthrown']) |
||||
} |
||||
self.event.trigger('revertWarning', ['']) |
||||
}) |
||||
}) |
||||
} |
||||
|
||||
triggerStepChanged (step) { |
||||
const self = this |
||||
this.traceManager.getLength(function (error, length) { |
||||
let stepState = 'valid' |
||||
|
||||
if (error) { |
||||
stepState = 'invalid' |
||||
} else if (step <= 0) { |
||||
stepState = 'initial' |
||||
} else if (step >= length - 1) { |
||||
stepState = 'end' |
||||
} |
||||
|
||||
let jumpOutDisabled = (step === self.traceManager.findStepOut(step)) |
||||
|
||||
self.event.trigger('stepChanged', [step, stepState, jumpOutDisabled]) |
||||
}) |
||||
} |
||||
|
||||
stepIntoBack () { |
||||
if (!this.traceManager.isLoaded()) return |
||||
var step = this.currentStepIndex - 1 |
||||
this.currentStepIndex = step |
||||
if (!this.traceManager.inRange(step)) { |
||||
return |
||||
} |
||||
this.event.trigger('stepChanged', [step]) |
||||
} |
||||
|
||||
stepIntoForward () { |
||||
if (!this.traceManager.isLoaded()) return |
||||
var step = this.currentStepIndex + 1 |
||||
this.currentStepIndex = step |
||||
if (!this.traceManager.inRange(step)) { |
||||
return |
||||
} |
||||
this.event.trigger('stepChanged', [step]) |
||||
} |
||||
|
||||
stepOverBack () { |
||||
if (!this.traceManager.isLoaded()) return |
||||
var step = this.traceManager.findStepOverBack(this.currentStepIndex) |
||||
this.currentStepIndex = step |
||||
this.event.trigger('stepChanged', [step]) |
||||
} |
||||
|
||||
stepOverForward () { |
||||
if (!this.traceManager.isLoaded()) return |
||||
var step = this.traceManager.findStepOverForward(this.currentStepIndex) |
||||
this.currentStepIndex = step |
||||
this.event.trigger('stepChanged', [step]) |
||||
} |
||||
|
||||
jumpOut () { |
||||
if (!this.traceManager.isLoaded()) return |
||||
var step = this.traceManager.findStepOut(this.currentStepIndex) |
||||
this.currentStepIndex = step |
||||
this.event.trigger('stepChanged', [step]) |
||||
} |
||||
|
||||
jumpTo (step) { |
||||
if (!this.traceManager.inRange(step)) return |
||||
this.currentStepIndex = step |
||||
this.event.trigger('stepChanged', [step]) |
||||
} |
||||
|
||||
jumpToException () { |
||||
this.jumpTo(this.revertionPoint) |
||||
} |
||||
|
||||
jumpNextBreakpoint () { |
||||
this.debugger.breakpointManager.jumpNextBreakpoint(this.currentStepIndex, true) |
||||
} |
||||
|
||||
jumpPreviousBreakpoint () { |
||||
this.debugger.breakpointManager.jumpPreviousBreakpoint(this.currentStepIndex, true) |
||||
} |
||||
|
||||
} |
||||
|
||||
module.exports = DebuggerStepManager |
@ -0,0 +1,161 @@ |
||||
var TxBrowser = require('./debuggerUI/TxBrowser') |
||||
var StepManagerUI = require('./debuggerUI/StepManager') |
||||
var VmDebugger = require('./debuggerUI/VmDebugger') |
||||
|
||||
var Debugger = require('./debugger/debugger') |
||||
|
||||
var SourceHighlighter = require('../editor/sourceHighlighter') |
||||
|
||||
var remixLib = require('remix-lib') |
||||
var EventManager = remixLib.EventManager |
||||
|
||||
var executionContext = require('../../execution-context') |
||||
var globalRegistry = require('../../global/registry') |
||||
|
||||
var yo = require('yo-yo') |
||||
var csjs = require('csjs-inject') |
||||
|
||||
var css = csjs` |
||||
.statusMessage { |
||||
margin-left: 15px; |
||||
} |
||||
.innerShift { |
||||
padding: 2px; |
||||
margin-left: 10px; |
||||
} |
||||
` |
||||
|
||||
class DebuggerUI { |
||||
|
||||
constructor (container) { |
||||
this.registry = globalRegistry |
||||
this.event = new EventManager() |
||||
|
||||
this.debugger = new Debugger({ |
||||
executionContext: executionContext, |
||||
offsetToLineColumnConverter: this.registry.get('offsettolinecolumnconverter').api, |
||||
compiler: this.registry.get('compiler').api, |
||||
compilersArtefacts: this.registry.get('compilersartefacts').api |
||||
}) |
||||
|
||||
this.isActive = false |
||||
|
||||
this.sourceHighlighter = new SourceHighlighter() |
||||
|
||||
this.startTxBrowser() |
||||
this.stepManager = null |
||||
|
||||
this.statusMessage = '' |
||||
|
||||
this.view |
||||
|
||||
container.appendChild(this.render()) |
||||
|
||||
this.setEditor() |
||||
this.listenToEvents() |
||||
} |
||||
|
||||
setEditor () { |
||||
const self = this |
||||
this.editor = this.registry.get('editor').api |
||||
|
||||
self.editor.event.register('breakpointCleared', (fileName, row) => { |
||||
self.debugger.breakPointManager.remove({fileName: fileName, row: row}) |
||||
}) |
||||
|
||||
self.editor.event.register('breakpointAdded', (fileName, row) => { |
||||
self.debugger.breakPointManager.add({fileName: fileName, row: row}) |
||||
}) |
||||
|
||||
self.editor.event.register('contentChanged', function () { |
||||
self.debugger.unload() |
||||
}) |
||||
} |
||||
|
||||
listenToEvents () { |
||||
const self = this |
||||
this.debugger.event.register('debuggerStatus', function (isActive) { |
||||
self.sourceHighlighter.currentSourceLocation(null) |
||||
self.isActive = isActive |
||||
}) |
||||
|
||||
this.debugger.event.register('newSourceLocation', function (lineColumnPos, rawLocation) { |
||||
self.sourceHighlighter.currentSourceLocation(lineColumnPos, rawLocation) |
||||
}) |
||||
|
||||
this.debugger.event.register('debuggerUnloaded', self.unLoad.bind(this)) |
||||
} |
||||
|
||||
startTxBrowser () { |
||||
const self = this |
||||
let txBrowser = new TxBrowser() |
||||
this.txBrowser = txBrowser |
||||
|
||||
txBrowser.event.register('requestDebug', function (blockNumber, txNumber, tx) { |
||||
self.debugger.unload() |
||||
self.startDebugging(blockNumber, txNumber, tx) |
||||
}) |
||||
|
||||
txBrowser.event.register('unloadRequested', this, function (blockNumber, txIndex, tx) { |
||||
self.debugger.unload() |
||||
}) |
||||
} |
||||
|
||||
isDebuggerActive () { |
||||
return this.isActive |
||||
} |
||||
|
||||
startDebugging (blockNumber, txNumber, tx) { |
||||
const self = this |
||||
|
||||
this.debugger.debug(blockNumber, txNumber, tx, () => { |
||||
self.stepManager = new StepManagerUI(this.debugger.step_manager) |
||||
self.vmDebugger = new VmDebugger(this.debugger.vmDebuggerLogic) |
||||
self.renderDebugger() |
||||
}) |
||||
} |
||||
|
||||
debug (txHash) { |
||||
this.startDebugging(null, txHash, null) |
||||
} |
||||
|
||||
render () { |
||||
this.debuggerPanelsView = yo`<div class="${css.innerShift}"></div>` |
||||
this.debuggerHeadPanelsView = yo`<div class="${css.innerShift}"></div>` |
||||
this.stepManagerView = yo`<div class="${css.innerShift}"></div>` |
||||
|
||||
var view = yo`<div>
|
||||
<div class="${css.innerShift}"> |
||||
${this.txBrowser.render()} |
||||
${this.debuggerHeadPanelsView} |
||||
${this.stepManagerView} |
||||
</div> |
||||
<div class="${css.statusMessage}" >${this.statusMessage}</div> |
||||
${this.debuggerPanelsView} |
||||
</div>` |
||||
if (!this.view) { |
||||
this.view = view |
||||
} |
||||
return view |
||||
} |
||||
|
||||
unLoad () { |
||||
yo.update(this.debuggerHeadPanelsView, yo`<div></div>`) |
||||
yo.update(this.debuggerPanelsView, yo`<div></div>`) |
||||
yo.update(this.stepManagerView, yo`<div></div>`) |
||||
if (this.vmDebugger) this.vmDebugger.remove() |
||||
if (this.stepManager) this.stepManager.remove() |
||||
this.vmDebugger = null |
||||
this.stepManager = null |
||||
this.event.trigger('traceUnloaded') |
||||
} |
||||
|
||||
renderDebugger () { |
||||
yo.update(this.debuggerHeadPanelsView, this.vmDebugger.renderHead()) |
||||
yo.update(this.debuggerPanelsView, this.vmDebugger.render()) |
||||
yo.update(this.stepManagerView, this.stepManager.render()) |
||||
} |
||||
|
||||
} |
||||
|
||||
module.exports = DebuggerUI |
@ -0,0 +1,58 @@ |
||||
'use strict' |
||||
var remixLib = require('remix-lib') |
||||
var EventManager = remixLib.EventManager |
||||
var yo = require('yo-yo') |
||||
|
||||
class Slider { |
||||
constructor () { |
||||
this.event = new EventManager() |
||||
this.max |
||||
this.disabled = true |
||||
this.view |
||||
this.previousValue = null |
||||
} |
||||
|
||||
setSliderLength (length) { |
||||
if (!this.view) return |
||||
this.view.querySelector('#slider').setAttribute('max', length - 1) |
||||
this.max = length - 1 |
||||
this.disabled = (length === 0) |
||||
|
||||
if (this.disabled) { |
||||
this.view.querySelector('#slider').setAttribute('disabled', true) |
||||
} else { |
||||
this.view.querySelector('#slider').removeAttribute('disabled') |
||||
} |
||||
|
||||
this.setValue(0) |
||||
} |
||||
|
||||
onChange (event) { |
||||
if (!this.view) return |
||||
var value = parseInt(this.view.querySelector('#slider').value) |
||||
if (value === this.previousValue) return |
||||
|
||||
this.previousValue = value |
||||
this.event.trigger('sliderMoved', [value]) |
||||
} |
||||
|
||||
setValue (value) { |
||||
if (!this.view) return |
||||
this.view.querySelector('#slider').value = value |
||||
} |
||||
|
||||
render () { |
||||
var self = this |
||||
var view = yo`<div>
|
||||
<input id='slider' style='width: 100%' type='range' min=0 max=${this.max} value=0 |
||||
onchange=${function () { self.onChange() }} oninput=${function () { self.onChange() }} disabled=${this.disabled} /> |
||||
</div>` |
||||
if (!this.view) { |
||||
this.view = view |
||||
} |
||||
return view |
||||
} |
||||
|
||||
} |
||||
|
||||
module.exports = Slider |
@ -0,0 +1,59 @@ |
||||
var remixLib = require('remix-lib') |
||||
var EventManager = remixLib.EventManager |
||||
var yo = require('yo-yo') |
||||
|
||||
var ButtonNavigator = require('./ButtonNavigator') |
||||
var Slider = require('./Slider') |
||||
|
||||
function StepManager (stepManager) { |
||||
this.event = new EventManager() |
||||
this.stepManager = stepManager |
||||
this.startSlider() |
||||
this.startButtonNavigator() |
||||
this.stepManager.event.register('stepChanged', this.updateStep.bind(this)) |
||||
} |
||||
|
||||
StepManager.prototype.startSlider = function () { |
||||
this.slider = new Slider() |
||||
this.slider.event.register('sliderMoved', this.stepManager.jumpTo.bind(this.stepManager)) |
||||
this.stepManager.event.register('traceLengthChanged', this.slider.setSliderLength.bind(this.slider)) |
||||
} |
||||
|
||||
StepManager.prototype.startButtonNavigator = function () { |
||||
this.buttonNavigator = new ButtonNavigator() |
||||
|
||||
this.stepManager.event.register('revertWarning', this.buttonNavigator.resetWarning.bind(this.buttonNavigator)) |
||||
|
||||
this.buttonNavigator.event.register('stepIntoBack', this.stepManager.stepIntoBack.bind(this.stepManager)) |
||||
this.buttonNavigator.event.register('stepIntoForward', this.stepManager.stepIntoForward.bind(this.stepManager)) |
||||
this.buttonNavigator.event.register('stepOverBack', this.stepManager.stepOverBack.bind(this.stepManager)) |
||||
this.buttonNavigator.event.register('stepOverForward', this.stepManager.stepOverForward.bind(this.stepManager)) |
||||
this.buttonNavigator.event.register('jumpOut', this.stepManager.jumpOut.bind(this.stepManager)) |
||||
this.buttonNavigator.event.register('jumpToException', this.stepManager.jumpToException.bind(this.stepManager)) |
||||
this.buttonNavigator.event.register('jumpNextBreakpoint', this.stepManager.jumpNextBreakpoint.bind(this.stepManager)) |
||||
this.buttonNavigator.event.register('jumpPreviousBreakpoint', this.stepManager.jumpPreviousBreakpoint.bind(this.stepManager)) |
||||
} |
||||
|
||||
StepManager.prototype.updateStep = function (step, stepState, jumpOutDisabled) { |
||||
if (!this.slider) return |
||||
this.slider.setValue(step) |
||||
this.buttonNavigator.stepChanged(stepState, jumpOutDisabled) |
||||
this.event.trigger('stepChanged', [step]) |
||||
} |
||||
|
||||
StepManager.prototype.remove = function () { |
||||
// used to stop listenning on event. bad and should be "refactored"
|
||||
this.slider.view = null |
||||
this.slider = null |
||||
this.buttonNavigator.view = null |
||||
this.buttonNavigator = null |
||||
} |
||||
|
||||
StepManager.prototype.render = function () { |
||||
return yo`<div>
|
||||
${this.slider.render()} |
||||
${this.buttonNavigator.render()} |
||||
</div>` |
||||
} |
||||
|
||||
module.exports = StepManager |
@ -0,0 +1,122 @@ |
||||
var remixLib = require('remix-lib') |
||||
var EventManager = remixLib.EventManager |
||||
var yo = require('yo-yo') |
||||
var csjs = require('csjs-inject') |
||||
var styleGuide = require('../../ui/styles-guide/theme-chooser') |
||||
var styles = styleGuide.chooser() |
||||
|
||||
var css = csjs` |
||||
.container { |
||||
display: flex; |
||||
flex-direction: column; |
||||
} |
||||
.txContainer { |
||||
display: flex; |
||||
flex-direction: column; |
||||
} |
||||
.txinputs { |
||||
width: 100%; |
||||
display: flex; |
||||
justify-content: center; |
||||
} |
||||
.txinput { |
||||
${styles.rightPanel.debuggerTab.input_Debugger} |
||||
margin: 3px; |
||||
width: inherit; |
||||
} |
||||
.txbuttons { |
||||
width: 100%; |
||||
display: flex; |
||||
justify-content: center; |
||||
} |
||||
.txbutton { |
||||
${styles.rightPanel.debuggerTab.button_Debugger} |
||||
width: inherit; |
||||
} |
||||
.txbuttonstart { |
||||
${styles.rightPanel.debuggerTab.button_Debugger} |
||||
} |
||||
.txbutton:hover { |
||||
color: ${styles.rightPanel.debuggerTab.button_Debugger_icon_HoverColor}; |
||||
} |
||||
.vmargin { |
||||
margin-top: 10px; |
||||
margin-bottom: 10px; |
||||
} |
||||
` |
||||
|
||||
function TxBrowser () { |
||||
this.event = new EventManager() |
||||
|
||||
this.blockNumber |
||||
this.txNumber |
||||
this.view |
||||
this.setDefaultValues() |
||||
} |
||||
|
||||
TxBrowser.prototype.setDefaultValues = function () { |
||||
this.connectInfo = '' |
||||
if (this.view) { |
||||
yo.update(this.view, this.render()) |
||||
} |
||||
} |
||||
|
||||
TxBrowser.prototype.submit = function (tx) { |
||||
this.event.trigger('requestDebug', [this.blockNumber, this.txNumber, tx]) |
||||
} |
||||
|
||||
TxBrowser.prototype.update = function (error, tx) { |
||||
if (error) { |
||||
this.view.querySelector('#error').innerHTML = error |
||||
return |
||||
} |
||||
|
||||
if (!tx) { |
||||
this.view.querySelector('#error').innerHTML = 'Cannot find transaction with reference. Block number: ' + this.blockNumber + '. Transaction index/hash: ' + this.txNumber |
||||
return |
||||
} |
||||
|
||||
this.view.querySelector('#error').innerHTML = '' |
||||
} |
||||
|
||||
TxBrowser.prototype.updateBlockN = function (ev) { |
||||
this.blockNumber = ev.target.value |
||||
} |
||||
|
||||
TxBrowser.prototype.updateTxN = function (ev) { |
||||
this.txNumber = ev.target.value |
||||
} |
||||
|
||||
TxBrowser.prototype.load = function (txHash, tx) { |
||||
this.txNumber = txHash |
||||
} |
||||
|
||||
TxBrowser.prototype.unload = function (txHash) { |
||||
this.event.trigger('unloadRequested') |
||||
this.setDefaultValues() |
||||
} |
||||
|
||||
TxBrowser.prototype.render = function () { |
||||
var self = this |
||||
var view = yo`<div class="${css.container}">
|
||||
<div class="${css.txContainer}"> |
||||
<div class="${css.txinputs}"> |
||||
<input class="${css.txinput}" onkeyup=${function () { self.updateBlockN(arguments[0]) }} type='text' placeholder=${'Block number'} /> |
||||
<input class="${css.txinput}" id='txinput' onkeyup=${function () { self.updateTxN(arguments[0]) }} type='text' placeholder=${'Transaction index or hash'} /> |
||||
</div> |
||||
<div class="${css.txbuttons}"> |
||||
<button id='load' class='${css.txbutton}' title='start debugging' onclick=${function () { self.submit() }}>Start debugging</button> |
||||
<button id='unload' class='${css.txbutton}' title='stop debugging' onclick=${function () { self.unload() }}>Stop</button> |
||||
</div> |
||||
</div> |
||||
<span id='error'></span> |
||||
</div>` |
||||
|
||||
if (!this.view) { |
||||
this.view = view |
||||
} |
||||
|
||||
return view |
||||
} |
||||
|
||||
module.exports = TxBrowser |
@ -0,0 +1,163 @@ |
||||
'use strict' |
||||
var csjs = require('csjs-inject') |
||||
var yo = require('yo-yo') |
||||
|
||||
var CodeListView = require('./vmDebugger/CodeListView') |
||||
var CalldataPanel = require('./vmDebugger/CalldataPanel') |
||||
var MemoryPanel = require('./vmDebugger/MemoryPanel') |
||||
var CallstackPanel = require('./vmDebugger/CallstackPanel') |
||||
var StackPanel = require('./vmDebugger/StackPanel') |
||||
var StoragePanel = require('./vmDebugger/StoragePanel') |
||||
var StepDetail = require('./vmDebugger/StepDetail') |
||||
var SolidityState = require('./vmDebugger/SolidityState') |
||||
var SolidityLocals = require('./vmDebugger/SolidityLocals') |
||||
var FullStoragesChangesPanel = require('./vmDebugger/FullStoragesChanges') |
||||
var DropdownPanel = require('./vmDebugger/DropdownPanel') |
||||
|
||||
var css = csjs` |
||||
.asmCode { |
||||
float: left; |
||||
width: 50%; |
||||
} |
||||
.stepDetail { |
||||
} |
||||
.vmheadView { |
||||
margin-top:10px; |
||||
} |
||||
` |
||||
|
||||
function VmDebugger (vmDebuggerLogic) { |
||||
var self = this |
||||
this.view |
||||
|
||||
this.vmDebuggerLogic = vmDebuggerLogic |
||||
|
||||
this.asmCode = new CodeListView() |
||||
this.vmDebuggerLogic.event.register('codeManagerChanged', this.asmCode.changed.bind(this.asmCode)) |
||||
this.vmDebuggerLogic.event.register('traceUnloaded', this.asmCode.reset.bind(this.asmCode)) |
||||
|
||||
this.calldataPanel = new CalldataPanel() |
||||
this.vmDebuggerLogic.event.register('traceManagerCallDataUpdate', this.calldataPanel.update.bind(this.calldataPanel)) |
||||
|
||||
this.memoryPanel = new MemoryPanel() |
||||
this.vmDebuggerLogic.event.register('traceManagerMemoryUpdate', this.memoryPanel.update.bind(this.memoryPanel)) |
||||
|
||||
this.callstackPanel = new CallstackPanel() |
||||
this.vmDebuggerLogic.event.register('traceManagerCallStackUpdate', this.callstackPanel.update.bind(this.callstackPanel)) |
||||
|
||||
this.stackPanel = new StackPanel() |
||||
this.vmDebuggerLogic.event.register('traceManagerStackUpdate', this.stackPanel.update.bind(this.stackPanel)) |
||||
|
||||
this.storagePanel = new StoragePanel() |
||||
this.vmDebuggerLogic.event.register('traceManagerStorageUpdate', this.storagePanel.update.bind(this.storagePanel)) |
||||
|
||||
this.stepDetail = new StepDetail() |
||||
this.vmDebuggerLogic.event.register('traceUnloaded', this.stepDetail.reset.bind(this.stepDetail)) |
||||
this.vmDebuggerLogic.event.register('newTraceLoaded', this.stepDetail.reset.bind(this.stepDetail)) |
||||
|
||||
this.vmDebuggerLogic.event.register('traceCurrentStepUpdate', function (error, step) { |
||||
self.stepDetail.updateField('execution step', (error ? '-' : step)) |
||||
}) |
||||
|
||||
this.vmDebuggerLogic.event.register('traceMemExpandUpdate', function (error, addmem) { |
||||
self.stepDetail.updateField('add memory', (error ? '-' : addmem)) |
||||
}) |
||||
|
||||
this.vmDebuggerLogic.event.register('traceStepCostUpdate', function (error, gas) { |
||||
self.stepDetail.updateField('gas', (error ? '-' : gas)) |
||||
}) |
||||
|
||||
this.vmDebuggerLogic.event.register('traceCurrentCalledAddressAtUpdate', function (error, address) { |
||||
self.stepDetail.updateField('loaded address', (error ? '-' : address)) |
||||
}) |
||||
|
||||
this.vmDebuggerLogic.event.register('traceRemainingGasUpdate', function (error, remainingGas) { |
||||
self.stepDetail.updateField('remaining gas', (error ? '-' : remainingGas)) |
||||
}) |
||||
|
||||
this.vmDebuggerLogic.event.register('indexUpdate', function (index) { |
||||
self.stepDetail.updateField('vm trace step', index) |
||||
}) |
||||
|
||||
this.solidityState = new SolidityState() |
||||
this.vmDebuggerLogic.event.register('solidityState', this.solidityState.update.bind(this.solidityState)) |
||||
this.vmDebuggerLogic.event.register('solidityStateMessage', this.solidityState.setMessage.bind(this.solidityState)) |
||||
this.vmDebuggerLogic.event.register('solidityStateUpdating', this.solidityState.setUpdating.bind(this.solidityState)) |
||||
|
||||
this.solidityLocals = new SolidityLocals() |
||||
this.vmDebuggerLogic.event.register('solidityLocals', this.solidityLocals.update.bind(this.solidityLocals)) |
||||
this.vmDebuggerLogic.event.register('solidityLocalsMessage', this.solidityLocals.setMessage.bind(this.solidityLocals)) |
||||
this.vmDebuggerLogic.event.register('solidityLocalsUpdating', this.solidityLocals.setUpdating.bind(this.solidityLocals)) |
||||
|
||||
this.returnValuesPanel = new DropdownPanel('Return Value', {json: true}) |
||||
this.returnValuesPanel.data = {} |
||||
this.vmDebuggerLogic.event.register('traceReturnValueUpdate', this.returnValuesPanel.update.bind(this.returnValuesPanel)) |
||||
|
||||
this.fullStoragesChangesPanel = new FullStoragesChangesPanel() |
||||
this.addresses = [] |
||||
|
||||
this.vmDebuggerLogic.event.register('traceAddressesUpdate', function (_addresses) { |
||||
self.fullStoragesChangesPanel.update({}) |
||||
}) |
||||
|
||||
this.vmDebuggerLogic.event.register('traceStorageUpdate', this.fullStoragesChangesPanel.update.bind(this.fullStoragesChangesPanel)) |
||||
|
||||
this.vmDebuggerLogic.event.register('newTrace', () => { |
||||
if (!self.view) return |
||||
|
||||
self.asmCode.basicPanel.show() |
||||
self.stackPanel.basicPanel.show() |
||||
self.storagePanel.basicPanel.show() |
||||
self.memoryPanel.basicPanel.show() |
||||
self.calldataPanel.basicPanel.show() |
||||
self.callstackPanel.basicPanel.show() |
||||
}) |
||||
|
||||
this.vmDebuggerLogic.event.register('newCallTree', () => { |
||||
if (!self.view) return |
||||
self.solidityLocals.basicPanel.show() |
||||
self.solidityState.basicPanel.show() |
||||
}) |
||||
|
||||
this.vmDebuggerLogic.start() |
||||
} |
||||
|
||||
VmDebugger.prototype.renderHead = function () { |
||||
var headView = yo`<div id='vmheadView' class=${css.vmheadView}>
|
||||
<div> |
||||
<div class=${css.asmCode}>${this.asmCode.render()}</div> |
||||
<div class=${css.stepDetail}>${this.stepDetail.render()}</div> |
||||
</div> |
||||
</div>` |
||||
if (!this.headView) { |
||||
this.headView = headView |
||||
} |
||||
return headView |
||||
} |
||||
|
||||
VmDebugger.prototype.remove = function () { |
||||
// used to stop listenning on event. bad and should be "refactored"
|
||||
this.view = null |
||||
} |
||||
|
||||
VmDebugger.prototype.render = function () { |
||||
var view = yo`<div id='vmdebugger'>
|
||||
<div> |
||||
${this.solidityLocals.render()} |
||||
${this.solidityState.render()} |
||||
${this.stackPanel.render()} |
||||
${this.memoryPanel.render()} |
||||
${this.storagePanel.render()} |
||||
${this.callstackPanel.render()} |
||||
${this.calldataPanel.render()} |
||||
${this.returnValuesPanel.render()} |
||||
${this.fullStoragesChangesPanel.render()} |
||||
</div> |
||||
</div>` |
||||
if (!this.view) { |
||||
this.view = view |
||||
} |
||||
return view |
||||
} |
||||
|
||||
module.exports = VmDebugger |
@ -0,0 +1,17 @@ |
||||
'use strict' |
||||
var DropdownPanel = require('./DropdownPanel') |
||||
var yo = require('yo-yo') |
||||
|
||||
function CalldataPanel () { |
||||
this.basicPanel = new DropdownPanel('Call Data', {json: true}) |
||||
} |
||||
|
||||
CalldataPanel.prototype.update = function (calldata) { |
||||
this.basicPanel.update(calldata) |
||||
} |
||||
|
||||
CalldataPanel.prototype.render = function () { |
||||
return yo`<div id='calldatapanel' >${this.basicPanel.render()}</div>` |
||||
} |
||||
|
||||
module.exports = CalldataPanel |
@ -0,0 +1,18 @@ |
||||
'use strict' |
||||
var DropdownPanel = require('./DropdownPanel') |
||||
var yo = require('yo-yo') |
||||
|
||||
function CallstackPanel () { |
||||
this.basicPanel = new DropdownPanel('Call Stack', {json: true}) |
||||
} |
||||
|
||||
CallstackPanel.prototype.update = function (calldata) { |
||||
this.basicPanel.update(calldata) |
||||
} |
||||
|
||||
CallstackPanel.prototype.render = function () { |
||||
return yo`<div id='callstackpanel' >${this.basicPanel.render()}</div>` |
||||
} |
||||
|
||||
module.exports = CallstackPanel |
||||
|
@ -0,0 +1,21 @@ |
||||
var DropdownPanel = require('./DropdownPanel') |
||||
var yo = require('yo-yo') |
||||
|
||||
function FullStoragesChanges () { |
||||
this.view |
||||
this.basicPanel = new DropdownPanel('Full Storages Changes', {json: true}) |
||||
} |
||||
|
||||
FullStoragesChanges.prototype.update = function (storageData) { |
||||
this.basicPanel.update(storageData) |
||||
} |
||||
|
||||
FullStoragesChanges.prototype.render = function () { |
||||
var view = yo`<div id='fullstorageschangespanel' >${this.basicPanel.render()}</div>` |
||||
if (!this.view) { |
||||
this.view = view |
||||
} |
||||
return view |
||||
} |
||||
|
||||
module.exports = FullStoragesChanges |
@ -0,0 +1,21 @@ |
||||
'use strict' |
||||
var DropdownPanel = require('./DropdownPanel') |
||||
var yo = require('yo-yo') |
||||
|
||||
function MemoryPanel () { |
||||
this.basicPanel = new DropdownPanel('Memory', { |
||||
json: true, |
||||
css: { |
||||
'font-family': 'monospace' |
||||
}}) |
||||
} |
||||
|
||||
MemoryPanel.prototype.update = function (calldata) { |
||||
this.basicPanel.update(calldata) |
||||
} |
||||
|
||||
MemoryPanel.prototype.render = function () { |
||||
return yo`<div id='memorypanel' >${this.basicPanel.render()}</div>` |
||||
} |
||||
|
||||
module.exports = MemoryPanel |
@ -0,0 +1,38 @@ |
||||
'use strict' |
||||
var remixLib = require('remix-lib') |
||||
var EventManager = remixLib.EventManager |
||||
var DropdownPanel = require('./DropdownPanel') |
||||
var solidityTypeFormatter = require('./utils/SolidityTypeFormatter') |
||||
var yo = require('yo-yo') |
||||
|
||||
class SolidityLocals { |
||||
|
||||
constructor (_parent, _traceManager, _internalTreeCall) { |
||||
this.event = new EventManager() |
||||
this.basicPanel = new DropdownPanel('Solidity Locals', { |
||||
json: true, |
||||
formatSelf: solidityTypeFormatter.formatSelf, |
||||
extractData: solidityTypeFormatter.extractData |
||||
}) |
||||
this.view |
||||
} |
||||
|
||||
update (data) { |
||||
this.basicPanel.update(data) |
||||
} |
||||
|
||||
setMessage (message) { |
||||
this.basicPanel.setMessage(message) |
||||
} |
||||
|
||||
setUpdating () { |
||||
this.basicPanel.setUpdating() |
||||
} |
||||
|
||||
render () { |
||||
this.view = yo`<div id='soliditylocals'>${this.basicPanel.render()}</div>` |
||||
return this.view |
||||
} |
||||
} |
||||
|
||||
module.exports = SolidityLocals |
@ -0,0 +1,35 @@ |
||||
var DropdownPanel = require('./DropdownPanel') |
||||
var solidityTypeFormatter = require('./utils/SolidityTypeFormatter') |
||||
var yo = require('yo-yo') |
||||
|
||||
function SolidityState () { |
||||
this.basicPanel = new DropdownPanel('Solidity State', { |
||||
json: true, |
||||
// TODO: used by TreeView ui
|
||||
formatSelf: solidityTypeFormatter.formatSelf, |
||||
extractData: solidityTypeFormatter.extractData |
||||
}) |
||||
this.view |
||||
} |
||||
|
||||
SolidityState.prototype.update = function (data) { |
||||
this.basicPanel.update(data) |
||||
} |
||||
|
||||
SolidityState.prototype.setMessage = function (message) { |
||||
this.basicPanel.setMessage(message) |
||||
} |
||||
|
||||
SolidityState.prototype.setUpdating = function () { |
||||
this.basicPanel.setUpdating() |
||||
} |
||||
|
||||
SolidityState.prototype.render = function () { |
||||
if (this.view) return |
||||
this.view = yo`<div id='soliditystate' >
|
||||
${this.basicPanel.render()} |
||||
</div>` |
||||
return this.view |
||||
} |
||||
|
||||
module.exports = SolidityState |
@ -0,0 +1,17 @@ |
||||
'use strict' |
||||
var DropdownPanel = require('./DropdownPanel') |
||||
var yo = require('yo-yo') |
||||
|
||||
function StackPanel () { |
||||
this.basicPanel = new DropdownPanel('Stack', {json: true, displayContentOnly: false}) |
||||
} |
||||
|
||||
StackPanel.prototype.update = function (calldata) { |
||||
this.basicPanel.update(calldata) |
||||
} |
||||
|
||||
StackPanel.prototype.render = function () { |
||||
return yo`<div id='stackpanel' >${this.basicPanel.render()}</div>` |
||||
} |
||||
|
||||
module.exports = StackPanel |
@ -0,0 +1,23 @@ |
||||
var yo = require('yo-yo') |
||||
var DropdownPanel = require('./DropdownPanel') |
||||
|
||||
function StepDetail () { |
||||
this.basicPanel = new DropdownPanel('Step detail', {json: true, displayContentOnly: true}) |
||||
this.detail = { 'vm trace step': '-', 'execution step': '-', 'add memory': '', 'gas': '', 'remaining gas': '-', 'loaded address': '-' } |
||||
} |
||||
|
||||
StepDetail.prototype.reset = function () { |
||||
this.detail = { 'vm trace step': '-', 'execution step': '-', 'add memory': '', 'gas': '', 'remaining gas': '-', 'loaded address': '-' } |
||||
this.basicPanel.update(this.detail) |
||||
} |
||||
|
||||
StepDetail.prototype.updateField = function (key, value) { |
||||
this.detail[key] = value |
||||
this.basicPanel.update(this.detail) |
||||
} |
||||
|
||||
StepDetail.prototype.render = function () { |
||||
return yo`<div id='stepdetail' >${this.basicPanel.render()}</div>` |
||||
} |
||||
|
||||
module.exports = StepDetail |
@ -0,0 +1,17 @@ |
||||
'use strict' |
||||
var DropdownPanel = require('./DropdownPanel') |
||||
var yo = require('yo-yo') |
||||
|
||||
function StoragePanel (_parent, _traceManager) { |
||||
this.basicPanel = new DropdownPanel('Storage', {json: true}) |
||||
} |
||||
|
||||
StoragePanel.prototype.update = function (storage, header) { |
||||
this.basicPanel.update(storage, header) |
||||
} |
||||
|
||||
StoragePanel.prototype.render = function () { |
||||
return yo`<div id='storagepanel' >${this.basicPanel.render()}</div>` |
||||
} |
||||
|
||||
module.exports = StoragePanel |
@ -1,33 +0,0 @@ |
||||
'use strict' |
||||
var DropdownPanel = require('./DropdownPanel') |
||||
var yo = require('yo-yo') |
||||
|
||||
function CalldataPanel (_parentUI, _traceManager) { |
||||
this._parentUI = _parentUI |
||||
this.traceManager = _traceManager |
||||
this.basicPanel = new DropdownPanel('Call Data', {json: true}) |
||||
this.init() |
||||
} |
||||
|
||||
CalldataPanel.prototype.render = function () { |
||||
return yo`<div id='calldatapanel' >${this.basicPanel.render()}</div>` |
||||
} |
||||
|
||||
CalldataPanel.prototype.init = function () { |
||||
var self = this |
||||
this._parentUI.event.register('indexChanged', this, function (index) { |
||||
if (index < 0) return |
||||
if (self._parentUI.currentStepIndex !== index) return |
||||
|
||||
self.traceManager.getCallDataAt(index, function (error, calldata) { |
||||
if (error) { |
||||
self.basicPanel.update({}) |
||||
console.log(error) |
||||
} else if (self._parentUI.currentStepIndex === index) { |
||||
self.basicPanel.update(calldata) |
||||
} |
||||
}) |
||||
}) |
||||
} |
||||
|
||||
module.exports = CalldataPanel |
@ -1,33 +0,0 @@ |
||||
'use strict' |
||||
var DropdownPanel = require('./DropdownPanel') |
||||
var yo = require('yo-yo') |
||||
|
||||
function CallstackPanel (_parent, _traceManager) { |
||||
this.parent = _parent |
||||
this.traceManager = _traceManager |
||||
this.basicPanel = new DropdownPanel('Call Stack', {json: true}) |
||||
this.init() |
||||
} |
||||
|
||||
CallstackPanel.prototype.render = function () { |
||||
return yo`<div id='callstackpanel' >${this.basicPanel.render()}</div>` |
||||
} |
||||
|
||||
CallstackPanel.prototype.init = function () { |
||||
var self = this |
||||
this.parent.event.register('indexChanged', this, function (index) { |
||||
if (index < 0) return |
||||
if (self.parent.currentStepIndex !== index) return |
||||
|
||||
self.traceManager.getCallStackAt(index, function (error, callstack) { |
||||
if (error) { |
||||
console.log(error) |
||||
self.basicPanel.update({}) |
||||
} else if (self.parent.currentStepIndex === index) { |
||||
self.basicPanel.update(callstack) |
||||
} |
||||
}) |
||||
}) |
||||
} |
||||
|
||||
module.exports = CallstackPanel |
@ -1,210 +0,0 @@ |
||||
'use strict' |
||||
var TxBrowser = require('./TxBrowser') |
||||
var StepManager = require('./StepManager') |
||||
var remixLib = require('remix-lib') |
||||
var TraceManager = remixLib.trace.TraceManager |
||||
var VmDebugger = require('./VmDebugger') |
||||
var init = remixLib.init |
||||
var executionContext = remixLib.execution.executionContext |
||||
var EventManager = remixLib.EventManager |
||||
var yo = require('yo-yo') |
||||
var csjs = require('csjs-inject') |
||||
var Web3Providers = remixLib.vm.Web3Providers |
||||
var DummyProvider = remixLib.vm.DummyProvider |
||||
var CodeManager = remixLib.code.CodeManager |
||||
var remixDebug = require('remix-debug') |
||||
var SolidityProxy = remixDebug.SolidityDecoder.SolidityProxy |
||||
var InternalCallTree = remixDebug.SolidityDecoder.InternalCallTree |
||||
|
||||
var css = csjs` |
||||
.statusMessage { |
||||
margin-left: 15px; |
||||
} |
||||
.innerShift { |
||||
padding: 2px; |
||||
margin-left: 10px; |
||||
} |
||||
` |
||||
|
||||
function Ethdebugger (opts) { |
||||
this.opts = opts || {} |
||||
if (!this.opts.compilationResult) this.opts.compilationResult = () => { return null } |
||||
|
||||
var self = this |
||||
this.event = new EventManager() |
||||
|
||||
this.currentStepIndex = -1 |
||||
this.tx |
||||
this.statusMessage = '' |
||||
|
||||
this.view |
||||
this.web3Providers = new Web3Providers() |
||||
this.addProvider('DUMMYWEB3', new DummyProvider()) |
||||
this.switchProvider('DUMMYWEB3') |
||||
this.traceManager = new TraceManager() |
||||
this.codeManager = new CodeManager(this.traceManager) |
||||
this.solidityProxy = new SolidityProxy(this.traceManager, this.codeManager) |
||||
|
||||
var callTree = new InternalCallTree(this.event, this.traceManager, this.solidityProxy, this.codeManager, { includeLocalVariables: true }) |
||||
this.callTree = callTree // TODO: currently used by browser solidity, we should improve the API
|
||||
|
||||
this.event.register('indexChanged', this, function (index) { |
||||
self.codeManager.resolveStep(index, self.tx) |
||||
}) |
||||
|
||||
this.txBrowser = new TxBrowser(this) |
||||
this.txBrowser.event.register('newTxLoading', this, function () { |
||||
self.unLoad() |
||||
}) |
||||
this.txBrowser.event.register('newTraceRequested', this, function (blockNumber, txIndex, tx) { |
||||
console.dir('newTraceRequestd') |
||||
console.dir(arguments) |
||||
self.startDebugging(blockNumber, txIndex, tx) |
||||
}) |
||||
this.txBrowser.event.register('unloadRequested', this, function (blockNumber, txIndex, tx) { |
||||
self.unLoad() |
||||
}) |
||||
this.stepManager = new StepManager(this, this.traceManager) |
||||
this.stepManager.event.register('stepChanged', this, function (stepIndex) { |
||||
self.stepChanged(stepIndex) |
||||
}) |
||||
this.vmDebugger = new VmDebugger(this, this.traceManager, this.codeManager, this.solidityProxy, callTree) |
||||
|
||||
this.codeManager.event.register('changed', this, (code, address, instIndex) => { |
||||
this.callTree.sourceLocationTracker.getSourceLocationFromVMTraceIndex(address, this.currentStepIndex, this.solidityProxy.contracts, (error, sourceLocation) => { |
||||
if (!error) { |
||||
this.event.trigger('sourceLocationChanged', [sourceLocation]) |
||||
} |
||||
}) |
||||
}) |
||||
} |
||||
|
||||
Ethdebugger.prototype.setManagers = function () { |
||||
this.traceManager = new TraceManager({web3: this.web3}) |
||||
this.codeManager = new CodeManager(this.traceManager) |
||||
this.solidityProxy = new SolidityProxy(this.traceManager, this.codeManager) |
||||
this.storageResolver = null |
||||
var callTree = new InternalCallTree(this.event, this.traceManager, this.solidityProxy, this.codeManager, { includeLocalVariables: true }) |
||||
this.callTree = callTree // TODO: currently used by browser solidity, we should improve the API
|
||||
this.vmDebugger = new VmDebugger(this, this.traceManager, this.codeManager, this.solidityProxy, callTree) |
||||
|
||||
this.callTree = new InternalCallTree(this.event, this.traceManager, this.solidityProxy, this.codeManager, { includeLocalVariables: true }) |
||||
} |
||||
|
||||
Ethdebugger.prototype.setBreakpointManager = function (breakpointManager) { |
||||
this.breakpointManager = breakpointManager |
||||
} |
||||
|
||||
Ethdebugger.prototype.web3 = function () { |
||||
return global.web3 |
||||
} |
||||
|
||||
Ethdebugger.prototype.addProvider = function (type, obj) { |
||||
this.web3Providers.addProvider(type, obj) |
||||
this.event.trigger('providerAdded', [type]) |
||||
} |
||||
|
||||
Ethdebugger.prototype.updateWeb3Reference = function () { |
||||
if (!this.txBrowser) return |
||||
this.txBrowser.web3 = this.web3 |
||||
} |
||||
|
||||
Ethdebugger.prototype.switchProvider = function (type) { |
||||
var self = this |
||||
this.web3Providers.get(type, function (error, obj) { |
||||
if (error) { |
||||
console.log('provider ' + type + ' not defined') |
||||
} else { |
||||
self.web3 = obj |
||||
self.setManagers() |
||||
self.updateWeb3Reference() |
||||
executionContext.detectNetwork((error, network) => { |
||||
if (error || !network) { |
||||
global.web3Debug = obj |
||||
} else { |
||||
var webDebugNode = init.web3DebugNode(network.name) |
||||
global.web3Debug = !webDebugNode ? obj : webDebugNode |
||||
} |
||||
self.updateWeb3Reference() |
||||
}) |
||||
self.event.trigger('providerChanged', [type]) |
||||
} |
||||
}) |
||||
} |
||||
|
||||
Ethdebugger.prototype.setCompilationResult = function (compilationResult) { |
||||
if (compilationResult && compilationResult.sources && compilationResult.contracts) { |
||||
this.solidityProxy.reset(compilationResult) |
||||
} else { |
||||
this.solidityProxy.reset({}) |
||||
} |
||||
} |
||||
|
||||
Ethdebugger.prototype.debug = function (tx) { |
||||
this.setCompilationResult(this.opts.compilationResult()) |
||||
if (tx instanceof Object) { |
||||
this.txBrowser.load(tx.hash) |
||||
} else if (tx instanceof String) { |
||||
this.txBrowser.load(tx) |
||||
} |
||||
} |
||||
|
||||
Ethdebugger.prototype.render = function () { |
||||
var view = yo`<div>
|
||||
<div class="${css.innerShift}"> |
||||
${this.txBrowser.render()} |
||||
${this.vmDebugger.renderHead()} |
||||
${this.stepManager.render()} |
||||
</div> |
||||
<div class="${css.statusMessage}" >${this.statusMessage}</div> |
||||
${this.vmDebugger.render()} |
||||
</div>` |
||||
if (!this.view) { |
||||
this.view = view |
||||
} |
||||
return view |
||||
} |
||||
|
||||
Ethdebugger.prototype.unLoad = function () { |
||||
this.traceManager.init() |
||||
this.codeManager.clear() |
||||
this.stepManager.reset() |
||||
this.event.trigger('traceUnloaded') |
||||
} |
||||
|
||||
Ethdebugger.prototype.stepChanged = function (stepIndex) { |
||||
this.currentStepIndex = stepIndex |
||||
this.event.trigger('indexChanged', [stepIndex]) |
||||
} |
||||
|
||||
Ethdebugger.prototype.startDebugging = function (blockNumber, txIndex, tx) { |
||||
console.dir('startDebugging') |
||||
console.dir(arguments) |
||||
if (this.traceManager.isLoading) { |
||||
return |
||||
} |
||||
this.setCompilationResult(this.opts.compilationResult()) |
||||
this.statusMessage = 'Loading trace...' |
||||
yo.update(this.view, this.render()) |
||||
console.log('loading trace...') |
||||
this.tx = tx |
||||
var self = this |
||||
console.dir('resolving a trace with tx: ') |
||||
console.dir(tx) |
||||
this.traceManager.resolveTrace(tx, function (error, result) { |
||||
console.log('trace loaded ' + result) |
||||
if (result) { |
||||
self.statusMessage = '' |
||||
yo.update(self.view, self.render()) |
||||
self.event.trigger('newTraceLoaded', [self.traceManager.trace]) |
||||
if (self.breakpointManager && self.breakpointManager.hasBreakpoint()) { |
||||
self.breakpointManager.jumpNextBreakpoint(0, false) |
||||
} |
||||
} else { |
||||
self.statusMessage = error ? error.message : 'Trace not loaded' |
||||
yo.update(self.view, self.render()) |
||||
} |
||||
}) |
||||
} |
||||
|
||||
module.exports = Ethdebugger |
@ -1,154 +0,0 @@ |
||||
'use strict' |
||||
var TxBrowser = require('./TxBrowser') |
||||
var StepManager = require('./StepManager') |
||||
var VmDebugger = require('./VmDebugger') |
||||
|
||||
var yo = require('yo-yo') |
||||
var csjs = require('csjs-inject') |
||||
|
||||
var remixLib = require('remix-lib') |
||||
var executionContext = remixLib.execution.executionContext |
||||
var EventManager = remixLib.EventManager |
||||
|
||||
var css = csjs` |
||||
.statusMessage { |
||||
margin-left: 15px; |
||||
} |
||||
.innerShift { |
||||
padding: 2px; |
||||
margin-left: 10px; |
||||
} |
||||
` |
||||
|
||||
function EthdebuggerUI (opts) { |
||||
this.opts = opts || {} |
||||
this.debugger = opts.debugger |
||||
|
||||
if (!this.opts.compilationResult) this.opts.compilationResult = () => { return null } |
||||
|
||||
var self = this |
||||
this.event = new EventManager() |
||||
|
||||
this.currentStepIndex = -1 |
||||
this.tx |
||||
this.statusMessage = '' |
||||
|
||||
this.view |
||||
|
||||
this.event.register('indexChanged', this, function (index) { |
||||
self.debugger.codeManager.resolveStep(index, self.tx) |
||||
}) |
||||
|
||||
executionContext.event.register('contextChanged', this, function () { |
||||
self.updateWeb3Reference() |
||||
}) |
||||
|
||||
this.txBrowser = new TxBrowser(this, {displayConnectionSetting: false, web3: executionContext.web3()}) |
||||
this.txBrowser.event.register('newTxLoading', this, function () { |
||||
self.unLoad() |
||||
}) |
||||
this.txBrowser.event.register('newTraceRequested', this, function (blockNumber, txIndex, tx) { |
||||
self.startDebugging(blockNumber, txIndex, tx) |
||||
}) |
||||
this.txBrowser.event.register('unloadRequested', this, function (blockNumber, txIndex, tx) { |
||||
self.unLoad() |
||||
}) |
||||
} |
||||
|
||||
EthdebuggerUI.prototype.setBreakpointManager = function (breakpointManager) { |
||||
this.breakpointManager = breakpointManager |
||||
} |
||||
|
||||
EthdebuggerUI.prototype.get_web3 = function () { |
||||
return this.web3 |
||||
} |
||||
|
||||
EthdebuggerUI.prototype.updateWeb3Reference = function (web3) { |
||||
if (!this.txBrowser) return |
||||
this.txBrowser.web3 = web3 || executionContext.web3() |
||||
} |
||||
|
||||
EthdebuggerUI.prototype.setCompilationResult = function (compilationResult) { |
||||
if (compilationResult && compilationResult.sources && compilationResult.contracts) { |
||||
this.debugger.solidityProxy.reset(compilationResult) |
||||
} else { |
||||
this.debugger.solidityProxy.reset({}) |
||||
} |
||||
} |
||||
|
||||
EthdebuggerUI.prototype.debug = function (tx) { |
||||
this.setCompilationResult(this.opts.compilationResult()) |
||||
if (tx instanceof Object) { |
||||
this.txBrowser.load(tx.hash, tx) |
||||
} else if (tx instanceof String) { |
||||
this.txBrowser.load(tx) |
||||
} |
||||
} |
||||
|
||||
EthdebuggerUI.prototype.render = function () { |
||||
this.debuggerPanelsView = yo`<div class="${css.innerShift}"></div>` |
||||
this.debuggerHeadPanelsView = yo`<div class="${css.innerShift}"></div>` |
||||
this.stepManagerView = yo`<div class="${css.innerShift}"></div>` |
||||
|
||||
var view = yo`<div>
|
||||
<div class="${css.innerShift}"> |
||||
${this.txBrowser.render()} |
||||
${this.debuggerHeadPanelsView} |
||||
${this.stepManagerView} |
||||
</div> |
||||
<div class="${css.statusMessage}" >${this.statusMessage}</div> |
||||
${this.debuggerPanelsView} |
||||
</div>` |
||||
if (!this.view) { |
||||
this.view = view |
||||
} |
||||
return view |
||||
} |
||||
|
||||
EthdebuggerUI.prototype.unLoad = function () { |
||||
this.debugger.unLoad() |
||||
yo.update(this.debuggerHeadPanelsView, yo`<div></div>`) |
||||
yo.update(this.debuggerPanelsView, yo`<div></div>`) |
||||
yo.update(this.stepManagerView, yo`<div></div>`) |
||||
if (this.vmDebugger) this.vmDebugger.remove() |
||||
if (this.stepManager) this.stepManager.remove() |
||||
this.vmDebugger = null |
||||
this.stepManager = null |
||||
this.event.trigger('traceUnloaded') |
||||
} |
||||
|
||||
EthdebuggerUI.prototype.stepChanged = function (stepIndex) { |
||||
this.currentStepIndex = stepIndex |
||||
this.event.trigger('indexChanged', [stepIndex]) |
||||
} |
||||
|
||||
EthdebuggerUI.prototype.startDebugging = function (blockNumber, txIndex, tx) { |
||||
const self = this |
||||
if (this.debugger.traceManager.isLoading) { |
||||
return |
||||
} |
||||
|
||||
this.tx = tx |
||||
|
||||
this.stepManager = new StepManager(this, this.debugger.traceManager) |
||||
this.stepManager.event.register('stepChanged', this, function (stepIndex) { |
||||
self.stepChanged(stepIndex) |
||||
}) |
||||
|
||||
this.debugger.codeManager.event.register('changed', this, (code, address, instIndex) => { |
||||
self.debugger.callTree.sourceLocationTracker.getSourceLocationFromVMTraceIndex(address, this.currentStepIndex, this.debugger.solidityProxy.contracts, (error, sourceLocation) => { |
||||
if (!error) { |
||||
self.event.trigger('sourceLocationChanged', [sourceLocation]) |
||||
} |
||||
}) |
||||
}) |
||||
|
||||
this.vmDebugger = new VmDebugger(this, this.debugger.traceManager, this.debugger.codeManager, this.debugger.solidityProxy, this.debugger.callTree) |
||||
yo.update(this.debuggerHeadPanelsView, this.vmDebugger.renderHead()) |
||||
yo.update(this.debuggerPanelsView, this.vmDebugger.render()) |
||||
yo.update(this.stepManagerView, this.stepManager.render()) |
||||
|
||||
this.debugger.debug(tx) |
||||
} |
||||
|
||||
module.exports = EthdebuggerUI |
@ -1,72 +0,0 @@ |
||||
'use strict' |
||||
var DropdownPanel = require('./DropdownPanel') |
||||
var remixDebug = require('remix-debug') |
||||
var StorageViewer = remixDebug.storage.StorageViewer |
||||
var yo = require('yo-yo') |
||||
|
||||
function FullStoragesChanges (_parent, _traceManager) { |
||||
this.storageResolver = null |
||||
this.parent = _parent |
||||
this.debugger = _parent.debugger |
||||
this.traceManager = _traceManager |
||||
this.addresses = [] |
||||
this.view |
||||
this.traceLength |
||||
this.basicPanel = new DropdownPanel('Full Storages Changes', {json: true}) |
||||
this.init() |
||||
} |
||||
|
||||
FullStoragesChanges.prototype.render = function () { |
||||
var view = yo`<div id='fullstorageschangespanel' >${this.basicPanel.render()}</div>` |
||||
if (!this.view) { |
||||
this.view = view |
||||
} |
||||
return view |
||||
} |
||||
|
||||
FullStoragesChanges.prototype.init = function () { |
||||
var self = this |
||||
this.debugger.event.register('newTraceLoaded', this, function (length) { |
||||
self.panels = [] |
||||
self.traceManager.getAddresses(function (error, addresses) { |
||||
if (!error) { |
||||
self.addresses = addresses |
||||
self.basicPanel.update({}) |
||||
} |
||||
}) |
||||
|
||||
self.traceManager.getLength(function (error, length) { |
||||
if (!error) { |
||||
self.traceLength = length |
||||
} |
||||
}) |
||||
}) |
||||
|
||||
this.debugger.event.register('indexChanged', this, function (index) { |
||||
if (index < 0) return |
||||
if (self.parent.currentStepIndex !== index) return |
||||
if (!self.storageResolver) return |
||||
|
||||
if (index === self.traceLength - 1) { |
||||
var storageJSON = {} |
||||
for (var k in self.addresses) { |
||||
var address = self.addresses[k] |
||||
var storageViewer = new StorageViewer({ |
||||
stepIndex: self.parent.currentStepIndex, |
||||
tx: self.parent.tx, |
||||
address: address |
||||
}, self.storageResolver, self.traceManager) |
||||
storageViewer.storageRange(function (error, result) { |
||||
if (!error) { |
||||
storageJSON[address] = result |
||||
self.basicPanel.update(storageJSON) |
||||
} |
||||
}) |
||||
} |
||||
} else { |
||||
self.basicPanel.update({}) |
||||
} |
||||
}) |
||||
} |
||||
|
||||
module.exports = FullStoragesChanges |
@ -1,39 +0,0 @@ |
||||
'use strict' |
||||
var DropdownPanel = require('./DropdownPanel') |
||||
var remixLib = require('remix-lib') |
||||
var ui = remixLib.helpers.ui |
||||
var yo = require('yo-yo') |
||||
|
||||
function MemoryPanel (_parent, _traceManager) { |
||||
this.parent = _parent |
||||
this.traceManager = _traceManager |
||||
this.basicPanel = new DropdownPanel('Memory', { |
||||
json: true, |
||||
css: { |
||||
'font-family': 'monospace' |
||||
}}) |
||||
this.init() |
||||
} |
||||
|
||||
MemoryPanel.prototype.render = function () { |
||||
return yo`<div id='memorypanel' >${this.basicPanel.render()}</div>` |
||||
} |
||||
|
||||
MemoryPanel.prototype.init = function () { |
||||
var self = this |
||||
this.parent.event.register('indexChanged', this, function (index) { |
||||
if (index < 0) return |
||||
if (self.parent.currentStepIndex !== index) return |
||||
|
||||
self.traceManager.getMemoryAt(index, function (error, memory) { |
||||
if (error) { |
||||
console.log(error) |
||||
self.basicPanel.update({}) |
||||
} else if (self.parent.currentStepIndex === index) { |
||||
self.basicPanel.update(ui.formatMemory(memory, 16)) |
||||
} |
||||
}) |
||||
}) |
||||
} |
||||
|
||||
module.exports = MemoryPanel |
@ -1,75 +0,0 @@ |
||||
'use strict' |
||||
var remixLib = require('remix-lib') |
||||
var EventManager = remixLib.EventManager |
||||
var yo = require('yo-yo') |
||||
|
||||
class Slider { |
||||
constructor (_traceManager, _stepOverride) { |
||||
this.event = new EventManager() |
||||
this.traceManager = _traceManager |
||||
this.max |
||||
this.disabled = true |
||||
this.view |
||||
this.solidityMode = false |
||||
this.stepOverride = _stepOverride |
||||
|
||||
this.previousValue = null |
||||
} |
||||
|
||||
render () { |
||||
var self = this |
||||
var view = yo`<div>
|
||||
<input |
||||
id='slider' |
||||
style='width: 100%' |
||||
type='range' |
||||
min=0 |
||||
max=${this.max} |
||||
value=0 |
||||
onchange=${function () { self.onChange() }} |
||||
oninput=${function () { self.onChange() }} |
||||
disabled=${this.disabled} /> |
||||
</div>` |
||||
if (!this.view) { |
||||
this.view = view |
||||
} |
||||
return view |
||||
} |
||||
|
||||
init (length) { |
||||
var slider = this.view.querySelector('#slider') |
||||
slider.setAttribute('max', length - 1) |
||||
this.max = length - 1 |
||||
this.updateDisabled(length === 0) |
||||
this.disabled = length === 0 |
||||
this.setValue(0) |
||||
} |
||||
|
||||
onChange (event) { |
||||
var value = parseInt(this.view.querySelector('#slider').value) |
||||
if (this.stepOverride) { |
||||
var correctedValue = this.stepOverride(value) |
||||
if (correctedValue !== value) { |
||||
this.setValue(correctedValue) |
||||
value = correctedValue |
||||
} |
||||
} |
||||
if (value === this.previousValue) return |
||||
this.previousValue = value |
||||
this.event.trigger('moved', [value]) |
||||
} |
||||
|
||||
setValue (value) { |
||||
this.view.querySelector('#slider').value = value |
||||
} |
||||
|
||||
updateDisabled (disabled) { |
||||
if (disabled) { |
||||
this.view.querySelector('#slider').setAttribute('disabled', true) |
||||
} else { |
||||
this.view.querySelector('#slider').removeAttribute('disabled') |
||||
} |
||||
} |
||||
} |
||||
|
||||
module.exports = Slider |
@ -1,83 +0,0 @@ |
||||
'use strict' |
||||
var DropdownPanel = require('./DropdownPanel') |
||||
var remixDebug = require('remix-debug') |
||||
var localDecoder = remixDebug.SolidityDecoder.localDecoder |
||||
var solidityTypeFormatter = require('./SolidityTypeFormatter') |
||||
var StorageViewer = remixDebug.storage.StorageViewer |
||||
var yo = require('yo-yo') |
||||
|
||||
class SolidityLocals { |
||||
|
||||
constructor (_parent, _traceManager, _internalTreeCall) { |
||||
this.parent = _parent |
||||
this.internalTreeCall = _internalTreeCall |
||||
this.storageResolver = null |
||||
this.traceManager = _traceManager |
||||
this.basicPanel = new DropdownPanel('Solidity Locals', { |
||||
json: true, |
||||
formatSelf: solidityTypeFormatter.formatSelf, |
||||
extractData: solidityTypeFormatter.extractData |
||||
}) |
||||
this.init() |
||||
this.view |
||||
} |
||||
|
||||
render () { |
||||
this.view = yo`<div id='soliditylocals' >
|
||||
${this.basicPanel.render()} |
||||
</div>` |
||||
return this.view |
||||
} |
||||
|
||||
init () { |
||||
var decodeTimeout = null |
||||
this.parent.event.register('sourceLocationChanged', this, (sourceLocation) => { |
||||
if (!this.storageResolver) { |
||||
this.basicPanel.setMessage('storage not ready') |
||||
return |
||||
} |
||||
if (decodeTimeout) { |
||||
window.clearTimeout(decodeTimeout) |
||||
} |
||||
this.basicPanel.setUpdating() |
||||
decodeTimeout = setTimeout(() => { |
||||
decode(this, sourceLocation) |
||||
}, 500) |
||||
}) |
||||
} |
||||
} |
||||
|
||||
function decode (self, sourceLocation) { |
||||
self.basicPanel.setMessage('') |
||||
self.traceManager.waterfall([ |
||||
self.traceManager.getStackAt, |
||||
self.traceManager.getMemoryAt, |
||||
self.traceManager.getCurrentCalledAddressAt], |
||||
self.parent.currentStepIndex, |
||||
(error, result) => { |
||||
if (!error) { |
||||
var stack = result[0].value |
||||
var memory = result[1].value |
||||
try { |
||||
var storageViewer = new StorageViewer({ |
||||
stepIndex: self.parent.currentStepIndex, |
||||
tx: self.parent.tx, |
||||
address: result[2].value |
||||
}, self.storageResolver, self.traceManager) |
||||
localDecoder.solidityLocals(self.parent.currentStepIndex, self.internalTreeCall, stack, memory, storageViewer, sourceLocation).then((locals) => { |
||||
if (!locals.error) { |
||||
self.basicPanel.update(locals) |
||||
} |
||||
if (!Object.keys(locals).length) { |
||||
self.basicPanel.setMessage('no locals') |
||||
} |
||||
}) |
||||
} catch (e) { |
||||
self.basicPanel.setMessage(e.message) |
||||
} |
||||
} else { |
||||
console.log(error) |
||||
} |
||||
}) |
||||
} |
||||
module.exports = SolidityLocals |
@ -1,103 +0,0 @@ |
||||
'use strict' |
||||
var DropdownPanel = require('./DropdownPanel') |
||||
var remixDebug = require('remix-debug') |
||||
var stateDecoder = remixDebug.SolidityDecoder.stateDecoder |
||||
var solidityTypeFormatter = require('./SolidityTypeFormatter') |
||||
var StorageViewer = remixDebug.storage.StorageViewer |
||||
var yo = require('yo-yo') |
||||
|
||||
function SolidityState (_parent, _traceManager, _codeManager, _solidityProxy) { |
||||
this.storageResolver = null |
||||
this.parent = _parent |
||||
this.traceManager = _traceManager |
||||
this.codeManager = _codeManager |
||||
this.solidityProxy = _solidityProxy |
||||
this.basicPanel = new DropdownPanel('Solidity State', { |
||||
json: true, |
||||
formatSelf: solidityTypeFormatter.formatSelf, |
||||
extractData: solidityTypeFormatter.extractData |
||||
}) |
||||
this.init() |
||||
this.view |
||||
this.stateVariablesByAddresses = {} |
||||
_parent.event.register('traceUnloaded', () => { this.stateVariablesByAddresses = {} }) |
||||
_parent.event.register('newTraceLoaded', () => { this.stateVariablesByAddresses = {} }) |
||||
} |
||||
|
||||
SolidityState.prototype.render = function () { |
||||
if (!this.view) { |
||||
this.view = yo`<div id='soliditystate' >
|
||||
${this.basicPanel.render()} |
||||
</div>` |
||||
} |
||||
return this.view |
||||
} |
||||
|
||||
SolidityState.prototype.init = function () { |
||||
var self = this |
||||
var decodeTimeout = null |
||||
this.parent.event.register('indexChanged', this, function (index) { |
||||
if (index < 0) { |
||||
self.basicPanel.setMessage('invalid step index') |
||||
return |
||||
} |
||||
|
||||
if (self.parent.currentStepIndex !== index) return |
||||
if (!self.solidityProxy.loaded()) { |
||||
self.basicPanel.setMessage('no source has been specified') |
||||
return |
||||
} |
||||
|
||||
if (!self.storageResolver) { |
||||
return |
||||
} |
||||
if (decodeTimeout) { |
||||
window.clearTimeout(decodeTimeout) |
||||
} |
||||
self.basicPanel.setUpdating() |
||||
decodeTimeout = setTimeout(() => { |
||||
decode(self, index) |
||||
}, 500) |
||||
}) |
||||
} |
||||
|
||||
function decode (self, index) { |
||||
self.traceManager.getCurrentCalledAddressAt(self.parent.currentStepIndex, (error, address) => { |
||||
if (error) { |
||||
self.basicPanel.update({}) |
||||
console.log(error) |
||||
} else { |
||||
if (self.stateVariablesByAddresses[address]) { |
||||
extractStateVariables(self, self.stateVariablesByAddresses[address], address) |
||||
} else { |
||||
self.solidityProxy.extractStateVariablesAt(index, function (error, stateVars) { |
||||
if (error) { |
||||
self.basicPanel.update({}) |
||||
console.log(error) |
||||
} else { |
||||
self.stateVariablesByAddresses[address] = stateVars |
||||
extractStateVariables(self, stateVars, address) |
||||
} |
||||
}) |
||||
} |
||||
} |
||||
}) |
||||
} |
||||
|
||||
function extractStateVariables (self, stateVars, address) { |
||||
var storageViewer = new StorageViewer({ |
||||
stepIndex: self.parent.currentStepIndex, |
||||
tx: self.parent.tx, |
||||
address: address |
||||
}, self.storageResolver, self.traceManager) |
||||
stateDecoder.decodeState(stateVars, storageViewer).then((result) => { |
||||
self.basicPanel.setMessage('') |
||||
if (!result.error) { |
||||
self.basicPanel.update(result) |
||||
} else { |
||||
self.basicPanel.setMessage(result.error) |
||||
} |
||||
}) |
||||
} |
||||
|
||||
module.exports = SolidityState |
@ -1,33 +0,0 @@ |
||||
'use strict' |
||||
var DropdownPanel = require('./DropdownPanel') |
||||
var yo = require('yo-yo') |
||||
|
||||
function StackPanel (_parent, _traceManager) { |
||||
this.parent = _parent |
||||
this.traceManager = _traceManager |
||||
this.basicPanel = new DropdownPanel('Stack', {json: true, displayContentOnly: false}) |
||||
this.init() |
||||
} |
||||
|
||||
StackPanel.prototype.render = function () { |
||||
return yo`<div id='stackpanel' >${this.basicPanel.render()}</div>` |
||||
} |
||||
|
||||
StackPanel.prototype.init = function () { |
||||
var self = this |
||||
this.parent.event.register('indexChanged', this, function (index) { |
||||
if (index < 0) return |
||||
if (self.parent.currentStepIndex !== index) return |
||||
|
||||
self.traceManager.getStackAt(index, function (error, stack) { |
||||
if (error) { |
||||
self.basicPanel.update({}) |
||||
console.log(error) |
||||
} else if (self.parent.currentStepIndex === index) { |
||||
self.basicPanel.update(stack) |
||||
} |
||||
}) |
||||
}) |
||||
} |
||||
|
||||
module.exports = StackPanel |
@ -1,101 +0,0 @@ |
||||
'use strict' |
||||
var yo = require('yo-yo') |
||||
var DropdownPanel = require('./DropdownPanel') |
||||
|
||||
function StepDetail (_parentUI, _traceManager) { |
||||
this.debugger = _parentUI.debugger |
||||
this.parentUI = _parentUI |
||||
this.traceManager = _traceManager |
||||
|
||||
this.basicPanel = new DropdownPanel('Step detail', {json: true, displayContentOnly: true}) |
||||
|
||||
this.detail = initDetail() |
||||
this.view |
||||
this.init() |
||||
} |
||||
|
||||
StepDetail.prototype.render = function () { |
||||
return yo`<div id='stepdetail' >${this.basicPanel.render()}</div>` |
||||
} |
||||
|
||||
StepDetail.prototype.init = function () { |
||||
var self = this |
||||
this.debugger.event.register('traceUnloaded', this, function () { |
||||
self.detail = initDetail() |
||||
self.basicPanel.update(self.detail) |
||||
}) |
||||
|
||||
this.debugger.event.register('newTraceLoaded', this, function () { |
||||
self.detail = initDetail() |
||||
self.basicPanel.update(self.detail) |
||||
}) |
||||
|
||||
this.parentUI.event.register('indexChanged', this, function (index) { |
||||
if (index < 0) return |
||||
|
||||
self.detail['vm trace step'] = index |
||||
|
||||
self.traceManager.getCurrentStep(index, function (error, step) { |
||||
if (error) { |
||||
console.log(error) |
||||
self.detail['execution step'] = '-' |
||||
} else { |
||||
self.detail['execution step'] = step |
||||
} |
||||
self.basicPanel.update(self.detail) |
||||
}) |
||||
|
||||
self.traceManager.getMemExpand(index, function (error, addmem) { |
||||
if (error) { |
||||
console.log(error) |
||||
self.detail['add memory'] = '-' |
||||
} else { |
||||
self.detail['add memory'] = addmem |
||||
} |
||||
self.basicPanel.update(self.detail) |
||||
}) |
||||
|
||||
self.traceManager.getStepCost(index, function (error, gas) { |
||||
if (error) { |
||||
console.log(error) |
||||
self.detail.gas = '-' |
||||
} else { |
||||
self.detail.gas = gas |
||||
} |
||||
self.basicPanel.update(self.detail) |
||||
}) |
||||
|
||||
self.traceManager.getCurrentCalledAddressAt(index, function (error, address) { |
||||
if (error) { |
||||
console.log(error) |
||||
self.detail['loaded address'] = '-' |
||||
} else { |
||||
self.detail['loaded address'] = address |
||||
} |
||||
self.basicPanel.update(self.detail) |
||||
}) |
||||
|
||||
self.traceManager.getRemainingGas(index, function (error, remaingas) { |
||||
if (error) { |
||||
console.log(error) |
||||
self.detail['remaining gas'] = '-' |
||||
} else { |
||||
self.detail['remaining gas'] = remaingas |
||||
} |
||||
self.basicPanel.update(self.detail) |
||||
}) |
||||
}) |
||||
} |
||||
|
||||
module.exports = StepDetail |
||||
|
||||
function initDetail () { |
||||
return { |
||||
'vm trace step': '-', |
||||
'execution step': '-', |
||||
'add memory': '', |
||||
'gas': '', |
||||
'remaining gas': '-', |
||||
'loaded address': '-' |
||||
} |
||||
} |
@ -1,205 +0,0 @@ |
||||
'use strict' |
||||
var ButtonNavigator = require('./ButtonNavigator') |
||||
var Slider = require('./Slider') |
||||
var remixLib = require('remix-lib') |
||||
var EventManager = remixLib.EventManager |
||||
var yo = require('yo-yo') |
||||
var util = remixLib.util |
||||
|
||||
function StepManager (_parent, _traceManager) { |
||||
this.event = new EventManager() |
||||
this.parent = _parent.debugger |
||||
this.traceManager = _traceManager |
||||
this.sourceMapByAddress = {} |
||||
this.solidityMode = false |
||||
|
||||
var self = this |
||||
this.parent.event.register('newTraceLoaded', this, function () { |
||||
if (!this.slider) return |
||||
self.traceManager.getLength(function (error, length) { |
||||
if (error) { |
||||
console.log(error) |
||||
} else { |
||||
self.slider.init(length) |
||||
self.init() |
||||
} |
||||
}) |
||||
}) |
||||
|
||||
this.slider = new Slider(this.traceManager, (step) => { |
||||
return this.solidityMode ? this.resolveToReducedTrace(step, 0) : step |
||||
}) |
||||
this.slider.event.register('moved', this, function (step) { |
||||
self.sliderMoved(step) |
||||
}) |
||||
|
||||
this.parent.callTree.event.register('callTreeReady', () => { |
||||
if (!this.slider) return |
||||
if (this.parent.callTree.functionCallStack.length) { |
||||
this.jumpTo(this.parent.callTree.functionCallStack[0]) |
||||
} |
||||
}) |
||||
|
||||
this.buttonNavigator = new ButtonNavigator(_parent, this.traceManager) |
||||
this.buttonNavigator.event.register('stepIntoBack', this, function () { |
||||
self.stepIntoBack() |
||||
}) |
||||
this.buttonNavigator.event.register('stepIntoForward', this, function () { |
||||
self.stepIntoForward() |
||||
}) |
||||
this.buttonNavigator.event.register('stepOverBack', this, function () { |
||||
self.stepOverBack() |
||||
}) |
||||
this.buttonNavigator.event.register('stepOverForward', this, function () { |
||||
self.stepOverForward() |
||||
}) |
||||
this.buttonNavigator.event.register('jumpOut', this, function () { |
||||
self.jumpOut() |
||||
}) |
||||
this.buttonNavigator.event.register('jumpToException', this, function (exceptionIndex) { |
||||
self.jumpTo(exceptionIndex) |
||||
}) |
||||
this.buttonNavigator.event.register('jumpNextBreakpoint', (exceptionIndex) => { |
||||
self.parent.breakpointManager.jumpNextBreakpoint(_parent.currentStepIndex, true) |
||||
}) |
||||
this.buttonNavigator.event.register('jumpPreviousBreakpoint', (exceptionIndex) => { |
||||
self.parent.breakpointManager.jumpPreviousBreakpoint(_parent.currentStepIndex, true) |
||||
}) |
||||
} |
||||
|
||||
StepManager.prototype.remove = function () { |
||||
// used to stop listenning on event. bad and should be "refactored"
|
||||
this.slider.view = null |
||||
this.slider = null |
||||
this.buttonNavigator.view = null |
||||
this.buttonNavigator = null |
||||
} |
||||
|
||||
StepManager.prototype.resolveToReducedTrace = function (value, incr) { |
||||
if (this.parent.callTree.reducedTrace.length) { |
||||
var nextSource = util.findClosestIndex(value, this.parent.callTree.reducedTrace) |
||||
nextSource = nextSource + incr |
||||
if (nextSource <= 0) { |
||||
nextSource = 0 |
||||
} else if (nextSource > this.parent.callTree.reducedTrace.length) { |
||||
nextSource = this.parent.callTree.reducedTrace.length - 1 |
||||
} |
||||
return this.parent.callTree.reducedTrace[nextSource] |
||||
} |
||||
return value |
||||
} |
||||
|
||||
StepManager.prototype.render = function () { |
||||
return yo`<div>
|
||||
${this.slider.render()} |
||||
${this.buttonNavigator.render()} |
||||
</div>` |
||||
} |
||||
|
||||
StepManager.prototype.reset = function () { |
||||
this.slider.setValue(0) |
||||
this.currentStepIndex = 0 |
||||
this.buttonNavigator.reset() |
||||
} |
||||
|
||||
StepManager.prototype.init = function () { |
||||
this.slider.setValue(0) |
||||
this.changeState(0) |
||||
} |
||||
|
||||
StepManager.prototype.newTraceAvailable = function () { |
||||
this.init() |
||||
} |
||||
|
||||
StepManager.prototype.jumpTo = function (step) { |
||||
if (!this.traceManager.inRange(step)) { |
||||
return |
||||
} |
||||
this.slider.setValue(step) |
||||
this.changeState(step) |
||||
} |
||||
|
||||
StepManager.prototype.sliderMoved = function (step) { |
||||
if (!this.traceManager.inRange(step)) { |
||||
return |
||||
} |
||||
this.changeState(step) |
||||
} |
||||
|
||||
StepManager.prototype.stepIntoForward = function () { |
||||
if (!this.traceManager.isLoaded()) { |
||||
return |
||||
} |
||||
var step = this.currentStepIndex |
||||
if (this.solidityMode) { |
||||
step = this.resolveToReducedTrace(step, 1) |
||||
} else { |
||||
step += 1 |
||||
} |
||||
if (!this.traceManager.inRange(step)) { |
||||
return |
||||
} |
||||
this.slider.setValue(step) |
||||
this.changeState(step) |
||||
} |
||||
|
||||
StepManager.prototype.stepIntoBack = function () { |
||||
if (!this.traceManager.isLoaded()) { |
||||
return |
||||
} |
||||
var step = this.currentStepIndex |
||||
if (this.solidityMode) { |
||||
step = this.resolveToReducedTrace(step, -1) |
||||
} else { |
||||
step -= 1 |
||||
} |
||||
if (!this.traceManager.inRange(step)) { |
||||
return |
||||
} |
||||
this.slider.setValue(step) |
||||
this.changeState(step) |
||||
} |
||||
|
||||
StepManager.prototype.stepOverForward = function () { |
||||
if (!this.traceManager.isLoaded()) { |
||||
return |
||||
} |
||||
var step = this.traceManager.findStepOverForward(this.currentStepIndex) |
||||
if (this.solidityMode) { |
||||
step = this.resolveToReducedTrace(step, 1) |
||||
} |
||||
this.slider.setValue(step) |
||||
this.changeState(step) |
||||
} |
||||
|
||||
StepManager.prototype.stepOverBack = function () { |
||||
if (!this.traceManager.isLoaded()) { |
||||
return |
||||
} |
||||
var step = this.traceManager.findStepOverBack(this.currentStepIndex) |
||||
if (this.solidityMode) { |
||||
step = this.resolveToReducedTrace(step, -1) |
||||
} |
||||
this.slider.setValue(step) |
||||
this.changeState(step) |
||||
} |
||||
|
||||
StepManager.prototype.jumpOut = function () { |
||||
if (!this.traceManager.isLoaded()) { |
||||
return |
||||
} |
||||
var step = this.traceManager.findStepOut(this.currentStepIndex) |
||||
if (this.solidityMode) { |
||||
step = this.resolveToReducedTrace(step, 0) |
||||
} |
||||
this.slider.setValue(step) |
||||
this.changeState(step) |
||||
} |
||||
|
||||
StepManager.prototype.changeState = function (step) { |
||||
this.currentStepIndex = step |
||||
this.buttonNavigator.stepChanged(step) |
||||
this.event.trigger('stepChanged', [step]) |
||||
} |
||||
|
||||
module.exports = StepManager |
@ -1,50 +0,0 @@ |
||||
'use strict' |
||||
var DropdownPanel = require('./DropdownPanel') |
||||
var remixDebug = require('remix-debug') |
||||
var StorageViewer = remixDebug.storage.StorageViewer |
||||
var yo = require('yo-yo') |
||||
|
||||
function StoragePanel (_parent, _traceManager) { |
||||
this.parent = _parent |
||||
this.storageResolver = null |
||||
this.traceManager = _traceManager |
||||
this.basicPanel = new DropdownPanel('Storage', {json: true}) |
||||
this.init() |
||||
this.disabled = false |
||||
} |
||||
|
||||
StoragePanel.prototype.render = function () { |
||||
return yo`<div id='storagepanel' >${this.basicPanel.render()}</div>` |
||||
} |
||||
|
||||
StoragePanel.prototype.init = function () { |
||||
var self = this |
||||
this.parent.event.register('indexChanged', this, function (index) { |
||||
if (self.disabled) return |
||||
if (index < 0) return |
||||
if (self.parent.currentStepIndex !== index) return |
||||
if (!self.storageResolver) return |
||||
|
||||
this.traceManager.getCurrentCalledAddressAt(index, (error, address) => { |
||||
if (!error) { |
||||
var storageViewer = new StorageViewer({ |
||||
stepIndex: self.parent.currentStepIndex, |
||||
tx: self.parent.tx, |
||||
address: address |
||||
}, self.storageResolver, self.traceManager) |
||||
|
||||
storageViewer.storageRange((error, storage) => { |
||||
if (error) { |
||||
console.log(error) |
||||
self.basicPanel.update({}) |
||||
} else if (self.parent.currentStepIndex === index) { |
||||
var header = storageViewer.isComplete(address) ? 'completely loaded' : 'partially loaded...' |
||||
self.basicPanel.update(storage, header) |
||||
} |
||||
}) |
||||
} |
||||
}) |
||||
}) |
||||
} |
||||
|
||||
module.exports = StoragePanel |
@ -1,206 +0,0 @@ |
||||
var remixLib = require('remix-lib') |
||||
var EventManager = remixLib.EventManager |
||||
var traceHelper = remixLib.helpers.trace |
||||
var yo = require('yo-yo') |
||||
var init = remixLib.init |
||||
var csjs = require('csjs-inject') |
||||
var styleGuide = require('../../../../ui/styles-guide/theme-chooser') |
||||
var styles = styleGuide.chooser() |
||||
|
||||
var css = csjs` |
||||
.container { |
||||
display: flex; |
||||
flex-direction: column; |
||||
} |
||||
.txContainer { |
||||
display: flex; |
||||
flex-direction: column; |
||||
} |
||||
.txinputs { |
||||
width: 100%; |
||||
display: flex; |
||||
justify-content: center; |
||||
} |
||||
.txinput { |
||||
${styles.rightPanel.debuggerTab.input_Debugger} |
||||
margin: 3px; |
||||
width: inherit; |
||||
} |
||||
.txbuttons { |
||||
width: 100%; |
||||
display: flex; |
||||
justify-content: center; |
||||
} |
||||
.txbutton { |
||||
${styles.rightPanel.debuggerTab.button_Debugger} |
||||
width: inherit; |
||||
} |
||||
.txbuttonstart { |
||||
${styles.rightPanel.debuggerTab.button_Debugger} |
||||
} |
||||
.txbutton:hover { |
||||
color: ${styles.rightPanel.debuggerTab.button_Debugger_icon_HoverColor}; |
||||
} |
||||
.vmargin { |
||||
margin-top: 10px; |
||||
margin-bottom: 10px; |
||||
} |
||||
` |
||||
function TxBrowser (_parent, opts) { |
||||
this.event = new EventManager() |
||||
|
||||
this.blockNumber |
||||
this.txNumber |
||||
this.view |
||||
this.displayConnectionSetting = opts.displayConnectionSetting |
||||
this.web3 = opts.web3 |
||||
var self = this |
||||
_parent.event.register('providerChanged', this, function (provider) { |
||||
self.setDefaultValues() |
||||
if (self.view) { |
||||
yo.update(self.view, self.render()) |
||||
} |
||||
}) |
||||
} |
||||
|
||||
// creation 0xa9619e1d0a35b2c1d686f5b661b3abd87f998d2844e8e9cc905edb57fc9ce349
|
||||
// invokation 0x71a6d583d16d142c5c3e8903060e8a4ee5a5016348a9448df6c3e63b68076ec4 0xcda2b2835add61af54cf83bd076664d98d7908c6cd98d86423b3b48d8b8e51ff
|
||||
// test:
|
||||
// creation: 0x72908de76f99fca476f9e3a3b5d352f350a98cd77d09cebfc59ffe32a6ecaa0b
|
||||
// invokation: 0x20ef65b8b186ca942fcccd634f37074dde49b541c27994fc7596740ef44cfd51
|
||||
|
||||
TxBrowser.prototype.setDefaultValues = function () { |
||||
this.connectInfo = '' |
||||
if (this.view) { |
||||
yo.update(this.view, this.render()) |
||||
} |
||||
} |
||||
|
||||
TxBrowser.prototype.submit = function (tx) { |
||||
var self = this |
||||
self.event.trigger('newTxLoading', [this.blockNumber, this.txNumber]) |
||||
if (tx) { |
||||
return self.update(null, tx) |
||||
} |
||||
if (!this.txNumber) { |
||||
self.update('no tx index or tx hash to look for') |
||||
return |
||||
} |
||||
try { |
||||
if (this.txNumber.indexOf('0x') !== -1) { |
||||
self.web3.eth.getTransaction(this.txNumber, function (error, result) { |
||||
self.update(error, result) |
||||
}) |
||||
} else { |
||||
self.web3.eth.getTransactionFromBlock(this.blockNumber, this.txNumber, function (error, result) { |
||||
self.update(error, result) |
||||
}) |
||||
} |
||||
} catch (e) { |
||||
self.update(e.message) |
||||
} |
||||
} |
||||
|
||||
TxBrowser.prototype.update = function (error, tx) { |
||||
var info = {} |
||||
if (error) { |
||||
this.view.querySelector('#error').innerHTML = error |
||||
} else { |
||||
if (tx) { |
||||
this.view.querySelector('#error').innerHTML = '' |
||||
if (!tx.to) { |
||||
tx.to = traceHelper.contractCreationToken('0') |
||||
} |
||||
info.from = tx.from |
||||
info.to = tx.to |
||||
info.hash = tx.hash |
||||
this.event.trigger('newTraceRequested', [this.blockNumber, this.txNumber, tx]) |
||||
} else { |
||||
var mes = '<not found>' |
||||
info.from = mes |
||||
info.to = mes |
||||
info.hash = mes |
||||
this.view.querySelector('#error').innerHTML = 'Cannot find transaction with reference. Block number: ' + this.blockNumber + '. Transaction index/hash: ' + this.txNumber |
||||
} |
||||
} |
||||
} |
||||
|
||||
TxBrowser.prototype.updateWeb3Url = function (newhost) { |
||||
init.setProvider(global.web3, newhost) |
||||
var self = this |
||||
this.checkWeb3(function (error, block) { |
||||
if (!error) { |
||||
self.connectInfo = 'Connected to ' + global.web3.currentProvider.host + '. Current block number: ' + block |
||||
} else { |
||||
self.connectInfo = 'Unable to connect to ' + global.web3.currentProvider.host + '. ' + error.message |
||||
} |
||||
yo.update(self.view, self.render()) |
||||
}) |
||||
} |
||||
|
||||
TxBrowser.prototype.checkWeb3 = function (callback) { |
||||
try { |
||||
global.web3.eth.getBlockNumber(function (error, block) { |
||||
callback(error, block) |
||||
}) |
||||
} catch (e) { |
||||
console.log(e) |
||||
callback(e.message, null) |
||||
} |
||||
} |
||||
|
||||
TxBrowser.prototype.updateBlockN = function (ev) { |
||||
this.blockNumber = ev.target.value |
||||
} |
||||
|
||||
TxBrowser.prototype.updateTxN = function (ev) { |
||||
this.txNumber = ev.target.value |
||||
} |
||||
|
||||
TxBrowser.prototype.load = function (txHash, tx) { |
||||
this.txNumber = txHash |
||||
this.submit(tx) |
||||
} |
||||
|
||||
TxBrowser.prototype.unload = function (txHash) { |
||||
this.event.trigger('unloadRequested') |
||||
this.init() |
||||
} |
||||
|
||||
TxBrowser.prototype.init = function (ev) { |
||||
this.setDefaultValues() |
||||
} |
||||
|
||||
TxBrowser.prototype.connectionSetting = function () { |
||||
if (this.displayConnectionSetting) { |
||||
var self = this |
||||
return yo`<div class="${css.vmargin}"><span>Node URL: </span><input onkeyup=${function () { self.updateWeb3Url(arguments[0].target.value) }} value=${global.web3.currentProvider ? global.web3.currentProvider.host : ' - none - '} type='text' />
|
||||
<span>${this.connectInfo}</span></div>` |
||||
} else { |
||||
return '' |
||||
} |
||||
} |
||||
|
||||
TxBrowser.prototype.render = function () { |
||||
var self = this |
||||
var view = yo`<div class="${css.container}">
|
||||
${this.connectionSetting()} |
||||
<div class="${css.txContainer}"> |
||||
<div class="${css.txinputs}"> |
||||
<input class="${css.txinput}" onkeyup=${function () { self.updateBlockN(arguments[0]) }} type='text' placeholder=${'Block number'} /> |
||||
<input class="${css.txinput}" id='txinput' onkeyup=${function () { self.updateTxN(arguments[0]) }} type='text' placeholder=${'Transaction index or hash'} /> |
||||
</div> |
||||
<div class="${css.txbuttons}"> |
||||
<button id='load' class='${css.txbutton}' title='start debugging' onclick=${function () { self.submit() }}>Start debugging</button> |
||||
<button id='unload' class='${css.txbutton}' title='stop debugging' onclick=${function () { self.unload() }}>Stop</button> |
||||
</div> |
||||
</div> |
||||
<span id='error'></span> |
||||
</div>` |
||||
if (!this.view) { |
||||
this.view = view |
||||
} |
||||
return view |
||||
} |
||||
|
||||
module.exports = TxBrowser |
@ -1,126 +0,0 @@ |
||||
'use strict' |
||||
var csjs = require('csjs-inject') |
||||
var CodeListView = require('./CodeListView') |
||||
var CalldataPanel = require('./CalldataPanel') |
||||
var MemoryPanel = require('./MemoryPanel') |
||||
var CallstackPanel = require('./CallstackPanel') |
||||
var StackPanel = require('./StackPanel') |
||||
var StoragePanel = require('./StoragePanel') |
||||
var FullStoragesChangesPanel = require('./FullStoragesChanges') |
||||
var StepDetail = require('./StepDetail') |
||||
var DropdownPanel = require('./DropdownPanel') |
||||
var SolidityState = require('./SolidityState') |
||||
var SolidityLocals = require('./SolidityLocals') |
||||
var remixDebug = require('remix-debug') |
||||
var StorageResolver = remixDebug.storage.StorageResolver |
||||
var yo = require('yo-yo') |
||||
|
||||
var css = csjs` |
||||
.asmCode { |
||||
float: left; |
||||
width: 50%; |
||||
} |
||||
.stepDetail { |
||||
} |
||||
.vmheadView { |
||||
margin-top:10px; |
||||
} |
||||
` |
||||
|
||||
function VmDebugger (_parentUI, _traceManager, _codeManager, _solidityProxy, _callTree) { |
||||
let _parent = _parentUI.debugger |
||||
var self = this |
||||
this.view |
||||
this.asmCode = new CodeListView(_parent, _codeManager) |
||||
this.stackPanel = new StackPanel(_parentUI, _traceManager) |
||||
this.storagePanel = new StoragePanel(_parentUI, _traceManager) |
||||
this.memoryPanel = new MemoryPanel(_parentUI, _traceManager) |
||||
this.calldataPanel = new CalldataPanel(_parentUI, _traceManager) |
||||
this.callstackPanel = new CallstackPanel(_parentUI, _traceManager) |
||||
this.stepDetail = new StepDetail(_parentUI, _traceManager) |
||||
this.solidityState = new SolidityState(_parentUI, _traceManager, _codeManager, _solidityProxy) |
||||
this.solidityLocals = new SolidityLocals(_parentUI, _traceManager, _callTree) |
||||
|
||||
/* Return values - */ |
||||
this.returnValuesPanel = new DropdownPanel('Return Value', {json: true}) |
||||
this.returnValuesPanel.data = {} |
||||
_parentUI.event.register('indexChanged', this.returnValuesPanel, function (index) { |
||||
if (!self.view) return |
||||
var innerself = this |
||||
_traceManager.getReturnValue(index, function (error, returnValue) { |
||||
if (error) { |
||||
innerself.update([error]) |
||||
} else if (_parentUI.currentStepIndex === index) { |
||||
innerself.update([returnValue]) |
||||
} |
||||
}) |
||||
}) |
||||
/* Return values - */ |
||||
|
||||
this.fullStoragesChangesPanel = new FullStoragesChangesPanel(_parentUI, _traceManager) |
||||
|
||||
_parent.event.register('newTraceLoaded', this, function () { |
||||
if (!self.view) return |
||||
var storageResolver = new StorageResolver({web3: _parent.web3}) |
||||
self.storagePanel.storageResolver = storageResolver |
||||
self.solidityState.storageResolver = storageResolver |
||||
self.solidityLocals.storageResolver = storageResolver |
||||
self.fullStoragesChangesPanel.storageResolver = storageResolver |
||||
self.asmCode.basicPanel.show() |
||||
self.stackPanel.basicPanel.show() |
||||
self.storagePanel.basicPanel.show() |
||||
self.memoryPanel.basicPanel.show() |
||||
self.calldataPanel.basicPanel.show() |
||||
self.callstackPanel.basicPanel.show() |
||||
}) |
||||
_parent.event.register('traceUnloaded', this, function () { |
||||
if (!self.view) return |
||||
}) |
||||
_parent.callTree.event.register('callTreeReady', () => { |
||||
if (!self.view) return |
||||
if (_parent.callTree.reducedTrace.length) { |
||||
self.solidityLocals.basicPanel.show() |
||||
self.solidityState.basicPanel.show() |
||||
} |
||||
}) |
||||
} |
||||
|
||||
VmDebugger.prototype.renderHead = function () { |
||||
var headView = yo`<div id='vmheadView' class=${css.vmheadView}>
|
||||
<div> |
||||
<div class=${css.asmCode}>${this.asmCode.render()}</div> |
||||
<div class=${css.stepDetail}>${this.stepDetail.render()}</div> |
||||
</div> |
||||
</div>` |
||||
if (!this.headView) { |
||||
this.headView = headView |
||||
} |
||||
return headView |
||||
} |
||||
|
||||
VmDebugger.prototype.remove = function () { |
||||
// used to stop listenning on event. bad and should be "refactored"
|
||||
this.view = null |
||||
} |
||||
|
||||
VmDebugger.prototype.render = function () { |
||||
var view = yo`<div id='vmdebugger'>
|
||||
<div> |
||||
${this.solidityLocals.render()} |
||||
${this.solidityState.render()} |
||||
${this.stackPanel.render()} |
||||
${this.memoryPanel.render()} |
||||
${this.storagePanel.render()} |
||||
${this.callstackPanel.render()} |
||||
${this.calldataPanel.render()} |
||||
${this.returnValuesPanel.render()} |
||||
${this.fullStoragesChangesPanel.render()} |
||||
</div> |
||||
</div>` |
||||
if (!this.view) { |
||||
this.view = view |
||||
} |
||||
return view |
||||
} |
||||
|
||||
module.exports = VmDebugger |
Loading…
Reference in new issue