From 2639b6b0beab497ddf4802b56223f895750ea1d7 Mon Sep 17 00:00:00 2001 From: yann300 Date: Tue, 6 Dec 2016 11:38:50 +0100 Subject: [PATCH 01/68] add getSourceLocation from stepindex --- src/code/sourceLocationTracker.js | 30 ++++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) diff --git a/src/code/sourceLocationTracker.js b/src/code/sourceLocationTracker.js index d312a868e6..401fa21156 100644 --- a/src/code/sourceLocationTracker.js +++ b/src/code/sourceLocationTracker.js @@ -36,6 +36,36 @@ SourceLocationTracker.prototype.getSourceLocation = function (address, index, co }) } +/** + * Return the source location associated with the given @arg pc + * + * @param {String} address - contract address from which the source location is retrieved + * @param {Int} vmtraceStepIndex - index of the current code in the vmtrace + * @param {Object} contractDetails - AST of compiled contracts + * @param {Function} cb - callback function + */ +SourceLocationTracker.prototype.getSourceLocation = function (address, vmtraceStepIndex, contractsDetails, cb) { + var self = this + this.codeManager.getCode(address, function (error, result) { + if (!error) { + var sourceMap = getSourceMap(address, result.bytecode, contractsDetails) + if (sourceMap) { + self.codeManager.getInstructionIndex(address, vmtraceStepIndex, function (error, index) { + if (error) { + cb(error) + } else { + cb(null, self.sourceMappingDecoder.atIndex(index, sourceMap)) + } + }) + } else { + cb('no srcmap associated with the code ' + address) + } + } else { + cb(error) + } + }) +} + /** * backwards compatibility - attribute name will certainly be changed */ From f0b34586483c9ef7888ff1a397e8bcd7c29960b5 Mon Sep 17 00:00:00 2001 From: yann300 Date: Tue, 6 Dec 2016 11:40:00 +0100 Subject: [PATCH 02/68] trigger events from TraceAnalyser --- src/trace/traceAnalyser.js | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/trace/traceAnalyser.js b/src/trace/traceAnalyser.js index 8acf27a17f..e6a0df897d 100644 --- a/src/trace/traceAnalyser.js +++ b/src/trace/traceAnalyser.js @@ -1,12 +1,15 @@ 'use strict' var traceHelper = require('../helpers/traceHelper') +var EventManager = require('../lib/eventManager') function TraceAnalyser (_cache) { + this.event = new EventManager() this.traceCache = _cache this.trace = null } TraceAnalyser.prototype.analyse = function (trace, tx, callback) { + this.event.trigger('startAnalysing') this.trace = trace this.traceCache.pushStoreChanges(0, tx.to) var context = { @@ -26,8 +29,10 @@ TraceAnalyser.prototype.analyse = function (trace, tx, callback) { context = this.buildDepth(k, step, tx, callStack, context) context = this.buildStorage(k, step, context) this.buildReturnValues(k, step) + this.event.trigger('onOp', [k, step, callStack, this.traceCache]) } callback(null, true) + this.event.trigger('finishAnalysing') } TraceAnalyser.prototype.buildReturnValues = function (index, step) { From 074e2ee57e231e5519495aadbf0482282f896def Mon Sep 17 00:00:00 2001 From: yann300 Date: Tue, 6 Dec 2016 11:40:28 +0100 Subject: [PATCH 03/68] add local decoder --- src/solidity/localDecoder.js | 58 ++++++++++++++++++++++++++++++++++++ src/ui/Ethdebugger.js | 4 +++ 2 files changed, 62 insertions(+) create mode 100644 src/solidity/localDecoder.js diff --git a/src/solidity/localDecoder.js b/src/solidity/localDecoder.js new file mode 100644 index 0000000000..655680a104 --- /dev/null +++ b/src/solidity/localDecoder.js @@ -0,0 +1,58 @@ +'use strict' +var SourceLocationTracker = require('../code/sourceLocationTracker') +var AstWalker = require('../util/astWalker') +var decodeInfo = require('../solidity/decodeInfo') + +function LocalDecoder (parent, codeManager, traceAnalyserEvent) { + this.astWalker = new AstWalker() + this.codeManager = this.codeManager + this.parent = parent + this.locals = {} + this.loading = false + this.sourceLocationTracker = new SourceLocationTracker(this.codeManager) + var self = this + traceAnalyserEvent.register('startAnalysing', function (step) { + self.clear() + }) + traceAnalyserEvent.register('onOp', function (index, step, callStack, cache) { + self.push(index, step, callStack, cache) + }) + traceAnalyserEvent.register('finishAnalysing', function (index, step) { + self.loading = true + }) +} + +LocalDecoder.prototype.push = function (index, step, callStack, cache) { + if (!this.parent.sources) return + if (step.op.indexOf('PUSH') === 0) { + var self = this + var compiledContracts = this.parent.contractsDetail + var address = callStack[callStack.length - 1] + this.sourceLocationTracker.getSourceLocation(address, index, compiledContracts, function (error, result) { + if (error) { + console.log(error) + } else { + var file = self.parent.sourceList[result.file] + var ast = self.parent.sources[file] + this.astWalker.walk(ast, function (node) { + if (node.name === 'VariableDeclaration' && node.src.indexOf(result.start + ':' + result.length) === 0) { + self.locals[node.attributes.name] = { + type: decodeInfo.parseType(node, []), + stack: step.stack + } + return false + } else { + return true + } + }) + } + }) + } +} + +LocalDecoder.prototype.clear = function () { + this.loading = false + this.locals = {} +} + +module.exports = LocalDecoder diff --git a/src/ui/Ethdebugger.js b/src/ui/Ethdebugger.js index c30e2ebbbe..ab4ce43d60 100644 --- a/src/ui/Ethdebugger.js +++ b/src/ui/Ethdebugger.js @@ -12,6 +12,7 @@ var Web3Providers = require('../web3Provider/web3Providers') var DummyProvider = require('../web3Provider/dummyProvider') var CodeManager = require('../code/codeManager') var SourceLocationTracker = require('../code/sourceLocationTracker') +var LocalDecoder = require('../solidity/localDecoder') function Ethdebugger () { this.event = new EventManager() @@ -29,6 +30,7 @@ function Ethdebugger () { this.traceManager = new TraceManager() this.codeManager = new CodeManager(this.traceManager) this.sourceLocationTracker = new SourceLocationTracker(this.codeManager) + this.locals = new LocalDecoder(this, this.codeManager, this.traceManager.traceAnalyser.event) var self = this this.event.register('indexChanged', this, function (index) { @@ -76,10 +78,12 @@ Ethdebugger.prototype.switchProvider = function (type) { Ethdebugger.prototype.setCompilationResult = function (compilationResult) { if (compilationResult && compilationResult.sources && compilationResult.contracts) { this.sources = compilationResult.sources + this.sourceList = compilationResult.sourceList this.contractsDetail = compilationResult.contracts } else { this.sources = null this.contractsDetail = null + this.sourceList = null } } From e5a0f2c056bbdefc0fda3d086fa325c64f1bd539 Mon Sep 17 00:00:00 2001 From: yann300 Date: Tue, 6 Dec 2016 11:40:41 +0100 Subject: [PATCH 04/68] add tests --- package.json | 5 +- test/solidity/contracts/intLocal.js | 24 ++++++++ test/solidity/localDecoder.js | 92 +++++++++++++++++++++++++++++ test/tests.js | 1 + 4 files changed, 121 insertions(+), 1 deletion(-) create mode 100644 test/solidity/contracts/intLocal.js create mode 100644 test/solidity/localDecoder.js diff --git a/package.json b/package.json index 3447a6196e..96ff02086d 100644 --- a/package.json +++ b/package.json @@ -47,7 +47,10 @@ "tape": "^4.6.0", "web3": "^0.15.3", "yo-yo": "^1.2.1", - "yo-yoify": "^3.1.0" + "yo-yoify": "^3.1.0", + "ethereumjs-block": "^1.2.2", + "ethereumjs-tx": "^1.1.1", + "ethereumjs-vm": "^2.0.1" }, "scripts": { "start_node": "./runNode.sh", diff --git a/test/solidity/contracts/intLocal.js b/test/solidity/contracts/intLocal.js new file mode 100644 index 0000000000..53f0957752 --- /dev/null +++ b/test/solidity/contracts/intLocal.js @@ -0,0 +1,24 @@ +'use strict' + +module.exports = { + contract: ` + contract intLocal { + function set () { + uint8 ui8 = 130; + uint16 ui16 = 456; + uint32 ui32 = 4356; + uint64 ui64 = 3543543543; + uint128 ui128 = 234567; + uint256 ui256 = 115792089237316195423570985008687907853269984665640564039457584007880697216513; + uint ui = 123545666; + int8 i8 = -45; + int16 i16 = -1234; + int32 i32 = 3455; + int64 i64 = -35566; + int128 i128 = -444444; + int256 i256 = 3434343; + int i = -32432423423; + int32 ishrink = 2; + } + } +`} diff --git a/test/solidity/localDecoder.js b/test/solidity/localDecoder.js new file mode 100644 index 0000000000..b6c2fc8758 --- /dev/null +++ b/test/solidity/localDecoder.js @@ -0,0 +1,92 @@ +'use strict' +var tape = require('tape') +var compiler = require('solc') +var intLocal = require('./contracts/intLocal') +var TraceManager = require('../../src/trace/traceManager') +var CodeManager = require('../../src/code/codeManager') +var VM = require('ethereumjs-vm') +var Tx = require('ethereumjs-tx') +var Block = require('ethereumjs-block') +var BN = require('ethereumjs-util').BN +var utileth = require('ethereumjs-util') +var Web3Providers = require('../../src/web3Provider/web3Providers') +var traceHelper = require('../../src/helpers/traceHelper') +var util = require('../../src/helpers/global') +var LocalDecoder = require('../../src/solidity/localDecoder') + +tape('solidity', function (t) { + t.test('storage decoder', function (st) { + var privateKey = new Buffer('dae9801649ba2d95a21e688b56f77905e5667c44ce868ec83f82e838712a2c7a', 'hex') + var address = utileth.privateToAddress(privateKey) + var vm = initVM(st, address) + var output = compiler.compile(intLocal.contract, 0) + + sendTx(vm, {nonce: 0, privateKey: privateKey}, null, 0, output.contracts['intLocal'].bytecode, function (error, txHash) { + if (error) { + st.fail(error) + } else { + util.web3.getTransaction(txHash, function (error, tx) { + if (error) { + st.fail(error) + } else { + tx.to = traceHelper.contractCreationToken('0') + var traceManager = new TraceManager() + var codeManager = new CodeManager(traceManager) + var locals = new LocalDecoder(output, codeManager, traceManager.traceAnalyser.event) + traceManager.resolveTrace(tx, function (error, result) { + if (error) { + st.fail(error) + } else { + console.log(locals) + } + }) + } + }) + } + }) + }) +}) + +function initVM (st, address) { + var vm = new VM({ + enableHomestead: true, + activatePrecompiles: true + }) + vm.stateManager.putAccountBalance(address, 'f00000000000000001', function cb () {}) + var web3Providers = new Web3Providers() + web3Providers.addVM('VM', vm) + web3Providers.get('VM', function (error, obj) { + if (error) { + var mes = 'provider TEST not defined' + console.log(mes) + st.fail(mes) + } else { + util.web3 = obj + st.end() + } + }) + return vm +} + +function sendTx (vm, from, to, value, data, cb) { + var tx = new Tx({ + nonce: new BN(from.nonce++), + gasPrice: new BN(1), + gasLimit: new BN(3000000, 10), + to: to, + value: new BN(value, 10), + data: new Buffer(data, 'hex') + }) + tx.sign(from.privateKey) + var block = new Block({ + header: { + timestamp: new Date().getTime() / 1000 | 0, + number: 0 + }, + transactions: [], + uncleHeaders: [] + }) + vm.runTx({block: block, tx: tx, skipBalance: true, skipNonce: true}, function (error, result) { + cb(error, utileth.bufferToHex(tx.hash())) + }) +} diff --git a/test/tests.js b/test/tests.js index 1f8bd4c59c..bcdab7bd47 100644 --- a/test/tests.js +++ b/test/tests.js @@ -10,4 +10,5 @@ require('./sourceMappingDecoder.js') require('./solidity/decodeInfo.js') require('./solidity/storageLocation.js') require('./solidity/storageDecoder.js') +require('./solidity/localDecoder.js') From 85de09176754bcfe455d86e0970ea97874706011 Mon Sep 17 00:00:00 2001 From: yann300 Date: Tue, 6 Dec 2016 11:51:38 +0100 Subject: [PATCH 05/68] rename contractsDetail contracts --- src/code/sourceLocationTracker.js | 16 ++++++++-------- src/solidity/localDecoder.js | 4 ++-- src/ui/Ethdebugger.js | 6 +++--- src/ui/SolidityState.js | 4 ++-- test/solidity/localDecoder.js | 2 +- 5 files changed, 16 insertions(+), 16 deletions(-) diff --git a/src/code/sourceLocationTracker.js b/src/code/sourceLocationTracker.js index 401fa21156..fada8a9102 100644 --- a/src/code/sourceLocationTracker.js +++ b/src/code/sourceLocationTracker.js @@ -20,11 +20,11 @@ function SourceLocationTracker (_codeManager) { * @param {Object} contractDetails - AST of compiled contracts * @param {Function} cb - callback function */ -SourceLocationTracker.prototype.getSourceLocation = function (address, index, contractsDetails, cb) { +SourceLocationTracker.prototype.getSourceLocation = function (address, index, contracts, cb) { var self = this this.codeManager.getCode(address, function (error, result) { if (!error) { - var sourceMap = getSourceMap(address, result.bytecode, contractsDetails) + var sourceMap = getSourceMap(address, result.bytecode, contracts) if (sourceMap) { cb(null, self.sourceMappingDecoder.atIndex(index, sourceMap)) } else { @@ -44,11 +44,11 @@ SourceLocationTracker.prototype.getSourceLocation = function (address, index, co * @param {Object} contractDetails - AST of compiled contracts * @param {Function} cb - callback function */ -SourceLocationTracker.prototype.getSourceLocation = function (address, vmtraceStepIndex, contractsDetails, cb) { +SourceLocationTracker.prototype.getSourceLocation = function (address, vmtraceStepIndex, contracts, cb) { var self = this this.codeManager.getCode(address, function (error, result) { if (!error) { - var sourceMap = getSourceMap(address, result.bytecode, contractsDetails) + var sourceMap = getSourceMap(address, result.bytecode, contracts) if (sourceMap) { self.codeManager.getInstructionIndex(address, vmtraceStepIndex, function (error, index) { if (error) { @@ -73,12 +73,12 @@ function srcmapRuntime (contract) { return contract.srcmapRuntime ? contract.srcmapRuntime : contract['srcmap-runtime'] } -function getSourceMap (address, code, contractsDetails) { +function getSourceMap (address, code, contracts) { var isCreation = helper.isContractCreation(address) var byteProp = isCreation ? 'bytecode' : 'runtimeBytecode' - for (var k in contractsDetails) { - if ('0x' + contractsDetails[k][byteProp] === code) { - return isCreation ? contractsDetails[k].srcmap : srcmapRuntime(contractsDetails[k]) + for (var k in contracts) { + if ('0x' + contracts[k][byteProp] === code) { + return isCreation ? contracts[k].srcmap : srcmapRuntime(contracts[k]) } } return null diff --git a/src/solidity/localDecoder.js b/src/solidity/localDecoder.js index 655680a104..5322b7bfac 100644 --- a/src/solidity/localDecoder.js +++ b/src/solidity/localDecoder.js @@ -5,7 +5,7 @@ var decodeInfo = require('../solidity/decodeInfo') function LocalDecoder (parent, codeManager, traceAnalyserEvent) { this.astWalker = new AstWalker() - this.codeManager = this.codeManager + this.codeManager = codeManager this.parent = parent this.locals = {} this.loading = false @@ -26,7 +26,7 @@ LocalDecoder.prototype.push = function (index, step, callStack, cache) { if (!this.parent.sources) return if (step.op.indexOf('PUSH') === 0) { var self = this - var compiledContracts = this.parent.contractsDetail + var compiledContracts = this.parent.contracts var address = callStack[callStack.length - 1] this.sourceLocationTracker.getSourceLocation(address, index, compiledContracts, function (error, result) { if (error) { diff --git a/src/ui/Ethdebugger.js b/src/ui/Ethdebugger.js index ab4ce43d60..5f53bc943b 100644 --- a/src/ui/Ethdebugger.js +++ b/src/ui/Ethdebugger.js @@ -20,7 +20,7 @@ function Ethdebugger () { this.currentStepIndex = -1 this.tx this.sources - this.contractsDetail + this.contracts this.statusMessage = '' this.view @@ -79,10 +79,10 @@ Ethdebugger.prototype.setCompilationResult = function (compilationResult) { if (compilationResult && compilationResult.sources && compilationResult.contracts) { this.sources = compilationResult.sources this.sourceList = compilationResult.sourceList - this.contractsDetail = compilationResult.contracts + this.contracts = compilationResult.contracts } else { this.sources = null - this.contractsDetail = null + this.contracts = null this.sourceList = null } } diff --git a/src/ui/SolidityState.js b/src/ui/SolidityState.js index 440cad6c99..22f705abc0 100644 --- a/src/ui/SolidityState.js +++ b/src/ui/SolidityState.js @@ -24,7 +24,7 @@ SolidityState.prototype.init = function () { return } if (self.parent.currentStepIndex !== index) return - if (!this.parent.contractsDetail || !this.parent.sources) { + if (!this.parent.contracts || !this.parent.sources) { self.basicPanel.update({info: 'no source has been specified'}) return } @@ -41,7 +41,7 @@ SolidityState.prototype.init = function () { if (error) { self.basicPanel.update({ info: error }) } else { - var contractName = contractNameFromCode(self.parent.contractsDetail, code.bytecode, address) + var contractName = contractNameFromCode(self.parent.contracts, code.bytecode, address) if (contractName === null) { self.basicPanel.update({ info: 'could not find compiled contract with address ' + address }) } else { diff --git a/test/solidity/localDecoder.js b/test/solidity/localDecoder.js index b6c2fc8758..e0f1edad68 100644 --- a/test/solidity/localDecoder.js +++ b/test/solidity/localDecoder.js @@ -15,7 +15,7 @@ var util = require('../../src/helpers/global') var LocalDecoder = require('../../src/solidity/localDecoder') tape('solidity', function (t) { - t.test('storage decoder', function (st) { + t.test('local decoder', function (st) { var privateKey = new Buffer('dae9801649ba2d95a21e688b56f77905e5667c44ce868ec83f82e838712a2c7a', 'hex') var address = utileth.privateToAddress(privateKey) var vm = initVM(st, address) From 3a921e35df20d7d9f3046e5604274ad88410b1b6 Mon Sep 17 00:00:00 2001 From: yann300 Date: Tue, 6 Dec 2016 13:37:29 +0100 Subject: [PATCH 06/68] fix tests --- src/solidity/localDecoder.js | 6 +++--- test/solidity/contracts/intLocal.js | 2 +- test/solidity/localDecoder.js | 19 +++++++++++++++++-- 3 files changed, 21 insertions(+), 6 deletions(-) diff --git a/src/solidity/localDecoder.js b/src/solidity/localDecoder.js index 5322b7bfac..649f103e91 100644 --- a/src/solidity/localDecoder.js +++ b/src/solidity/localDecoder.js @@ -33,11 +33,11 @@ LocalDecoder.prototype.push = function (index, step, callStack, cache) { console.log(error) } else { var file = self.parent.sourceList[result.file] - var ast = self.parent.sources[file] - this.astWalker.walk(ast, function (node) { + var ast = self.parent.sources[file].AST + self.astWalker.walk(ast, function (node) { if (node.name === 'VariableDeclaration' && node.src.indexOf(result.start + ':' + result.length) === 0) { self.locals[node.attributes.name] = { - type: decodeInfo.parseType(node, []), + type: decodeInfo.parseType(node.attributes.type, []), stack: step.stack } return false diff --git a/test/solidity/contracts/intLocal.js b/test/solidity/contracts/intLocal.js index 53f0957752..9860b7d3ac 100644 --- a/test/solidity/contracts/intLocal.js +++ b/test/solidity/contracts/intLocal.js @@ -3,7 +3,7 @@ module.exports = { contract: ` contract intLocal { - function set () { + function intLocal () { uint8 ui8 = 130; uint16 ui16 = 456; uint32 ui32 = 4356; diff --git a/test/solidity/localDecoder.js b/test/solidity/localDecoder.js index e0f1edad68..8663f173f4 100644 --- a/test/solidity/localDecoder.js +++ b/test/solidity/localDecoder.js @@ -32,12 +32,27 @@ tape('solidity', function (t) { tx.to = traceHelper.contractCreationToken('0') var traceManager = new TraceManager() var codeManager = new CodeManager(traceManager) - var locals = new LocalDecoder(output, codeManager, traceManager.traceAnalyser.event) + var localDecoder = new LocalDecoder(output, codeManager, traceManager.traceAnalyser.event) traceManager.resolveTrace(tx, function (error, result) { if (error) { st.fail(error) } else { - console.log(locals) + var locals = localDecoder.locals + st.equals(locals['ui8'].type.typeName, 'uint') + st.equals(locals['ui16'].type.typeName, 'uint') + st.equals(locals['ui32'].type.typeName, 'uint') + st.equals(locals['ui64'].type.typeName, 'uint') + st.equals(locals['ui128'].type.typeName, 'uint') + st.equals(locals['ui256'].type.typeName, 'uint') + st.equals(locals['ui'].type.typeName, 'uint') + st.equals(locals['i8'].type.typeName, 'int') + st.equals(locals['i16'].type.typeName, 'int') + st.equals(locals['i32'].type.typeName, 'int') + st.equals(locals['i64'].type.typeName, 'int') + st.equals(locals['i128'].type.typeName, 'int') + st.equals(locals['i256'].type.typeName, 'int') + st.equals(locals['i'].type.typeName, 'int') + st.equals(locals['ishrink'].type.typeName, 'int') } }) } From 6417483dc200909fc5a16a5c4688f5e112e2e322 Mon Sep 17 00:00:00 2001 From: yann300 Date: Tue, 6 Dec 2016 15:50:47 +0100 Subject: [PATCH 07/68] use solidityproxy to send statevar to localdecoder --- src/code/sourceLocationTracker.js | 53 ++++++++++-------- src/solidity/localDecoder.js | 93 ++++++++++++++++--------------- src/solidity/solidityProxy.js | 90 ++++++++++++++++++++++++++++++ src/ui/Ethdebugger.js | 19 ++----- src/ui/SolidityState.js | 33 ++--------- src/ui/VmDebugger.js | 4 +- test/solidity/localDecoder.js | 5 +- 7 files changed, 183 insertions(+), 114 deletions(-) create mode 100644 src/solidity/solidityProxy.js diff --git a/src/code/sourceLocationTracker.js b/src/code/sourceLocationTracker.js index fada8a9102..86c2357060 100644 --- a/src/code/sourceLocationTracker.js +++ b/src/code/sourceLocationTracker.js @@ -20,18 +20,13 @@ function SourceLocationTracker (_codeManager) { * @param {Object} contractDetails - AST of compiled contracts * @param {Function} cb - callback function */ -SourceLocationTracker.prototype.getSourceLocation = function (address, index, contracts, cb) { +SourceLocationTracker.prototype.getSourceLocationFromInstructionIndex = function (address, index, contracts, cb) { var self = this - this.codeManager.getCode(address, function (error, result) { - if (!error) { - var sourceMap = getSourceMap(address, result.bytecode, contracts) - if (sourceMap) { - cb(null, self.sourceMappingDecoder.atIndex(index, sourceMap)) - } else { - cb('no srcmap associated with the code ' + address) - } - } else { + extractSourceMap(this.codeManager, address, contracts, function (error, sourceMap) { + if (error) { cb(error) + } else { + cb(null, self.sourceMappingDecoder.atIndex(index, sourceMap)) } }) } @@ -44,22 +39,17 @@ SourceLocationTracker.prototype.getSourceLocation = function (address, index, co * @param {Object} contractDetails - AST of compiled contracts * @param {Function} cb - callback function */ -SourceLocationTracker.prototype.getSourceLocation = function (address, vmtraceStepIndex, contracts, cb) { +SourceLocationTracker.prototype.getSourceLocationFromVMTraceIndex = function (address, vmtraceStepIndex, contracts, cb) { var self = this - this.codeManager.getCode(address, function (error, result) { + extractSourceMap(this.codeManager, address, contracts, function (error, sourceMap) { if (!error) { - var sourceMap = getSourceMap(address, result.bytecode, contracts) - if (sourceMap) { - self.codeManager.getInstructionIndex(address, vmtraceStepIndex, function (error, index) { - if (error) { - cb(error) - } else { - cb(null, self.sourceMappingDecoder.atIndex(index, sourceMap)) - } - }) - } else { - cb('no srcmap associated with the code ' + address) - } + self.codeManager.getInstructionIndex(address, vmtraceStepIndex, function (error, index) { + if (error) { + cb(error) + } else { + cb(null, self.sourceMappingDecoder.atIndex(index, sourceMap)) + } + }) } else { cb(error) } @@ -84,4 +74,19 @@ function getSourceMap (address, code, contracts) { return null } +function extractSourceMap (codeManager, address, contracts, cb) { + codeManager.getCode(address, function (error, result) { + if (!error) { + var sourceMap = getSourceMap(address, result.bytecode, contracts) + if (sourceMap) { + cb(null, sourceMap) + } else { + cb('no srcmap associated with the code ' + address) + } + } else { + cb(error) + } + }) +} + module.exports = SourceLocationTracker diff --git a/src/solidity/localDecoder.js b/src/solidity/localDecoder.js index 649f103e91..c35ca93f7b 100644 --- a/src/solidity/localDecoder.js +++ b/src/solidity/localDecoder.js @@ -3,56 +3,57 @@ var SourceLocationTracker = require('../code/sourceLocationTracker') var AstWalker = require('../util/astWalker') var decodeInfo = require('../solidity/decodeInfo') -function LocalDecoder (parent, codeManager, traceAnalyserEvent) { - this.astWalker = new AstWalker() - this.codeManager = codeManager - this.parent = parent - this.locals = {} - this.loading = false - this.sourceLocationTracker = new SourceLocationTracker(this.codeManager) - var self = this - traceAnalyserEvent.register('startAnalysing', function (step) { - self.clear() - }) - traceAnalyserEvent.register('onOp', function (index, step, callStack, cache) { - self.push(index, step, callStack, cache) - }) - traceAnalyserEvent.register('finishAnalysing', function (index, step) { - self.loading = true - }) -} - -LocalDecoder.prototype.push = function (index, step, callStack, cache) { - if (!this.parent.sources) return - if (step.op.indexOf('PUSH') === 0) { +class LocalDecoder { + constructor (codeManager, traceAnalyserEvent, solidityProxy) { + this.astWalker = new AstWalker() + this.sourceLocationTracker = new SourceLocationTracker(codeManager) + this.solidityProxy = solidityProxy + this.locals = {} var self = this - var compiledContracts = this.parent.contracts - var address = callStack[callStack.length - 1] - this.sourceLocationTracker.getSourceLocation(address, index, compiledContracts, function (error, result) { - if (error) { - console.log(error) - } else { - var file = self.parent.sourceList[result.file] - var ast = self.parent.sources[file].AST - self.astWalker.walk(ast, function (node) { - if (node.name === 'VariableDeclaration' && node.src.indexOf(result.start + ':' + result.length) === 0) { - self.locals[node.attributes.name] = { - type: decodeInfo.parseType(node.attributes.type, []), - stack: step.stack - } - return false - } else { - return true - } - }) - } + traceAnalyserEvent.register('startAnalysing', function (step) { + self.clear() + }) + traceAnalyserEvent.register('onOp', function (index, step, callStack, cache) { + self.push(index, step, callStack, cache) + }) + traceAnalyserEvent.register('finishAnalysing', function (index, step) { }) } -} -LocalDecoder.prototype.clear = function () { - this.loading = false - this.locals = {} + push (index, step, callStack, cache) { + if (!this.solidityProxy.loaded()) return + if (step.op.indexOf('PUSH') === 0) { + var address = callStack[callStack.length - 1] + this.sourceLocationTracker.getSourceLocationFromVMTraceIndex(address, index, this.solidityProxy.contracts, (error, result) => { + if (error) { + console.log(error) + } else { + var ast = this.solidityProxy.ast(result) + this.solidityProxy.extractStateVariablesAt(index, (error, stateVars) => { // cached + if (error) { + console.log(error) + } else { + this.astWalker.walk(ast, (node) => { + if (node.name === 'VariableDeclaration' && node.src.indexOf(result.start + ':' + result.length) === 0) { + this.locals[node.attributes.name] = { + type: decodeInfo.parseType(node.attributes.type, stateVars), + stack: step.stack + } + return false + } else { + return true + } + }) + } + }) + } + }) + } + } + + clear () { + this.locals = {} + } } module.exports = LocalDecoder diff --git a/src/solidity/solidityProxy.js b/src/solidity/solidityProxy.js new file mode 100644 index 0000000000..af91b6db23 --- /dev/null +++ b/src/solidity/solidityProxy.js @@ -0,0 +1,90 @@ +'use strict' +var traceHelper = require('../helpers/traceHelper') +var stateDecoder = require('./stateDecoder') + +class SolidityProxy { + constructor (traceManager, codeManager) { + this.cache = new Cache() + this.reset({}) + this.traceManager = traceManager + this.codeManager = codeManager + } + + reset (compilationResult) { + this.sources = compilationResult.sources + this.sourceList = compilationResult.sourceList + this.contracts = compilationResult.contracts + this.cache.reset() + } + + loaded () { + return this.contracts !== undefined + } + + contractNameAt (vmTraceIndex, cb) { + this.traceManager.getCurrentCalledAddressAt(vmTraceIndex, (error, address) => { + if (error) { + cb(error) + } else { + if (this.cache.contractNameByAddress[address]) { + cb(null, this.cache.contractNameByAddress[address]) + } else { + this.codeManager.getCode(address, (error, code) => { + if (error) { + cb(error) + } else { + var contractName = contractNameFromCode(this.contracts, code.bytecode, address) + this.cache.contractNameByAddress[address] = contractName + cb(null, contractName) + } + }) + } + } + }) + } + + extractStateVariables (contractName) { + if (!this.cache.stateVariablesByContractName[contractName]) { + this.cache.stateVariablesByContractName[contractName] = stateDecoder.extractStateVariables(contractName, this.sources) + } + return this.cache.stateVariablesByContractName[contractName] + } + + extractStateVariablesAt (vmtraceIndex, cb) { + this.contractNameAt(vmtraceIndex, (error, contractName) => { + if (error) { + cb(error) + } else { + cb(null, this.extractStateVariables(contractName)) + } + }) + } + + ast (sourceLocation) { + var file = this.sourceList[sourceLocation.file] + return this.sources[file].AST + } +} + +function contractNameFromCode (contracts, code, address) { + var isCreation = traceHelper.isContractCreation(address) + var byteProp = isCreation ? 'bytecode' : 'runtimeBytecode' + for (var k in contracts) { + if ('0x' + contracts[k][byteProp] === code) { + return k + } + } + return null +} + +class Cache { + constructor () { + this.reset() + } + reset () { + this.contractNameByAddress = {} + this.stateVariablesByContractName = {} + } +} + +module.exports = SolidityProxy diff --git a/src/ui/Ethdebugger.js b/src/ui/Ethdebugger.js index 5f53bc943b..0d16eb049c 100644 --- a/src/ui/Ethdebugger.js +++ b/src/ui/Ethdebugger.js @@ -11,16 +11,14 @@ var ui = require('../helpers/ui') var Web3Providers = require('../web3Provider/web3Providers') var DummyProvider = require('../web3Provider/dummyProvider') var CodeManager = require('../code/codeManager') -var SourceLocationTracker = require('../code/sourceLocationTracker') var LocalDecoder = require('../solidity/localDecoder') +var SolidityProxy = require('../solidity/solidityProxy') function Ethdebugger () { this.event = new EventManager() this.currentStepIndex = -1 this.tx - this.sources - this.contracts this.statusMessage = '' this.view @@ -29,9 +27,8 @@ function Ethdebugger () { this.switchProvider('DUMMYWEB3') this.traceManager = new TraceManager() this.codeManager = new CodeManager(this.traceManager) - this.sourceLocationTracker = new SourceLocationTracker(this.codeManager) - this.locals = new LocalDecoder(this, this.codeManager, this.traceManager.traceAnalyser.event) - + this.solidityProxy = new SolidityProxy(this.traceManager, this.codeManager) + this.locals = new LocalDecoder(this.codeManager, this.traceManager.traceAnalyser.event, this.solidityProxy) var self = this this.event.register('indexChanged', this, function (index) { self.codeManager.resolveStep(index, self.tx) @@ -51,7 +48,7 @@ function Ethdebugger () { this.stepManager.event.register('stepChanged', this, function (stepIndex) { self.stepChanged(stepIndex) }) - this.vmDebugger = new VmDebugger(this, this.traceManager, this.codeManager) + this.vmDebugger = new VmDebugger(this, this.traceManager, this.codeManager, this.solidityProxy) } Ethdebugger.prototype.web3 = function () { @@ -77,13 +74,9 @@ Ethdebugger.prototype.switchProvider = function (type) { Ethdebugger.prototype.setCompilationResult = function (compilationResult) { if (compilationResult && compilationResult.sources && compilationResult.contracts) { - this.sources = compilationResult.sources - this.sourceList = compilationResult.sourceList - this.contracts = compilationResult.contracts + this.solidityProxy.reset(compilationResult) } else { - this.sources = null - this.contracts = null - this.sourceList = null + this.solidityProxy.reset({}) } } diff --git a/src/ui/SolidityState.js b/src/ui/SolidityState.js index 22f705abc0..bc4cc24e38 100644 --- a/src/ui/SolidityState.js +++ b/src/ui/SolidityState.js @@ -1,13 +1,13 @@ 'use strict' var DropdownPanel = require('./DropdownPanel') -var traceHelper = require('../helpers/traceHelper') var stateDecoder = require('../solidity/stateDecoder') var yo = require('yo-yo') -function SolidityState (_parent, _traceManager, _codeManager) { +function SolidityState (_parent, _traceManager, _codeManager, _solidityProxy) { this.parent = _parent this.traceManager = _traceManager this.codeManager = _codeManager + this.solidityProxy = _solidityProxy this.basicPanel = new DropdownPanel('Solidity State') this.init() } @@ -24,7 +24,7 @@ SolidityState.prototype.init = function () { return } if (self.parent.currentStepIndex !== index) return - if (!this.parent.contracts || !this.parent.sources) { + if (!this.solidityProxy.loaded()) { self.basicPanel.update({info: 'no source has been specified'}) return } @@ -33,23 +33,11 @@ SolidityState.prototype.init = function () { if (error) { self.basicPanel.update({ info: error }) } else { - self.traceManager.getCurrentCalledAddressAt(index, function (error, address) { + self.solidityProxy.extractStateVariablesAt(index, function (error, stateVars) { if (error) { self.basicPanel.update({ info: error }) } else { - self.codeManager.getCode(address, function (error, code) { - if (error) { - self.basicPanel.update({ info: error }) - } else { - var contractName = contractNameFromCode(self.parent.contracts, code.bytecode, address) - if (contractName === null) { - self.basicPanel.update({ info: 'could not find compiled contract with address ' + address }) - } else { - var state = stateDecoder.solidityState(storage, self.parent.sources, contractName) - self.basicPanel.update(state) - } - } - }) + self.basicPanel.update(stateDecoder.decodeState(stateVars, storage)) } }) } @@ -57,15 +45,4 @@ SolidityState.prototype.init = function () { }) } -function contractNameFromCode (contracts, code, address) { - var isCreation = traceHelper.isContractCreation(address) - var byteProp = isCreation ? 'bytecode' : 'runtimeBytecode' - for (var k in contracts) { - if ('0x' + contracts[k][byteProp] === code) { - return k - } - } - return null -} - module.exports = SolidityState diff --git a/src/ui/VmDebugger.js b/src/ui/VmDebugger.js index dac1d84e57..250e8249df 100644 --- a/src/ui/VmDebugger.js +++ b/src/ui/VmDebugger.js @@ -11,7 +11,7 @@ var DropdownPanel = require('./DropdownPanel') var SolidityState = require('./SolidityState') var yo = require('yo-yo') -function VmDebugger (_parent, _traceManager, _codeManager) { +function VmDebugger (_parent, _traceManager, _codeManager, _solidityProxy) { this.asmCode = new CodeListView(_parent, _codeManager) this.stackPanel = new StackPanel(_parent, _traceManager) this.storagePanel = new StoragePanel(_parent, _traceManager) @@ -19,7 +19,7 @@ function VmDebugger (_parent, _traceManager, _codeManager) { this.calldataPanel = new CalldataPanel(_parent, _traceManager) this.callstackPanel = new CallstackPanel(_parent, _traceManager) this.stepDetail = new StepDetail(_parent, _traceManager) - this.solidityState = new SolidityState(_parent, _traceManager, _codeManager) + this.solidityState = new SolidityState(_parent, _traceManager, _codeManager, _solidityProxy) /* Return values - */ this.returnValuesPanel = new DropdownPanel('Return Value') diff --git a/test/solidity/localDecoder.js b/test/solidity/localDecoder.js index 8663f173f4..9ea09bfd91 100644 --- a/test/solidity/localDecoder.js +++ b/test/solidity/localDecoder.js @@ -13,6 +13,7 @@ var Web3Providers = require('../../src/web3Provider/web3Providers') var traceHelper = require('../../src/helpers/traceHelper') var util = require('../../src/helpers/global') var LocalDecoder = require('../../src/solidity/localDecoder') +var SolidityProxy = require('../../src/solidity/solidityProxy') tape('solidity', function (t) { t.test('local decoder', function (st) { @@ -32,7 +33,9 @@ tape('solidity', function (t) { tx.to = traceHelper.contractCreationToken('0') var traceManager = new TraceManager() var codeManager = new CodeManager(traceManager) - var localDecoder = new LocalDecoder(output, codeManager, traceManager.traceAnalyser.event) + var solidityProxy = new SolidityProxy(traceManager, codeManager) + solidityProxy.reset(output) + var localDecoder = new LocalDecoder(codeManager, traceManager.traceAnalyser.event, solidityProxy) traceManager.resolveTrace(tx, function (error, result) { if (error) { st.fail(error) From 0e76ba49e48692489c747746d6043c04d7c55dff Mon Sep 17 00:00:00 2001 From: yann300 Date: Wed, 7 Dec 2016 09:19:58 +0100 Subject: [PATCH 08/68] cache variableDeclaration --- src/solidity/localDecoder.js | 35 ++++++++++++++++++++++++----------- 1 file changed, 24 insertions(+), 11 deletions(-) diff --git a/src/solidity/localDecoder.js b/src/solidity/localDecoder.js index c35ca93f7b..57d19aedfe 100644 --- a/src/solidity/localDecoder.js +++ b/src/solidity/localDecoder.js @@ -16,8 +16,8 @@ class LocalDecoder { traceAnalyserEvent.register('onOp', function (index, step, callStack, cache) { self.push(index, step, callStack, cache) }) - traceAnalyserEvent.register('finishAnalysing', function (index, step) { - }) + traceAnalyserEvent.register('finishAnalysing', function (index, step) {}) + this.variableDeclarationByFile = {} } push (index, step, callStack, cache) { @@ -28,22 +28,23 @@ class LocalDecoder { if (error) { console.log(error) } else { - var ast = this.solidityProxy.ast(result) + if (!this.variableDeclarationByFile[result.file]) { + var ast = this.solidityProxy.ast(result) + this.variableDeclarationByFile[result.file] = extractVariableDeclarations(ast, this.astWalker) + } + var variableDeclarations = this.variableDeclarationByFile[result.file] this.solidityProxy.extractStateVariablesAt(index, (error, stateVars) => { // cached if (error) { console.log(error) } else { - this.astWalker.walk(ast, (node) => { - if (node.name === 'VariableDeclaration' && node.src.indexOf(result.start + ':' + result.length) === 0) { - this.locals[node.attributes.name] = { - type: decodeInfo.parseType(node.attributes.type, stateVars), + for (var dec of variableDeclarations) { + if (dec.src.indexOf(result.start + ':' + result.length) === 0) { + this.locals[dec.attributes.name] = { + type: decodeInfo.parseType(dec.attributes.type, stateVars), stack: step.stack } - return false - } else { - return true } - }) + } } }) } @@ -53,7 +54,19 @@ class LocalDecoder { clear () { this.locals = {} + this.variableDeclarationByFile = {} } } +function extractVariableDeclarations (ast, astWalker) { + var ret = [] + astWalker.walk(ast, (node) => { + if (node.name === 'VariableDeclaration') { + ret.push(node) + } + return true + }) + return ret +} + module.exports = LocalDecoder From e77f1a355e85cefcf149db09873379e4b934ed39 Mon Sep 17 00:00:00 2001 From: yann300 Date: Thu, 8 Dec 2016 11:40:53 +0100 Subject: [PATCH 09/68] add function description --- src/solidity/solidityProxy.js | 34 ++++++++++++++++++++++++++++++++++ 1 file changed, 34 insertions(+) diff --git a/src/solidity/solidityProxy.js b/src/solidity/solidityProxy.js index af91b6db23..54237be7c0 100644 --- a/src/solidity/solidityProxy.js +++ b/src/solidity/solidityProxy.js @@ -10,6 +10,11 @@ class SolidityProxy { this.codeManager = codeManager } + /** + * reset the cache and apply a new @arg compilationResult + * + * @param {Object} compilationResult - result os a compilatiion (diectly returned by the compiler) + */ reset (compilationResult) { this.sources = compilationResult.sources this.sourceList = compilationResult.sourceList @@ -17,10 +22,21 @@ class SolidityProxy { this.cache.reset() } + /** + * check if the object has been properly loaded + * + * @return {Bool} - returns true if a compilation result has been applied + */ loaded () { return this.contracts !== undefined } + /** + * retrieve the compiled contract name at the @arg vmTraceIndex (cached) + * + * @param {Int} vmTraceIndex - index in the vm trave where to resolve the executed contract name + * @param {Function} cb - callback returns (error, contractName) + */ contractNameAt (vmTraceIndex, cb) { this.traceManager.getCurrentCalledAddressAt(vmTraceIndex, (error, address) => { if (error) { @@ -43,6 +59,12 @@ class SolidityProxy { }) } + /** + * extract the state variables of the given compiled @arg contractName (cached) + * + * @param {String} contractName - name of the contract to retrieve state variables from + * @return {Object} - returns state variables of @args contractName + */ extractStateVariables (contractName) { if (!this.cache.stateVariablesByContractName[contractName]) { this.cache.stateVariablesByContractName[contractName] = stateDecoder.extractStateVariables(contractName, this.sources) @@ -50,6 +72,12 @@ class SolidityProxy { return this.cache.stateVariablesByContractName[contractName] } + /** + * extract the state variables of the given compiled @arg vmtraceIndex (cached) + * + * @param {Int} vmTraceIndex - index in the vm trave where to resolve the state variables + * @return {Object} - returns state variables of @args vmTraceIndex + */ extractStateVariablesAt (vmtraceIndex, cb) { this.contractNameAt(vmtraceIndex, (error, contractName) => { if (error) { @@ -60,6 +88,12 @@ class SolidityProxy { }) } + /** + * get the AST of the file declare in the @arg sourceLocation + * + * @param {Object} sourceLocation - source location containing the 'file' to retrieve the AST from + * @return {Object} - AST of the current file + */ ast (sourceLocation) { var file = this.sourceList[sourceLocation.file] return this.sources[file].AST From c2b3d4c497a7ee1042a16c79e861b764029bbdcb Mon Sep 17 00:00:00 2001 From: yann300 Date: Thu, 8 Dec 2016 15:13:22 +0100 Subject: [PATCH 10/68] series call in tracemanager --- src/trace/traceManager.js | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/src/trace/traceManager.js b/src/trace/traceManager.js index 6906938c1d..9cb741bb42 100644 --- a/src/trace/traceManager.js +++ b/src/trace/traceManager.js @@ -281,4 +281,16 @@ TraceManager.prototype.checkRequestedStep = function (stepIndex) { return undefined } +TraceManager.prototype.waterfall = function (calls, stepindex, cb) { + var ret = [] + var retError = null + for (var call in calls) { + call.apply(this, [stepindex, function (error, result) { + retError = error + ret.push({ error: error, value: result }) + }]) + } + cb(retError, ret) +} + module.exports = TraceManager From 0e270ffbcf086eb71f665eb681e77ca94f7096ab Mon Sep 17 00:00:00 2001 From: yann300 Date: Thu, 8 Dec 2016 15:14:48 +0100 Subject: [PATCH 11/68] remove event traceAnalyser --- src/trace/traceAnalyser.js | 5 ----- 1 file changed, 5 deletions(-) diff --git a/src/trace/traceAnalyser.js b/src/trace/traceAnalyser.js index e6a0df897d..8acf27a17f 100644 --- a/src/trace/traceAnalyser.js +++ b/src/trace/traceAnalyser.js @@ -1,15 +1,12 @@ 'use strict' var traceHelper = require('../helpers/traceHelper') -var EventManager = require('../lib/eventManager') function TraceAnalyser (_cache) { - this.event = new EventManager() this.traceCache = _cache this.trace = null } TraceAnalyser.prototype.analyse = function (trace, tx, callback) { - this.event.trigger('startAnalysing') this.trace = trace this.traceCache.pushStoreChanges(0, tx.to) var context = { @@ -29,10 +26,8 @@ TraceAnalyser.prototype.analyse = function (trace, tx, callback) { context = this.buildDepth(k, step, tx, callStack, context) context = this.buildStorage(k, step, context) this.buildReturnValues(k, step) - this.event.trigger('onOp', [k, step, callStack, this.traceCache]) } callback(null, true) - this.event.trigger('finishAnalysing') } TraceAnalyser.prototype.buildReturnValues = function (index, step) { From 9a30bb5b2ea256890bcbcfdedee8863aec58bff5 Mon Sep 17 00:00:00 2001 From: yann300 Date: Thu, 8 Dec 2016 15:16:54 +0100 Subject: [PATCH 12/68] add InternalCallTree --- src/ui/Ethdebugger.js | 12 ++- src/ui/VmDebugger.js | 5 +- src/util/internalCallTree.js | 139 ++++++++++++++++++++++++++++ test/solidity/contracts/intLocal.js | 13 ++- test/solidity/localDecoder.js | 53 +++++++---- 5 files changed, 196 insertions(+), 26 deletions(-) create mode 100644 src/util/internalCallTree.js diff --git a/src/ui/Ethdebugger.js b/src/ui/Ethdebugger.js index 0d16eb049c..373e37dab8 100644 --- a/src/ui/Ethdebugger.js +++ b/src/ui/Ethdebugger.js @@ -11,10 +11,11 @@ var ui = require('../helpers/ui') var Web3Providers = require('../web3Provider/web3Providers') var DummyProvider = require('../web3Provider/dummyProvider') var CodeManager = require('../code/codeManager') -var LocalDecoder = require('../solidity/localDecoder') var SolidityProxy = require('../solidity/solidityProxy') +var InternalCallTree = require('../util/internalCallTree') function Ethdebugger () { + var self = this this.event = new EventManager() this.currentStepIndex = -1 @@ -28,8 +29,9 @@ function Ethdebugger () { this.traceManager = new TraceManager() this.codeManager = new CodeManager(this.traceManager) this.solidityProxy = new SolidityProxy(this.traceManager, this.codeManager) - this.locals = new LocalDecoder(this.codeManager, this.traceManager.traceAnalyser.event, this.solidityProxy) - var self = this + + var callTree = new InternalCallTree(this.event, this.traceManager, this.solidityProxy, this.codeManager) + this.event.register('indexChanged', this, function (index) { self.codeManager.resolveStep(index, self.tx) }) @@ -48,7 +50,7 @@ function Ethdebugger () { this.stepManager.event.register('stepChanged', this, function (stepIndex) { self.stepChanged(stepIndex) }) - this.vmDebugger = new VmDebugger(this, this.traceManager, this.codeManager, this.solidityProxy) + this.vmDebugger = new VmDebugger(this, this.traceManager, this.codeManager, this.solidityProxy, callTree) } Ethdebugger.prototype.web3 = function () { @@ -129,7 +131,7 @@ Ethdebugger.prototype.startDebugging = function (blockNumber, txIndex, tx) { if (result) { self.statusMessage = '' yo.update(self.view, self.render()) - self.event.trigger('newTraceLoaded') + self.event.trigger('newTraceLoaded', [self.traceManager.trace]) } else { self.statusMessage = error yo.update(self.view, self.render()) diff --git a/src/ui/VmDebugger.js b/src/ui/VmDebugger.js index 250e8249df..b4527df70a 100644 --- a/src/ui/VmDebugger.js +++ b/src/ui/VmDebugger.js @@ -9,9 +9,10 @@ var FullStoragesChangesPanel = require('./FullStoragesChanges') var StepDetail = require('./StepDetail') var DropdownPanel = require('./DropdownPanel') var SolidityState = require('./SolidityState') +var SolidityLocals = require('./SolidityLocals') var yo = require('yo-yo') -function VmDebugger (_parent, _traceManager, _codeManager, _solidityProxy) { +function VmDebugger (_parent, _traceManager, _codeManager, _solidityProxy, _callTree) { this.asmCode = new CodeListView(_parent, _codeManager) this.stackPanel = new StackPanel(_parent, _traceManager) this.storagePanel = new StoragePanel(_parent, _traceManager) @@ -20,6 +21,7 @@ function VmDebugger (_parent, _traceManager, _codeManager, _solidityProxy) { this.callstackPanel = new CallstackPanel(_parent, _traceManager) this.stepDetail = new StepDetail(_parent, _traceManager) this.solidityState = new SolidityState(_parent, _traceManager, _codeManager, _solidityProxy) + this.solidityLocals = new SolidityLocals(_parent, _traceManager, _callTree) /* Return values - */ this.returnValuesPanel = new DropdownPanel('Return Value') @@ -53,6 +55,7 @@ VmDebugger.prototype.render = function () { var view = yo`