parent
cfe1903a05
commit
79ae4bf993
@ -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 ( |
||||
<select |
||||
size='10' |
||||
ref='itemsList' |
||||
style={style.instructionsList} |
||||
value={this.state.selected}> |
||||
{this.renderAssemblyItems()} |
||||
</select> |
||||
) |
||||
}, |
||||
|
||||
renderAssemblyItems: function () { |
||||
if (this.state.code) { |
||||
return this.state.code.map(function (item, i) { |
||||
return <option key={i} value={i}>{item}</option> |
||||
}) |
||||
} |
||||
}, |
||||
|
||||
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) |
||||
}) |
||||
}) |
||||
} |
||||
}) |
@ -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] |
||||
} |
||||
} |
@ -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 ( |
||||
<div style={style.wrapper}> |
||||
<h1 style={style.container}>Eth Debugger</h1> |
||||
<TxBrowser onNewTxRequested={this.retrieveVmTrace} /> |
||||
<div style={style.container}> |
||||
{this.state.state} |
||||
</div> |
||||
<AssemblyItemsBrowser vmTrace={this.state.vmTrace} transaction={this.state.transaction} /> |
||||
<TxBrowser onNewTxRequested={this.startDebugging} /> |
||||
<StepManager ref='stepManager' onStepChanged={this.stepChanged} /> |
||||
<AssemblyItemsBrowser currentStepIndex={this.state.currentStepIndex} /> |
||||
</div> |
||||
) |
||||
}, |
||||
|
||||
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() |
||||
}) |
||||
} |
||||
}) |
||||
|
@ -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 ( |
||||
<div style={style.container}> |
||||
<Slider |
||||
ref='slider' |
||||
onChange={this.sliderMoved} |
||||
min='0' |
||||
max={this.state.traceLength} /> |
||||
<ButtonNavigator |
||||
stepIntoBack={this.stepIntoBack} |
||||
stepIntoForward={this.stepIntoForward} |
||||
stepOverBack={this.stepOverBack} |
||||
stepOverForward={this.stepOverForward} |
||||
jumpToNextCall={this.jumpToNextCall} |
||||
max={this.state.traceLength} /> |
||||
</div> |
||||
) |
||||
}, |
||||
|
||||
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 |
||||
}) |
||||
} |
||||
}) |
@ -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] |
||||
} |
||||
} |
||||
} |
||||
} |
||||
}) |
@ -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') |
||||
} |
||||
} |
||||
} |
Loading…
Reference in new issue