diff --git a/src/asmCode.js b/src/asmCode.js
index 765c64e89d..4e7098504c 100644
--- a/src/asmCode.js
+++ b/src/asmCode.js
@@ -48,13 +48,17 @@ module.exports = React.createClass({
if (nextProps.currentStepIndex < 0) return
codeResolver.setWeb3(this.context.web3)
var self = this
- this.context.traceManager.getCurrentCalledAddressAt(nextProps.currentStepIndex, function (error, address) {
- if (error) {
- console.log(error)
- } else {
- self.ensureCodeLoaded(address, nextProps.currentStepIndex)
- }
- })
+ if (nextProps.currentStepIndex === 0) {
+ self.ensureCodeLoaded(this.context.tx.to, nextProps.currentStepIndex)
+ } else {
+ this.context.traceManager.getCurrentCalledAddressAt(nextProps.currentStepIndex, function (error, address) {
+ if (error) {
+ console.log(error)
+ } else {
+ self.ensureCodeLoaded(address, nextProps.currentStepIndex)
+ }
+ })
+ }
},
ensureCodeLoaded: function (address, currentStep) {
diff --git a/src/basicPanel.js b/src/basicPanel.js
index f5780d7022..cda0818765 100644
--- a/src/basicPanel.js
+++ b/src/basicPanel.js
@@ -6,8 +6,7 @@ module.exports = React.createClass({
getDefaultProps: function () {
return {
data: null,
- name: null,
- renderRow: null
+ name: null
}
},
@@ -18,33 +17,9 @@ module.exports = React.createClass({
{this.props.name}
-
-
- {this.renderItems()}
-
-
+
{this.props.data}
)
- },
-
- renderItems: function () {
- if (!this.props.data) {
- return []
- }
- if (!this.props.renderRow) {
- var ret = []
- for (var key in this.props.data) {
- ret.push(
-
-
- {this.props.data[key]}
- |
-
)
- }
- return ret
- } else {
- return this.props.renderRow(this.props.data)
- }
}
})
diff --git a/src/buttonNavigator.js b/src/buttonNavigator.js
index 1b23e343d9..e834ad35b9 100644
--- a/src/buttonNavigator.js
+++ b/src/buttonNavigator.js
@@ -10,7 +10,8 @@ module.exports = React.createClass({
stepIntoBack: React.PropTypes.func.isRequired,
stepIntoForward: React.PropTypes.func.isRequired,
stepOverBack: React.PropTypes.func.isRequired,
- stepOverForward: React.PropTypes.func.isRequired
+ stepOverForward: React.PropTypes.func.isRequired,
+ jumpNextCall: React.PropTypes.func.isRequired
},
render: function () {
@@ -28,15 +29,27 @@ module.exports = React.createClass({
+
)
},
checkButtonState: function (incr) {
- if (incr === -1) {
- return this.props.step === 0 ? 'disabled' : ''
- } else if (incr === 1) {
- return this.props.step >= this.props.max - 1 ? 'disabled' : ''
+ if (!this.context.traceManager) {
+ return false
}
+ var self = this
+ this.context.traceManager.getLength(function (error, length) {
+ if (error) {
+ return false
+ }
+ if (incr === -1) {
+ return self.props.step === 0 ? 'disabled' : ''
+ } else if (incr === 1) {
+ return self.props.step >= self.props.max - 1 ? 'disabled' : ''
+ }
+ })
}
})
diff --git a/src/calldataPanel.js b/src/calldataPanel.js
index 752a2bf15e..7bc9bc0baa 100644
--- a/src/calldataPanel.js
+++ b/src/calldataPanel.js
@@ -35,9 +35,17 @@ module.exports = React.createClass({
console.log(error)
} else if (window.ethDebuggerSelectedItem === nextProps.currentStepIndex) {
self.setState({
- data: calldata
+ data: self.format(calldata)
})
}
})
+ },
+
+ format: function (calldata) {
+ var ret = ''
+ for (var key in calldata) {
+ ret += calldata[key] + '\n'
+ }
+ return ret
}
})
diff --git a/src/callstackPanel.js b/src/callstackPanel.js
index 83ec5ce94a..e223b8d411 100644
--- a/src/callstackPanel.js
+++ b/src/callstackPanel.js
@@ -35,9 +35,17 @@ module.exports = React.createClass({
console.log(error)
} else if (window.ethDebuggerSelectedItem === nextProps.currentStepIndex) {
self.setState({
- data: callstack
+ data: self.format(callstack)
})
}
})
+ },
+
+ format: function (callstack) {
+ var ret = ''
+ for (var key in callstack) {
+ ret += callstack[key] + '\n'
+ }
+ return ret
}
})
diff --git a/src/codeResolver.js b/src/codeResolver.js
index 69250b6d74..77d3fec33c 100644
--- a/src/codeResolver.js
+++ b/src/codeResolver.js
@@ -18,7 +18,7 @@ module.exports = {
return
}
- if (vmTraceIndex === 0 && transaction.to === null) { // start of the trace
+ if (address === '(Contract Creation Code)') { // start of the trace
callBack(address, this.cacheExecutingCode(address, transaction.input).code)
return
}
@@ -41,9 +41,14 @@ module.exports = {
},
cacheExecutingCode: function (address, hexCode) {
+ var codes = this.formatCode(hexCode)
+ this.codes[address] = codes[0]
+ this.instructionsIndexByBytesOffset[address] = codes[1]
+ return codes
+ },
+
+ formatCode: function (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]
diff --git a/src/debugger.js b/src/debugger.js
index f7e1e9a7a0..87816aa1b1 100644
--- a/src/debugger.js
+++ b/src/debugger.js
@@ -61,7 +61,7 @@ module.exports = React.createClass({
tx: tx
})
var self = this
- this.state.traceManager.resolveTrace(blockNumber, txIndex, function (success) {
+ this.state.traceManager.resolveTrace(tx, function (success) {
console.log('trace loaded ' + success)
self.setState({
currentStepIndex: 0
diff --git a/src/memoryPanel.js b/src/memoryPanel.js
index 2a5f6f10d1..c972989f33 100644
--- a/src/memoryPanel.js
+++ b/src/memoryPanel.js
@@ -1,7 +1,6 @@
'use strict'
var React = require('react')
var BasicPanel = require('./basicPanel')
-var style = require('./basicStyles')
module.exports = React.createClass({
contextTypes: {
@@ -23,7 +22,7 @@ module.exports = React.createClass({
render: function () {
return (
-
+
)
},
@@ -43,36 +42,20 @@ module.exports = React.createClass({
})
},
- renderMemoryRow: function (data) {
- var ret = []
- if (data) {
- for (var key in data) {
- var memSlot = data[key]
- ret.push(
-
-
- {memSlot.address}
- |
-
- {memSlot.content.raw}
- |
-
- {memSlot.content.ascii}
- |
-
)
- }
+ formatMemory: function (mem, width) {
+ var ret = ''
+ if (!mem) {
+ return ret
+ }
+
+ if (!mem.substr) {
+ mem = mem.join('') // geth returns an array, eth return raw string
}
- 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)
- })
+ var content = this.tryAsciiFormat(memory)
+ ret += this.context.web3.toHex(k) + ' ' + content.raw + ' ' + content.ascii + '\n'
}
return ret
},
diff --git a/src/stackPanel.js b/src/stackPanel.js
index a4ff3c8472..0d5e117662 100644
--- a/src/stackPanel.js
+++ b/src/stackPanel.js
@@ -35,9 +35,17 @@ module.exports = React.createClass({
console.log(error)
} else if (window.ethDebuggerSelectedItem === nextProps.currentStepIndex) {
self.setState({
- data: stack
+ data: self.format(stack)
})
}
})
+ },
+
+ format: function (stack) {
+ var ret = ''
+ for (var key in stack) {
+ ret += stack[key] + '\n'
+ }
+ return ret
}
})
diff --git a/src/stepManager.js b/src/stepManager.js
index 9967318309..2b5000f82f 100644
--- a/src/stepManager.js
+++ b/src/stepManager.js
@@ -33,7 +33,7 @@ module.exports = React.createClass({
stepIntoForward={this.stepIntoForward}
stepOverBack={this.stepOverBack}
stepOverForward={this.stepOverForward}
- jumpToNextCall={this.jumpToNextCall}
+ jumpNextCall={this.jumpToNextCall}
max={this.state.traceLength} />
)
diff --git a/src/storagePanel.js b/src/storagePanel.js
index 96356cbe70..71b1bc8d62 100644
--- a/src/storagePanel.js
+++ b/src/storagePanel.js
@@ -1,7 +1,6 @@
'use strict'
var React = require('react')
var BasicPanel = require('./basicPanel')
-var style = require('./basicStyles')
module.exports = React.createClass({
contextTypes: {
@@ -23,7 +22,7 @@ module.exports = React.createClass({
render: function () {
return (
-
+
)
},
@@ -32,31 +31,21 @@ 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 (error, storage) {
+ this.context.traceManager.getStorageAt(nextProps.currentStepIndex, this.context.tx, function (error, storage) {
if (error) {
console.log(error)
} else if (window.ethDebuggerSelectedItem === nextProps.currentStepIndex) {
self.setState({
- data: storage
+ data: self.formatStorage(storage)
})
}
})
},
- renderStorageRow: function (data) {
- var ret = []
- if (data) {
- for (var key in data) {
- ret.push(
-
-
- {key}
- |
-
- {data[key]}
- |
-
)
- }
+ formatStorage: function (storage) {
+ var ret = ''
+ for (var key in storage) {
+ ret += key + ' ' + storage[key] + '\n'
}
return ret
}
diff --git a/src/traceAnalyser.js b/src/traceAnalyser.js
index d79368c1ba..873b874412 100644
--- a/src/traceAnalyser.js
+++ b/src/traceAnalyser.js
@@ -1,25 +1,29 @@
'use strict'
+var traceManagerUtil = require('./traceManagerUtil')
+
function TraceAnalyser (_cache) {
this.traceCache = _cache
this.trace = null
}
-TraceAnalyser.prototype.analyse = function (trace, callback) {
+TraceAnalyser.prototype.analyse = function (trace, root, callback) {
this.trace = trace
- var currentDepth = 0
+
+ this.traceCache.pushStoreChanges(0, root)
var context = {
- currentStorageAddress: trace[0].address,
- previousStorageAddress: trace[0].address
+ currentStorageAddress: root,
+ previousStorageAddress: root
}
- var callStack = []
- for (var k in this.trace) {
+ var callStack = [root]
+ this.traceCache.pushCallStack(0, {
+ callStack: callStack.slice(0)
+ })
+
+ for (var k = 0; k < this.trace.length; k++) {
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
- }
+ this.buildDepth(k, step, callStack)
context = this.buildStorage(k, step, context)
}
callback(null, true)
@@ -38,40 +42,45 @@ TraceAnalyser.prototype.buildMemory = function (index, step) {
}
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
+ if (traceManagerUtil.newContextStorage(step)) {
+ var calledAddress = traceManagerUtil.resolveCalledAddress(index, this.trace)
+ if (calledAddress) {
+ context.currentStorageAddress = calledAddress
+ } else {
+ console.log('unable to build storage changes. ' + index + ' does not match with a CALL. storage changes will be corrupted')
+ }
+ this.traceCache.pushStoreChanges(index + 1, context.currentStorageAddress)
+ } else if (step.op === 'SSTORE') {
+ this.traceCache.pushStoreChanges(index + 1, context.currentStorageAddress, step.stack[step.stack.length - 1], step.stack[step.stack.length - 2])
+ } else if (!step.op === 'RETURN') {
context.currentStorageAddress = context.previousStorageAddress
- this.traceCache.pushStoreChanges(index, context.currentStorageAddress)
+ this.traceCache.pushStoreChanges(index + 1, 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
+TraceAnalyser.prototype.buildDepth = function (index, step, callStack) {
+ if (traceManagerUtil.isCallInstruction(step) && !traceManagerUtil.isCallToPrecompiledContract(index, this.trace)) {
+ var newAddress = traceManagerUtil.resolveCalledAddress(index, this.trace)
+ if (newAddress) {
+ callStack.push(newAddress)
} 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
+ console.log('unable to build depth changes. ' + index + ' does not match with a CALL. depth changes will be corrupted')
}
- } else if (step.depth < currentDepth) {
- callStack.pop() // returning from context
+ this.traceCache.pushCallChanges(step, index + 1)
+ this.traceCache.pushCallStack(index + 1, {
+ callStack: callStack.slice(0)
+ })
+ } else if (traceManagerUtil.isReturnInstruction(step)) {
+ this.traceCache.pushCallChanges(step, index)
+ this.traceCache.pushCallStack(index, {
+ callStack: callStack.slice(0)
+ })
+ callStack.pop()
}
- this.traceCache.pushCallStack(index, {
- stack: callStack.slice(0),
- depth: step.depth
- })
- this.traceCache.pushDepthChanges(index)
- return step.depth
}
+// 0x90a99e9dbfc38ce0fd6330f97a192a9ef27b8329b57309e8b2abe47a6fe74574
+// 0xc0e95f27e1482ba09dea8162c4b4090e3d89e214416df2ce9d5517ff2107de19
+
module.exports = TraceAnalyser
diff --git a/src/traceCache.js b/src/traceCache.js
index d7cb3e9a3a..9fc4ac5a79 100644
--- a/src/traceCache.js
+++ b/src/traceCache.js
@@ -5,9 +5,13 @@ function TraceCache () {
TraceCache.prototype.init = function () {
// ...Changes contains index in the vmtrace of the corresponding changes
- this.depthChanges = []
- this.memoryChanges = []
+
+ this.callChanges = []
+ this.returnChanges = []
+ this.calls = {}
+
this.callDataChanges = []
+ this.memoryChanges = []
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)
@@ -21,8 +25,15 @@ TraceCache.prototype.pushMemoryChanges = function (value) {
this.memoryChanges.push(value)
}
-TraceCache.prototype.pushDepthChanges = function (value) {
- this.depthChanges.push(value)
+TraceCache.prototype.pushCallChanges = function (step, value) {
+ this.callChanges.push(value)
+ this.calls[value] = {
+ op: step.op
+ }
+}
+
+TraceCache.prototype.pushReturnChanges = function (value) {
+ this.returnChanges.push(value)
}
TraceCache.prototype.pushCallStack = function (index, callStack) {
diff --git a/src/traceManager.js b/src/traceManager.js
index c53e66b81e..0ed6f4ba36 100644
--- a/src/traceManager.js
+++ b/src/traceManager.js
@@ -13,27 +13,36 @@ function TraceManager (_web3) {
this.traceAnalyser = new TraceAnalyser(this.traceCache)
this.traceRetriever = new TraceRetriever(_web3)
this.traceStepManager = new TraceStepManager(this.traceAnalyser)
+ this.tx
}
// init section
-TraceManager.prototype.resolveTrace = function (blockNumber, txNumber, callback) {
- this.isLoading = true
+TraceManager.prototype.resolveTrace = function (tx, callback) {
+ this.tx = tx
this.init()
if (!this.web3) callback(false)
+ this.isLoading = true
var self = this
- this.traceRetriever.getTrace(blockNumber, parseInt(txNumber), function (error, result) {
- self.trace = result
+ this.traceRetriever.getTrace(tx.hash, function (error, result) {
if (error) {
console.log(error)
+ self.isLoading = false
} else {
- self.traceAnalyser.analyse(result, function (error, result) {
- if (error) {
- console.log(error)
- callback(false)
- } else {
- callback(true)
- }
- })
+ if (result.structLogs.length > 0) {
+ self.trace = result.structLogs
+ self.traceAnalyser.analyse(result.structLogs, tx.to, function (error, result) {
+ if (error) {
+ console.log(error)
+ callback(false)
+ } else {
+ callback(true)
+ }
+ self.isLoading = false
+ })
+ } else {
+ console.log(tx.hash + ' is not a contract invokation or contract creation.')
+ self.isLoading = false
+ }
}
})
}
@@ -45,39 +54,62 @@ TraceManager.prototype.init = function () {
// API section
TraceManager.prototype.getLength = function (callback) {
- if (!this.trace) callback('no trace available', null)
- callback(null, this.trace.length)
+ if (!this.trace) {
+ callback('no trace available', null)
+ } else {
+ callback(null, this.trace.length)
+ }
}
-TraceManager.prototype.getStorageAt = function (stepIndex, blockNumber, txIndex, callback) {
+TraceManager.prototype.getStorageAt = function (stepIndex, tx, callback) {
+ if (stepIndex >= this.trace.length) {
+ callback('trace smaller than requested', null)
+ return
+ }
var stoChange = traceManagerUtil.findLowerBound(stepIndex, this.traceCache.storageChanges)
-
- var address = this.traceCache.sstore[stoChange].address
+ if (stoChange === undefined) return callback('no storage found', null)
var self = this
- 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)
- }
- })
+ if (this.traceRetriever.debugStorageAtAvailable()) {
+ var address = this.traceCache.sstore[stoChange].address
+ this.traceRetriever.getStorage(tx, address, function (error, result) {
+ if (error) {
+ console.log(error)
+ callback(error, null)
+ } else {
+ var storage = self.traceCache.rebuildStorage(address, result, stepIndex)
+ callback(null, storage)
+ }
+ })
+ } else {
+ callback(null, this.trace[stoChange].storage)
+ }
}
TraceManager.prototype.getCallDataAt = function (stepIndex, callback) {
+ if (stepIndex >= this.trace.length) {
+ callback('trace smaller than requested', null)
+ return
+ }
var callDataChange = traceManagerUtil.findLowerBound(stepIndex, this.traceCache.callDataChanges)
- if (!callDataChange) return callback('no calldata found', null)
+ if (callDataChange === undefined) return callback('no calldata found', null)
callback(null, [this.trace[callDataChange].calldata])
}
TraceManager.prototype.getCallStackAt = function (stepIndex, callback) {
- var callStackChange = traceManagerUtil.findLowerBound(stepIndex, this.traceCache.depthChanges)
- if (!callStackChange) return callback('no callstack found', null)
- callback(null, this.traceCache.callStack[callStackChange].stack)
+ if (stepIndex >= this.trace.length) {
+ callback('trace smaller than requested', null)
+ return
+ }
+ var callStackChange = traceManagerUtil.findLowerBound(stepIndex, this.traceCache.callChanges)
+ if (callStackChange === undefined) return callback('no callstack found', null)
+ callback(null, this.traceCache.callStack[callStackChange].callStack)
}
TraceManager.prototype.getStackAt = function (stepIndex, callback) {
+ if (stepIndex >= this.trace.length) {
+ callback('trace smaller than requested', null)
+ return
+ }
var stack
if (this.trace[stepIndex].stack) { // there's always a stack
stack = this.trace[stepIndex].stack.slice(0)
@@ -88,48 +120,103 @@ TraceManager.prototype.getStackAt = function (stepIndex, callback) {
}
}
-TraceManager.prototype.getLastDepthIndexChangeSince = function (stepIndex, callback) {
- var depthIndex = traceManagerUtil.findLowerBound(stepIndex, this.traceCache.depthChanges)
- callback(null, depthIndex)
+TraceManager.prototype.getLastCallChangeSince = function (stepIndex, callback) {
+ if (stepIndex >= this.trace.length) {
+ callback('trace smaller than requested', null)
+ return
+ }
+ var callChange = traceManagerUtil.findLowerBound(stepIndex, this.traceCache.callChanges)
+ if (callChange === undefined) {
+ callback(null, 0)
+ } else {
+ callback(null, callChange)
+ }
}
TraceManager.prototype.getCurrentCalledAddressAt = function (stepIndex, callback) {
+ if (stepIndex > this.trace.length) {
+ callback('trace smaller than requested', null)
+ return
+ }
var self = this
- this.getLastDepthIndexChangeSince(stepIndex, function (error, addressIndex) {
+ this.getLastCallChangeSince(stepIndex, function (error, addressIndex) {
if (error) {
callback(error, null)
} else {
- callback(null, traceManagerUtil.resolveCalledAddress(addressIndex, self.trace))
+ if (addressIndex === 0) {
+ callback(null, self.tx.to)
+ } else {
+ var step = this.trace[addressIndex]
+ if (traceManagerUtil.isCreateInstruction(step)) {
+ callback(null, '(Contract Creation Code)')
+ } else {
+ var callStack = self.traceCache.callStack[addressIndex].callStack
+ var calledAddress = callStack[callStack.length - 1]
+ if (calledAddress) {
+ callback(null, calledAddress)
+ } else {
+ callback('unable to get current called address. ' + stepIndex + ' does not match with a CALL', null)
+ }
+ }
+ }
}
})
}
TraceManager.prototype.getMemoryAt = function (stepIndex, callback) {
+ if (stepIndex >= this.trace.length) {
+ callback('trace smaller than requested', null)
+ return
+ }
var lastChanges = traceManagerUtil.findLowerBound(stepIndex, this.traceCache.memoryChanges)
- if (!lastChanges) return callback('no memory found', null)
+ if (lastChanges === undefined) return callback('no memory found', null)
callback(null, this.trace[lastChanges].memory)
}
TraceManager.prototype.getCurrentPC = function (stepIndex, callback) {
+ if (stepIndex >= this.trace.length) {
+ callback('trace smaller than requested', null)
+ return
+ }
callback(null, this.trace[stepIndex].pc)
}
TraceManager.prototype.getCurrentStep = function (stepIndex, callback) {
+ if (stepIndex >= this.trace.length) {
+ callback('trace smaller than requested', null)
+ return
+ }
callback(null, this.trace[stepIndex].steps)
}
TraceManager.prototype.getMemExpand = function (stepIndex, callback) {
+ if (stepIndex >= this.trace.length) {
+ callback('trace smaller than requested', null)
+ return
+ }
callback(null, this.trace[stepIndex].memexpand ? this.trace[stepIndex].memexpand : '')
}
TraceManager.prototype.getStepCost = function (stepIndex, callback) {
- callback(null, this.trace[stepIndex].gascost)
+ if (stepIndex >= this.trace.length) {
+ callback('trace smaller than requested', null)
+ return
+ }
+ callback(null, this.trace[stepIndex].gasCost)
}
TraceManager.prototype.getRemainingGas = function (stepIndex, callback) {
+ if (stepIndex >= this.trace.length) {
+ callback('trace smaller than requested', null)
+ return
+ }
callback(null, this.trace[stepIndex].gas)
}
+TraceManager.prototype.isCreationStep = function (stepIndex) {
+ return traceManagerUtil.isCreateInstruction(stepIndex, this.trace)
+}
+
// step section
TraceManager.prototype.findStepOverBack = function (currentStep) {
return this.traceStepManager.findStepOverBack(currentStep)
@@ -147,4 +234,8 @@ TraceManager.prototype.findStepOutForward = function (currentStep) {
return this.traceStepManager.findStepOutForward(currentStep)
}
+TraceManager.prototype.findNextCall = function (currentStep) {
+ return this.traceStepManager.findNextCall(currentStep)
+}
+
module.exports = TraceManager
diff --git a/src/traceManagerUtil.js b/src/traceManagerUtil.js
index 3231efa5af..61f3f1f7cb 100644
--- a/src/traceManagerUtil.js
+++ b/src/traceManagerUtil.js
@@ -24,13 +24,39 @@ module.exports = {
}
},
+ // vmTraceIndex has to point to a CALL, CODECALL, ...
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]
+ var step = trace[vmTraceIndex]
+ if (this.isCallInstruction(step)) {
+ var stack = step.stack // callcode, delegatecall, ...
+ return stack[stack.length - 2]
}
- return address
- }
+ return undefined
+ },
+
+ isCallInstruction: function (step) {
+ return step.op === 'CALL' || step.op === 'CALLCODE' || step.op === 'CREATE' || step.op === 'DELEGATECALL'
+ },
+
+ isCreateInstruction: function (step) {
+ return step.op === 'CREATE'
+ },
+
+ isReturnInstruction: function (step) {
+ return step.op === 'RETURN'
+ },
+
+ newContextStorage: function (step) {
+ return step.op === 'CREATE' || step.op === 'CALL'
+ },
+ isCallToPrecompiledContract: function (index, trace) {
+ // if stack empty => this is not a precompiled contract
+ var step = trace[index]
+ if (this.isCallInstruction(step)) {
+ return trace[index + 1].stack.length !== 0
+ } else {
+ return false
+ }
+ }
}
diff --git a/src/traceRetriever.js b/src/traceRetriever.js
index 238510b66b..7f2343ba90 100644
--- a/src/traceRetriever.js
+++ b/src/traceRetriever.js
@@ -4,22 +4,34 @@ function TraceRetriever (_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) {
+TraceRetriever.prototype.getTrace = function (txHash, callback) {
+ var options = {
+ disableStorage: this.debugStorageAtAvailable(),
+ disableMemory: false,
+ disableStack: false,
+ fullStorage: !this.debugStorageAtAvailable()
+ }
+ this.web3.debug.traceTransaction(txHash, options, function (error, result) {
callback(error, result)
})
}
-TraceRetriever.prototype.getStorage = function (blockNumber, txIndex, address, callback) {
- if (this.storages[address]) {
+TraceRetriever.prototype.getStorage = function (tx, address, callback) {
+ if (tx.to === '(Contract Creation Code)') {
+ callback(null, {})
+ } else if (this.storages[address]) {
callback(null, this.storages[address])
} else {
var self = this
- this.web3.debug.storageAt(blockNumber, txIndex, address, function (error, result) {
+ this.web3.debug.storageAt(tx.blockNumber.toString(), tx.transactionIndex, address, function (error, result) {
self.storages[address] = result
callback(error, result)
})
}
}
+TraceRetriever.prototype.debugStorageAtAvailable = function () {
+ return true // storageAt not available if using geth
+}
+
module.exports = TraceRetriever
diff --git a/src/traceStepManager.js b/src/traceStepManager.js
index 40d9afc098..38e074fd39 100644
--- a/src/traceStepManager.js
+++ b/src/traceStepManager.js
@@ -1,32 +1,28 @@
'use strict'
+var traceManagerUtil = require('./traceManagerUtil')
+
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'
+ return traceManagerUtil.isCallInstruction(state)
}
TraceStepManager.prototype.isReturnInstruction = function (index) {
var state = this.traceAnalyser.trace[index]
- return state.instname === 'RETURN'
+ return traceManagerUtil.isReturnInstruction(state)
}
TraceStepManager.prototype.findStepOverBack = function (currentStep) {
- if (this.isReturnInstruction(currentStep - 1)) {
- return this.findStepOutBack(currentStep)
- } else {
- return currentStep - 1
- }
+ if (currentStep === 0) return 0
+ return this.findStepOutBack(currentStep)
}
TraceStepManager.prototype.findStepOverForward = function (currentStep) {
- if (this.isCallInstruction(currentStep)) {
- return this.findStepOutForward(currentStep)
- } else {
- return currentStep + 1
- }
+ if (currentStep === this.traceAnalyser.trace.length - 1) return currentStep
+ return this.findStepOutForward(currentStep)
}
TraceStepManager.prototype.findStepOutBack = function (currentStep) {
@@ -49,7 +45,7 @@ TraceStepManager.prototype.findStepOutBack = function (currentStep) {
TraceStepManager.prototype.findStepOutForward = function (currentStep) {
var i = currentStep
var depth = 0
- while (++i < this.traceAnalyser.length) {
+ while (++i < this.traceAnalyser.trace.length) {
if (this.isReturnInstruction(i)) {
if (depth === 0) {
break
@@ -60,7 +56,17 @@ TraceStepManager.prototype.findStepOutForward = function (currentStep) {
depth++
}
}
- return i + 1
+ return i
+}
+
+TraceStepManager.prototype.findNextCall = function (currentStep) {
+ var i = currentStep
+ while (++i < this.traceAnalyser.trace.length) {
+ if (this.isCallInstruction(i)) {
+ return i
+ }
+ }
+ return currentStep
}
module.exports = TraceStepManager
diff --git a/src/txBrowser.js b/src/txBrowser.js
index 61dad1c78e..a3717f4f68 100644
--- a/src/txBrowser.js
+++ b/src/txBrowser.js
@@ -12,12 +12,23 @@ module.exports = React.createClass({
},
getInitialState: function () {
- return {blockNumber: '1382256', txNumber: '1', from: '', to: '', hash: ''}
+ return {blockNumber: '1000110', txNumber: '0x71a6d583d16d142c5c3e8903060e8a4ee5a5016348a9448df6c3e63b68076ec4', from: '', to: '', hash: ''}
},
+ // creation 0xa9619e1d0a35b2c1d686f5b661b3abd87f998d2844e8e9cc905edb57fc9ce349
+ // invokation 0x71a6d583d16d142c5c3e8903060e8a4ee5a5016348a9448df6c3e63b68076ec4
+
submit: function () {
- var tx = this.context.web3.eth.getTransactionFromBlock(this.state.blockNumber, this.state.txNumber)
+ var tx
+ if (this.state.txNumber.indexOf('0x') !== -1) {
+ tx = this.context.web3.eth.getTransaction(this.state.txNumber)
+ } else {
+ tx = this.context.web3.eth.getTransactionFromBlock(this.state.blockNumber, this.state.txNumber)
+ }
if (tx) {
+ if (!tx.to) {
+ tx.to = '(Contract Creation Code)'
+ }
this.setState({from: tx.from, to: tx.to, hash: tx.hash})
this.props.onNewTxRequested(this.state.blockNumber, parseInt(this.state.txNumber), tx)
} else {
@@ -25,6 +36,10 @@ module.exports = React.createClass({
}
},
+ updateTxhash: function (ev) {
+ this.state.hash = ev.target.value
+ },
+
updateBlockN: function (ev) {
this.state.blockNumber = ev.target.value
},
@@ -36,8 +51,8 @@ module.exports = React.createClass({
render: function () {
return (
-
+
|
-
+
|
-
+
|
-
+
|
-
+
|
diff --git a/src/web3Admin.js b/src/web3Admin.js
index a3a37661c9..492f139337 100644
--- a/src/web3Admin.js
+++ b/src/web3Admin.js
@@ -96,8 +96,8 @@ module.exports = {
params: 3
}),
new web3._extend.Method({
- name: 'trace',
- call: 'debug_trace',
+ name: 'traceTransaction',
+ call: 'debug_traceTransaction',
inputFormatter: [null, null],
params: 2
}),