Commit ee7e8558 authored by yann300's avatar yann300

declare traceManager func in prototype

parent 505d7436
...@@ -3,14 +3,15 @@ var React = require('react') ...@@ -3,14 +3,15 @@ var React = require('react')
var TxBrowser = require('./txBrowser') var TxBrowser = require('./txBrowser')
var StepManager = require('./stepManager') var StepManager = require('./stepManager')
var AssemblyItemsBrowser = require('./vmDebugger') var AssemblyItemsBrowser = require('./vmDebugger')
var traceManager = require('./traceManager') var TraceManager = require('./traceManager')
var style = require('./basicStyles') var style = require('./basicStyles')
module.exports = React.createClass({ module.exports = React.createClass({
getInitialState: function () { getInitialState: function () {
return { return {
currentStepIndex: -1, // index of the selected item in the vmtrace currentStepIndex: -1, // index of the selected item in the vmtrace
tx: null tx: null,
traceManager: null
} }
}, },
...@@ -23,13 +24,15 @@ module.exports = React.createClass({ ...@@ -23,13 +24,15 @@ module.exports = React.createClass({
getChildContext: function () { getChildContext: function () {
return { return {
web3: this.props.web3, web3: this.props.web3,
traceManager: traceManager, traceManager: this.state.traceManager,
tx: this.state.tx tx: this.state.tx
} }
}, },
componentDidMount: function () { componentDidMount: function () {
traceManager.setWeb3(this.props.web3) this.setState({
traceManager: new TraceManager(this.props.web3)
})
}, },
render: function () { render: function () {
...@@ -50,7 +53,7 @@ module.exports = React.createClass({ ...@@ -50,7 +53,7 @@ module.exports = React.createClass({
}, },
startDebugging: function (blockNumber, txIndex, tx) { startDebugging: function (blockNumber, txIndex, tx) {
if (traceManager.isLoading) { if (this.state.traceManager.isLoading) {
return return
} }
console.log('loading trace...') console.log('loading trace...')
...@@ -58,7 +61,7 @@ module.exports = React.createClass({ ...@@ -58,7 +61,7 @@ module.exports = React.createClass({
tx: tx tx: tx
}) })
var self = this var self = this
traceManager.resolveTrace(blockNumber, txIndex, function (success) { this.state.traceManager.resolveTrace(blockNumber, txIndex, function (success) {
console.log('trace loaded ' + success) console.log('trace loaded ' + success)
self.setState({ self.setState({
currentStepIndex: 0 currentStepIndex: 0
......
'use strict' 'use strict'
module.exports = { function TraceManager (_web3) {
isLoading: false, this.web3 = _web3
web3: null,
transaction: null, this.isLoading = false
trace: null, this.trace = null
// vmtrace changes section // vmtrace changes section
depthChanges: [], this.depthChanges = []
callStack: {}, this.callStack = {}
memoryChanges: [], this.memoryChanges = []
callDataChanges: [], this.callDataChanges = []
// storage section // storage section
storageChanges: [], this.storageChanges = []
vmTraceIndexByStorageChange: {}, this.vmTraceIndexByStorageChange = {}
vmTraceChangesRef: [], this.vmTraceChangesRef = []
storages: {}, this.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
}
}
},
// compute trace section // init section
buildCalldata: function (index, step) { TraceManager.prototype.resolveTrace = function (blockNumber, txNumber, callback) {
if (step.calldata) { this.isLoading = true
this.callDataChanges.push(index) 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) { TraceManager.prototype.init = function () {
if (step.memory) { this.trace = null
this.memoryChanges.push(index) this.depthChanges = []
} this.memoryChanges = []
}, this.callDataChanges = []
this.storageChanges = []
buildStorage: function (index, step, currentAddress) { this.vmTraceIndexByStorageChange = {}
var change = false this.vmTraceChangesRef = []
if (step.address) { this.callStack = {}
// 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) { TraceManager.prototype.computeTrace = function (trace) {
this.vmTraceIndexByStorageChange[index] = { this.trace = trace
context: this.storageChanges.length - 1, var currentDepth = 0
changes: this.storageChanges[this.storageChanges.length - 1].changes.length - 1 var currentStorageAddress
} var callStack = []
this.vmTraceChangesRef.push(index) 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) { // compute trace section
if (step.depth === undefined) return TraceManager.prototype.buildCalldata = function (index, step) {
if (step.depth > currentDepth) { if (step.calldata) {
if (index === 0) { this.callDataChanges.push(index)
callStack.push('0x' + step.address) // new context }
} else { }
// getting the address from the stack
var callTrace = this.trace[index - 1] TraceManager.prototype.buildMemory = function (index, step) {
var address = callTrace.stack[callTrace.stack.length - 2] if (step.memory) {
callStack.push(address) // new context this.memoryChanges.push(index)
} }
} else if (step.depth < currentDepth) { }
callStack.pop() // returning from context
} TraceManager.prototype.buildStorage = function (index, step, currentAddress) {
this.callStack[index] = { var change = false
stack: callStack.slice(0), if (step.address) {
depth: step.depth, // new context
address: step.address this.storageChanges.push({ address: step.address, changes: [] })
} change = true
this.depthChanges.push(index) } else if (step.inst === 'SSTORE') {
return step.depth this.storageChanges[this.storageChanges.length - 1].changes.push(
}, {
'key': step.stack[step.stack.length - 1],
// API section 'value': step.stack[step.stack.length - 2]
getLength: function (callback) { })
if (!this.trace) callback('no trace available', null) change = true
callback(null, this.trace.length) } else if (!step.address && step.depth) {
}, // returned from context
var address = this.storageChanges[this.storageChanges.length - 2].address
getStorageAt: function (stepIndex, blockNumber, txIndex, callback) { this.storageChanges.push({ address: address, changes: [] })
var stoChange = this.findLowerBound(stepIndex, this.vmTraceChangesRef) change = true
if (!stoChange) { }
callback('cannot rebuild storage', null)
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] TraceManager.prototype.buildDepth = function (index, step, currentDepth, callStack) {
var address = this.storageChanges[changeRefs.context].address if (step.depth === undefined) return
var self = this if (step.depth > currentDepth) {
this.retrieveStorage(address, blockNumber, txIndex, function (storage) { if (index === 0) {
for (var k = 0; k < changeRefs.context; k++) { callStack.push('0x' + step.address) // new context
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)
} else { } 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) { // API section
var depthIndex = this.findLowerBound(stepIndex, this.depthChanges) TraceManager.prototype.getLength = function (callback) {
callback(null, depthIndex) if (!this.trace) callback('no trace available', null)
}, callback(null, this.trace.length)
}
getCurrentCalledAddressAt: function (stepIndex, callback) { TraceManager.prototype.getStorageAt = function (stepIndex, blockNumber, txIndex, callback) {
var self = this var stoChange = this.findLowerBound(stepIndex, this.vmTraceChangesRef)
this.getLastDepthIndexChangeSince(stepIndex, function (error, addressIndex) { if (!stoChange) {
if (error) { callback('cannot rebuild storage', null)
callback(error, null) }
} else {
callback(null, self.resolveAddress(addressIndex)) 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) { TraceManager.prototype.getCallStackAt = function (stepIndex, callback) {
if (this.isCallInstruction(currentStep)) { var callStackChange = this.findLowerBound(stepIndex, this.depthChanges)
return this.findStepOutForward(currentStep) 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 { } else {
return currentStep + 1 callback(null, self.resolveAddress(addressIndex))
}
},
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) { TraceManager.prototype.getMemoryAt = function (stepIndex, callback) {
var i = currentStep var lastChanges = this.findLowerBound(stepIndex, this.memoryChanges)
var depth = 0 if (!lastChanges) return callback('no memory found', null)
while (++i < this.trace.length) { callback(null, this.trace[lastChanges].memory)
if (this.isReturnInstruction(i)) { }
if (depth === 0) {
break TraceManager.prototype.getCurrentPC = function (stepIndex, callback) {
} else { callback(null, this.trace[stepIndex].pc)
depth-- }
}
} else if (this.isCallInstruction(i)) { TraceManager.prototype.getCurrentStep = function (stepIndex, callback) {
depth++ 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 }
}, return i
}
// util section
findLowerBound: function (target, changes) { TraceManager.prototype.findStepOutForward = function (currentStep) {
if (changes.length === 1) { var i = currentStep
if (changes[0] > target) { var depth = 0
// we only a closest maximum, returning 0 while (++i < this.trace.length) {
return null if (this.isReturnInstruction(i)) {
if (depth === 0) {
break
} else { } else {
return changes[0] depth--
} }
} else if (this.isCallInstruction(i)) {
depth++
} }
}
return i + 1
}
var middle = Math.floor(changes.length / 2) // util section
if (changes[middle] > target) { TraceManager.prototype.findLowerBound = function (target, changes) {
return this.findLowerBound(target, changes.slice(0, middle)) if (changes.length === 1) {
} else if (changes[middle] < target) { if (changes[0] > target) {
return this.findLowerBound(target, changes.slice(middle, changes.length)) // we only a closest maximum, returning 0
return null
} else { } else {
return changes[middle] return changes[0]
} }
}, }
resolveAddress: function (vmTraceIndex) { var middle = Math.floor(changes.length / 2)
var address = this.trace[vmTraceIndex].address if (changes[middle] > target) {
if (vmTraceIndex > 0) { return this.findLowerBound(target, changes.slice(0, middle))
var stack = this.trace[vmTraceIndex - 1].stack // callcode, delegatecall, ... } else if (changes[middle] < target) {
address = stack[stack.length - 2] return this.findLowerBound(target, changes.slice(middle, changes.length))
} } else {
return address return changes[middle]
}, }
}
// retrieve the storage of an account just after the execution of tx TraceManager.prototype.resolveAddress = function (vmTraceIndex) {
retrieveStorage: function (address, blockNumber, txIndex, callBack) { var address = this.trace[vmTraceIndex].address
if (this.storages[address]) { if (vmTraceIndex > 0) {
callBack(this.storages[address]) var stack = this.trace[vmTraceIndex - 1].stack // callcode, delegatecall, ...
} address = stack[stack.length - 2]
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 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
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment