'use strict' var TxBrowser = require('./TxBrowser') var StepManager = require('./StepManager') var remixCore = require('remix-core') var TraceManager = remixCore.trace.TraceManager var VmDebugger = require('./VmDebugger') var remixLib = require('remix-lib') var global = remixLib.global 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 = remixCore.code.CodeManager var remixSolidity = require('remix-solidity') var SolidityProxy = remixSolidity.SolidityProxy var InternalCallTree = remixSolidity.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) { 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.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.switchProvider = function (type) { var self = this this.web3Providers.get(type, function (error, obj) { if (error) { console.log('provider ' + type + ' not defined') } else { global.web3 = obj executionContext.detectNetwork((error, network) => { if (error || !network) { global.web3Debug = obj } else { var webDebugNode = init.web3DebugNode(network.name) global.web3Debug = !webDebugNode ? obj : webDebugNode } }) 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`
${this.txBrowser.render()} ${this.stepManager.render()}
${this.statusMessage}
${this.vmDebugger.render()}
` 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) { 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 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(false) } } else { self.statusMessage = error ? error.message : 'Trace not loaded' yo.update(self.view, self.render()) } }) } module.exports = Ethdebugger