use solidityproxy to send statevar to localdecoder

pull/7/head
yann300 8 years ago
parent 3a921e35df
commit 6417483dc2
  1. 53
      src/code/sourceLocationTracker.js
  2. 93
      src/solidity/localDecoder.js
  3. 90
      src/solidity/solidityProxy.js
  4. 19
      src/ui/Ethdebugger.js
  5. 33
      src/ui/SolidityState.js
  6. 4
      src/ui/VmDebugger.js
  7. 5
      test/solidity/localDecoder.js

@ -20,18 +20,13 @@ function SourceLocationTracker (_codeManager) {
* @param {Object} contractDetails - AST of compiled contracts
* @param {Function} cb - callback function
*/
SourceLocationTracker.prototype.getSourceLocation = function (address, index, contracts, cb) {
SourceLocationTracker.prototype.getSourceLocationFromInstructionIndex = function (address, index, contracts, cb) {
var self = this
this.codeManager.getCode(address, function (error, result) {
if (!error) {
var sourceMap = getSourceMap(address, result.bytecode, contracts)
if (sourceMap) {
cb(null, self.sourceMappingDecoder.atIndex(index, sourceMap))
} else {
cb('no srcmap associated with the code ' + address)
}
} else {
extractSourceMap(this.codeManager, address, contracts, function (error, sourceMap) {
if (error) {
cb(error)
} else {
cb(null, self.sourceMappingDecoder.atIndex(index, sourceMap))
}
})
}
@ -44,22 +39,17 @@ SourceLocationTracker.prototype.getSourceLocation = function (address, index, co
* @param {Object} contractDetails - AST of compiled contracts
* @param {Function} cb - callback function
*/
SourceLocationTracker.prototype.getSourceLocation = function (address, vmtraceStepIndex, contracts, cb) {
SourceLocationTracker.prototype.getSourceLocationFromVMTraceIndex = function (address, vmtraceStepIndex, contracts, cb) {
var self = this
this.codeManager.getCode(address, function (error, result) {
extractSourceMap(this.codeManager, address, contracts, function (error, sourceMap) {
if (!error) {
var sourceMap = getSourceMap(address, result.bytecode, contracts)
if (sourceMap) {
self.codeManager.getInstructionIndex(address, vmtraceStepIndex, function (error, index) {
if (error) {
cb(error)
} else {
cb(null, self.sourceMappingDecoder.atIndex(index, sourceMap))
}
})
} else {
cb('no srcmap associated with the code ' + address)
}
self.codeManager.getInstructionIndex(address, vmtraceStepIndex, function (error, index) {
if (error) {
cb(error)
} else {
cb(null, self.sourceMappingDecoder.atIndex(index, sourceMap))
}
})
} else {
cb(error)
}
@ -84,4 +74,19 @@ function getSourceMap (address, code, contracts) {
return null
}
function extractSourceMap (codeManager, address, contracts, cb) {
codeManager.getCode(address, function (error, result) {
if (!error) {
var sourceMap = getSourceMap(address, result.bytecode, contracts)
if (sourceMap) {
cb(null, sourceMap)
} else {
cb('no srcmap associated with the code ' + address)
}
} else {
cb(error)
}
})
}
module.exports = SourceLocationTracker

@ -3,56 +3,57 @@ var SourceLocationTracker = require('../code/sourceLocationTracker')
var AstWalker = require('../util/astWalker')
var decodeInfo = require('../solidity/decodeInfo')
function LocalDecoder (parent, codeManager, traceAnalyserEvent) {
this.astWalker = new AstWalker()
this.codeManager = codeManager
this.parent = parent
this.locals = {}
this.loading = false
this.sourceLocationTracker = new SourceLocationTracker(this.codeManager)
var self = this
traceAnalyserEvent.register('startAnalysing', function (step) {
self.clear()
})
traceAnalyserEvent.register('onOp', function (index, step, callStack, cache) {
self.push(index, step, callStack, cache)
})
traceAnalyserEvent.register('finishAnalysing', function (index, step) {
self.loading = true
})
}
LocalDecoder.prototype.push = function (index, step, callStack, cache) {
if (!this.parent.sources) return
if (step.op.indexOf('PUSH') === 0) {
class LocalDecoder {
constructor (codeManager, traceAnalyserEvent, solidityProxy) {
this.astWalker = new AstWalker()
this.sourceLocationTracker = new SourceLocationTracker(codeManager)
this.solidityProxy = solidityProxy
this.locals = {}
var self = this
var compiledContracts = this.parent.contracts
var address = callStack[callStack.length - 1]
this.sourceLocationTracker.getSourceLocation(address, index, compiledContracts, function (error, result) {
if (error) {
console.log(error)
} else {
var file = self.parent.sourceList[result.file]
var ast = self.parent.sources[file].AST
self.astWalker.walk(ast, function (node) {
if (node.name === 'VariableDeclaration' && node.src.indexOf(result.start + ':' + result.length) === 0) {
self.locals[node.attributes.name] = {
type: decodeInfo.parseType(node.attributes.type, []),
stack: step.stack
}
return false
} else {
return true
}
})
}
traceAnalyserEvent.register('startAnalysing', function (step) {
self.clear()
})
traceAnalyserEvent.register('onOp', function (index, step, callStack, cache) {
self.push(index, step, callStack, cache)
})
traceAnalyserEvent.register('finishAnalysing', function (index, step) {
})
}
}
LocalDecoder.prototype.clear = function () {
this.loading = false
this.locals = {}
push (index, step, callStack, cache) {
if (!this.solidityProxy.loaded()) return
if (step.op.indexOf('PUSH') === 0) {
var address = callStack[callStack.length - 1]
this.sourceLocationTracker.getSourceLocationFromVMTraceIndex(address, index, this.solidityProxy.contracts, (error, result) => {
if (error) {
console.log(error)
} else {
var ast = this.solidityProxy.ast(result)
this.solidityProxy.extractStateVariablesAt(index, (error, stateVars) => { // cached
if (error) {
console.log(error)
} else {
this.astWalker.walk(ast, (node) => {
if (node.name === 'VariableDeclaration' && node.src.indexOf(result.start + ':' + result.length) === 0) {
this.locals[node.attributes.name] = {
type: decodeInfo.parseType(node.attributes.type, stateVars),
stack: step.stack
}
return false
} else {
return true
}
})
}
})
}
})
}
}
clear () {
this.locals = {}
}
}
module.exports = LocalDecoder

@ -0,0 +1,90 @@
'use strict'
var traceHelper = require('../helpers/traceHelper')
var stateDecoder = require('./stateDecoder')
class SolidityProxy {
constructor (traceManager, codeManager) {
this.cache = new Cache()
this.reset({})
this.traceManager = traceManager
this.codeManager = codeManager
}
reset (compilationResult) {
this.sources = compilationResult.sources
this.sourceList = compilationResult.sourceList
this.contracts = compilationResult.contracts
this.cache.reset()
}
loaded () {
return this.contracts !== undefined
}
contractNameAt (vmTraceIndex, cb) {
this.traceManager.getCurrentCalledAddressAt(vmTraceIndex, (error, address) => {
if (error) {
cb(error)
} else {
if (this.cache.contractNameByAddress[address]) {
cb(null, this.cache.contractNameByAddress[address])
} else {
this.codeManager.getCode(address, (error, code) => {
if (error) {
cb(error)
} else {
var contractName = contractNameFromCode(this.contracts, code.bytecode, address)
this.cache.contractNameByAddress[address] = contractName
cb(null, contractName)
}
})
}
}
})
}
extractStateVariables (contractName) {
if (!this.cache.stateVariablesByContractName[contractName]) {
this.cache.stateVariablesByContractName[contractName] = stateDecoder.extractStateVariables(contractName, this.sources)
}
return this.cache.stateVariablesByContractName[contractName]
}
extractStateVariablesAt (vmtraceIndex, cb) {
this.contractNameAt(vmtraceIndex, (error, contractName) => {
if (error) {
cb(error)
} else {
cb(null, this.extractStateVariables(contractName))
}
})
}
ast (sourceLocation) {
var file = this.sourceList[sourceLocation.file]
return this.sources[file].AST
}
}
function contractNameFromCode (contracts, code, address) {
var isCreation = traceHelper.isContractCreation(address)
var byteProp = isCreation ? 'bytecode' : 'runtimeBytecode'
for (var k in contracts) {
if ('0x' + contracts[k][byteProp] === code) {
return k
}
}
return null
}
class Cache {
constructor () {
this.reset()
}
reset () {
this.contractNameByAddress = {}
this.stateVariablesByContractName = {}
}
}
module.exports = SolidityProxy

@ -11,16 +11,14 @@ var ui = require('../helpers/ui')
var Web3Providers = require('../web3Provider/web3Providers')
var DummyProvider = require('../web3Provider/dummyProvider')
var CodeManager = require('../code/codeManager')
var SourceLocationTracker = require('../code/sourceLocationTracker')
var LocalDecoder = require('../solidity/localDecoder')
var SolidityProxy = require('../solidity/solidityProxy')
function Ethdebugger () {
this.event = new EventManager()
this.currentStepIndex = -1
this.tx
this.sources
this.contracts
this.statusMessage = ''
this.view
@ -29,9 +27,8 @@ function Ethdebugger () {
this.switchProvider('DUMMYWEB3')
this.traceManager = new TraceManager()
this.codeManager = new CodeManager(this.traceManager)
this.sourceLocationTracker = new SourceLocationTracker(this.codeManager)
this.locals = new LocalDecoder(this, this.codeManager, this.traceManager.traceAnalyser.event)
this.solidityProxy = new SolidityProxy(this.traceManager, this.codeManager)
this.locals = new LocalDecoder(this.codeManager, this.traceManager.traceAnalyser.event, this.solidityProxy)
var self = this
this.event.register('indexChanged', this, function (index) {
self.codeManager.resolveStep(index, self.tx)
@ -51,7 +48,7 @@ function Ethdebugger () {
this.stepManager.event.register('stepChanged', this, function (stepIndex) {
self.stepChanged(stepIndex)
})
this.vmDebugger = new VmDebugger(this, this.traceManager, this.codeManager)
this.vmDebugger = new VmDebugger(this, this.traceManager, this.codeManager, this.solidityProxy)
}
Ethdebugger.prototype.web3 = function () {
@ -77,13 +74,9 @@ Ethdebugger.prototype.switchProvider = function (type) {
Ethdebugger.prototype.setCompilationResult = function (compilationResult) {
if (compilationResult && compilationResult.sources && compilationResult.contracts) {
this.sources = compilationResult.sources
this.sourceList = compilationResult.sourceList
this.contracts = compilationResult.contracts
this.solidityProxy.reset(compilationResult)
} else {
this.sources = null
this.contracts = null
this.sourceList = null
this.solidityProxy.reset({})
}
}

@ -1,13 +1,13 @@
'use strict'
var DropdownPanel = require('./DropdownPanel')
var traceHelper = require('../helpers/traceHelper')
var stateDecoder = require('../solidity/stateDecoder')
var yo = require('yo-yo')
function SolidityState (_parent, _traceManager, _codeManager) {
function SolidityState (_parent, _traceManager, _codeManager, _solidityProxy) {
this.parent = _parent
this.traceManager = _traceManager
this.codeManager = _codeManager
this.solidityProxy = _solidityProxy
this.basicPanel = new DropdownPanel('Solidity State')
this.init()
}
@ -24,7 +24,7 @@ SolidityState.prototype.init = function () {
return
}
if (self.parent.currentStepIndex !== index) return
if (!this.parent.contracts || !this.parent.sources) {
if (!this.solidityProxy.loaded()) {
self.basicPanel.update({info: 'no source has been specified'})
return
}
@ -33,23 +33,11 @@ SolidityState.prototype.init = function () {
if (error) {
self.basicPanel.update({ info: error })
} else {
self.traceManager.getCurrentCalledAddressAt(index, function (error, address) {
self.solidityProxy.extractStateVariablesAt(index, function (error, stateVars) {
if (error) {
self.basicPanel.update({ info: error })
} else {
self.codeManager.getCode(address, function (error, code) {
if (error) {
self.basicPanel.update({ info: error })
} else {
var contractName = contractNameFromCode(self.parent.contracts, code.bytecode, address)
if (contractName === null) {
self.basicPanel.update({ info: 'could not find compiled contract with address ' + address })
} else {
var state = stateDecoder.solidityState(storage, self.parent.sources, contractName)
self.basicPanel.update(state)
}
}
})
self.basicPanel.update(stateDecoder.decodeState(stateVars, storage))
}
})
}
@ -57,15 +45,4 @@ SolidityState.prototype.init = function () {
})
}
function contractNameFromCode (contracts, code, address) {
var isCreation = traceHelper.isContractCreation(address)
var byteProp = isCreation ? 'bytecode' : 'runtimeBytecode'
for (var k in contracts) {
if ('0x' + contracts[k][byteProp] === code) {
return k
}
}
return null
}
module.exports = SolidityState

@ -11,7 +11,7 @@ var DropdownPanel = require('./DropdownPanel')
var SolidityState = require('./SolidityState')
var yo = require('yo-yo')
function VmDebugger (_parent, _traceManager, _codeManager) {
function VmDebugger (_parent, _traceManager, _codeManager, _solidityProxy) {
this.asmCode = new CodeListView(_parent, _codeManager)
this.stackPanel = new StackPanel(_parent, _traceManager)
this.storagePanel = new StoragePanel(_parent, _traceManager)
@ -19,7 +19,7 @@ function VmDebugger (_parent, _traceManager, _codeManager) {
this.calldataPanel = new CalldataPanel(_parent, _traceManager)
this.callstackPanel = new CallstackPanel(_parent, _traceManager)
this.stepDetail = new StepDetail(_parent, _traceManager)
this.solidityState = new SolidityState(_parent, _traceManager, _codeManager)
this.solidityState = new SolidityState(_parent, _traceManager, _codeManager, _solidityProxy)
/* Return values - */
this.returnValuesPanel = new DropdownPanel('Return Value')

@ -13,6 +13,7 @@ var Web3Providers = require('../../src/web3Provider/web3Providers')
var traceHelper = require('../../src/helpers/traceHelper')
var util = require('../../src/helpers/global')
var LocalDecoder = require('../../src/solidity/localDecoder')
var SolidityProxy = require('../../src/solidity/solidityProxy')
tape('solidity', function (t) {
t.test('local decoder', function (st) {
@ -32,7 +33,9 @@ tape('solidity', function (t) {
tx.to = traceHelper.contractCreationToken('0')
var traceManager = new TraceManager()
var codeManager = new CodeManager(traceManager)
var localDecoder = new LocalDecoder(output, codeManager, traceManager.traceAnalyser.event)
var solidityProxy = new SolidityProxy(traceManager, codeManager)
solidityProxy.reset(output)
var localDecoder = new LocalDecoder(codeManager, traceManager.traceAnalyser.event, solidityProxy)
traceManager.resolveTrace(tx, function (error, result) {
if (error) {
st.fail(error)

Loading…
Cancel
Save