diff --git a/assets/css/universal-dapp.css b/assets/css/universal-dapp.css index 4d4f7c289e..79c8dfd8b6 100644 --- a/assets/css/universal-dapp.css +++ b/assets/css/universal-dapp.css @@ -100,6 +100,14 @@ word-wrap: break-word; } +.udapp .output .result .debugTx { + position: absolute; + top: 0.4em; + right: 1.4em; + height: 1.5em; + width: 2.5em; +} + .udapp .output .result:last-child { margin: 0; } .udapp .output:empty { @@ -200,6 +208,10 @@ width: 25%; } +.udapp .contractProperty button.debug { + width: 21px; +} + .udapp .contractProperty .call { background-color: #FF8B8B; border-color: #FF8B8B; diff --git a/package.json b/package.json index a1a9522fd0..ade61f4107 100644 --- a/package.json +++ b/package.json @@ -34,7 +34,7 @@ "webworkify": "^1.2.1", "yo-yo": "^1.2.2", "yo-yoify": "^3.3.0", - "ethereum-remix": "0.0.2-alpha.0.0.4" + "ethereum-remix": "0.0.2-alpha.0.0.7" }, "repository": { "type": "git", diff --git a/src/app.js b/src/app.js index d19d2e8a0c..0909bbdbee 100644 --- a/src/app.js +++ b/src/app.js @@ -15,6 +15,7 @@ var Compiler = require('./app/compiler'); var ExecutionContext = require('./app/execution-context'); var Debugger = require('./app/debugger'); var FormalVerification = require('./app/formalVerification'); +var EthJSVM = require('ethereumjs-vm'); // The event listener needs to be registered as early as possible, because the // parent will send the message upon the "load" event. @@ -431,13 +432,17 @@ var run = function () { $('#output').append($('
').append($('').text('Loading github.com/' + root + '/' + path + ' ...'))); return $.getJSON('https://api.github.com/repos/' + root + '/contents/' + path, cb); } - - var executionContext = new ExecutionContext(); - var transactionDebugger = new Debugger(executionContext, '#debugger'); + var transactionDebugger = new Debugger('#debugger'); + var vm = new EthJSVM(null, null, { activatePrecompiles: true, enableHomestead: true }); + vm.stateManager.checkpoint(); + transactionDebugger.addProvider('VM', vm); + transactionDebugger.switchProvider('VM'); + var executionContext = new ExecutionContext(transactionDebugger); + transactionDebugger.addProvider('EXTERNAL', executionContext.web3()); transactionDebugger.onDebugRequested = function () { selectTab($('ul#options li.debugView')); }; - var renderer = new Renderer(editor, executionContext, updateFiles, transactionDebugger); + var renderer = new Renderer(editor, executionContext, updateFiles, transactionDebugger, vm); var formalVerification = new FormalVerification($('#verificationView'), renderer); var compiler = new Compiler(editor, renderer, queryParams, handleGithubCall, $('#output'), getHidingRHP, formalVerification, updateFiles); executionContext.setCompiler(compiler); diff --git a/src/app/debugger.js b/src/app/debugger.js index 1ad34aa78c..b44432558a 100644 --- a/src/app/debugger.js +++ b/src/app/debugger.js @@ -1,20 +1,31 @@ var remix = require('ethereum-remix'); -function Debugger (_executionContext, _id) { - this.el = document.querySelector(_id); - this.debugger = new remix.Debugger(_executionContext.web3()); +function Debugger (id) { + this.el = document.querySelector(id); + this.debugger = new remix.ui.Debugger(); this.el.appendChild(this.debugger.render()); - this.web3 = _executionContext.web3(); - - Debugger.prototype.debug = function (receipt) { - if (this.onDebugRequested) this.onDebugRequested(); - var self = this; - this.web3.eth.getTransaction(receipt.transactionHash, function (error, tx) { - if (!error) { - self.debugger.debug(tx); - } - }); - }; } +Debugger.prototype.debug = function (receipt) { + if (this.onDebugRequested) this.onDebugRequested(); + var self = this; + this.debugger.web3().eth.getTransaction(receipt.transactionHash, function (error, tx) { + if (!error) { + self.debugger.debug(tx); + } + }); +}; + +Debugger.prototype.addProvider = function (type, obj) { + this.debugger.addProvider(type, obj); +}; + +Debugger.prototype.switchProvider = function (type) { + this.debugger.switchProvider(type); +}; + +Debugger.prototype.web3 = function (type) { + return this.debugger.web3(); +}; + module.exports = Debugger; diff --git a/src/app/execution-context.js b/src/app/execution-context.js index db67897a80..70591307df 100644 --- a/src/app/execution-context.js +++ b/src/app/execution-context.js @@ -13,7 +13,8 @@ if (typeof window.web3 !== 'undefined') { web3 = new Web3(new Web3.providers.HttpProvider('http://localhost:8545')); } -function ExecutionContext () { +function ExecutionContext (_txDebugger) { + var txDebugger = _txDebugger; var compiler; var executionContext = injectedProvider ? 'injected' : 'vm'; @@ -59,8 +60,12 @@ function ExecutionContext () { executionContext = ev.target.value; if (executionContext === 'web3') { setProviderFromEndpoint(); + txDebugger.switchProvider('EXTERNAL'); } else if (executionContext === 'injected') { web3.setProvider(injectedProvider); + txDebugger.switchProvider('EXTERNAL'); + } else if (executionContext === 'vm') { + txDebugger.switchProvider('VM'); } } compiler.compile(); diff --git a/src/app/renderer.js b/src/app/renderer.js index 0639bdf991..ab9872cc75 100644 --- a/src/app/renderer.js +++ b/src/app/renderer.js @@ -4,7 +4,7 @@ var UniversalDApp = require('../universal-dapp.js'); var utils = require('./utils'); -function Renderer (editor, executionContext, updateFiles, transactionDebugger) { +function Renderer (editor, executionContext, updateFiles, transactionDebugger, vm) { var detailsOpen = {}; function renderError (message, container, noAnnotations) { @@ -61,6 +61,9 @@ function Renderer (editor, executionContext, updateFiles, transactionDebugger) { }); } + vm.stateManager.revert(function () { + vm.stateManager.checkpoint(); + }); var dapp = new UniversalDApp(udappContracts, { mode: executionContext.isVM() ? 'vm' : 'web3', web3: executionContext.web3(), @@ -86,7 +89,7 @@ function Renderer (editor, executionContext, updateFiles, transactionDebugger) { } return $contractOutput.append(getDetails(contract, source, contractName)); } - }, transactionDebugger); + }, transactionDebugger, vm); var $contractOutput = dapp.render(); diff --git a/src/universal-dapp.js b/src/universal-dapp.js index 44422bd59f..b69f2f4488 100644 --- a/src/universal-dapp.js +++ b/src/universal-dapp.js @@ -1,14 +1,13 @@ /* global prompt */ var $ = require('jquery'); -var EthJSVM = require('ethereumjs-vm'); var ethJSUtil = require('ethereumjs-util'); var EthJSTX = require('ethereumjs-tx'); var ethJSABI = require('ethereumjs-abi'); var EthJSBlock = require('ethereumjs-block'); var BN = ethJSUtil.BN; -function UniversalDApp (contracts, options, transactionDebugger) { +function UniversalDApp (contracts, options, transactionDebugger, vm) { var self = this; self.options = options || {}; @@ -18,14 +17,13 @@ function UniversalDApp (contracts, options, transactionDebugger) { self.web3 = options.web3; self.transactionDebugger = transactionDebugger; + if (options.mode === 'vm') { // FIXME: use `options.vm` or `self.vm` consistently options.vm = true; self.accounts = {}; - - self.vm = new EthJSVM(null, null, { activatePrecompiles: true, enableHomestead: true }); - + self.vm = vm; self.addAccount('3cd7232cd6f3fc66a57a6bedc1a8ed6c228fff0a327e169c2bcc5e869ed49511'); self.addAccount('2ac6c190b09897cd8987869cc7b918cfea07ee82038d492abce033c75c1b1d0c'); } else if (options.mode !== 'web3') { @@ -354,7 +352,17 @@ UniversalDApp.prototype.getCallButton = function (args) { var getDebugTransaction = function (result) { var $debugTx = $('