diff --git a/assets/css/universal-dapp.css b/assets/css/universal-dapp.css index 4d4f7c289e..cbbac4683b 100644 --- a/assets/css/universal-dapp.css +++ b/assets/css/universal-dapp.css @@ -200,6 +200,10 @@ width: 25%; } +.udapp .contractProperty button.debug { + width: 3%; +} + .udapp .contractProperty .call { background-color: #FF8B8B; border-color: #FF8B8B; 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 1b60ecfef1..b44432558a 100644
--- a/src/app/debugger.js
+++ b/src/app/debugger.js
@@ -1,6 +1,6 @@
 var remix = require('ethereum-remix');
 
-function Debugger (executionContext, id) {
+function Debugger (id) {
   this.el = document.querySelector(id);
   this.debugger = new remix.ui.Debugger();
   this.el.appendChild(this.debugger.render());
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 808a347590..9a6837f271 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(),
@@ -81,7 +84,7 @@ function Renderer (editor, executionContext, updateFiles, transactionDebugger) {
           .append(textRow('uDApp', combined(contractName, contract['interface'], contract.bytecode), 'deploy'))
           .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 044512495a..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,15 +17,13 @@ function UniversalDApp (contracts, options, transactionDebugger) {
 
   self.web3 = options.web3;
   self.transactionDebugger = transactionDebugger;
-  transactionDebugger.addProvider('EXTERNAL', self.web3);
+
   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 });
-    transactionDebugger.addProvider('VM', self.vm);
+    self.vm = vm;
     self.addAccount('3cd7232cd6f3fc66a57a6bedc1a8ed6c228fff0a327e169c2bcc5e869ed49511');
     self.addAccount('2ac6c190b09897cd8987869cc7b918cfea07ee82038d492abce033c75c1b1d0c');
   } else if (options.mode !== 'web3') {
@@ -355,7 +352,7 @@ UniversalDApp.prototype.getCallButton = function (args) {
 
   var getDebugTransaction = function (result) {
     var $debugTx = $('
'); - var $button = $(''); + var $button = $(''); $button.click(function () { self.transactionDebugger.debug(result); }); @@ -365,7 +362,7 @@ UniversalDApp.prototype.getCallButton = function (args) { var getDebugCall = function (result) { var $debugTx = $('
'); - var $button = $(''); + var $button = $(''); $button.click(function () { self.transactionDebugger.debug(result); }); @@ -666,7 +663,6 @@ UniversalDApp.prototype.runTx = function (data, args, cb) { var tx; if (!self.vm) { - self.transactionDebugger.switchProvider('EXTERNAL'); tx = { from: self.options.getAddress ? self.options.getAddress() : self.web3.eth.accounts[0], to: to, @@ -699,7 +695,6 @@ UniversalDApp.prototype.runTx = function (data, args, cb) { } } else { try { - self.transactionDebugger.switchProvider('VM'); var address = self.options.getAddress ? self.options.getAddress() : self.getAccounts()[0]; var account = self.accounts[address]; tx = new EthJSTX({ @@ -720,9 +715,7 @@ UniversalDApp.prototype.runTx = function (data, args, cb) { uncleHeaders: [] }); self.vm.runTx({block: block, tx: tx, skipBalance: true, skipNonce: true}, function (err, result) { - if (self.vm) { - result.transactionHash = self.transactionDebugger.web3().releaseCurrentHash(); // used to keep track of the transaction - } + result.transactionHash = self.transactionDebugger.web3().releaseCurrentHash(); // used to keep track of the transaction cb(err, result); }); } catch (e) {