diff --git a/src/index.js b/src/index.js index 5259620a75..d15b366946 100644 --- a/src/index.js +++ b/src/index.js @@ -1,13 +1,30 @@ 'use strict' -var Debugger = require('./Ethdebugger') +var VMDebugger = require('./ui/VmDebugger') +var Debugger = require('./ui/Ethdebugger') +var BasicPanel = require('./ui/BasicPanel') +var TraceManager = require('./trace/traceManager') +var CodeManager = require('./code/codeManager') + if (typeof (module) !== 'undefined' && typeof (module.exports) !== 'undefined') { - module.exports = { - Debugger: Debugger - } + module.exports = modules() } if (window) { - window.remix = { - Debugger: Debugger + window.remix = modules() +} + +function modules () { + return { + code: { + codeManager: CodeManager + }, + trace: { + traceManager: TraceManager + }, + ui: { + Debugger: Debugger, + VMdebugger: VMDebugger, + BasicPanel: BasicPanel + } } } diff --git a/src/ASMCode.js b/src/ui/ASMCode.js similarity index 94% rename from src/ASMCode.js rename to src/ui/ASMCode.js index e57707ca0e..025c17ed59 100644 --- a/src/ASMCode.js +++ b/src/ui/ASMCode.js @@ -1,8 +1,8 @@ 'use strict' var style = require('./styles/basicStyles') var yo = require('yo-yo') -var CodeManager = require('./code/codeManager') -var ui = require('./helpers/ui') +var CodeManager = require('../code/codeManager') +var ui = require('../helpers/ui') function ASMCode (_parent, _traceManager, _web3) { this.parent = _parent diff --git a/src/BasicPanel.js b/src/ui/BasicPanel.js similarity index 96% rename from src/BasicPanel.js rename to src/ui/BasicPanel.js index c883556581..aa4eae240d 100644 --- a/src/BasicPanel.js +++ b/src/ui/BasicPanel.js @@ -1,7 +1,7 @@ 'use strict' var style = require('./styles/basicStyles') var yo = require('yo-yo') -var ui = require('./helpers/ui') +var ui = require('../helpers/ui') function BasicPanel (_name, _width, _height) { this.data diff --git a/src/ButtonNavigator.js b/src/ui/ButtonNavigator.js similarity index 96% rename from src/ButtonNavigator.js rename to src/ui/ButtonNavigator.js index 9580688a26..8a60f1a861 100644 --- a/src/ButtonNavigator.js +++ b/src/ui/ButtonNavigator.js @@ -1,6 +1,6 @@ 'use strict' -var util = require('./helpers/global') -var EventManager = require('./lib/eventManager') +var util = require('../helpers/global') +var EventManager = require('../lib/eventManager') var yo = require('yo-yo') function ButtonNavigator (_traceManager) { diff --git a/src/CalldataPanel.js b/src/ui/CalldataPanel.js similarity index 100% rename from src/CalldataPanel.js rename to src/ui/CalldataPanel.js diff --git a/src/CallstackPanel.js b/src/ui/CallstackPanel.js similarity index 100% rename from src/CallstackPanel.js rename to src/ui/CallstackPanel.js diff --git a/src/Ethdebugger.js b/src/ui/Ethdebugger.js similarity index 74% rename from src/Ethdebugger.js rename to src/ui/Ethdebugger.js index d0524bc0bf..aefe926ed3 100644 --- a/src/Ethdebugger.js +++ b/src/ui/Ethdebugger.js @@ -1,17 +1,18 @@ 'use strict' var TxBrowser = require('./TxBrowser') var StepManager = require('./StepManager') -var TraceManager = require('./trace/traceManager') +var TraceManager = require('../trace/traceManager') var VmDebugger = require('./VmDebugger') var Sticker = require('./Sticker') var style = require('./styles/basicStyles') -var util = require('./helpers/global') -var EventManager = require('./lib/eventManager') +var util = require('../helpers/global') +var EventManager = require('../lib/eventManager') var yo = require('yo-yo') -var init = require('./helpers/init') -var ui = require('./helpers/ui') +var init = require('../helpers/init') +var ui = require('../helpers/ui') +var Web3Provider = require('../web3Provider/web3Provider') -function Ethdebugger (_web3) { +function Ethdebugger (_web) { util.extend(this, new EventManager()) this.currentStepIndex = -1 this.tx @@ -19,12 +20,12 @@ function Ethdebugger (_web3) { this.view this.displayConnectionSetting = true - if (_web3) { - this.web3 = _web3 - init.extendWeb3(this.web3) - this.displayConnectionSetting = false + + this.web3 = new Web3Provider() + if (_web) { + this.setProvider('EXTERNAL', _web) } else { - this.web3 = init.loadWeb3() + this.setProvider('EXTERNAL', init.loadWeb3()) } this.traceManager = new TraceManager(this.web3) @@ -48,6 +49,29 @@ function Ethdebugger (_web3) { this.sticker = new Sticker(this, this.traceManager, this.web3) } +Ethdebugger.prototype.setProvider = function (type, obj) { + if (type === 'EXTERNAL') { + init.extendWeb3(obj) + this.web3.initWeb3(obj) + this.displayConnectionSetting = true + } else if (type === 'VM') { + this.web3.initVM(obj) + this.displayConnectionSetting = false + } +} + +Ethdebugger.prototype.getWeb3Provider = function () { + return this.web3 +} + +Ethdebugger.prototype.changeProvider = function (type) { + this.web3.switchTo(type, function (error, result) { + if (error) { + console.log('provider ' + type + ' not defined') + } + }) +} + Ethdebugger.prototype.debug = function (tx) { this.txBrowser.load(tx.hash) } diff --git a/src/FullStoragesChanges.js b/src/ui/FullStoragesChanges.js similarity index 100% rename from src/FullStoragesChanges.js rename to src/ui/FullStoragesChanges.js diff --git a/src/MemoryPanel.js b/src/ui/MemoryPanel.js similarity index 96% rename from src/MemoryPanel.js rename to src/ui/MemoryPanel.js index 42d8b6c07c..0a7e6a8ef7 100644 --- a/src/MemoryPanel.js +++ b/src/ui/MemoryPanel.js @@ -1,6 +1,6 @@ 'use strict' var BasicPanel = require('./BasicPanel') -var util = require('./helpers/ui') +var util = require('../helpers/ui') var yo = require('yo-yo') function MemoryPanel (_parent, _traceManager) { diff --git a/src/Slider.js b/src/ui/Slider.js similarity index 92% rename from src/Slider.js rename to src/ui/Slider.js index c557a245c9..f0d9d08377 100644 --- a/src/Slider.js +++ b/src/ui/Slider.js @@ -1,9 +1,9 @@ 'use strict' var style = require('./styles/sliderStyles') -var util = require('./helpers/global') -var EventManager = require('./lib/eventManager') +var util = require('../helpers/global') +var EventManager = require('../lib/eventManager') var yo = require('yo-yo') -var ui = require('./helpers/ui') +var ui = require('../helpers/ui') function Slider (_traceManager) { util.extend(this, new EventManager()) diff --git a/src/StackPanel.js b/src/ui/StackPanel.js similarity index 96% rename from src/StackPanel.js rename to src/ui/StackPanel.js index c4916ef483..956ea1fb65 100644 --- a/src/StackPanel.js +++ b/src/ui/StackPanel.js @@ -1,6 +1,6 @@ 'use strict' var BasicPanel = require('./BasicPanel') -var ui = require('./helpers/ui') +var ui = require('../helpers/ui') var yo = require('yo-yo') function StackPanel (_parent, _traceManager) { diff --git a/src/StepManager.js b/src/ui/StepManager.js similarity index 96% rename from src/StepManager.js rename to src/ui/StepManager.js index 7f847fdb72..bb7763e824 100644 --- a/src/StepManager.js +++ b/src/ui/StepManager.js @@ -2,10 +2,10 @@ var ButtonNavigator = require('./ButtonNavigator') var Slider = require('./Slider') var style = require('./styles/basicStyles') -var util = require('./helpers/global') -var EventManager = require('./lib/eventManager') +var util = require('../helpers/global') +var EventManager = require('../lib/eventManager') var yo = require('yo-yo') -var ui = require('./helpers/ui') +var ui = require('../helpers/ui') function StepManager (_parent, _traceManager) { util.extend(this, new EventManager()) diff --git a/src/Sticker.js b/src/ui/Sticker.js similarity index 100% rename from src/Sticker.js rename to src/ui/Sticker.js diff --git a/src/StoragePanel.js b/src/ui/StoragePanel.js similarity index 100% rename from src/StoragePanel.js rename to src/ui/StoragePanel.js diff --git a/src/TxBrowser.js b/src/ui/TxBrowser.js similarity index 94% rename from src/TxBrowser.js rename to src/ui/TxBrowser.js index cc4dd952f1..c549bafb0c 100644 --- a/src/TxBrowser.js +++ b/src/ui/TxBrowser.js @@ -1,10 +1,10 @@ var style = require('./styles/basicStyles') -var util = require('./helpers/global') -var EventManager = require('./lib/eventManager') -var traceHelper = require('./helpers/traceHelper') +var util = require('../helpers/global') +var EventManager = require('../lib/eventManager') +var traceHelper = require('../helpers/traceHelper') var yo = require('yo-yo') -var ui = require('./helpers/ui') -var init = require('./helpers/init') +var ui = require('../helpers/ui') +var init = require('../helpers/init') function TxBrowser (_web3, _displayConnectionSetting) { util.extend(this, new EventManager()) @@ -20,8 +20,9 @@ function TxBrowser (_web3, _displayConnectionSetting) { if (_displayConnectionSetting !== undefined) { this.displayConnectionSetting = _displayConnectionSetting } - - this.setDefaultValues() + if (this.displayConnectionSetting) { + this.setDefaultValues() + } } // creation 0xa9619e1d0a35b2c1d686f5b661b3abd87f998d2844e8e9cc905edb57fc9ce349 diff --git a/src/VmDebugger.js b/src/ui/VmDebugger.js similarity index 98% rename from src/VmDebugger.js rename to src/ui/VmDebugger.js index 8ead243827..1a67ac8731 100644 --- a/src/VmDebugger.js +++ b/src/ui/VmDebugger.js @@ -9,7 +9,7 @@ var StoragePanel = require('./StoragePanel') var BasicPanel = require('./BasicPanel') var FullStoragesChangesPanel = require('./FullStoragesChanges') var yo = require('yo-yo') -var ui = require('./helpers/ui') +var ui = require('../helpers/ui') function VmDebugger (_parent, _traceManager, _web3) { this.asmCode = new ASMCode(_parent, _traceManager, _web3) diff --git a/src/styles/basicStyles.js b/src/ui/styles/basicStyles.js similarity index 100% rename from src/styles/basicStyles.js rename to src/ui/styles/basicStyles.js diff --git a/src/styles/sliderStyles.js b/src/ui/styles/sliderStyles.js similarity index 100% rename from src/styles/sliderStyles.js rename to src/ui/styles/sliderStyles.js diff --git a/src/web3Provider/web3Provider.js b/src/web3Provider/web3Provider.js new file mode 100644 index 0000000000..45285c84ce --- /dev/null +++ b/src/web3Provider/web3Provider.js @@ -0,0 +1,70 @@ +var Web3VMProvider = require('./web3VmProvider') + +function Web3Provider () { + var self = this + this.currentMode + this.actions = {} + this.modes = {} + this.currentProvider = {'host': 'browser-solidity proxy provider'} + this.providers = { 'HttpProvider': function (url) {} } + this.eth = {} + this.debug = {} + this.eth.getCode = function (address, cb) { if (self.check(cb)) { return self.actions[self.currentMode]['eth.getCode'].apply(self.executingMode(), arguments) } } + this.setProvider = function (provider) { if (self.check()) { return self.actions[self.currentMode]['setProvider'].apply(self.executingMode(), [provider]) } } + this.debug.traceTransaction = function (txHash, options, cb) { if (self.check()) { return self.actions[self.currentMode]['debug.traceTransaction'].apply(self.executingMode(), arguments) } } + this.debug.storageAt = function (blockNumber, txIndex, address, cb) { if (self.check()) { return self.actions[self.currentMode]['debug.storageAt'].apply(self.executingMode(), arguments) } } + this.eth.getTransaction = function (txHash) { if (self.check()) { return self.actions[self.currentMode]['eth.getTransaction'].apply(self.executingMode(), arguments) } } + this.eth.getTransactionFromBlock = function (blockNumber, txIndex) { if (self.check()) { return self.actions[self.currentMode]['eth.getTransactionFromBlock'].apply(self.executingMode(), arguments) } } + this.eth.getBlockNumber = function (cb) { if (self.check()) { return self.actions[self.currentMode]['eth.getBlockNumber'].apply(self.executingMode(), arguments) } } +} + +Web3Provider.prototype.check = function (cb) { + if (!this.currentMode) { + if (cb) { + cb('error: no provider has been setup ', null) + } + return false + } + return true +} + +Web3Provider.prototype.switchTo = function (type, cb) { + if (this.actions[type]) { + this.currentMode = type + cb(null, 'ok') + } else { + cb('error: this provider has not been setup (' + type + ')', null) + } +} + +Web3Provider.prototype.executingMode = function () { + return this.modes[this.currentMode] +} + +Web3Provider.prototype.initWeb3 = function (web3) { + this.actions['EXTERNAL'] = {} + this.actions['EXTERNAL']['eth.getCode'] = web3.eth.getCode + this.actions['EXTERNAL']['setProvider'] = web3.setProvider + this.actions['EXTERNAL']['debug.traceTransaction'] = web3.debug.traceTransaction + this.actions['EXTERNAL']['debug.storageAt'] = web3.debug.storageAt + this.actions['EXTERNAL']['eth.getTransaction'] = web3.eth.getTransaction + this.actions['EXTERNAL']['eth.getTransactionFromBlock'] = web3.eth.getTransactionFromBlock + this.actions['EXTERNAL']['eth.getBlockNumber'] = web3.eth.getBlockNumber + this.modes['EXTERNAL'] = web3 +} + +Web3Provider.prototype.initVM = function (vm) { + var vmProvider = new Web3VMProvider() + vmProvider.setVM(vm) + this.actions['VM'] = {} + this.actions['VM']['eth.getCode'] = vmProvider.getCode + this.actions['VM']['setProvider'] = vmProvider.setProvider + this.actions['VM']['debug.traceTransaction'] = vmProvider.traceTransaction + this.actions['VM']['debug.storageAt'] = vmProvider.storageAt + this.actions['VM']['eth.getTransaction'] = vmProvider.getTransaction + this.actions['VM']['eth.getTransactionFromBlock'] = vmProvider.getTransactionFromBlock + this.actions['VM']['eth.getBlockNumber'] = vmProvider.getBlockNumber + this.modes['VM'] = vmProvider +} + +module.exports = Web3Provider diff --git a/src/web3Provider/web3VmProvider.js b/src/web3Provider/web3VmProvider.js new file mode 100644 index 0000000000..069b0c2f75 --- /dev/null +++ b/src/web3Provider/web3VmProvider.js @@ -0,0 +1,168 @@ +var ethJSUtil = require('ethereumjs-util') +var BN = ethJSUtil.BN + +function web3VmProvider () { + this.vm + this.vmTraces = {} + this.txs = {} + this.processingHash + this.incr = 0 +} + +var hexConvert = function (ints) { + var ret = '0x' + for (var i = 0; i < ints.length; i++) { + try { + var h = ints[i] + if (h) { + h = h.toString(16) + ret += ('0x' + h) < 0x10 ? '0' + h : h + } else { + ret += '00' + } + } catch (e) { + console.log('hexconvert ' + i + ' ' + ints.length) + console.log(e) + } + } + return ret +} + +var hexListConvert = function (intsList) { + var ret = [] + for (var k in intsList) { + ret.push(hexConvert(intsList[k])) + } + return ret +} + +var formatMemory = function (mem) { + var hexMem = hexConvert(mem).substr(2) + var ret = [] + for (var k = 0; k < hexMem.length; k += 32) { + var row = hexMem.substr(k, 32) + ret.push(row) + } + return ret +} + +web3VmProvider.prototype.setVM = function (vm) { + var self = this + this.vm = vm + this.vm.on('step', function (data) { + self.pushTrace(self, data) + }) + this.vm.on('afterTx', function (data) { + self.txProcessed(self, data) + }) + this.vm.on('beforeTx', function (data) { + self.txWillProcess(self, data) + }) +} + +web3VmProvider.prototype.releaseCurrentHash = function () { + var ret = this.processingHash + this.processingHash = undefined + return ret +} + +web3VmProvider.prototype.txWillProcess = function (self, data) { + self.incr++ + self.processingHash = '0x' + ethJSUtil.sha3([data.r, data.s, data.v, self.incr]).join('') + self.vmTraces[self.processingHash] = { + gas: '0x0', + return: '0x0', + structLogs: [] + } + var tx = {} + tx.hash = self.processingHash + tx.from = hexConvert(data.getSenderAddress()) + if (data.to && data.to.length) { + tx.to = hexConvert(data.to) + } + tx.data = hexConvert(data.data) + tx.input = hexConvert(data.input) + tx.gas = hexConvert(data.gas) + if (data.value) { + tx.value = hexConvert(data.value) + } + self.txs[self.processingHash] = tx +} + +web3VmProvider.prototype.txProcessed = function (self, data) { + self.vmTraces[self.processingHash].gas = '0x' + data.gasUsed.toString(16) + if (data.createdAddress) { + self.vmTraces[self.processingHash].return = hexConvert(data.createdAddress) + } else { + self.vmTraces[self.processingHash].return = hexConvert(data.vm.return) + } +} + +web3VmProvider.prototype.pushTrace = function (self, data) { + if (!self.processingHash) { + console.log('no tx processing') + return + } + var step = { + stack: hexListConvert(data.stack), + memory: formatMemory(data.memory), + storage: data.storage, + op: data.opcode.name, + pc: data.pc, + gas: data.opcode.fee.toString(), + gasLeft: data.gasLeft.toString(), + gasCost: self.vmTraces[self.processingHash].structLogs.length > 0 ? ((new BN(self.vmTraces[self.processingHash].structLogs[0].gasLeft)) - data.gasLeft).toString() : data.opcode.fee.toString() + } + self.vmTraces[self.processingHash].structLogs.push(step) +} + +web3VmProvider.prototype.getCode = function (address, cb) { + this.vm.stateManager.getContractCode(address, function (error, result) { + cb(error, hexConvert(result)) + }) +} + +web3VmProvider.prototype.setProvider = function (provider) {} + +web3VmProvider.prototype.traceTransaction = function (txHash, options, cb) { + if (this.vmTraces[txHash]) { + if (cb) { + cb(null, this.vmTraces[txHash]) + } + return this.vmTraces[txHash] + } else { + var mes = 'unable to retrieve traces ' + txHash + if (cb) { + cb('unable to retrieve traces ' + txHash, null) + } + throw mes + } +} + +web3VmProvider.prototype.storageAt = function (blockNumber, txIndex, address, cb) { cb(null, {}) } + +web3VmProvider.prototype.getTransaction = function (txHash, cb) { + if (this.txs[txHash]) { + if (cb) { + cb(null, this.txs[txHash]) + } + return this.txs[txHash] + } else { + var mes = 'unable to retrieve tx ' + txHash + if (cb) { + cb('unable to retrieve tx ' + txHash, null) + } + throw mes + } +} + +web3VmProvider.prototype.getTransactionFromBlock = function (blockNumber, txIndex, cb) { + var mes = 'not supposed to be needed by remix' + console.log(mes) + if (cb) { + cb(mes, null) + } + throw mes +} + +module.exports = web3VmProvider