From cfe1903a05aaf7ad833e12be6382175fd899c4e2 Mon Sep 17 00:00:00 2001 From: yann300 Date: Wed, 11 May 2016 13:50:20 +0200 Subject: [PATCH 01/11] load storage async --- src/assemblyItemsBrowser.js | 178 +++++++++++++++++++++++++++--------- src/debugger.js | 19 ++-- src/storageResolver.js | 113 +++++++++++++++++++++++ src/txBrowser.js | 4 +- src/vmTraceBrowser.js | 13 --- src/vmTraceManager.js | 8 -- src/web3Admin.js | 6 ++ 7 files changed, 271 insertions(+), 70 deletions(-) create mode 100644 src/storageResolver.js delete mode 100644 src/vmTraceBrowser.js delete mode 100644 src/vmTraceManager.js diff --git a/src/assemblyItemsBrowser.js b/src/assemblyItemsBrowser.js index 266d88babc..b66f14661b 100644 --- a/src/assemblyItemsBrowser.js +++ b/src/assemblyItemsBrowser.js @@ -6,12 +6,13 @@ var ButtonNavigator = require('./vmTraceButtonNavigator') var codeUtils = require('./codeUtils') var style = require('./basicStyles') var Slider = require('./slider') +var StorageResolver = require('./storageResolver.js') module.exports = React.createClass({ contextTypes: { web3: React.PropTypes.object }, - + getInitialState: function () { return { currentSelected: -1, // current selected item in the vmTrace @@ -24,14 +25,17 @@ module.exports = React.createClass({ currentCallData: null, currentStepInfo: null, codes: {}, // assembly items instructions list by contract addesses + executingCode: [], // code currently loaded in the debugger instructionsIndexByBytesOffset: {}, // mapping between bytes offset and instructions index. - callStack: {} + callStack: {}, + storageStates: {} } }, getDefaultProps: function () { return { - vmTrace: null + vmTrace: null, + transaction: null } }, @@ -53,8 +57,10 @@ module.exports = React.createClass({ stepIntoBack={this.stepIntoBack} stepIntoForward={this.stepIntoForward} stepOverBack={this.stepOverBack} - stepOverForward={this.stepOverForward} /> + stepOverForward={this.stepOverForward} + jumpToNextCall={this.jumpToNextCall} /> +
@@ -138,84 +144,131 @@ module.exports = React.createClass({ return ret }, - resolveAddress: function (address) { - if (!this.state.codes[address]) { - var hexCode = this.context.web3.eth.getCode(address) - var code = codeUtils.nameOpCodes(new Buffer(hexCode.substring(2), 'hex')) - this.state.codes[address] = code[0] - this.state.instructionsIndexByBytesOffset[address] = code[1] + loadCode: function (address, callback) { + console.log('loading new code from web3 ' + address) + this.context.web3.eth.getCode(address, function (error, result) { + if (error) { + console.log(error) + } else { + callback(result) + } + }) + }, + + cacheExecutingCode: function (address, hexCode) { + var code = codeUtils.nameOpCodes(new Buffer(hexCode.substring(2), 'hex')) + this.state.codes[address] = code[0] + this.state.instructionsIndexByBytesOffset[address] = code[1] + return { + code: code[0], + instructionsIndexByBytesOffset: code[1] + } + }, + + getExecutingCodeFromCache: function (address) { + if (this.state.codes[address]) { + return { + code: this.state.codes[address], + instructionsIndexByBytesOffset: this.state.instructionsIndexByBytesOffset[address] + } + } else { + return null } }, renderAssemblyItems: function () { - if (this.props.vmTrace) { - return this.state.codes[this.state.currentAddress].map(function (item, i) { + if (this.props.vmTrace && this.state.executingCode) { + return this.state.executingCode.map(function (item, i) { return }) } }, componentWillReceiveProps: function (nextProps) { + this.setState(this.getInitialState()) if (!nextProps.vmTrace) { return } this.buildCallStack(nextProps.vmTrace) - this.setState({'currentSelected': -1}) this.updateState(nextProps, 0) }, buildCallStack: function (vmTrace) { - if (!vmTrace) { - return - } + if (!vmTrace) return var callStack = [] + var callStackFrame = {} var depth = -1 + this.refs.storageResolver.init(this.props.transaction) for (var k = 0; k < vmTrace.length; k++) { var trace = vmTrace[k] - if (trace.depth === undefined || trace.depth === depth) { - continue - } + if (trace.depth === undefined || trace.depth === depth) continue if (trace.depth > depth) { - callStack.push(trace.address) // new context + if (k === 0) { + callStack.push('0x' + vmTrace[k].address) // new context + } else { + // getting the address from the stack + var callTrace = vmTrace[k - 1] + var address = callTrace.stack[callTrace.stack.length - 2] + callStack.push(address) // new context + } } else if (trace.depth < depth) { callStack.pop() // returning from context } depth = trace.depth - this.state.callStack[k] = callStack.slice(0) + callStackFrame[k] = callStack.slice(0) + + this.refs.storageResolver.trackStorageChange(k, trace) } + this.setState({'callStack': callStackFrame}) }, updateState: function (props, vmTraceIndex) { - if (!props.vmTrace || !props.vmTrace[vmTraceIndex]) { - return - } + if (!props.vmTrace || !props.vmTrace[vmTraceIndex]) return var previousIndex = this.state.currentSelected var stateChanges = {} + var stack if (props.vmTrace[vmTraceIndex].stack) { // there's always a stack - var stack = props.vmTrace[vmTraceIndex].stack + stack = props.vmTrace[vmTraceIndex].stack.slice(0) stack.reverse() - stateChanges['currentStack'] = stack - } - - var currentAddress = this.state.currentAddress - var addressIndex = this.shouldUpdateStateProperty('address', vmTraceIndex, previousIndex, props.vmTrace) - if (addressIndex > -1) { - currentAddress = props.vmTrace[addressIndex].address - this.resolveAddress(currentAddress) - Object.assign(stateChanges, { 'currentAddress': currentAddress }) + Object.assign(stateChanges, { 'currentStack': stack }) } + var newContextLoaded = false var depthIndex = this.shouldUpdateStateProperty('depth', vmTraceIndex, previousIndex, props.vmTrace) if (depthIndex > -1) { - Object.assign(stateChanges, { 'currentCallStack': this.state.callStack[depthIndex] }) + Object.assign(stateChanges, {'currentCallStack': this.state.callStack[depthIndex]}) + // updating exectution context: + var address = this.resolveAddress(depthIndex, props) + if (address !== this.state.currentAddress) { + var self = this + this.ensureExecutingCodeUpdated(address, vmTraceIndex, props, function (code) { + if (self.state.currentAddress !== address) { + console.log('updating executing code ' + self.state.currentAddress + ' -> ' + address) + self.setState( + { + 'selectedInst': code.instructionsIndexByBytesOffset[props.vmTrace[vmTraceIndex].pc], + 'executingCode': code.code, + 'currentAddress': address + }) + } + }) + newContextLoaded = true + } } - - var storageIndex = this.shouldUpdateStateProperty('storage', vmTraceIndex, previousIndex, props.vmTrace) - if (storageIndex > -1) { - Object.assign(stateChanges, { 'currentStorage': props.vmTrace[storageIndex].storage }) + if (!newContextLoaded) { + Object.assign(stateChanges, + { + 'selectedInst': this.getExecutingCodeFromCache(this.state.currentAddress).instructionsIndexByBytesOffset[props.vmTrace[vmTraceIndex].pc] + }) } + Object.assign(stateChanges, { 'currentSelected': vmTraceIndex }) + + this.refs.storageResolver.rebuildStorageAt(vmTraceIndex, props.transaction, function (storage) { + Object.assign(stateChanges, { 'currentStorage': storage }) + }) + var memoryIndex = this.shouldUpdateStateProperty('memory', vmTraceIndex, previousIndex, props.vmTrace) if (memoryIndex > -1) { Object.assign(stateChanges, { 'currentMemory': this.formatMemory(props.vmTrace[memoryIndex].memory, 16) }) @@ -226,19 +279,50 @@ module.exports = React.createClass({ Object.assign(stateChanges, { 'currentCallData': [props.vmTrace[callDataIndex].calldata] }) } - stateChanges['selectedInst'] = this.state.instructionsIndexByBytesOffset[currentAddress][props.vmTrace[vmTraceIndex].pc] - stateChanges['currentSelected'] = vmTraceIndex - stateChanges['currentStepInfo'] = [ 'Current Step: ' + props.vmTrace[vmTraceIndex].steps, 'Adding Memory: ' + (props.vmTrace[vmTraceIndex].memexpand ? props.vmTrace[vmTraceIndex].memexpand : ''), 'Step Cost: ' + props.vmTrace[vmTraceIndex].gascost, 'Remaining Gas: ' + props.vmTrace[vmTraceIndex].gas ] + this.refs.slider.setValue(vmTraceIndex) this.setState(stateChanges) }, + ensureExecutingCodeUpdated: function (address, vmTraceIndex, props, callBack) { + this.resolveCode(address, vmTraceIndex, props, function (address, code) { + callBack(code) + }) + }, + + resolveAddress: function (vmTraceIndex, props) { + var address = props.vmTrace[vmTraceIndex].address + if (vmTraceIndex > 0) { + var stack = this.state.callStack[vmTraceIndex] // callcode, delegatecall, ... + address = stack[stack.length - 1] + } + return address + }, + + resolveCode: function (address, vmTraceIndex, props, callBack) { + var cache = this.getExecutingCodeFromCache(address) + if (cache) { + callBack(address, cache) + return + } + + if (vmTraceIndex === 0 && props.transaction.to === null) { // start of the trace + callBack(address, this.cacheExecutingCode(address, props.transaction.input)) + return + } + + var self = this + this.loadCode(address, function (code) { + callBack(address, self.cacheExecutingCode(address, code)) + }) + }, + shouldUpdateStateProperty: function (vmTraceName, nextIndex, previousIndex, vmTrace) { var propIndex = -1 if (previousIndex + 1 === nextIndex) { @@ -265,6 +349,16 @@ module.exports = React.createClass({ return index }, + jumpToNextCall: function () { + var i = this.state.currentSelected + while (++i < this.props.vmTrace.length) { + if (this.isCallInstruction(i)) { + this.selectState(i + 1) + break + } + } + }, + stepIntoBack: function () { this.moveSelection(-1) }, diff --git a/src/debugger.js b/src/debugger.js index ff7109ea59..d56348f33d 100644 --- a/src/debugger.js +++ b/src/debugger.js @@ -1,12 +1,16 @@ 'use strict' var React = require('react') var TxBrowser = require('./txBrowser') -var VmTraceBrowser = require('./vmTraceBrowser') +var AssemblyItemsBrowser = require('./assemblyItemsBrowser') var style = require('./basicStyles') module.exports = React.createClass({ getInitialState: function () { - return {vmTrace: null, state: '', currentStep: -1} + return { + vmTrace: null, + state: '', + currentStep: -1 + } }, childContextTypes: { @@ -25,19 +29,22 @@ module.exports = React.createClass({
{this.state.state}
- + ) }, - retrieveVmTrace: function (blockNumber, txNumber) { - this.setState({state: 'loading...'}) + retrieveVmTrace: function (blockNumber, txNumber, tx) { + if (this.state.state !== '') return + var self = this + this.setState({state: 'loading...'}) + this.props.web3.debug.trace(blockNumber, parseInt(txNumber), function (error, result) { if (error) { console.log(error) } else { - self.setState({vmTrace: result, state: ''}) + self.setState({vmTrace: result, transaction: tx, state: ''}) } }) } diff --git a/src/storageResolver.js b/src/storageResolver.js new file mode 100644 index 0000000000..8935f793a9 --- /dev/null +++ b/src/storageResolver.js @@ -0,0 +1,113 @@ +'use strict' +var React = require('react') + +module.exports = React.createClass({ + contextTypes: { + web3: React.PropTypes.object + }, + + getInitialState: function () { + return { + storage: {}, + storageChanges: [], + vmTraceIndexByStorageChange: {}, + vmTraceChangesRef: [] + } + }, + + init: function () { + var defaultState = this.getInitialState() + this.state.storage = defaultState.storage + this.state.storageChanges = defaultState.storageChanges + this.state.vmTraceIndexByStorageChange = defaultState.vmTraceIndexByStorageChange + this.state.vmTraceChangesRef = defaultState.vmTraceChangesRef + }, + + render: function () { + return null + }, + + // retrieve the storage of an account just after the execution of txHash + retrieveStorage: function (address, transaction, callBack) { + if (this.state.storage[address]) { + callBack(this.state.storage[address]) + } + var self = this + if (transaction) { + this.context.web3.debug.storageAt(transaction.blockNumber.toString(), transaction.transactionIndex, address, function (error, result) { + if (error) { + console.log(error) + } else { + self.state.storage[address] = result + callBack(result) + } + }) + } else { + console.log('transaction is not defined') + } + }, + + trackStorageChange: function (vmTraceIndex, trace) { + var change = false + if (trace.address) { + // new context + this.state.storageChanges.push({ address: trace.address, changes: [] }) + change = true + } else if (trace.depth && !trace.address) { + // returned from context + this.state.storageChanges.push({ address: this.state.storageChanges[this.state.storageChanges.length - 1].address, changes: [] }) + change = true + } else if (trace.inst === 'SSTORE') { + this.state.storageChanges[this.state.storageChanges.length - 1].changes.push( + { + 'key': trace.stack[trace.stack.length - 1], + 'value': trace.stack[trace.stack.length - 2] + }) + change = true + } + + if (change) { + this.state.vmTraceIndexByStorageChange[vmTraceIndex] = { + context: this.state.storageChanges.length - 1, + changes: this.state.storageChanges[this.state.storageChanges.length - 1].changes.length - 1 + } + this.state.vmTraceChangesRef.push(vmTraceIndex) + } + }, + + rebuildStorageAt: function (vmTraceIndex, transaction, callBack) { + var changesLocation = this.retrieveLastChange(vmTraceIndex) + if (!changesLocation) { + console.log('unable to build storage') + callBack({}) + } else { + var address = this.state.storageChanges[changesLocation.context].address + this.retrieveStorage(address, transaction, function (storage) { + for (var k = 0; k < changesLocation.context; k++) { + var context = this.state.storageChanges[k] + if (context.address === address) { + for (var i = 0; i < context.changes.length; i++) { + if (i > changesLocation.changes) break + var change = context.changes[i] + storage[change.key] = change.value + } + } + } + callBack(storage) + }) + } + }, + + retrieveLastChange: function (vmTraceIndex) { + var change = this.state.vmTraceIndexByStorageChange[vmTraceIndex] + if (change) { + return change + } else { + for (var k in this.state.vmTraceChangesRef) { + if (this.state.vmTraceChangesRef[k] > vmTraceIndex) { + return this.state.vmTraceIndexByStorageChange[k - 1] + } + } + } + } +}) diff --git a/src/txBrowser.js b/src/txBrowser.js index 8bb3eced04..0bba5312c4 100644 --- a/src/txBrowser.js +++ b/src/txBrowser.js @@ -19,8 +19,10 @@ module.exports = React.createClass({ var tx = this.context.web3.eth.getTransactionFromBlock(this.state.blockNumber, this.state.txNumber) if (tx) { this.setState({from: tx.from, to: tx.to, hash: tx.hash}) + this.props.onNewTxRequested(this.state.blockNumber, parseInt(this.state.txNumber), tx) + } else { + console.log('cannot find ' + this.state.blockNumber + ' ' + this.state.txNumber) } - this.props.onNewTxRequested(this.state.blockNumber, parseInt(this.state.txNumber)) }, updateBlockN: function (ev) { diff --git a/src/vmTraceBrowser.js b/src/vmTraceBrowser.js deleted file mode 100644 index eee6492b82..0000000000 --- a/src/vmTraceBrowser.js +++ /dev/null @@ -1,13 +0,0 @@ -'use strict' -var React = require('react') -var AssemblyItemsBrowser = require('./assemblyItemsBrowser') - -module.exports = React.createClass({ - render: function () { - return ( -
- -
- ) - } -}) diff --git a/src/vmTraceManager.js b/src/vmTraceManager.js deleted file mode 100644 index 137d4721e2..0000000000 --- a/src/vmTraceManager.js +++ /dev/null @@ -1,8 +0,0 @@ -'use strict' -module.exports = { - retrieveVmTrace: function (blockNumber, txNumber, callBack) { - this.context.web3.debug.trace(blockNumber, parseInt(txNumber), function (error, result) { - callBack(error, result) - }) - } -} diff --git a/src/web3Admin.js b/src/web3Admin.js index cebe2f64f7..a3a37661c9 100644 --- a/src/web3Admin.js +++ b/src/web3Admin.js @@ -89,6 +89,12 @@ module.exports = { web3._extend({ property: 'debug', methods: [ + new web3._extend.Method({ + name: 'storageAt', + call: 'debug_storageAt', + inputFormatter: [null, null, null], + params: 3 + }), new web3._extend.Method({ name: 'trace', call: 'debug_trace', From 79ae4bf99311a98fa4bcab05489c2d743508e062 Mon Sep 17 00:00:00 2001 From: yann300 Date: Thu, 19 May 2016 12:21:44 +0200 Subject: [PATCH 02/11] modularisation --- src/asmCode.js | 83 ++++ src/assemblyItemsBrowser.js | 357 ++---------------- ...eButtonNavigator.js => buttonNavigator.js} | 6 +- src/codeResolver.js | 67 ++++ src/debugger.js | 59 ++- src/slider.js | 10 +- src/stepManager.js | 98 +++++ src/sticker.js | 81 +++- src/storageResolver.js | 113 ------ src/traceManager.js | 340 +++++++++++++++++ src/txBrowser.js | 28 +- 11 files changed, 771 insertions(+), 471 deletions(-) create mode 100644 src/asmCode.js rename src/{vmTraceButtonNavigator.js => buttonNavigator.js} (88%) create mode 100644 src/codeResolver.js create mode 100644 src/stepManager.js delete mode 100644 src/storageResolver.js create mode 100644 src/traceManager.js diff --git a/src/asmCode.js b/src/asmCode.js new file mode 100644 index 0000000000..2d9e723da4 --- /dev/null +++ b/src/asmCode.js @@ -0,0 +1,83 @@ +'use strict' +var React = require('react') +var style = require('./basicStyles') +var codeResolver = require('./codeResolver') + +module.exports = React.createClass({ + contextTypes: { + traceManager: React.PropTypes.object, + tx: React.PropTypes.object, + web3: React.PropTypes.object + }, + + getInitialState: function () { + return { + code: [], + selected: -1, + address: '' // selected instruction in the asm + } + }, + + getDefaultProps: function () { + return { + currentStepIndex: -1 + } + }, + + render: function () { + return ( + + ) + }, + + renderAssemblyItems: function () { + if (this.state.code) { + return this.state.code.map(function (item, i) { + return + }) + } + }, + + componentWillReceiveProps: function (nextProps) { + console.log('asm' + JSON.stringify(nextProps)) + if (nextProps.currentStepIndex < 0) return + codeResolver.setWeb3(this.context.web3) + var self = this + this.context.traceManager.getCurrentCalledAddressAt(nextProps.currentStepIndex, function (address) { + self.ensureCodeLoaded(address, nextProps.currentStepIndex) + }) + }, + + ensureCodeLoaded: function (address, currentStep) { + if (address !== this.state.address) { + this.setState({ + code: ['loading...'] + }) + var self = this + codeResolver.resolveCode(address, currentStep, this.context.tx, function (address, code) { + self.setState({ + code: code, + address: address + }) + self.setInstructionIndex(address, currentStep) + }) + } else { + this.setInstructionIndex(this.state.address, currentStep) + } + }, + + setInstructionIndex: function (address, step) { + var self = this + this.context.traceManager.getCurrentPC(step, function (instIndex) { + self.setState({ + selected: codeResolver.getInstructionIndex(address, instIndex) + }) + }) + } +}) diff --git a/src/assemblyItemsBrowser.js b/src/assemblyItemsBrowser.js index b66f14661b..13e788d89c 100644 --- a/src/assemblyItemsBrowser.js +++ b/src/assemblyItemsBrowser.js @@ -2,40 +2,28 @@ var React = require('react') var BasicPanel = require('./basicPanel') var Sticker = require('./sticker') -var ButtonNavigator = require('./vmTraceButtonNavigator') -var codeUtils = require('./codeUtils') var style = require('./basicStyles') -var Slider = require('./slider') -var StorageResolver = require('./storageResolver.js') +var ASMCode = require('./asmCode') module.exports = React.createClass({ contextTypes: { + traceManager: React.PropTypes.object, web3: React.PropTypes.object }, - + getInitialState: function () { return { - currentSelected: -1, // current selected item in the vmTrace - selectedInst: -1, // current selected item in the contract assembly code currentAddress: null, currentStack: null, - currentLevels: null, currentStorage: null, currentMemory: null, - currentCallData: null, - currentStepInfo: null, - codes: {}, // assembly items instructions list by contract addesses - executingCode: [], // code currently loaded in the debugger - instructionsIndexByBytesOffset: {}, // mapping between bytes offset and instructions index. - callStack: {}, - storageStates: {} + currentCallData: null } }, getDefaultProps: function () { return { - vmTrace: null, - transaction: null + currentStepIndex: -1 // index of the selected item in the vmtrace } }, @@ -45,36 +33,14 @@ module.exports = React.createClass({
Current code: {this.state.currentAddress}
-
- - -
-
@@ -70,112 +69,16 @@ module.exports = React.createClass({ ) }, - renderStorageRow: function (data) { - var ret = [] - if (data) { - for (var key in data) { - ret.push( - - - - ) - } - } - return ret - }, - - renderMemoryRow: function (data) { - var ret = [] - if (data) { - for (var key in data) { - var memSlot = data[key] - ret.push( - - - - - ) - } - } - return ret - }, - componentWillReceiveProps: function (nextProps) { - console.log("asse " + JSON.stringify(nextProps)) if (nextProps.currentStepIndex < 0) return - + if (window.ethDebuggerSelectedItem !== nextProps.currentStepIndex) return var self = this - this.context.traceManager.getCallDataAt(nextProps.currentStepIndex, function (calldata) { - self.setState({ - currentCallData: calldata - }) - }) - - this.context.traceManager.getCallStackAt(nextProps.currentStepIndex, function (callstack) { - self.setState({ - currentCallStack: callstack - }) - }) - - this.context.traceManager.getMemoryAt(nextProps.currentStepIndex, function (memory) { - self.setState({ - currentMemory: self.formatMemory(memory, 16) - }) - }) - - this.context.traceManager.getStorageAt(nextProps.currentStepIndex, function (storage) { - self.setState({ - currentStorage: storage - }) - }) - - this.context.traceManager.getStackAt(nextProps.currentStepIndex, function (stack) { - self.setState({ - currentStack: stack - }) - }) - this.context.traceManager.getCurrentCalledAddressAt(nextProps.currentStepIndex, function (address) { - self.setState({ - currentAddress: address - }) - }) - }, - - formatMemory: function (mem, width) { - var ret = [] - for (var k = 0; k < mem.length; k += (width * 2)) { - var memory = mem.substr(k, width * 2) - ret.push({ - address: this.context.web3.toHex(k), - content: this.tryAsciiFormat(memory) - }) - } - return ret - }, - - tryAsciiFormat: function (memorySlot) { - var ret = { ascii: '', raw: '' } - for (var k = 0; k < memorySlot.length; k += 2) { - var raw = memorySlot.substr(k, 2) - var ascii = this.context.web3.toAscii(raw) - if (ascii === String.fromCharCode(0)) { - ret.ascii += '?' - } else { - ret.ascii += ascii + if (window.ethDebuggerSelectedItem === nextProps.currentStepIndex) { + self.setState({ + currentAddress: address + }) } - ret.raw += ' ' + raw - } - return ret + }) } }) diff --git a/src/calldataPanel.js b/src/calldataPanel.js new file mode 100644 index 0000000000..525794c72d --- /dev/null +++ b/src/calldataPanel.js @@ -0,0 +1,41 @@ +'use strict' +var React = require('react') +var BasicPanel = require('./basicPanel') + +module.exports = React.createClass({ + contextTypes: { + traceManager: React.PropTypes.object + }, + + getDefaultProps: function () { + return { + currentStepIndex: -1 + } + }, + + getInitialState: function () { + return { + data: null + } + }, + + render: function () { + return ( + + ) + }, + + componentWillReceiveProps: function (nextProps) { + if (nextProps.currentStepIndex < 0) return + if (window.ethDebuggerSelectedItem !== nextProps.currentStepIndex) return + + var self = this + this.context.traceManager.getCallDataAt(nextProps.currentStepIndex, function (calldata) { + if (window.ethDebuggerSelectedItem === nextProps.currentStepIndex) { + self.setState({ + data: calldata + }) + } + }) + } +}) diff --git a/src/callstackPanel.js b/src/callstackPanel.js new file mode 100644 index 0000000000..0907bc2cb0 --- /dev/null +++ b/src/callstackPanel.js @@ -0,0 +1,41 @@ +'use strict' +var React = require('react') +var BasicPanel = require('./basicPanel') + +module.exports = React.createClass({ + contextTypes: { + traceManager: React.PropTypes.object + }, + + getDefaultProps: function () { + return { + currentStepIndex: -1 + } + }, + + getInitialState: function () { + return { + data: null + } + }, + + render: function () { + return ( + + ) + }, + + componentWillReceiveProps: function (nextProps) { + if (nextProps.currentStepIndex < 0) return + if (window.ethDebuggerSelectedItem !== nextProps.currentStepIndex) return + + var self = this + this.context.traceManager.getCallStackAt(nextProps.currentStepIndex, function (callstack) { + if (window.ethDebuggerSelectedItem === nextProps.currentStepIndex) { + self.setState({ + data: callstack + }) + } + }) + } +}) diff --git a/src/debugger.js b/src/debugger.js index 81a209f1cb..576e0bb0ad 100644 --- a/src/debugger.js +++ b/src/debugger.js @@ -9,8 +9,8 @@ var style = require('./basicStyles') module.exports = React.createClass({ getInitialState: function () { return { - tx: null, - currentStepIndex: -1 // index of the selected item in the vmtrace + currentStepIndex: -1, // index of the selected item in the vmtrace + tx: null } }, @@ -38,7 +38,7 @@ module.exports = React.createClass({

Eth Debugger

- + ) }, diff --git a/src/memoryPanel.js b/src/memoryPanel.js new file mode 100644 index 0000000000..0d2c3348d6 --- /dev/null +++ b/src/memoryPanel.js @@ -0,0 +1,91 @@ +'use strict' +var React = require('react') +var BasicPanel = require('./basicPanel') + +module.exports = React.createClass({ + contextTypes: { + traceManager: React.PropTypes.object, + web3: React.PropTypes.object + }, + + getDefaultProps: function () { + return { + currentStepIndex: -1 + } + }, + + getInitialState: function () { + return { + data: null + } + }, + + render: function () { + return ( + + ) + }, + + componentWillReceiveProps: function (nextProps) { + if (nextProps.currentStepIndex < 0) return + if (window.ethDebuggerSelectedItem !== nextProps.currentStepIndex) return + + var self = this + this.context.traceManager.getMemoryAt(nextProps.currentStepIndex, function (memory) { + if (window.ethDebuggerSelectedItem === nextProps.currentStepIndex) { + self.setState({ + data: self.formatMemory(memory, 16) + }) + } + }) + }, + + renderMemoryRow: function (data) { + var ret = [] + if (data) { + for (var key in data) { + var memSlot = data[key] + ret.push( +
+ + + + ) + } + } + return ret + }, + + formatMemory: function (mem, width) { + var ret = [] + for (var k = 0; k < mem.length; k += (width * 2)) { + var memory = mem.substr(k, width * 2) + ret.push({ + address: this.context.web3.toHex(k), + content: this.tryAsciiFormat(memory) + }) + } + return ret + }, + + tryAsciiFormat: function (memorySlot) { + var ret = { ascii: '', raw: '' } + for (var k = 0; k < memorySlot.length; k += 2) { + var raw = memorySlot.substr(k, 2) + var ascii = this.context.web3.toAscii(raw) + if (ascii === String.fromCharCode(0)) { + ret.ascii += '?' + } else { + ret.ascii += ascii + } + ret.raw += ' ' + raw + } + return ret + } +}) diff --git a/src/stackPanel.js b/src/stackPanel.js new file mode 100644 index 0000000000..0dae966632 --- /dev/null +++ b/src/stackPanel.js @@ -0,0 +1,41 @@ +'use strict' +var React = require('react') +var BasicPanel = require('./basicPanel') + +module.exports = React.createClass({ + contextTypes: { + traceManager: React.PropTypes.object + }, + + getDefaultProps: function () { + return { + currentStepIndex: -1 + } + }, + + getInitialState: function () { + return { + data: null + } + }, + + render: function () { + return ( + + ) + }, + + componentWillReceiveProps: function (nextProps) { + if (nextProps.currentStepIndex < 0) return + if (window.ethDebuggerSelectedItem !== nextProps.currentStepIndex) return + + var self = this + this.context.traceManager.getStackAt(nextProps.currentStepIndex, function (stack) { + if (window.ethDebuggerSelectedItem === nextProps.currentStepIndex) { + self.setState({ + data: stack + }) + } + }) + } +}) diff --git a/src/stepManager.js b/src/stepManager.js index 607f0f1af9..5033709f45 100644 --- a/src/stepManager.js +++ b/src/stepManager.js @@ -39,6 +39,14 @@ module.exports = React.createClass({ ) }, + componentDidMount: function () { + this.updateGlobalSelectedItem(0) + }, + + updateGlobalSelectedItem: function (value) { + window.ethDebuggerSelectedItem = value + }, + init: function () { this.refs.slider.setValue(0) }, @@ -91,6 +99,7 @@ module.exports = React.createClass({ }, changeState: function (step) { + this.updateGlobalSelectedItem(step) this.setState({ currentStepIndex: step }) diff --git a/src/storagePanel.js b/src/storagePanel.js new file mode 100644 index 0000000000..daa63076bf --- /dev/null +++ b/src/storagePanel.js @@ -0,0 +1,59 @@ +'use strict' +var React = require('react') +var BasicPanel = require('./basicPanel') + +module.exports = React.createClass({ + contextTypes: { + traceManager: React.PropTypes.object + }, + + getDefaultProps: function () { + return { + currentStepIndex: -1 + } + }, + + getInitialState: function () { + return { + data: null + } + }, + + render: function () { + return ( + + ) + }, + + componentWillReceiveProps: function (nextProps) { + if (nextProps.currentStepIndex < 0) return + if (window.ethDebuggerSelectedItem !== nextProps.currentStepIndex) return + + var self = this + this.context.traceManager.getStorageAt(nextProps.currentStepIndex, function (storage) { + if (window.ethDebuggerSelectedItem === nextProps.currentStepIndex) { + self.setState({ + data: storage + }) + } + }) + }, + + renderStorageRow: function (data) { + var ret = [] + if (data) { + for (var key in data) { + ret.push( + + + + ) + } + } + return ret + } +}) From da22990a660ab6e7f44be3a33fd847b76cbc1442 Mon Sep 17 00:00:00 2001 From: yann300 Date: Thu, 19 May 2016 15:21:15 +0200 Subject: [PATCH 04/11] rename assemblyitemsbrowser --- src/debugger.js | 2 +- src/{assemblyItemsBrowser.js => vmDebugger.js} | 0 2 files changed, 1 insertion(+), 1 deletion(-) rename src/{assemblyItemsBrowser.js => vmDebugger.js} (100%) diff --git a/src/debugger.js b/src/debugger.js index 576e0bb0ad..82dcec88a0 100644 --- a/src/debugger.js +++ b/src/debugger.js @@ -2,7 +2,7 @@ var React = require('react') var TxBrowser = require('./txBrowser') var StepManager = require('./stepManager') -var AssemblyItemsBrowser = require('./assemblyItemsBrowser') +var AssemblyItemsBrowser = require('./vmDebugger') var traceManager = require('./traceManager') var style = require('./basicStyles') diff --git a/src/assemblyItemsBrowser.js b/src/vmDebugger.js similarity index 100% rename from src/assemblyItemsBrowser.js rename to src/vmDebugger.js From ecbfbf1b9a8ab5458909e255937e29ba61ae599f Mon Sep 17 00:00:00 2001 From: yann300 Date: Thu, 19 May 2016 15:25:04 +0200 Subject: [PATCH 05/11] rename lastPropertyChange --- src/asmCode.js | 1 - src/traceManager.js | 16 ++++++++-------- 2 files changed, 8 insertions(+), 9 deletions(-) diff --git a/src/asmCode.js b/src/asmCode.js index 552389541c..a0cfe4a2ca 100644 --- a/src/asmCode.js +++ b/src/asmCode.js @@ -45,7 +45,6 @@ module.exports = React.createClass({ }, componentWillReceiveProps: function (nextProps) { - console.log('new prop asmCode') if (nextProps.currentStepIndex < 0) return codeResolver.setWeb3(this.context.web3) var self = this diff --git a/src/traceManager.js b/src/traceManager.js index 256538bc35..a0b2c2db81 100644 --- a/src/traceManager.js +++ b/src/traceManager.js @@ -145,7 +145,7 @@ module.exports = { }, getStorageAt: function (stepIndex, callback) { - var stoChange = this.lastPropertyChange(stepIndex, this.vmTraceChangesRef) + var stoChange = this.findLowerBound(stepIndex, this.vmTraceChangesRef) if (!stoChange) { return {} } @@ -169,13 +169,13 @@ module.exports = { }, getCallDataAt: function (stepIndex, callback) { - var callDataChange = this.lastPropertyChange(stepIndex, this.callDataChanges) + var callDataChange = this.findLowerBound(stepIndex, this.callDataChanges) if (!callDataChange) return [''] callback([this.trace[callDataChange].calldata]) }, getCallStackAt: function (stepIndex, callback) { - var callStackChange = this.lastPropertyChange(stepIndex, this.depthChanges) + var callStackChange = this.findLowerBound(stepIndex, this.depthChanges) if (!callStackChange) return '' callback(this.callStack[callStackChange].stack) }, @@ -190,7 +190,7 @@ module.exports = { }, getLastDepthIndexChangeSince: function (stepIndex, callback) { - var depthIndex = this.lastPropertyChange(stepIndex, this.depthChanges) + var depthIndex = this.findLowerBound(stepIndex, this.depthChanges) callback(depthIndex) }, @@ -202,7 +202,7 @@ module.exports = { }, getMemoryAt: function (stepIndex, callback) { - var lastChanges = this.lastPropertyChange(stepIndex, this.memoryChanges) + var lastChanges = this.findLowerBound(stepIndex, this.memoryChanges) if (!lastChanges) return '' callback(this.trace[lastChanges].memory) }, @@ -289,7 +289,7 @@ module.exports = { }, // util section - lastPropertyChange: function (target, changes) { + findLowerBound: function (target, changes) { if (changes.length === 1) { if (changes[0] > target) { // we only a closest maximum, returning 0 @@ -301,9 +301,9 @@ module.exports = { var middle = Math.floor(changes.length / 2) if (changes[middle] > target) { - return this.lastPropertyChange(target, changes.slice(0, middle)) + return this.findLowerBound(target, changes.slice(0, middle)) } else if (changes[middle] < target) { - return this.lastPropertyChange(target, changes.slice(middle, changes.length)) + return this.findLowerBound(target, changes.slice(middle, changes.length)) } else { return changes[middle] } From c00a995d05f9118a68dd2cc06988456edfb58cfa Mon Sep 17 00:00:00 2001 From: yann300 Date: Thu, 19 May 2016 15:33:14 +0200 Subject: [PATCH 06/11] remove tx from traceManager --- .gitignore | 1 + src/debugger.js | 1 - src/storagePanel.js | 5 +++-- src/traceManager.js | 16 ++++++---------- 4 files changed, 10 insertions(+), 13 deletions(-) diff --git a/.gitignore b/.gitignore index d64f9c06ba..856fe89d72 100644 --- a/.gitignore +++ b/.gitignore @@ -2,3 +2,4 @@ build node_modules npm-debug.log lint.xml +.vscode diff --git a/src/debugger.js b/src/debugger.js index 82dcec88a0..e67ed0243c 100644 --- a/src/debugger.js +++ b/src/debugger.js @@ -57,7 +57,6 @@ module.exports = React.createClass({ this.setState({ tx: tx }) - traceManager.setTransaction(tx) var self = this traceManager.resolveTrace(blockNumber, txIndex, function (success) { console.log('trace loaded ' + success) diff --git a/src/storagePanel.js b/src/storagePanel.js index daa63076bf..56268a271e 100644 --- a/src/storagePanel.js +++ b/src/storagePanel.js @@ -4,7 +4,8 @@ var BasicPanel = require('./basicPanel') module.exports = React.createClass({ contextTypes: { - traceManager: React.PropTypes.object + traceManager: React.PropTypes.object, + tx: React.PropTypes.object }, getDefaultProps: function () { @@ -30,7 +31,7 @@ module.exports = React.createClass({ if (window.ethDebuggerSelectedItem !== nextProps.currentStepIndex) return var self = this - this.context.traceManager.getStorageAt(nextProps.currentStepIndex, function (storage) { + this.context.traceManager.getStorageAt(nextProps.currentStepIndex, this.context.tx.blockNumber.toString(), this.context.tx.transactionIndex, function (storage) { if (window.ethDebuggerSelectedItem === nextProps.currentStepIndex) { self.setState({ data: storage diff --git a/src/traceManager.js b/src/traceManager.js index a0b2c2db81..c29c24c7f0 100644 --- a/src/traceManager.js +++ b/src/traceManager.js @@ -22,10 +22,6 @@ module.exports = { this.web3 = web3 }, - setTransaction: function (tx) { - this.transaction = tx - }, - resolveTrace: function (blockNumber, txNumber, callback) { this.isLoading = true this.init() @@ -144,7 +140,7 @@ module.exports = { callback(this.trace.length) }, - getStorageAt: function (stepIndex, callback) { + getStorageAt: function (stepIndex, blockNumber, txIndex, callback) { var stoChange = this.findLowerBound(stepIndex, this.vmTraceChangesRef) if (!stoChange) { return {} @@ -153,7 +149,7 @@ module.exports = { var changeRefs = this.vmTraceIndexByStorageChange[stoChange] var address = this.storageChanges[changeRefs.context].address var self = this - this.retrieveStorage(address, function (storage) { + this.retrieveStorage(address, blockNumber, txIndex, function (storage) { for (var k = 0; k < changeRefs.context; k++) { var context = self.storageChanges[k] if (context.address === address) { @@ -319,13 +315,13 @@ module.exports = { }, // retrieve the storage of an account just after the execution of tx - retrieveStorage: function (address, callBack) { + retrieveStorage: function (address, blockNumber, txIndex, callBack) { if (this.storages[address]) { callBack(this.storages[address]) } var self = this - if (this.transaction) { - this.web3.debug.storageAt(this.transaction.blockNumber.toString(), this.transaction.transactionIndex, address, function (error, result) { + if (blockNumber !== null && txIndex !== null) { + this.web3.debug.storageAt(blockNumber, txIndex, address, function (error, result) { if (error) { console.log(error) } else { @@ -334,7 +330,7 @@ module.exports = { } }) } else { - console.log('transaction is not defined') + console.log('blockNumber/txIndex are not defined') } } } From 28cb70ee127b15313d7424ed50a21c8db30131ef Mon Sep 17 00:00:00 2001 From: yann300 Date: Thu, 19 May 2016 15:38:24 +0200 Subject: [PATCH 07/11] rename function --- src/traceManager.js | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/src/traceManager.js b/src/traceManager.js index c29c24c7f0..c6c1e287dd 100644 --- a/src/traceManager.js +++ b/src/traceManager.js @@ -58,10 +58,10 @@ module.exports = { for (var k in this.trace) { var step = this.trace[k] - this.calldata(k, step) - this.memory(k, step) - currentStorageAddress = this.storage(k, step, currentStorageAddress) - var depth = this.depth(k, step, currentDepth, callStack) + this.buildCalldata(k, step) + this.buildMemory(k, step) + currentStorageAddress = this.buildStorage(k, step, currentStorageAddress) + var depth = this.buildDepth(k, step, currentDepth, callStack) if (depth) { currentDepth = depth } @@ -69,19 +69,19 @@ module.exports = { }, // compute trace section - calldata: function (index, step) { + buildCalldata: function (index, step) { if (step.calldata) { this.callDataChanges.push(index) } }, - memory: function (index, step) { + buildMemory: function (index, step) { if (step.memory) { this.memoryChanges.push(index) } }, - storage: function (index, step, currentAddress) { + buildStorage: function (index, step, currentAddress) { var change = false if (step.address) { // new context @@ -111,7 +111,7 @@ module.exports = { return currentAddress }, - depth: function (index, step, currentDepth, callStack) { + buildDepth: function (index, step, currentDepth, callStack) { if (step.depth === undefined) return if (step.depth > currentDepth) { if (index === 0) { From 505d74365a170a50fbd5a4f761b6ebd619c9f397 Mon Sep 17 00:00:00 2001 From: yann300 Date: Thu, 19 May 2016 15:57:18 +0200 Subject: [PATCH 08/11] add error param in callback functions --- src/asmCode.js | 20 ++++++++++++------ src/calldataPanel.js | 6 ++++-- src/callstackPanel.js | 6 ++++-- src/memoryPanel.js | 6 ++++-- src/stackPanel.js | 6 ++++-- src/stepManager.js | 8 ++++++-- src/sticker.js | 48 ++++++++++++++++++++++++++++--------------- src/storagePanel.js | 6 ++++-- src/traceManager.js | 44 ++++++++++++++++++++++----------------- src/vmDebugger.js | 6 ++++-- 10 files changed, 101 insertions(+), 55 deletions(-) diff --git a/src/asmCode.js b/src/asmCode.js index a0cfe4a2ca..765c64e89d 100644 --- a/src/asmCode.js +++ b/src/asmCode.js @@ -48,8 +48,12 @@ module.exports = React.createClass({ if (nextProps.currentStepIndex < 0) return codeResolver.setWeb3(this.context.web3) var self = this - this.context.traceManager.getCurrentCalledAddressAt(nextProps.currentStepIndex, function (address) { - self.ensureCodeLoaded(address, nextProps.currentStepIndex) + this.context.traceManager.getCurrentCalledAddressAt(nextProps.currentStepIndex, function (error, address) { + if (error) { + console.log(error) + } else { + self.ensureCodeLoaded(address, nextProps.currentStepIndex) + } }) }, @@ -77,10 +81,14 @@ module.exports = React.createClass({ setInstructionIndex: function (address, step) { var self = this - this.context.traceManager.getCurrentPC(step, function (instIndex) { - self.setState({ - selected: codeResolver.getInstructionIndex(address, instIndex) - }) + this.context.traceManager.getCurrentPC(step, function (error, instIndex) { + if (error) { + console.log(error) + } else { + self.setState({ + selected: codeResolver.getInstructionIndex(address, instIndex) + }) + } }) } }) diff --git a/src/calldataPanel.js b/src/calldataPanel.js index 525794c72d..752a2bf15e 100644 --- a/src/calldataPanel.js +++ b/src/calldataPanel.js @@ -30,8 +30,10 @@ module.exports = React.createClass({ if (window.ethDebuggerSelectedItem !== nextProps.currentStepIndex) return var self = this - this.context.traceManager.getCallDataAt(nextProps.currentStepIndex, function (calldata) { - if (window.ethDebuggerSelectedItem === nextProps.currentStepIndex) { + this.context.traceManager.getCallDataAt(nextProps.currentStepIndex, function (error, calldata) { + if (error) { + console.log(error) + } else if (window.ethDebuggerSelectedItem === nextProps.currentStepIndex) { self.setState({ data: calldata }) diff --git a/src/callstackPanel.js b/src/callstackPanel.js index 0907bc2cb0..83ec5ce94a 100644 --- a/src/callstackPanel.js +++ b/src/callstackPanel.js @@ -30,8 +30,10 @@ module.exports = React.createClass({ if (window.ethDebuggerSelectedItem !== nextProps.currentStepIndex) return var self = this - this.context.traceManager.getCallStackAt(nextProps.currentStepIndex, function (callstack) { - if (window.ethDebuggerSelectedItem === nextProps.currentStepIndex) { + this.context.traceManager.getCallStackAt(nextProps.currentStepIndex, function (error, callstack) { + if (error) { + console.log(error) + } else if (window.ethDebuggerSelectedItem === nextProps.currentStepIndex) { self.setState({ data: callstack }) diff --git a/src/memoryPanel.js b/src/memoryPanel.js index 0d2c3348d6..8dbfb066b3 100644 --- a/src/memoryPanel.js +++ b/src/memoryPanel.js @@ -31,8 +31,10 @@ module.exports = React.createClass({ if (window.ethDebuggerSelectedItem !== nextProps.currentStepIndex) return var self = this - this.context.traceManager.getMemoryAt(nextProps.currentStepIndex, function (memory) { - if (window.ethDebuggerSelectedItem === nextProps.currentStepIndex) { + this.context.traceManager.getMemoryAt(nextProps.currentStepIndex, function (error, memory) { + if (error) { + console.log(error) + } else if (window.ethDebuggerSelectedItem === nextProps.currentStepIndex) { self.setState({ data: self.formatMemory(memory, 16) }) diff --git a/src/stackPanel.js b/src/stackPanel.js index 0dae966632..a4ff3c8472 100644 --- a/src/stackPanel.js +++ b/src/stackPanel.js @@ -30,8 +30,10 @@ module.exports = React.createClass({ if (window.ethDebuggerSelectedItem !== nextProps.currentStepIndex) return var self = this - this.context.traceManager.getStackAt(nextProps.currentStepIndex, function (stack) { - if (window.ethDebuggerSelectedItem === nextProps.currentStepIndex) { + this.context.traceManager.getStackAt(nextProps.currentStepIndex, function (error, stack) { + if (error) { + console.log(error) + } else if (window.ethDebuggerSelectedItem === nextProps.currentStepIndex) { self.setState({ data: stack }) diff --git a/src/stepManager.js b/src/stepManager.js index 5033709f45..9967318309 100644 --- a/src/stepManager.js +++ b/src/stepManager.js @@ -54,8 +54,12 @@ module.exports = React.createClass({ newTraceAvailable: function () { this.init() var self = this - this.context.traceManager.getLength(function (length) { - self.setState({ traceLength: length }) + this.context.traceManager.getLength(function (error, length) { + if (error) { + console.log(error) + } else { + self.setState({ traceLength: length }) + } }) }, diff --git a/src/sticker.js b/src/sticker.js index 8a593cfafb..a75eee1b9c 100644 --- a/src/sticker.js +++ b/src/sticker.js @@ -84,28 +84,44 @@ module.exports = React.createClass({ if (nextProps.currentStepIndex < 0) return var self = this - this.context.traceManager.getCurrentStep(nextProps.currentStepIndex, function (step) { - self.setState({ - step: step - }) + this.context.traceManager.getCurrentStep(nextProps.currentStepIndex, function (error, step) { + if (error) { + console.log(error) + } else { + self.setState({ + step: step + }) + } }) - this.context.traceManager.getMemExpand(nextProps.currentStepIndex, function (addmem) { - self.setState({ - addmemory: addmem - }) + this.context.traceManager.getMemExpand(nextProps.currentStepIndex, function (error, addmem) { + if (error) { + console.log(error) + } else { + self.setState({ + addmemory: addmem + }) + } }) - this.context.traceManager.getStepCost(nextProps.currentStepIndex, function (gas) { - self.setState({ - gas: gas - }) + this.context.traceManager.getStepCost(nextProps.currentStepIndex, function (error, gas) { + if (error) { + console.log(error) + } else { + self.setState({ + gas: gas + }) + } }) - this.context.traceManager.getRemainingGas(nextProps.currentStepIndex, function (remaingas) { - self.setState({ - remaininGas: remaingas - }) + this.context.traceManager.getRemainingGas(nextProps.currentStepIndex, function (error, remaingas) { + if (error) { + console.log(error) + } else { + self.setState({ + remaininGas: remaingas + }) + } }) } }) diff --git a/src/storagePanel.js b/src/storagePanel.js index 56268a271e..d6799b72ec 100644 --- a/src/storagePanel.js +++ b/src/storagePanel.js @@ -31,8 +31,10 @@ module.exports = React.createClass({ if (window.ethDebuggerSelectedItem !== nextProps.currentStepIndex) return var self = this - this.context.traceManager.getStorageAt(nextProps.currentStepIndex, this.context.tx.blockNumber.toString(), this.context.tx.transactionIndex, function (storage) { - if (window.ethDebuggerSelectedItem === nextProps.currentStepIndex) { + this.context.traceManager.getStorageAt(nextProps.currentStepIndex, this.context.tx.blockNumber.toString(), this.context.tx.transactionIndex, function (error, storage) { + if (error) { + console.log(error) + } else if (window.ethDebuggerSelectedItem === nextProps.currentStepIndex) { self.setState({ data: storage }) diff --git a/src/traceManager.js b/src/traceManager.js index c6c1e287dd..03c8606632 100644 --- a/src/traceManager.js +++ b/src/traceManager.js @@ -136,14 +136,14 @@ module.exports = { // API section getLength: function (callback) { - if (!this.trace) callback(0) - callback(this.trace.length) + if (!this.trace) callback('no trace available', null) + callback(null, this.trace.length) }, getStorageAt: function (stepIndex, blockNumber, txIndex, callback) { var stoChange = this.findLowerBound(stepIndex, this.vmTraceChangesRef) if (!stoChange) { - return {} + callback('cannot rebuild storage', null) } var changeRefs = this.vmTraceIndexByStorageChange[stoChange] @@ -160,20 +160,20 @@ module.exports = { } } } - callback(storage) + callback(null, storage) }) }, getCallDataAt: function (stepIndex, callback) { var callDataChange = this.findLowerBound(stepIndex, this.callDataChanges) - if (!callDataChange) return [''] - callback([this.trace[callDataChange].calldata]) + if (!callDataChange) return callback('no calldata found', null) + callback(null, [this.trace[callDataChange].calldata]) }, getCallStackAt: function (stepIndex, callback) { var callStackChange = this.findLowerBound(stepIndex, this.depthChanges) - if (!callStackChange) return '' - callback(this.callStack[callStackChange].stack) + if (!callStackChange) return callback('no callstack found', null) + callback(null, this.callStack[callStackChange].stack) }, getStackAt: function (stepIndex, callback) { @@ -181,46 +181,52 @@ module.exports = { if (this.trace[stepIndex].stack) { // there's always a stack stack = this.trace[stepIndex].stack.slice(0) stack.reverse() - callback(stack) + callback(null, stack) + } else { + callback('no stack found', null) } }, getLastDepthIndexChangeSince: function (stepIndex, callback) { var depthIndex = this.findLowerBound(stepIndex, this.depthChanges) - callback(depthIndex) + callback(null, depthIndex) }, getCurrentCalledAddressAt: function (stepIndex, callback) { var self = this - this.getLastDepthIndexChangeSince(stepIndex, function (addressIndex) { - callback(self.resolveAddress(addressIndex)) + this.getLastDepthIndexChangeSince(stepIndex, function (error, addressIndex) { + if (error) { + callback(error, null) + } else { + callback(null, self.resolveAddress(addressIndex)) + } }) }, getMemoryAt: function (stepIndex, callback) { var lastChanges = this.findLowerBound(stepIndex, this.memoryChanges) - if (!lastChanges) return '' - callback(this.trace[lastChanges].memory) + if (!lastChanges) return callback('no memory found', null) + callback(null, this.trace[lastChanges].memory) }, getCurrentPC: function (stepIndex, callback) { - callback(this.trace[stepIndex].pc) + callback(null, this.trace[stepIndex].pc) }, getCurrentStep: function (stepIndex, callback) { - callback(this.trace[stepIndex].steps) + callback(null, this.trace[stepIndex].steps) }, getMemExpand: function (stepIndex, callback) { - callback(this.trace[stepIndex].memexpand ? this.trace[stepIndex].memexpand : '') + callback(null, this.trace[stepIndex].memexpand ? this.trace[stepIndex].memexpand : '') }, getStepCost: function (stepIndex, callback) { - callback(this.trace[stepIndex].gascost) + callback(null, this.trace[stepIndex].gascost) }, getRemainingGas: function (stepIndex, callback) { - callback(this.trace[stepIndex].gas) + callback(null, this.trace[stepIndex].gas) }, // step section diff --git a/src/vmDebugger.js b/src/vmDebugger.js index 53bf646e6e..e340b5c74e 100644 --- a/src/vmDebugger.js +++ b/src/vmDebugger.js @@ -73,8 +73,10 @@ module.exports = React.createClass({ if (nextProps.currentStepIndex < 0) return if (window.ethDebuggerSelectedItem !== nextProps.currentStepIndex) return var self = this - this.context.traceManager.getCurrentCalledAddressAt(nextProps.currentStepIndex, function (address) { - if (window.ethDebuggerSelectedItem === nextProps.currentStepIndex) { + this.context.traceManager.getCurrentCalledAddressAt(nextProps.currentStepIndex, function (error, address) { + if (error) { + console.log(error) + } else if (window.ethDebuggerSelectedItem === nextProps.currentStepIndex) { self.setState({ currentAddress: address }) From ee7e8558e31cd9d1999cb1cb8f2c0cfccfffd158 Mon Sep 17 00:00:00 2001 From: yann300 Date: Thu, 19 May 2016 16:34:18 +0200 Subject: [PATCH 09/11] declare traceManager func in prototype --- src/debugger.js | 15 +- src/traceManager.js | 616 ++++++++++++++++++++++---------------------- 2 files changed, 316 insertions(+), 315 deletions(-) diff --git a/src/debugger.js b/src/debugger.js index e67ed0243c..02d8f2d119 100644 --- a/src/debugger.js +++ b/src/debugger.js @@ -3,14 +3,15 @@ var React = require('react') var TxBrowser = require('./txBrowser') var StepManager = require('./stepManager') var AssemblyItemsBrowser = require('./vmDebugger') -var traceManager = require('./traceManager') +var TraceManager = require('./traceManager') var style = require('./basicStyles') module.exports = React.createClass({ getInitialState: function () { return { currentStepIndex: -1, // index of the selected item in the vmtrace - tx: null + tx: null, + traceManager: null } }, @@ -23,13 +24,15 @@ module.exports = React.createClass({ getChildContext: function () { return { web3: this.props.web3, - traceManager: traceManager, + traceManager: this.state.traceManager, tx: this.state.tx } }, componentDidMount: function () { - traceManager.setWeb3(this.props.web3) + this.setState({ + traceManager: new TraceManager(this.props.web3) + }) }, render: function () { @@ -50,7 +53,7 @@ module.exports = React.createClass({ }, startDebugging: function (blockNumber, txIndex, tx) { - if (traceManager.isLoading) { + if (this.state.traceManager.isLoading) { return } console.log('loading trace...') @@ -58,7 +61,7 @@ module.exports = React.createClass({ tx: tx }) var self = this - traceManager.resolveTrace(blockNumber, txIndex, function (success) { + this.state.traceManager.resolveTrace(blockNumber, txIndex, function (success) { console.log('trace loaded ' + success) self.setState({ currentStepIndex: 0 diff --git a/src/traceManager.js b/src/traceManager.js index 03c8606632..ab0f4cc843 100644 --- a/src/traceManager.js +++ b/src/traceManager.js @@ -1,342 +1,340 @@ 'use strict' -module.exports = { - isLoading: false, - web3: null, - transaction: null, - trace: null, +function TraceManager (_web3) { + this.web3 = _web3 + + this.isLoading = false + this.trace = null // vmtrace changes section - depthChanges: [], - callStack: {}, - memoryChanges: [], - callDataChanges: [], + this.depthChanges = [] + this.callStack = {} + this.memoryChanges = [] + this.callDataChanges = [] // storage section - storageChanges: [], - vmTraceIndexByStorageChange: {}, - vmTraceChangesRef: [], - storages: {}, - - // init section - setWeb3: function (web3) { - this.web3 = web3 - }, - - resolveTrace: function (blockNumber, txNumber, callback) { - this.isLoading = true - this.init() - if (!this.web3) callback(false) - var self = this - this.web3.debug.trace(blockNumber, parseInt(txNumber), function (error, result) { - if (!error) { - self.computeTrace(result) - callback(true) - } else { - console.log(error) - callback(false) - } - this.isLoading = false - }) - }, - - init: function () { - this.trace = null - this.depthChanges = [] - this.memoryChanges = [] - this.callDataChanges = [] - this.storageChanges = [] - this.vmTraceIndexByStorageChange = {} - this.vmTraceChangesRef = [] - this.callStack = {} - }, - - computeTrace: function (trace) { - this.trace = trace - var currentDepth = 0 - var currentStorageAddress - var callStack = [] - for (var k in this.trace) { - var step = this.trace[k] - - this.buildCalldata(k, step) - this.buildMemory(k, step) - currentStorageAddress = this.buildStorage(k, step, currentStorageAddress) - var depth = this.buildDepth(k, step, currentDepth, callStack) - if (depth) { - currentDepth = depth - } - } - }, + this.storageChanges = [] + this.vmTraceIndexByStorageChange = {} + this.vmTraceChangesRef = [] + this.storages = {} +} - // compute trace section - buildCalldata: function (index, step) { - if (step.calldata) { - this.callDataChanges.push(index) +// init section +TraceManager.prototype.resolveTrace = function (blockNumber, txNumber, callback) { + this.isLoading = true + this.init() + if (!this.web3) callback(false) + var self = this + this.web3.debug.trace(blockNumber, parseInt(txNumber), function (error, result) { + if (!error) { + self.computeTrace(result) + callback(true) + } else { + console.log(error) + callback(false) } - }, + this.isLoading = false + }) +} - buildMemory: function (index, step) { - if (step.memory) { - this.memoryChanges.push(index) - } - }, - - buildStorage: function (index, step, currentAddress) { - var change = false - if (step.address) { - // new context - this.storageChanges.push({ address: step.address, changes: [] }) - change = true - } else if (step.inst === 'SSTORE') { - this.storageChanges[this.storageChanges.length - 1].changes.push( - { - 'key': step.stack[step.stack.length - 1], - 'value': step.stack[step.stack.length - 2] - }) - change = true - } else if (!step.address && step.depth) { - // returned from context - var address = this.storageChanges[this.storageChanges.length - 2].address - this.storageChanges.push({ address: address, changes: [] }) - change = true - } +TraceManager.prototype.init = function () { + this.trace = null + this.depthChanges = [] + this.memoryChanges = [] + this.callDataChanges = [] + this.storageChanges = [] + this.vmTraceIndexByStorageChange = {} + this.vmTraceChangesRef = [] + this.callStack = {} +} - if (change) { - this.vmTraceIndexByStorageChange[index] = { - context: this.storageChanges.length - 1, - changes: this.storageChanges[this.storageChanges.length - 1].changes.length - 1 - } - this.vmTraceChangesRef.push(index) +TraceManager.prototype.computeTrace = function (trace) { + this.trace = trace + var currentDepth = 0 + var currentStorageAddress + var callStack = [] + for (var k in this.trace) { + var step = this.trace[k] + + this.buildCalldata(k, step) + this.buildMemory(k, step) + currentStorageAddress = this.buildStorage(k, step, currentStorageAddress) + var depth = this.buildDepth(k, step, currentDepth, callStack) + if (depth) { + currentDepth = depth } - return currentAddress - }, - - buildDepth: function (index, step, currentDepth, callStack) { - if (step.depth === undefined) return - if (step.depth > currentDepth) { - if (index === 0) { - callStack.push('0x' + step.address) // new context - } else { - // getting the address from the stack - var callTrace = this.trace[index - 1] - var address = callTrace.stack[callTrace.stack.length - 2] - callStack.push(address) // new context - } - } else if (step.depth < currentDepth) { - callStack.pop() // returning from context - } - this.callStack[index] = { - stack: callStack.slice(0), - depth: step.depth, - address: step.address - } - this.depthChanges.push(index) - return step.depth - }, - - // API section - getLength: function (callback) { - if (!this.trace) callback('no trace available', null) - callback(null, this.trace.length) - }, - - getStorageAt: function (stepIndex, blockNumber, txIndex, callback) { - var stoChange = this.findLowerBound(stepIndex, this.vmTraceChangesRef) - if (!stoChange) { - callback('cannot rebuild storage', null) + } +} + +// compute trace section +TraceManager.prototype.buildCalldata = function (index, step) { + if (step.calldata) { + this.callDataChanges.push(index) + } +} + +TraceManager.prototype.buildMemory = function (index, step) { + if (step.memory) { + this.memoryChanges.push(index) + } +} + +TraceManager.prototype.buildStorage = function (index, step, currentAddress) { + var change = false + if (step.address) { + // new context + this.storageChanges.push({ address: step.address, changes: [] }) + change = true + } else if (step.inst === 'SSTORE') { + this.storageChanges[this.storageChanges.length - 1].changes.push( + { + 'key': step.stack[step.stack.length - 1], + 'value': step.stack[step.stack.length - 2] + }) + change = true + } else if (!step.address && step.depth) { + // returned from context + var address = this.storageChanges[this.storageChanges.length - 2].address + this.storageChanges.push({ address: address, changes: [] }) + change = true + } + + if (change) { + this.vmTraceIndexByStorageChange[index] = { + context: this.storageChanges.length - 1, + changes: this.storageChanges[this.storageChanges.length - 1].changes.length - 1 } + this.vmTraceChangesRef.push(index) + } + return currentAddress +} - var changeRefs = this.vmTraceIndexByStorageChange[stoChange] - var address = this.storageChanges[changeRefs.context].address - var self = this - this.retrieveStorage(address, blockNumber, txIndex, function (storage) { - for (var k = 0; k < changeRefs.context; k++) { - var context = self.storageChanges[k] - if (context.address === address) { - for (var i = 0; i < context.changes.length; i++) { - if (i > changeRefs.changes) break - var change = context.changes[i] - storage[change.key] = change.value - } - } - } - callback(null, storage) - }) - }, - - getCallDataAt: function (stepIndex, callback) { - var callDataChange = this.findLowerBound(stepIndex, this.callDataChanges) - if (!callDataChange) return callback('no calldata found', null) - callback(null, [this.trace[callDataChange].calldata]) - }, - - getCallStackAt: function (stepIndex, callback) { - var callStackChange = this.findLowerBound(stepIndex, this.depthChanges) - if (!callStackChange) return callback('no callstack found', null) - callback(null, this.callStack[callStackChange].stack) - }, - - getStackAt: function (stepIndex, callback) { - var stack - if (this.trace[stepIndex].stack) { // there's always a stack - stack = this.trace[stepIndex].stack.slice(0) - stack.reverse() - callback(null, stack) +TraceManager.prototype.buildDepth = function (index, step, currentDepth, callStack) { + if (step.depth === undefined) return + if (step.depth > currentDepth) { + if (index === 0) { + callStack.push('0x' + step.address) // new context } else { - callback('no stack found', null) + // getting the address from the stack + var callTrace = this.trace[index - 1] + var address = callTrace.stack[callTrace.stack.length - 2] + callStack.push(address) // new context } - }, + } else if (step.depth < currentDepth) { + callStack.pop() // returning from context + } + this.callStack[index] = { + stack: callStack.slice(0), + depth: step.depth, + address: step.address + } + this.depthChanges.push(index) + return step.depth +} - getLastDepthIndexChangeSince: function (stepIndex, callback) { - var depthIndex = this.findLowerBound(stepIndex, this.depthChanges) - callback(null, depthIndex) - }, +// API section +TraceManager.prototype.getLength = function (callback) { + if (!this.trace) callback('no trace available', null) + callback(null, this.trace.length) +} - getCurrentCalledAddressAt: function (stepIndex, callback) { - var self = this - this.getLastDepthIndexChangeSince(stepIndex, function (error, addressIndex) { - if (error) { - callback(error, null) - } else { - callback(null, self.resolveAddress(addressIndex)) +TraceManager.prototype.getStorageAt = function (stepIndex, blockNumber, txIndex, callback) { + var stoChange = this.findLowerBound(stepIndex, this.vmTraceChangesRef) + if (!stoChange) { + callback('cannot rebuild storage', null) + } + + var changeRefs = this.vmTraceIndexByStorageChange[stoChange] + var address = this.storageChanges[changeRefs.context].address + var self = this + this.retrieveStorage(address, blockNumber, txIndex, function (storage) { + for (var k = 0; k < changeRefs.context; k++) { + var context = self.storageChanges[k] + if (context.address === address) { + for (var i = 0; i < context.changes.length; i++) { + if (i > changeRefs.changes) break + var change = context.changes[i] + storage[change.key] = change.value + } } - }) - }, - - getMemoryAt: function (stepIndex, callback) { - var lastChanges = this.findLowerBound(stepIndex, this.memoryChanges) - if (!lastChanges) return callback('no memory found', null) - callback(null, this.trace[lastChanges].memory) - }, - - getCurrentPC: function (stepIndex, callback) { - callback(null, this.trace[stepIndex].pc) - }, - - getCurrentStep: function (stepIndex, callback) { - callback(null, this.trace[stepIndex].steps) - }, - - getMemExpand: function (stepIndex, callback) { - callback(null, this.trace[stepIndex].memexpand ? this.trace[stepIndex].memexpand : '') - }, - - getStepCost: function (stepIndex, callback) { - callback(null, this.trace[stepIndex].gascost) - }, - - getRemainingGas: function (stepIndex, callback) { - callback(null, this.trace[stepIndex].gas) - }, - - // step section - isCallInstruction: function (index) { - var state = this.trace[index] - return state.instname === 'CALL' || state.instname === 'CALLCODE' || state.instname === 'CREATE' || state.instname === 'DELEGATECALL' - }, - - isReturnInstruction: function (index) { - var state = this.trace[index] - return state.instname === 'RETURN' - }, - - findStepOverBack: function (currentStep) { - if (this.isReturnInstruction(currentStep - 1)) { - return this.findStepOutBack(currentStep) - } else { - return currentStep - 1 } - }, + callback(null, storage) + }) +} + +TraceManager.prototype.getCallDataAt = function (stepIndex, callback) { + var callDataChange = this.findLowerBound(stepIndex, this.callDataChanges) + if (!callDataChange) return callback('no calldata found', null) + callback(null, [this.trace[callDataChange].calldata]) +} - findStepOverForward: function (currentStep) { - if (this.isCallInstruction(currentStep)) { - return this.findStepOutForward(currentStep) +TraceManager.prototype.getCallStackAt = function (stepIndex, callback) { + var callStackChange = this.findLowerBound(stepIndex, this.depthChanges) + if (!callStackChange) return callback('no callstack found', null) + callback(null, this.callStack[callStackChange].stack) +} + +TraceManager.prototype.getStackAt = function (stepIndex, callback) { + var stack + if (this.trace[stepIndex].stack) { // there's always a stack + stack = this.trace[stepIndex].stack.slice(0) + stack.reverse() + callback(null, stack) + } else { + callback('no stack found', null) + } +} + +TraceManager.prototype.getLastDepthIndexChangeSince = function (stepIndex, callback) { + var depthIndex = this.findLowerBound(stepIndex, this.depthChanges) + callback(null, depthIndex) +} + +TraceManager.prototype.getCurrentCalledAddressAt = function (stepIndex, callback) { + var self = this + this.getLastDepthIndexChangeSince(stepIndex, function (error, addressIndex) { + if (error) { + callback(error, null) } else { - return currentStep + 1 - } - }, - - findStepOutBack: function (currentStep) { - var i = currentStep - 1 - var depth = 0 - while (--i >= 0) { - if (this.isCallInstruction(i)) { - if (depth === 0) { - break - } else { - depth-- - } - } else if (this.isReturnInstruction(i)) { - depth++ - } + callback(null, self.resolveAddress(addressIndex)) } - return i - }, - - findStepOutForward: function (currentStep) { - var i = currentStep - var depth = 0 - while (++i < this.trace.length) { - if (this.isReturnInstruction(i)) { - if (depth === 0) { - break - } else { - depth-- - } - } else if (this.isCallInstruction(i)) { - depth++ + }) +} + +TraceManager.prototype.getMemoryAt = function (stepIndex, callback) { + var lastChanges = this.findLowerBound(stepIndex, this.memoryChanges) + if (!lastChanges) return callback('no memory found', null) + callback(null, this.trace[lastChanges].memory) +} + +TraceManager.prototype.getCurrentPC = function (stepIndex, callback) { + callback(null, this.trace[stepIndex].pc) +} + +TraceManager.prototype.getCurrentStep = function (stepIndex, callback) { + callback(null, this.trace[stepIndex].steps) +} + +TraceManager.prototype.getMemExpand = function (stepIndex, callback) { + callback(null, this.trace[stepIndex].memexpand ? this.trace[stepIndex].memexpand : '') +} + +TraceManager.prototype.getStepCost = function (stepIndex, callback) { + callback(null, this.trace[stepIndex].gascost) +} + +TraceManager.prototype.getRemainingGas = function (stepIndex, callback) { + callback(null, this.trace[stepIndex].gas) +} + +// step section +TraceManager.prototype.isCallInstruction = function (index) { + var state = this.trace[index] + return state.instname === 'CALL' || state.instname === 'CALLCODE' || state.instname === 'CREATE' || state.instname === 'DELEGATECALL' +} + +TraceManager.prototype.isReturnInstruction = function (index) { + var state = this.trace[index] + return state.instname === 'RETURN' +} + +TraceManager.prototype.findStepOverBack = function (currentStep) { + if (this.isReturnInstruction(currentStep - 1)) { + return this.findStepOutBack(currentStep) + } else { + return currentStep - 1 + } +} + +TraceManager.prototype.findStepOverForward = function (currentStep) { + if (this.isCallInstruction(currentStep)) { + return this.findStepOutForward(currentStep) + } else { + return currentStep + 1 + } +} + +TraceManager.prototype.findStepOutBack = function (currentStep) { + var i = currentStep - 1 + var depth = 0 + while (--i >= 0) { + if (this.isCallInstruction(i)) { + if (depth === 0) { + break + } else { + depth-- } + } else if (this.isReturnInstruction(i)) { + depth++ } - return i + 1 - }, - - // util section - findLowerBound: function (target, changes) { - if (changes.length === 1) { - if (changes[0] > target) { - // we only a closest maximum, returning 0 - return null + } + return i +} + +TraceManager.prototype.findStepOutForward = function (currentStep) { + var i = currentStep + var depth = 0 + while (++i < this.trace.length) { + if (this.isReturnInstruction(i)) { + if (depth === 0) { + break } else { - return changes[0] + depth-- } + } else if (this.isCallInstruction(i)) { + depth++ } + } + return i + 1 +} - var middle = Math.floor(changes.length / 2) - if (changes[middle] > target) { - return this.findLowerBound(target, changes.slice(0, middle)) - } else if (changes[middle] < target) { - return this.findLowerBound(target, changes.slice(middle, changes.length)) +// util section +TraceManager.prototype.findLowerBound = function (target, changes) { + if (changes.length === 1) { + if (changes[0] > target) { + // we only a closest maximum, returning 0 + return null } else { - return changes[middle] + return changes[0] } - }, + } - resolveAddress: function (vmTraceIndex) { - var address = this.trace[vmTraceIndex].address - if (vmTraceIndex > 0) { - var stack = this.trace[vmTraceIndex - 1].stack // callcode, delegatecall, ... - address = stack[stack.length - 2] - } - return address - }, + var middle = Math.floor(changes.length / 2) + if (changes[middle] > target) { + return this.findLowerBound(target, changes.slice(0, middle)) + } else if (changes[middle] < target) { + return this.findLowerBound(target, changes.slice(middle, changes.length)) + } else { + return changes[middle] + } +} - // retrieve the storage of an account just after the execution of tx - retrieveStorage: function (address, blockNumber, txIndex, callBack) { - if (this.storages[address]) { - callBack(this.storages[address]) - } - var self = this - if (blockNumber !== null && txIndex !== null) { - this.web3.debug.storageAt(blockNumber, txIndex, address, function (error, result) { - if (error) { - console.log(error) - } else { - self.storages[address] = result - callBack(result) - } - }) - } else { - console.log('blockNumber/txIndex are not defined') - } +TraceManager.prototype.resolveAddress = function (vmTraceIndex) { + var address = this.trace[vmTraceIndex].address + if (vmTraceIndex > 0) { + var stack = this.trace[vmTraceIndex - 1].stack // callcode, delegatecall, ... + address = stack[stack.length - 2] } + return address } + +// retrieve the storage of an account just after the execution of tx +TraceManager.prototype.retrieveStorage = function (address, blockNumber, txIndex, callBack) { + if (this.storages[address]) { + callBack(this.storages[address]) + } + var self = this + if (blockNumber !== null && txIndex !== null) { + this.web3.debug.storageAt(blockNumber, txIndex, address, function (error, result) { + if (error) { + console.log(error) + } else { + self.storages[address] = result + callBack(result) + } + }) + } else { + console.log('blockNumber/txIndex are not defined') + } +} + +module.exports = TraceManager From 2846b48268cf5a1fdf740da5089fcd3abd55a4e2 Mon Sep 17 00:00:00 2001 From: yann300 Date: Mon, 23 May 2016 10:04:42 +0200 Subject: [PATCH 10/11] modularisation --- src/basicPanel.js | 2 +- src/memoryPanel.js | 6 +- src/storagePanel.js | 4 +- src/traceAnalyser.js | 77 +++++++++++ src/traceCache.js | 55 ++++++++ src/traceManager.js | 274 ++++++---------------------------------- src/traceManagerUtil.js | 36 ++++++ src/traceRetriever.js | 25 ++++ src/traceStepManager.js | 66 ++++++++++ 9 files changed, 307 insertions(+), 238 deletions(-) create mode 100644 src/traceAnalyser.js create mode 100644 src/traceCache.js create mode 100644 src/traceManagerUtil.js create mode 100644 src/traceRetriever.js create mode 100644 src/traceStepManager.js diff --git a/src/basicPanel.js b/src/basicPanel.js index 7ce113cacc..a1e02a6189 100644 --- a/src/basicPanel.js +++ b/src/basicPanel.js @@ -38,7 +38,7 @@ module.exports = React.createClass({ ret.push( ) } diff --git a/src/memoryPanel.js b/src/memoryPanel.js index 8dbfb066b3..1724b32a07 100644 --- a/src/memoryPanel.js +++ b/src/memoryPanel.js @@ -50,13 +50,13 @@ module.exports = React.createClass({ ret.push( ) } diff --git a/src/storagePanel.js b/src/storagePanel.js index d6799b72ec..b5eac32de7 100644 --- a/src/storagePanel.js +++ b/src/storagePanel.js @@ -49,10 +49,10 @@ module.exports = React.createClass({ ret.push( ) } diff --git a/src/traceAnalyser.js b/src/traceAnalyser.js new file mode 100644 index 0000000000..d79368c1ba --- /dev/null +++ b/src/traceAnalyser.js @@ -0,0 +1,77 @@ +'use strict' +function TraceAnalyser (_cache) { + this.traceCache = _cache + this.trace = null +} + +TraceAnalyser.prototype.analyse = function (trace, callback) { + this.trace = trace + var currentDepth = 0 + var context = { + currentStorageAddress: trace[0].address, + previousStorageAddress: trace[0].address + } + var callStack = [] + for (var k in this.trace) { + var step = this.trace[k] + this.buildCalldata(k, step) + this.buildMemory(k, step) + var depth = this.buildDepth(k, step, currentDepth, callStack) + if (depth) { + currentDepth = depth + } + context = this.buildStorage(k, step, context) + } + callback(null, true) +} + +TraceAnalyser.prototype.buildCalldata = function (index, step) { + if (step.calldata) { + this.traceCache.pushCallDataChanges(index) + } +} + +TraceAnalyser.prototype.buildMemory = function (index, step) { + if (step.memory) { + this.traceCache.pushMemoryChanges(index) + } +} + +TraceAnalyser.prototype.buildStorage = function (index, step, context) { + if (step.address) { + // new context + context.currentStorageAddress = step.address + this.traceCache.pushStoreChanges(index, context.currentStorageAddress) + } else if (step.inst === 'SSTORE') { + this.traceCache.pushStoreChanges(index, context.currentStorageAddress, step.stack[step.stack.length - 1], step.stack[step.stack.length - 2]) + } else if (!step.address && step.depth) { + // returned from context + context.currentStorageAddress = context.previousStorageAddress + this.traceCache.pushStoreChanges(index, context.currentStorageAddress) + } + return context +} + +TraceAnalyser.prototype.buildDepth = function (index, step, currentDepth, callStack) { + if (step.depth === undefined) return + if (step.depth > currentDepth) { + if (index === 0) { + callStack.push('0x' + step.address) // new context + } else { + // getting the address from the stack + var callTrace = this.trace[index - 1] + var address = callTrace.stack[callTrace.stack.length - 2] + callStack.push(address) // new context + } + } else if (step.depth < currentDepth) { + callStack.pop() // returning from context + } + this.traceCache.pushCallStack(index, { + stack: callStack.slice(0), + depth: step.depth + }) + this.traceCache.pushDepthChanges(index) + return step.depth +} + +module.exports = TraceAnalyser diff --git a/src/traceCache.js b/src/traceCache.js new file mode 100644 index 0000000000..d7cb3e9a3a --- /dev/null +++ b/src/traceCache.js @@ -0,0 +1,55 @@ +'use strict' +function TraceCache () { + this.init() +} + +TraceCache.prototype.init = function () { + // ...Changes contains index in the vmtrace of the corresponding changes + this.depthChanges = [] + this.memoryChanges = [] + this.callDataChanges = [] + this.storageChanges = [] + this.sstore = {} // all sstore occurence in the trace + this.callStack = {} // contains all callStack by vmtrace index (we need to rebuild it, callstack is not included in the vmtrace) +} + +TraceCache.prototype.pushCallDataChanges = function (value) { + this.callDataChanges.push(value) +} + +TraceCache.prototype.pushMemoryChanges = function (value) { + this.memoryChanges.push(value) +} + +TraceCache.prototype.pushDepthChanges = function (value) { + this.depthChanges.push(value) +} + +TraceCache.prototype.pushCallStack = function (index, callStack) { + this.callStack[index] = callStack +} + +TraceCache.prototype.pushStoreChanges = function (index, address, key, value) { + this.sstore[index] = { + 'address': address, + 'key': key, + 'value': value + } + this.storageChanges.push(index) +} + +TraceCache.prototype.rebuildStorage = function (address, storage, index) { + for (var k in this.storageChanges) { + var changesIndex = this.storageChanges[k] + if (changesIndex > index) { + return storage + } + var sstore = this.sstore[changesIndex] + if (sstore.address === address && sstore.key) { + storage[sstore.key] = sstore.value + } + } + return storage +} + +module.exports = TraceCache diff --git a/src/traceManager.js b/src/traceManager.js index ab0f4cc843..c53e66b81e 100644 --- a/src/traceManager.js +++ b/src/traceManager.js @@ -1,21 +1,18 @@ 'use strict' +var TraceAnalyser = require('./traceAnalyser') +var TraceRetriever = require('./traceRetriever') +var TraceCache = require('./traceCache') +var TraceStepManager = require('./traceStepManager') +var traceManagerUtil = require('./traceManagerUtil') + function TraceManager (_web3) { this.web3 = _web3 - this.isLoading = false this.trace = null - - // vmtrace changes section - this.depthChanges = [] - this.callStack = {} - this.memoryChanges = [] - this.callDataChanges = [] - - // storage section - this.storageChanges = [] - this.vmTraceIndexByStorageChange = {} - this.vmTraceChangesRef = [] - this.storages = {} + this.traceCache = new TraceCache() + this.traceAnalyser = new TraceAnalyser(this.traceCache) + this.traceRetriever = new TraceRetriever(_web3) + this.traceStepManager = new TraceStepManager(this.traceAnalyser) } // init section @@ -24,111 +21,26 @@ TraceManager.prototype.resolveTrace = function (blockNumber, txNumber, callback) this.init() if (!this.web3) callback(false) var self = this - this.web3.debug.trace(blockNumber, parseInt(txNumber), function (error, result) { - if (!error) { - self.computeTrace(result) - callback(true) - } else { + this.traceRetriever.getTrace(blockNumber, parseInt(txNumber), function (error, result) { + self.trace = result + if (error) { console.log(error) - callback(false) + } else { + self.traceAnalyser.analyse(result, function (error, result) { + if (error) { + console.log(error) + callback(false) + } else { + callback(true) + } + }) } - this.isLoading = false }) } TraceManager.prototype.init = function () { this.trace = null - this.depthChanges = [] - this.memoryChanges = [] - this.callDataChanges = [] - this.storageChanges = [] - this.vmTraceIndexByStorageChange = {} - this.vmTraceChangesRef = [] - this.callStack = {} -} - -TraceManager.prototype.computeTrace = function (trace) { - this.trace = trace - var currentDepth = 0 - var currentStorageAddress - var callStack = [] - for (var k in this.trace) { - var step = this.trace[k] - - this.buildCalldata(k, step) - this.buildMemory(k, step) - currentStorageAddress = this.buildStorage(k, step, currentStorageAddress) - var depth = this.buildDepth(k, step, currentDepth, callStack) - if (depth) { - currentDepth = depth - } - } -} - -// compute trace section -TraceManager.prototype.buildCalldata = function (index, step) { - if (step.calldata) { - this.callDataChanges.push(index) - } -} - -TraceManager.prototype.buildMemory = function (index, step) { - if (step.memory) { - this.memoryChanges.push(index) - } -} - -TraceManager.prototype.buildStorage = function (index, step, currentAddress) { - var change = false - if (step.address) { - // new context - this.storageChanges.push({ address: step.address, changes: [] }) - change = true - } else if (step.inst === 'SSTORE') { - this.storageChanges[this.storageChanges.length - 1].changes.push( - { - 'key': step.stack[step.stack.length - 1], - 'value': step.stack[step.stack.length - 2] - }) - change = true - } else if (!step.address && step.depth) { - // returned from context - var address = this.storageChanges[this.storageChanges.length - 2].address - this.storageChanges.push({ address: address, changes: [] }) - change = true - } - - if (change) { - this.vmTraceIndexByStorageChange[index] = { - context: this.storageChanges.length - 1, - changes: this.storageChanges[this.storageChanges.length - 1].changes.length - 1 - } - this.vmTraceChangesRef.push(index) - } - return currentAddress -} - -TraceManager.prototype.buildDepth = function (index, step, currentDepth, callStack) { - if (step.depth === undefined) return - if (step.depth > currentDepth) { - if (index === 0) { - callStack.push('0x' + step.address) // new context - } else { - // getting the address from the stack - var callTrace = this.trace[index - 1] - var address = callTrace.stack[callTrace.stack.length - 2] - callStack.push(address) // new context - } - } else if (step.depth < currentDepth) { - callStack.pop() // returning from context - } - this.callStack[index] = { - stack: callStack.slice(0), - depth: step.depth, - address: step.address - } - this.depthChanges.push(index) - return step.depth + this.traceCache.init() } // API section @@ -138,39 +50,31 @@ TraceManager.prototype.getLength = function (callback) { } TraceManager.prototype.getStorageAt = function (stepIndex, blockNumber, txIndex, callback) { - var stoChange = this.findLowerBound(stepIndex, this.vmTraceChangesRef) - if (!stoChange) { - callback('cannot rebuild storage', null) - } + var stoChange = traceManagerUtil.findLowerBound(stepIndex, this.traceCache.storageChanges) - var changeRefs = this.vmTraceIndexByStorageChange[stoChange] - var address = this.storageChanges[changeRefs.context].address + var address = this.traceCache.sstore[stoChange].address var self = this - this.retrieveStorage(address, blockNumber, txIndex, function (storage) { - for (var k = 0; k < changeRefs.context; k++) { - var context = self.storageChanges[k] - if (context.address === address) { - for (var i = 0; i < context.changes.length; i++) { - if (i > changeRefs.changes) break - var change = context.changes[i] - storage[change.key] = change.value - } - } + this.traceRetriever.getStorage(blockNumber, txIndex, address, function (error, result) { + if (error) { + console.log(error) + callback(error, null) + } else { + var storage = self.traceCache.rebuildStorage(address, result, stepIndex) + callback(null, storage) } - callback(null, storage) }) } TraceManager.prototype.getCallDataAt = function (stepIndex, callback) { - var callDataChange = this.findLowerBound(stepIndex, this.callDataChanges) + var callDataChange = traceManagerUtil.findLowerBound(stepIndex, this.traceCache.callDataChanges) if (!callDataChange) return callback('no calldata found', null) callback(null, [this.trace[callDataChange].calldata]) } TraceManager.prototype.getCallStackAt = function (stepIndex, callback) { - var callStackChange = this.findLowerBound(stepIndex, this.depthChanges) + var callStackChange = traceManagerUtil.findLowerBound(stepIndex, this.traceCache.depthChanges) if (!callStackChange) return callback('no callstack found', null) - callback(null, this.callStack[callStackChange].stack) + callback(null, this.traceCache.callStack[callStackChange].stack) } TraceManager.prototype.getStackAt = function (stepIndex, callback) { @@ -185,7 +89,7 @@ TraceManager.prototype.getStackAt = function (stepIndex, callback) { } TraceManager.prototype.getLastDepthIndexChangeSince = function (stepIndex, callback) { - var depthIndex = this.findLowerBound(stepIndex, this.depthChanges) + var depthIndex = traceManagerUtil.findLowerBound(stepIndex, this.traceCache.depthChanges) callback(null, depthIndex) } @@ -195,13 +99,13 @@ TraceManager.prototype.getCurrentCalledAddressAt = function (stepIndex, callback if (error) { callback(error, null) } else { - callback(null, self.resolveAddress(addressIndex)) + callback(null, traceManagerUtil.resolveCalledAddress(addressIndex, self.trace)) } }) } TraceManager.prototype.getMemoryAt = function (stepIndex, callback) { - var lastChanges = this.findLowerBound(stepIndex, this.memoryChanges) + var lastChanges = traceManagerUtil.findLowerBound(stepIndex, this.traceCache.memoryChanges) if (!lastChanges) return callback('no memory found', null) callback(null, this.trace[lastChanges].memory) } @@ -227,114 +131,20 @@ TraceManager.prototype.getRemainingGas = function (stepIndex, callback) { } // step section -TraceManager.prototype.isCallInstruction = function (index) { - var state = this.trace[index] - return state.instname === 'CALL' || state.instname === 'CALLCODE' || state.instname === 'CREATE' || state.instname === 'DELEGATECALL' -} - -TraceManager.prototype.isReturnInstruction = function (index) { - var state = this.trace[index] - return state.instname === 'RETURN' -} - TraceManager.prototype.findStepOverBack = function (currentStep) { - if (this.isReturnInstruction(currentStep - 1)) { - return this.findStepOutBack(currentStep) - } else { - return currentStep - 1 - } + return this.traceStepManager.findStepOverBack(currentStep) } TraceManager.prototype.findStepOverForward = function (currentStep) { - if (this.isCallInstruction(currentStep)) { - return this.findStepOutForward(currentStep) - } else { - return currentStep + 1 - } + return this.traceStepManager.findStepOverForward(currentStep) } TraceManager.prototype.findStepOutBack = function (currentStep) { - var i = currentStep - 1 - var depth = 0 - while (--i >= 0) { - if (this.isCallInstruction(i)) { - if (depth === 0) { - break - } else { - depth-- - } - } else if (this.isReturnInstruction(i)) { - depth++ - } - } - return i + return this.traceStepManager.findStepOutBack(currentStep) } TraceManager.prototype.findStepOutForward = function (currentStep) { - var i = currentStep - var depth = 0 - while (++i < this.trace.length) { - if (this.isReturnInstruction(i)) { - if (depth === 0) { - break - } else { - depth-- - } - } else if (this.isCallInstruction(i)) { - depth++ - } - } - return i + 1 -} - -// util section -TraceManager.prototype.findLowerBound = function (target, changes) { - if (changes.length === 1) { - if (changes[0] > target) { - // we only a closest maximum, returning 0 - return null - } else { - return changes[0] - } - } - - var middle = Math.floor(changes.length / 2) - if (changes[middle] > target) { - return this.findLowerBound(target, changes.slice(0, middle)) - } else if (changes[middle] < target) { - return this.findLowerBound(target, changes.slice(middle, changes.length)) - } else { - return changes[middle] - } -} - -TraceManager.prototype.resolveAddress = function (vmTraceIndex) { - var address = this.trace[vmTraceIndex].address - if (vmTraceIndex > 0) { - var stack = this.trace[vmTraceIndex - 1].stack // callcode, delegatecall, ... - address = stack[stack.length - 2] - } - return address -} - -// retrieve the storage of an account just after the execution of tx -TraceManager.prototype.retrieveStorage = function (address, blockNumber, txIndex, callBack) { - if (this.storages[address]) { - callBack(this.storages[address]) - } - var self = this - if (blockNumber !== null && txIndex !== null) { - this.web3.debug.storageAt(blockNumber, txIndex, address, function (error, result) { - if (error) { - console.log(error) - } else { - self.storages[address] = result - callBack(result) - } - }) - } else { - console.log('blockNumber/txIndex are not defined') - } + return this.traceStepManager.findStepOutForward(currentStep) } module.exports = TraceManager diff --git a/src/traceManagerUtil.js b/src/traceManagerUtil.js new file mode 100644 index 0000000000..3231efa5af --- /dev/null +++ b/src/traceManagerUtil.js @@ -0,0 +1,36 @@ +module.exports = { + // util section + findLowerBound: function (target, changes) { + if (changes.length === 0) { + return undefined + } + + if (changes.length === 1) { + if (changes[0] > target) { + // we only a closest maximum, returning O + return 0 + } else { + return changes[0] + } + } + + var middle = Math.floor(changes.length / 2) + if (changes[middle] > target) { + return this.findLowerBound(target, changes.slice(0, middle)) + } else if (changes[middle] < target) { + return this.findLowerBound(target, changes.slice(middle, changes.length)) + } else { + return changes[middle] + } + }, + + resolveCalledAddress: function (vmTraceIndex, trace) { + var address = trace[vmTraceIndex].address + if (vmTraceIndex > 0) { + var stack = trace[vmTraceIndex - 1].stack // callcode, delegatecall, ... + address = stack[stack.length - 2] + } + return address + } + +} diff --git a/src/traceRetriever.js b/src/traceRetriever.js new file mode 100644 index 0000000000..238510b66b --- /dev/null +++ b/src/traceRetriever.js @@ -0,0 +1,25 @@ +'use strict' +function TraceRetriever (_web3) { + this.web3 = _web3 + this.storages = {} // contains all intial storage (by addresses) +} + +TraceRetriever.prototype.getTrace = function (blockNumber, txNumber, callback) { + this.web3.debug.trace(blockNumber, parseInt(txNumber), function (error, result) { + callback(error, result) + }) +} + +TraceRetriever.prototype.getStorage = function (blockNumber, txIndex, address, callback) { + if (this.storages[address]) { + callback(null, this.storages[address]) + } else { + var self = this + this.web3.debug.storageAt(blockNumber, txIndex, address, function (error, result) { + self.storages[address] = result + callback(error, result) + }) + } +} + +module.exports = TraceRetriever diff --git a/src/traceStepManager.js b/src/traceStepManager.js new file mode 100644 index 0000000000..40d9afc098 --- /dev/null +++ b/src/traceStepManager.js @@ -0,0 +1,66 @@ +'use strict' +function TraceStepManager (_traceAnalyser) { + this.traceAnalyser = _traceAnalyser +} + +TraceStepManager.prototype.isCallInstruction = function (index) { + var state = this.traceAnalyser.trace[index] + return state.instname === 'CALL' || state.instname === 'CALLCODE' || state.instname === 'CREATE' || state.instname === 'DELEGATECALL' +} + +TraceStepManager.prototype.isReturnInstruction = function (index) { + var state = this.traceAnalyser.trace[index] + return state.instname === 'RETURN' +} + +TraceStepManager.prototype.findStepOverBack = function (currentStep) { + if (this.isReturnInstruction(currentStep - 1)) { + return this.findStepOutBack(currentStep) + } else { + return currentStep - 1 + } +} + +TraceStepManager.prototype.findStepOverForward = function (currentStep) { + if (this.isCallInstruction(currentStep)) { + return this.findStepOutForward(currentStep) + } else { + return currentStep + 1 + } +} + +TraceStepManager.prototype.findStepOutBack = function (currentStep) { + var i = currentStep - 1 + var depth = 0 + while (--i >= 0) { + if (this.isCallInstruction(i)) { + if (depth === 0) { + break + } else { + depth-- + } + } else if (this.isReturnInstruction(i)) { + depth++ + } + } + return i +} + +TraceStepManager.prototype.findStepOutForward = function (currentStep) { + var i = currentStep + var depth = 0 + while (++i < this.traceAnalyser.length) { + if (this.isReturnInstruction(i)) { + if (depth === 0) { + break + } else { + depth-- + } + } else if (this.isCallInstruction(i)) { + depth++ + } + } + return i + 1 +} + +module.exports = TraceStepManager From 7a90aee4d45c80ba766570f4d83de87ce68a43d1 Mon Sep 17 00:00:00 2001 From: yann300 Date: Mon, 23 May 2016 10:53:47 +0200 Subject: [PATCH 11/11] styling --- src/basicPanel.js | 2 +- src/basicStyles.js | 7 ++++--- src/debugger.js | 2 +- src/memoryPanel.js | 7 ++++--- src/sticker.js | 4 ++-- src/storagePanel.js | 5 +++-- 6 files changed, 15 insertions(+), 12 deletions(-) diff --git a/src/basicPanel.js b/src/basicPanel.js index a1e02a6189..f5780d7022 100644 --- a/src/basicPanel.js +++ b/src/basicPanel.js @@ -38,7 +38,7 @@ module.exports = React.createClass({ ret.push( ) } diff --git a/src/basicStyles.js b/src/basicStyles.js index 05be6ef967..4d319b988b 100644 --- a/src/basicStyles.js +++ b/src/basicStyles.js @@ -1,6 +1,6 @@ 'use strict' module.exports = { - wrapper: { + font: { 'fontFamily': 'arial,sans-serif' }, container: { @@ -11,7 +11,8 @@ module.exports = { 'fontStyle': 'italic' }, instructionsList: { - 'width': '320px' + 'width': '320px', + 'height': '300px' }, transactionInfo: { 'marginTop': '5px' @@ -22,7 +23,7 @@ module.exports = { 'width': '600px' }, tableContainer: { - 'height': '150px', + 'height': '300px', 'overflowY': 'auto' }, table: { diff --git a/src/debugger.js b/src/debugger.js index 02d8f2d119..f7e1e9a7a0 100644 --- a/src/debugger.js +++ b/src/debugger.js @@ -37,7 +37,7 @@ module.exports = React.createClass({ render: function () { return ( -
+

Eth Debugger

diff --git a/src/memoryPanel.js b/src/memoryPanel.js index 1724b32a07..2a5f6f10d1 100644 --- a/src/memoryPanel.js +++ b/src/memoryPanel.js @@ -1,6 +1,7 @@ 'use strict' var React = require('react') var BasicPanel = require('./basicPanel') +var style = require('./basicStyles') module.exports = React.createClass({ contextTypes: { @@ -50,13 +51,13 @@ module.exports = React.createClass({ ret.push(
) } diff --git a/src/sticker.js b/src/sticker.js index a75eee1b9c..92cffd19ed 100644 --- a/src/sticker.js +++ b/src/sticker.js @@ -55,7 +55,7 @@ module.exports = React.createClass({ remaining gas @@ -119,7 +119,7 @@ module.exports = React.createClass({ console.log(error) } else { self.setState({ - remaininGas: remaingas + remainingGas: remaingas }) } }) diff --git a/src/storagePanel.js b/src/storagePanel.js index b5eac32de7..96356cbe70 100644 --- a/src/storagePanel.js +++ b/src/storagePanel.js @@ -1,6 +1,7 @@ 'use strict' var React = require('react') var BasicPanel = require('./basicPanel') +var style = require('./basicStyles') module.exports = React.createClass({ contextTypes: { @@ -49,10 +50,10 @@ module.exports = React.createClass({ ret.push( ) }
- +
- +
@@ -144,295 +110,46 @@ module.exports = React.createClass({ return ret }, - loadCode: function (address, callback) { - console.log('loading new code from web3 ' + address) - this.context.web3.eth.getCode(address, function (error, result) { - if (error) { - console.log(error) - } else { - callback(result) - } - }) - }, - - cacheExecutingCode: function (address, hexCode) { - var code = codeUtils.nameOpCodes(new Buffer(hexCode.substring(2), 'hex')) - this.state.codes[address] = code[0] - this.state.instructionsIndexByBytesOffset[address] = code[1] - return { - code: code[0], - instructionsIndexByBytesOffset: code[1] - } - }, - - getExecutingCodeFromCache: function (address) { - if (this.state.codes[address]) { - return { - code: this.state.codes[address], - instructionsIndexByBytesOffset: this.state.instructionsIndexByBytesOffset[address] - } - } else { - return null - } - }, - - renderAssemblyItems: function () { - if (this.props.vmTrace && this.state.executingCode) { - return this.state.executingCode.map(function (item, i) { - return - }) - } - }, - componentWillReceiveProps: function (nextProps) { - this.setState(this.getInitialState()) - if (!nextProps.vmTrace) { - return - } - this.buildCallStack(nextProps.vmTrace) - this.updateState(nextProps, 0) - }, + console.log("asse " + JSON.stringify(nextProps)) + if (nextProps.currentStepIndex < 0) return - buildCallStack: function (vmTrace) { - if (!vmTrace) return - var callStack = [] - var callStackFrame = {} - var depth = -1 - this.refs.storageResolver.init(this.props.transaction) - for (var k = 0; k < vmTrace.length; k++) { - var trace = vmTrace[k] - if (trace.depth === undefined || trace.depth === depth) continue - if (trace.depth > depth) { - if (k === 0) { - callStack.push('0x' + vmTrace[k].address) // new context - } else { - // getting the address from the stack - var callTrace = vmTrace[k - 1] - var address = callTrace.stack[callTrace.stack.length - 2] - callStack.push(address) // new context - } - } else if (trace.depth < depth) { - callStack.pop() // returning from context - } - depth = trace.depth - callStackFrame[k] = callStack.slice(0) - - this.refs.storageResolver.trackStorageChange(k, trace) - } - this.setState({'callStack': callStackFrame}) - }, - - updateState: function (props, vmTraceIndex) { - if (!props.vmTrace || !props.vmTrace[vmTraceIndex]) return - var previousIndex = this.state.currentSelected - var stateChanges = {} - - var stack - if (props.vmTrace[vmTraceIndex].stack) { // there's always a stack - stack = props.vmTrace[vmTraceIndex].stack.slice(0) - stack.reverse() - Object.assign(stateChanges, { 'currentStack': stack }) - } - - var newContextLoaded = false - var depthIndex = this.shouldUpdateStateProperty('depth', vmTraceIndex, previousIndex, props.vmTrace) - if (depthIndex > -1) { - Object.assign(stateChanges, {'currentCallStack': this.state.callStack[depthIndex]}) - // updating exectution context: - var address = this.resolveAddress(depthIndex, props) - if (address !== this.state.currentAddress) { - var self = this - this.ensureExecutingCodeUpdated(address, vmTraceIndex, props, function (code) { - if (self.state.currentAddress !== address) { - console.log('updating executing code ' + self.state.currentAddress + ' -> ' + address) - self.setState( - { - 'selectedInst': code.instructionsIndexByBytesOffset[props.vmTrace[vmTraceIndex].pc], - 'executingCode': code.code, - 'currentAddress': address - }) - } - }) - newContextLoaded = true - } - } - if (!newContextLoaded) { - Object.assign(stateChanges, - { - 'selectedInst': this.getExecutingCodeFromCache(this.state.currentAddress).instructionsIndexByBytesOffset[props.vmTrace[vmTraceIndex].pc] - }) - } - - Object.assign(stateChanges, { 'currentSelected': vmTraceIndex }) - - this.refs.storageResolver.rebuildStorageAt(vmTraceIndex, props.transaction, function (storage) { - Object.assign(stateChanges, { 'currentStorage': storage }) + var self = this + this.context.traceManager.getCallDataAt(nextProps.currentStepIndex, function (calldata) { + self.setState({ + currentCallData: calldata + }) }) - var memoryIndex = this.shouldUpdateStateProperty('memory', vmTraceIndex, previousIndex, props.vmTrace) - if (memoryIndex > -1) { - Object.assign(stateChanges, { 'currentMemory': this.formatMemory(props.vmTrace[memoryIndex].memory, 16) }) - } - - var callDataIndex = this.shouldUpdateStateProperty('calldata', vmTraceIndex, previousIndex, props.vmTrace) - if (callDataIndex > -1) { - Object.assign(stateChanges, { 'currentCallData': [props.vmTrace[callDataIndex].calldata] }) - } - - stateChanges['currentStepInfo'] = [ - 'Current Step: ' + props.vmTrace[vmTraceIndex].steps, - 'Adding Memory: ' + (props.vmTrace[vmTraceIndex].memexpand ? props.vmTrace[vmTraceIndex].memexpand : ''), - 'Step Cost: ' + props.vmTrace[vmTraceIndex].gascost, - 'Remaining Gas: ' + props.vmTrace[vmTraceIndex].gas - ] - - this.refs.slider.setValue(vmTraceIndex) - this.setState(stateChanges) - }, - - ensureExecutingCodeUpdated: function (address, vmTraceIndex, props, callBack) { - this.resolveCode(address, vmTraceIndex, props, function (address, code) { - callBack(code) + this.context.traceManager.getCallStackAt(nextProps.currentStepIndex, function (callstack) { + self.setState({ + currentCallStack: callstack + }) }) - }, - - resolveAddress: function (vmTraceIndex, props) { - var address = props.vmTrace[vmTraceIndex].address - if (vmTraceIndex > 0) { - var stack = this.state.callStack[vmTraceIndex] // callcode, delegatecall, ... - address = stack[stack.length - 1] - } - return address - }, - resolveCode: function (address, vmTraceIndex, props, callBack) { - var cache = this.getExecutingCodeFromCache(address) - if (cache) { - callBack(address, cache) - return - } - - if (vmTraceIndex === 0 && props.transaction.to === null) { // start of the trace - callBack(address, this.cacheExecutingCode(address, props.transaction.input)) - return - } - - var self = this - this.loadCode(address, function (code) { - callBack(address, self.cacheExecutingCode(address, code)) + this.context.traceManager.getMemoryAt(nextProps.currentStepIndex, function (memory) { + self.setState({ + currentMemory: self.formatMemory(memory, 16) + }) }) - }, - - shouldUpdateStateProperty: function (vmTraceName, nextIndex, previousIndex, vmTrace) { - var propIndex = -1 - if (previousIndex + 1 === nextIndex) { - propIndex = nextIndex - } else { - propIndex = this.retrieveLastSeenProperty(nextIndex, vmTraceName, vmTrace) - } - - if (propIndex > -1 && vmTrace[propIndex][vmTraceName] !== undefined) { - return propIndex - } else { - return -1 - } - }, - - retrieveLastSeenProperty: function (currentIndex, propertyName, vmTrace) { - var index = currentIndex - while (index > 0) { - if (vmTrace[index][propertyName]) { - break - } - index-- - } - return index - }, - - jumpToNextCall: function () { - var i = this.state.currentSelected - while (++i < this.props.vmTrace.length) { - if (this.isCallInstruction(i)) { - this.selectState(i + 1) - break - } - } - }, - - stepIntoBack: function () { - this.moveSelection(-1) - }, - - stepIntoForward: function () { - this.moveSelection(1) - }, - stepOverBack: function () { - if (this.isReturnInstruction(this.state.currentSelected - 1)) { - this.stepOutBack() - } else { - this.moveSelection(-1) - } - }, - - stepOverForward: function () { - if (this.isCallInstruction(this.state.currentSelected)) { - this.stepOutForward() - } else { - this.moveSelection(1) - } - }, - - isCallInstruction: function (index) { - var state = this.props.vmTrace[index] - return state.instname === 'CALL' || state.instname === 'CALLCODE' || state.instname === 'CREATE' || state.instname === 'DELEGATECALL' - }, - - isReturnInstruction: function (index) { - var state = this.props.vmTrace[index] - return state.instname === 'RETURN' - }, - - stepOutBack: function () { - var i = this.state.currentSelected - 1 - var depth = 0 - while (--i >= 0) { - if (this.isCallInstruction(i)) { - if (depth === 0) { - break - } else { - depth-- - } - } else if (this.isReturnInstruction(i)) { - depth++ - } - } - this.selectState(i) - }, - - stepOutForward: function () { - var i = this.state.currentSelected - var depth = 0 - while (++i < this.props.vmTrace.length) { - if (this.isReturnInstruction(i)) { - if (depth === 0) { - break - } else { - depth-- - } - } else if (this.isCallInstruction(i)) { - depth++ - } - } - this.selectState(i + 1) - }, + this.context.traceManager.getStorageAt(nextProps.currentStepIndex, function (storage) { + self.setState({ + currentStorage: storage + }) + }) - moveSelection: function (incr) { - this.selectState(this.state.currentSelected + incr) - }, + this.context.traceManager.getStackAt(nextProps.currentStepIndex, function (stack) { + self.setState({ + currentStack: stack + }) + }) - selectState: function (index) { - this.updateState(this.props, index) + this.context.traceManager.getCurrentCalledAddressAt(nextProps.currentStepIndex, function (address) { + self.setState({ + currentAddress: address + }) + }) }, formatMemory: function (mem, width) { diff --git a/src/vmTraceButtonNavigator.js b/src/buttonNavigator.js similarity index 88% rename from src/vmTraceButtonNavigator.js rename to src/buttonNavigator.js index c634ab254e..1b23e343d9 100644 --- a/src/vmTraceButtonNavigator.js +++ b/src/buttonNavigator.js @@ -2,6 +2,10 @@ var React = require('react') module.exports = React.createClass({ + contextTypes: { + traceManager: React.PropTypes.object + }, + propTypes: { stepIntoBack: React.PropTypes.func.isRequired, stepIntoForward: React.PropTypes.func.isRequired, @@ -32,7 +36,7 @@ module.exports = React.createClass({ if (incr === -1) { return this.props.step === 0 ? 'disabled' : '' } else if (incr === 1) { - return this.props.step >= this.props.vmTraceLength - 1 ? 'disabled' : '' + return this.props.step >= this.props.max - 1 ? 'disabled' : '' } } }) diff --git a/src/codeResolver.js b/src/codeResolver.js new file mode 100644 index 0000000000..69250b6d74 --- /dev/null +++ b/src/codeResolver.js @@ -0,0 +1,67 @@ +'use strict' +var codeUtils = require('./codeUtils') + +module.exports = { + web3: null, + + codes: {}, // assembly items instructions list by contract addesses + instructionsIndexByBytesOffset: {}, // mapping between bytes offset and instructions index. + + setWeb3: function (web3) { + this.web3 = web3 + }, + + resolveCode: function (address, vmTraceIndex, transaction, callBack) { + var cache = this.getExecutingCodeFromCache(address) + if (cache) { + callBack(address, cache.code) + return + } + + if (vmTraceIndex === 0 && transaction.to === null) { // start of the trace + callBack(address, this.cacheExecutingCode(address, transaction.input).code) + return + } + + var self = this + this.loadCode(address, function (code) { + callBack(address, self.cacheExecutingCode(address, code).code) + }) + }, + + loadCode: function (address, callback) { + console.log('loading new code from web3 ' + address) + this.web3.eth.getCode(address, function (error, result) { + if (error) { + console.log(error) + } else { + callback(result) + } + }) + }, + + cacheExecutingCode: function (address, hexCode) { + var code = codeUtils.nameOpCodes(new Buffer(hexCode.substring(2), 'hex')) + this.codes[address] = code[0] + this.instructionsIndexByBytesOffset[address] = code[1] + return { + code: code[0], + instructionsIndexByBytesOffset: code[1] + } + }, + + getExecutingCodeFromCache: function (address) { + if (this.codes[address]) { + return { + code: this.codes[address], + instructionsIndexByBytesOffset: this.instructionsIndexByBytesOffset[address] + } + } else { + return null + } + }, + + getInstructionIndex: function (address, pc) { + return this.getExecutingCodeFromCache(address).instructionsIndexByBytesOffset[pc] + } +} diff --git a/src/debugger.js b/src/debugger.js index d56348f33d..81a209f1cb 100644 --- a/src/debugger.js +++ b/src/debugger.js @@ -1,51 +1,70 @@ 'use strict' var React = require('react') var TxBrowser = require('./txBrowser') +var StepManager = require('./stepManager') var AssemblyItemsBrowser = require('./assemblyItemsBrowser') +var traceManager = require('./traceManager') var style = require('./basicStyles') module.exports = React.createClass({ getInitialState: function () { return { - vmTrace: null, - state: '', - currentStep: -1 + tx: null, + currentStepIndex: -1 // index of the selected item in the vmtrace } }, childContextTypes: { - web3: React.PropTypes.object + web3: React.PropTypes.object, + traceManager: React.PropTypes.object, + tx: React.PropTypes.object }, getChildContext: function () { - return { web3: this.props.web3 } + return { + web3: this.props.web3, + traceManager: traceManager, + tx: this.state.tx + } + }, + + componentDidMount: function () { + traceManager.setWeb3(this.props.web3) }, render: function () { return (

Eth Debugger

- -
- {this.state.state} -
- + + +
) }, - retrieveVmTrace: function (blockNumber, txNumber, tx) { - if (this.state.state !== '') return + stepChanged: function (stepIndex) { + this.setState({ + currentStepIndex: stepIndex + }) + }, + startDebugging: function (blockNumber, txIndex, tx) { + if (traceManager.isLoading) { + return + } + console.log('loading trace...') + this.setState({ + tx: tx + }) + traceManager.setTransaction(tx) var self = this - this.setState({state: 'loading...'}) - - this.props.web3.debug.trace(blockNumber, parseInt(txNumber), function (error, result) { - if (error) { - console.log(error) - } else { - self.setState({vmTrace: result, transaction: tx, state: ''}) - } + traceManager.resolveTrace(blockNumber, txIndex, function (success) { + console.log('trace loaded ' + success) + self.setState({ + currentStepIndex: 0 + }) + self.refs.stepManager.newTraceAvailable() }) } }) diff --git a/src/slider.js b/src/slider.js index d22734aabc..b91ba08b4d 100644 --- a/src/slider.js +++ b/src/slider.js @@ -3,6 +3,10 @@ var React = require('react') var style = require('./sliderStyles') module.exports = React.createClass({ + contextTypes: { + traceManager: React.PropTypes.object + }, + propTypes: { onChange: React.PropTypes.func.isRequired }, @@ -10,7 +14,7 @@ module.exports = React.createClass({ getDefaultProps: function () { return { min: 0, - max: 500 + max: 1 } }, @@ -28,6 +32,10 @@ module.exports = React.createClass({ ) }, + componentDidMount: function () { + this.setValue(0) + }, + onMouseUp: function (event) { this.props.onChange(parseInt(this.refs.rule.value)) }, diff --git a/src/stepManager.js b/src/stepManager.js new file mode 100644 index 0000000000..607f0f1af9 --- /dev/null +++ b/src/stepManager.js @@ -0,0 +1,98 @@ +'use strict' +var React = require('react') +var ButtonNavigator = require('./buttonNavigator') +var Slider = require('./slider') +var style = require('./basicStyles') + +module.exports = React.createClass({ + propTypes: { + onStepChanged: React.PropTypes.func.isRequired + }, + + contextTypes: { + traceManager: React.PropTypes.object + }, + + getInitialState: function () { + return { + currentStepIndex: 0, + traceLength: 0 + } + }, + + render: function () { + return ( +
+ + +
+ ) + }, + + init: function () { + this.refs.slider.setValue(0) + }, + + newTraceAvailable: function () { + this.init() + var self = this + this.context.traceManager.getLength(function (length) { + self.setState({ traceLength: length }) + }) + }, + + sliderMoved: function (step) { + this.props.onStepChanged(step) + this.changeState(step) + }, + + stepIntoForward: function () { + var step = this.state.currentStepIndex + 1 + this.props.onStepChanged(step) + this.changeState(step) + }, + + stepIntoBack: function () { + var step = this.state.currentStepIndex - 1 + this.props.onStepChanged(step) + this.refs.slider.setValue(step) + this.changeState(step) + }, + + stepOverForward: function () { + var step = this.context.traceManager.findStepOverForward(this.state.currentStepIndex) + this.props.onStepChanged(step) + this.refs.slider.setValue(step) + this.changeState(step) + }, + + stepOverBack: function () { + var step = this.context.traceManager.findStepOverBack(this.state.currentStepIndex) + this.props.onStepChanged(step) + this.refs.slider.setValue(step) + this.changeState(step) + }, + + jumpToNextCall: function () { + var step = this.context.traceManager.findNextCall(this.state.currentStepIndex) + this.props.onStepChanged(step) + this.refs.slider.setValue(step) + this.changeState(step) + }, + + changeState: function (step) { + this.setState({ + currentStepIndex: step + }) + } +}) diff --git a/src/sticker.js b/src/sticker.js index 0f71648d6a..8a593cfafb 100644 --- a/src/sticker.js +++ b/src/sticker.js @@ -2,9 +2,22 @@ var React = require('react') module.exports = React.createClass({ + contextTypes: { + traceManager: React.PropTypes.object + }, + getDefaultProps: function () { return { - data: null + currentStepIndex: -1 + } + }, + + getInitialState: function () { + return { + step: '', + addmemory: '', + gas: '', + remainingGas: '' } }, @@ -13,7 +26,38 @@ module.exports = React.createClass({
- {this.renderItems()} + + + + + + + + + + + + + + + +
+ step + + {this.state.step} +
+ add memory + + {this.state.addmemory} +
+ gas + + {this.state.gas} +
+ remaining gas + + {this.state.remaingas} +
@@ -21,9 +65,9 @@ module.exports = React.createClass({ }, renderItems: function () { - if (this.props.data) { + if (this.state.data) { var ret = [] - for (var key in this.props.data) { + for (var key in this.state.data) { ret.push(
@@ -34,5 +78,34 @@ module.exports = React.createClass({ return ret } return null + }, + + componentWillReceiveProps: function (nextProps) { + if (nextProps.currentStepIndex < 0) return + + var self = this + this.context.traceManager.getCurrentStep(nextProps.currentStepIndex, function (step) { + self.setState({ + step: step + }) + }) + + this.context.traceManager.getMemExpand(nextProps.currentStepIndex, function (addmem) { + self.setState({ + addmemory: addmem + }) + }) + + this.context.traceManager.getStepCost(nextProps.currentStepIndex, function (gas) { + self.setState({ + gas: gas + }) + }) + + this.context.traceManager.getRemainingGas(nextProps.currentStepIndex, function (remaingas) { + self.setState({ + remaininGas: remaingas + }) + }) } }) diff --git a/src/storageResolver.js b/src/storageResolver.js deleted file mode 100644 index 8935f793a9..0000000000 --- a/src/storageResolver.js +++ /dev/null @@ -1,113 +0,0 @@ -'use strict' -var React = require('react') - -module.exports = React.createClass({ - contextTypes: { - web3: React.PropTypes.object - }, - - getInitialState: function () { - return { - storage: {}, - storageChanges: [], - vmTraceIndexByStorageChange: {}, - vmTraceChangesRef: [] - } - }, - - init: function () { - var defaultState = this.getInitialState() - this.state.storage = defaultState.storage - this.state.storageChanges = defaultState.storageChanges - this.state.vmTraceIndexByStorageChange = defaultState.vmTraceIndexByStorageChange - this.state.vmTraceChangesRef = defaultState.vmTraceChangesRef - }, - - render: function () { - return null - }, - - // retrieve the storage of an account just after the execution of txHash - retrieveStorage: function (address, transaction, callBack) { - if (this.state.storage[address]) { - callBack(this.state.storage[address]) - } - var self = this - if (transaction) { - this.context.web3.debug.storageAt(transaction.blockNumber.toString(), transaction.transactionIndex, address, function (error, result) { - if (error) { - console.log(error) - } else { - self.state.storage[address] = result - callBack(result) - } - }) - } else { - console.log('transaction is not defined') - } - }, - - trackStorageChange: function (vmTraceIndex, trace) { - var change = false - if (trace.address) { - // new context - this.state.storageChanges.push({ address: trace.address, changes: [] }) - change = true - } else if (trace.depth && !trace.address) { - // returned from context - this.state.storageChanges.push({ address: this.state.storageChanges[this.state.storageChanges.length - 1].address, changes: [] }) - change = true - } else if (trace.inst === 'SSTORE') { - this.state.storageChanges[this.state.storageChanges.length - 1].changes.push( - { - 'key': trace.stack[trace.stack.length - 1], - 'value': trace.stack[trace.stack.length - 2] - }) - change = true - } - - if (change) { - this.state.vmTraceIndexByStorageChange[vmTraceIndex] = { - context: this.state.storageChanges.length - 1, - changes: this.state.storageChanges[this.state.storageChanges.length - 1].changes.length - 1 - } - this.state.vmTraceChangesRef.push(vmTraceIndex) - } - }, - - rebuildStorageAt: function (vmTraceIndex, transaction, callBack) { - var changesLocation = this.retrieveLastChange(vmTraceIndex) - if (!changesLocation) { - console.log('unable to build storage') - callBack({}) - } else { - var address = this.state.storageChanges[changesLocation.context].address - this.retrieveStorage(address, transaction, function (storage) { - for (var k = 0; k < changesLocation.context; k++) { - var context = this.state.storageChanges[k] - if (context.address === address) { - for (var i = 0; i < context.changes.length; i++) { - if (i > changesLocation.changes) break - var change = context.changes[i] - storage[change.key] = change.value - } - } - } - callBack(storage) - }) - } - }, - - retrieveLastChange: function (vmTraceIndex) { - var change = this.state.vmTraceIndexByStorageChange[vmTraceIndex] - if (change) { - return change - } else { - for (var k in this.state.vmTraceChangesRef) { - if (this.state.vmTraceChangesRef[k] > vmTraceIndex) { - return this.state.vmTraceIndexByStorageChange[k - 1] - } - } - } - } -}) diff --git a/src/traceManager.js b/src/traceManager.js new file mode 100644 index 0000000000..256538bc35 --- /dev/null +++ b/src/traceManager.js @@ -0,0 +1,340 @@ +'use strict' +module.exports = { + isLoading: false, + web3: null, + transaction: null, + trace: null, + + // vmtrace changes section + depthChanges: [], + callStack: {}, + memoryChanges: [], + callDataChanges: [], + + // storage section + storageChanges: [], + vmTraceIndexByStorageChange: {}, + vmTraceChangesRef: [], + storages: {}, + + // init section + setWeb3: function (web3) { + this.web3 = web3 + }, + + setTransaction: function (tx) { + this.transaction = tx + }, + + resolveTrace: function (blockNumber, txNumber, callback) { + this.isLoading = true + this.init() + if (!this.web3) callback(false) + var self = this + this.web3.debug.trace(blockNumber, parseInt(txNumber), function (error, result) { + if (!error) { + self.computeTrace(result) + callback(true) + } else { + console.log(error) + callback(false) + } + this.isLoading = false + }) + }, + + init: function () { + this.trace = null + this.depthChanges = [] + this.memoryChanges = [] + this.callDataChanges = [] + this.storageChanges = [] + this.vmTraceIndexByStorageChange = {} + this.vmTraceChangesRef = [] + this.callStack = {} + }, + + computeTrace: function (trace) { + this.trace = trace + var currentDepth = 0 + var currentStorageAddress + var callStack = [] + for (var k in this.trace) { + var step = this.trace[k] + + this.calldata(k, step) + this.memory(k, step) + currentStorageAddress = this.storage(k, step, currentStorageAddress) + var depth = this.depth(k, step, currentDepth, callStack) + if (depth) { + currentDepth = depth + } + } + }, + + // compute trace section + calldata: function (index, step) { + if (step.calldata) { + this.callDataChanges.push(index) + } + }, + + memory: function (index, step) { + if (step.memory) { + this.memoryChanges.push(index) + } + }, + + storage: function (index, step, currentAddress) { + var change = false + if (step.address) { + // new context + this.storageChanges.push({ address: step.address, changes: [] }) + change = true + } else if (step.inst === 'SSTORE') { + this.storageChanges[this.storageChanges.length - 1].changes.push( + { + 'key': step.stack[step.stack.length - 1], + 'value': step.stack[step.stack.length - 2] + }) + change = true + } else if (!step.address && step.depth) { + // returned from context + var address = this.storageChanges[this.storageChanges.length - 2].address + this.storageChanges.push({ address: address, changes: [] }) + change = true + } + + if (change) { + this.vmTraceIndexByStorageChange[index] = { + context: this.storageChanges.length - 1, + changes: this.storageChanges[this.storageChanges.length - 1].changes.length - 1 + } + this.vmTraceChangesRef.push(index) + } + return currentAddress + }, + + depth: function (index, step, currentDepth, callStack) { + if (step.depth === undefined) return + if (step.depth > currentDepth) { + if (index === 0) { + callStack.push('0x' + step.address) // new context + } else { + // getting the address from the stack + var callTrace = this.trace[index - 1] + var address = callTrace.stack[callTrace.stack.length - 2] + callStack.push(address) // new context + } + } else if (step.depth < currentDepth) { + callStack.pop() // returning from context + } + this.callStack[index] = { + stack: callStack.slice(0), + depth: step.depth, + address: step.address + } + this.depthChanges.push(index) + return step.depth + }, + + // API section + getLength: function (callback) { + if (!this.trace) callback(0) + callback(this.trace.length) + }, + + getStorageAt: function (stepIndex, callback) { + var stoChange = this.lastPropertyChange(stepIndex, this.vmTraceChangesRef) + if (!stoChange) { + return {} + } + + var changeRefs = this.vmTraceIndexByStorageChange[stoChange] + var address = this.storageChanges[changeRefs.context].address + var self = this + this.retrieveStorage(address, function (storage) { + for (var k = 0; k < changeRefs.context; k++) { + var context = self.storageChanges[k] + if (context.address === address) { + for (var i = 0; i < context.changes.length; i++) { + if (i > changeRefs.changes) break + var change = context.changes[i] + storage[change.key] = change.value + } + } + } + callback(storage) + }) + }, + + getCallDataAt: function (stepIndex, callback) { + var callDataChange = this.lastPropertyChange(stepIndex, this.callDataChanges) + if (!callDataChange) return [''] + callback([this.trace[callDataChange].calldata]) + }, + + getCallStackAt: function (stepIndex, callback) { + var callStackChange = this.lastPropertyChange(stepIndex, this.depthChanges) + if (!callStackChange) return '' + callback(this.callStack[callStackChange].stack) + }, + + getStackAt: function (stepIndex, callback) { + var stack + if (this.trace[stepIndex].stack) { // there's always a stack + stack = this.trace[stepIndex].stack.slice(0) + stack.reverse() + callback(stack) + } + }, + + getLastDepthIndexChangeSince: function (stepIndex, callback) { + var depthIndex = this.lastPropertyChange(stepIndex, this.depthChanges) + callback(depthIndex) + }, + + getCurrentCalledAddressAt: function (stepIndex, callback) { + var self = this + this.getLastDepthIndexChangeSince(stepIndex, function (addressIndex) { + callback(self.resolveAddress(addressIndex)) + }) + }, + + getMemoryAt: function (stepIndex, callback) { + var lastChanges = this.lastPropertyChange(stepIndex, this.memoryChanges) + if (!lastChanges) return '' + callback(this.trace[lastChanges].memory) + }, + + getCurrentPC: function (stepIndex, callback) { + callback(this.trace[stepIndex].pc) + }, + + getCurrentStep: function (stepIndex, callback) { + callback(this.trace[stepIndex].steps) + }, + + getMemExpand: function (stepIndex, callback) { + callback(this.trace[stepIndex].memexpand ? this.trace[stepIndex].memexpand : '') + }, + + getStepCost: function (stepIndex, callback) { + callback(this.trace[stepIndex].gascost) + }, + + getRemainingGas: function (stepIndex, callback) { + callback(this.trace[stepIndex].gas) + }, + + // step section + isCallInstruction: function (index) { + var state = this.trace[index] + return state.instname === 'CALL' || state.instname === 'CALLCODE' || state.instname === 'CREATE' || state.instname === 'DELEGATECALL' + }, + + isReturnInstruction: function (index) { + var state = this.trace[index] + return state.instname === 'RETURN' + }, + + findStepOverBack: function (currentStep) { + if (this.isReturnInstruction(currentStep - 1)) { + return this.findStepOutBack(currentStep) + } else { + return currentStep - 1 + } + }, + + findStepOverForward: function (currentStep) { + if (this.isCallInstruction(currentStep)) { + return this.findStepOutForward(currentStep) + } else { + return currentStep + 1 + } + }, + + findStepOutBack: function (currentStep) { + var i = currentStep - 1 + var depth = 0 + while (--i >= 0) { + if (this.isCallInstruction(i)) { + if (depth === 0) { + break + } else { + depth-- + } + } else if (this.isReturnInstruction(i)) { + depth++ + } + } + return i + }, + + findStepOutForward: function (currentStep) { + var i = currentStep + var depth = 0 + while (++i < this.trace.length) { + if (this.isReturnInstruction(i)) { + if (depth === 0) { + break + } else { + depth-- + } + } else if (this.isCallInstruction(i)) { + depth++ + } + } + return i + 1 + }, + + // util section + lastPropertyChange: function (target, changes) { + if (changes.length === 1) { + if (changes[0] > target) { + // we only a closest maximum, returning 0 + return null + } else { + return changes[0] + } + } + + var middle = Math.floor(changes.length / 2) + if (changes[middle] > target) { + return this.lastPropertyChange(target, changes.slice(0, middle)) + } else if (changes[middle] < target) { + return this.lastPropertyChange(target, changes.slice(middle, changes.length)) + } else { + return changes[middle] + } + }, + + resolveAddress: function (vmTraceIndex) { + var address = this.trace[vmTraceIndex].address + if (vmTraceIndex > 0) { + var stack = this.trace[vmTraceIndex - 1].stack // callcode, delegatecall, ... + address = stack[stack.length - 2] + } + return address + }, + + // retrieve the storage of an account just after the execution of tx + retrieveStorage: function (address, callBack) { + if (this.storages[address]) { + callBack(this.storages[address]) + } + var self = this + if (this.transaction) { + this.web3.debug.storageAt(this.transaction.blockNumber.toString(), this.transaction.transactionIndex, address, function (error, result) { + if (error) { + console.log(error) + } else { + self.storages[address] = result + callBack(result) + } + }) + } else { + console.log('transaction is not defined') + } + } +} diff --git a/src/txBrowser.js b/src/txBrowser.js index 0bba5312c4..61dad1c78e 100644 --- a/src/txBrowser.js +++ b/src/txBrowser.js @@ -42,18 +42,22 @@ module.exports = React.createClass({ Get
-
- Hash: - {this.state.hash} -
-
- From: - {this.state.from} -
-
- To: - {this.state.to} -
+ + + + + + + + + + + + + + + +
Hash: {this.state.hash}
From: {this.state.from}
To: {this.state.to}
) From 5e7a26a36e6e3187215fd41c187383a8a5e913df Mon Sep 17 00:00:00 2001 From: yann300 Date: Thu, 19 May 2016 15:18:34 +0200 Subject: [PATCH 03/11] split assemblyitemsbrowser --- src/asmCode.js | 6 +- src/assemblyItemsBrowser.js | 133 +++++------------------------------- src/calldataPanel.js | 41 +++++++++++ src/callstackPanel.js | 41 +++++++++++ src/debugger.js | 6 +- src/memoryPanel.js | 91 ++++++++++++++++++++++++ src/stackPanel.js | 41 +++++++++++ src/stepManager.js | 9 +++ src/storagePanel.js | 59 ++++++++++++++++ 9 files changed, 308 insertions(+), 119 deletions(-) create mode 100644 src/calldataPanel.js create mode 100644 src/callstackPanel.js create mode 100644 src/memoryPanel.js create mode 100644 src/stackPanel.js create mode 100644 src/storagePanel.js diff --git a/src/asmCode.js b/src/asmCode.js index 2d9e723da4..552389541c 100644 --- a/src/asmCode.js +++ b/src/asmCode.js @@ -45,7 +45,7 @@ module.exports = React.createClass({ }, componentWillReceiveProps: function (nextProps) { - console.log('asm' + JSON.stringify(nextProps)) + console.log('new prop asmCode') if (nextProps.currentStepIndex < 0) return codeResolver.setWeb3(this.context.web3) var self = this @@ -61,6 +61,10 @@ module.exports = React.createClass({ }) var self = this codeResolver.resolveCode(address, currentStep, this.context.tx, function (address, code) { + if (window.ethDebuggerSelectedItem !== currentStep) { + console.log(currentStep + ' discarded. current is ' + window.ethDebuggerSelectedItem) + return + } self.setState({ code: code, address: address diff --git a/src/assemblyItemsBrowser.js b/src/assemblyItemsBrowser.js index 13e788d89c..53bf646e6e 100644 --- a/src/assemblyItemsBrowser.js +++ b/src/assemblyItemsBrowser.js @@ -1,23 +1,22 @@ 'use strict' var React = require('react') -var BasicPanel = require('./basicPanel') var Sticker = require('./sticker') var style = require('./basicStyles') var ASMCode = require('./asmCode') +var CalldataPanel = require('./calldataPanel') +var MemoryPanel = require('./memoryPanel') +var CallstackPanel = require('./callstackPanel') +var StackPanel = require('./stackPanel') +var StoragePanel = require('./storagePanel') module.exports = React.createClass({ contextTypes: { - traceManager: React.PropTypes.object, - web3: React.PropTypes.object + traceManager: React.PropTypes.object }, getInitialState: function () { return { - currentAddress: null, - currentStack: null, - currentStorage: null, - currentMemory: null, - currentCallData: null + currentAddress: null } }, @@ -44,23 +43,23 @@ module.exports = React.createClass({
- +
- + - +
- + - +
- {key} - - {data[key]} -
- {memSlot.address} - - {memSlot.content.raw} - - {memSlot.content.ascii} -
+ {memSlot.address} + + {memSlot.content.raw} + + {memSlot.content.ascii} +
+ {key} + + {data[key]} +
- {this.props.data[key]} +
{this.props.data[key]}
- {memSlot.address} +
{memSlot.address}
- {memSlot.content.raw} +
{memSlot.content.raw}
- {memSlot.content.ascii} +
{memSlot.content.ascii}
- {key} +
{key}
- {data[key]} +
{data[key]}
-
{this.props.data[key]}
+
{this.props.data[key]}
-
{memSlot.address}
+
{memSlot.address}
-
{memSlot.content.raw}
+
{memSlot.content.raw}
-
{memSlot.content.ascii}
+
{memSlot.content.ascii}
- {this.state.remaingas} + {this.state.remainingGas}
-
{key}
+
{key}
-
{data[key]}
+
{data[key]}