Merge pull request #1543 from ethereum/refactor_debugger
Refactor debugger - extract logic from views, move to separate modulepull/3094/head
commit
e9ef5a3ad0
@ -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