align trace with geth trace

pull/7/head
yann300 9 years ago
parent 7a90aee4d4
commit 006dc9b32a
  1. 18
      src/asmCode.js
  2. 29
      src/basicPanel.js
  3. 23
      src/buttonNavigator.js
  4. 10
      src/calldataPanel.js
  5. 10
      src/callstackPanel.js
  6. 11
      src/codeResolver.js
  7. 2
      src/debugger.js
  8. 39
      src/memoryPanel.js
  9. 10
      src/stackPanel.js
  10. 2
      src/stepManager.js
  11. 25
      src/storagePanel.js
  12. 81
      src/traceAnalyser.js
  13. 19
      src/traceCache.js
  14. 165
      src/traceManager.js
  15. 38
      src/traceManagerUtil.js
  16. 22
      src/traceRetriever.js
  17. 34
      src/traceStepManager.js
  18. 47
      src/txBrowser.js
  19. 10
      src/vmDebugger.js
  20. 4
      src/web3Admin.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) {

@ -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}
</div>
<div style={style.panel.tableContainer}>
<table style={style.panel.table}>
<tbody>
{this.renderItems()}
</tbody>
</table>
<pre style={Object.assign(style.panel.table, style.font)} >{this.props.data}</pre>
</div>
</div>
)
},
renderItems: function () {
if (!this.props.data) {
return []
}
if (!this.props.renderRow) {
var ret = []
for (var key in this.props.data) {
ret.push(
<tr key={key}>
<td>
<pre style={style.font} >{this.props.data[key]}</pre>
</td>
</tr>)
}
return ret
} else {
return this.props.renderRow(this.props.data)
}
}
})

@ -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({
<button onClick={this.props.stepIntoForward} disabled={this.checkButtonState(1)}>
Step Into Forward
</button>
<button onClick={this.props.jumpNextCall} disabled={this.checkButtonState(1)}>
Jump Next Call
</button>
</div>
)
},
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' : ''
}
})
}
})

@ -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
}
})

@ -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
}
})

@ -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]

@ -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

@ -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 (
<BasicPanel name='Memory' data={this.state.data} renderRow={this.renderMemoryRow} />
<BasicPanel name='Memory' data={this.state.data} />
)
},
@ -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(
<tr key={key}>
<td>
<pre style={style.font}>{memSlot.address}</pre>
</td>
<td>
<pre style={style.font}>{memSlot.content.raw}</pre>
</td>
<td>
<pre style={style.font}>{memSlot.content.ascii}</pre>
</td>
</tr>)
}
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
},

@ -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
}
})

@ -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} />
</div>
)

@ -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 (
<BasicPanel name='Storage' data={this.state.data} renderRow={this.renderStorageRow} />
<BasicPanel name='Storage' data={this.state.data} />
)
},
@ -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(
<tr key={key}>
<td>
<pre style={style.font} >{key}</pre>
</td>
<td>
<pre style={style.font}>{data[key]}</pre>
</td>
</tr>)
}
formatStorage: function (storage) {
var ret = ''
for (var key in storage) {
ret += key + ' ' + storage[key] + '\n'
}
return ret
}

@ -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

@ -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) {

@ -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

@ -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
}
}
}

@ -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

@ -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

@ -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 (
<div style={style.container}>
<input onChange={this.updateBlockN} type='text' placeholder={'Block number or hash (default 1382256)' + this.state.blockNumber}></input>
<input onChange={this.updateTxN} type='text' placeholder={'Transaction Number (default 1) ' + this.state.txNumber}></input>
<input onChange={this.updateBlockN} type='text' placeholder={'Block number (default 1000110)' + this.state.blockNumber}></input>
<input onChange={this.updateTxN} type='text' placeholder={'Transaction Number or hash (default 2) ' + this.state.txNumber}></input>
<button onClick={this.submit}>
Get
</button>
@ -45,16 +60,28 @@ module.exports = React.createClass({
<table>
<tbody>
<tr>
<td>Hash: </td>
<td>{this.state.hash}</td>
<td>
Hash:
</td>
<td>
{this.state.hash}
</td>
</tr>
<tr>
<td>From: </td>
<td>{this.state.from}</td>
<td>
From:
</td>
<td>
{this.state.from}
</td>
</tr>
<tr>
<td>To: </td>
<td>{this.state.to}</td>
<td>
To:
</td>
<td>
{this.state.to}
</td>
</tr>
</tbody>
</table>

@ -43,23 +43,23 @@ module.exports = React.createClass({
</div>
</td>
<td>
<CalldataPanel currentStepIndex={this.props.currentStepIndex} />
<StackPanel currentStepIndex={this.props.currentStepIndex} />
</td>
</tr>
<tr>
<td>
<StackPanel currentStepIndex={this.props.currentStepIndex} />
<StoragePanel currentStepIndex={this.props.currentStepIndex} />
</td>
<td>
<CallstackPanel currentStepIndex={this.props.currentStepIndex} />
<MemoryPanel currentStepIndex={this.props.currentStepIndex} />
</td>
</tr>
<tr>
<td>
<StoragePanel currentStepIndex={this.props.currentStepIndex} />
<CalldataPanel currentStepIndex={this.props.currentStepIndex} />
</td>
<td>
<MemoryPanel currentStepIndex={this.props.currentStepIndex} />
<CallstackPanel currentStepIndex={this.props.currentStepIndex} />
</td>
</tr>
</tbody>

@ -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
}),

Loading…
Cancel
Save