Merge pull request #512 from ethereum/improvemappingdecoder

Improve mapping decoder
pull/7/head
chriseth 8 years ago committed by GitHub
commit 415b1cf16e
  1. 52
      src/solidity/types/Mapping.js
  2. 4
      src/storage/mappingPreimages.js
  3. 52
      src/storage/storageViewer.js
  4. 44
      src/ui/SolidityState.js

@ -8,31 +8,25 @@ class Mapping extends RefType {
super(1, 32, fullType, 'storage')
this.keyType = underlyingTypes.keyType
this.valueType = underlyingTypes.valueType
this.initialDecodedState = null
}
async decodeFromStorage (location, storageResolver) {
var mappingsPreimages
try {
mappingsPreimages = await storageResolver.mappingsLocation()
} catch (e) {
return {
value: e.message,
type: this.typeName
if (!this.initialDecodedState) { // cache the decoded initial storage
var mappingsInitialPreimages
try {
mappingsInitialPreimages = await storageResolver.initialMappingsLocation()
this.initialDecodedState = await this.decodeMappingsLocation(mappingsInitialPreimages, location, storageResolver)
} catch (e) {
return {
value: e.message,
type: this.typeName
}
}
}
var mapSlot = util.normalizeHex(ethutil.bufferToHex(location.slot))
console.log(mapSlot, mappingsPreimages)
var mappingPreimages = mappingsPreimages[mapSlot]
var ret = {}
for (var i in mappingPreimages) {
var mapLocation = getMappingLocation(i, location.slot)
var globalLocation = {
offset: location.offset,
slot: mapLocation
}
ret[i] = await this.valueType.decodeFromStorage(globalLocation, storageResolver)
}
var mappingPreimages = await storageResolver.mappingsLocation()
var ret = await this.decodeMappingsLocation(mappingPreimages, location, storageResolver) // fetch mapping storage changes
ret = Object.assign({}, this.initialDecodedState, ret) // merge changes
return {
value: ret,
type: this.typeName
@ -48,6 +42,24 @@ class Mapping extends RefType {
type: this.typeName
}
}
async decodeMappingsLocation (preimages, location, storageResolver) {
var mapSlot = util.normalizeHex(ethutil.bufferToHex(location.slot))
if (!preimages[mapSlot]) {
return {}
}
var ret = {}
for (var i in preimages[mapSlot]) {
var mapLocation = getMappingLocation(i, location.slot)
var globalLocation = {
offset: location.offset,
slot: mapLocation
}
ret[i] = await this.valueType.decodeFromStorage(globalLocation, storageResolver)
console.log('global location', globalLocation, i, ret[i])
}
return ret
}
}
function getMappingLocation (key, position) {

@ -43,9 +43,9 @@ async function decodeMappingsKeys (storage, callback) {
*/
function getPreimage (key) {
return new Promise((resolve, reject) => {
global.web3.debug.preimage(key, function (error, preimage) {
global.web3.debug.preimage(key.indexOf('0x') === 0 ? key : '0x' + key, function (error, preimage) {
if (error) {
reject(error)
resolve(null)
} else {
resolve(preimage)
}

@ -11,7 +11,8 @@ class StorageViewer {
constructor (_context, _storageResolver, _traceManager) {
this.context = _context
this.storageResolver = _storageResolver
this.completeMapingsLocationPromise = null
this.initialMappingsLocationPromise = null
this.currentMappingsLocationPromise = null
_traceManager.accumulateStorageChanges(this.context.stepIndex, this.context.address, {}, (error, storageChanges) => {
if (!error) {
this.storageChanges = storageChanges
@ -67,38 +68,43 @@ class StorageViewer {
}
/**
* return all the possible mappings locations for the current context (cached)
* return all the possible mappings locations for the current context (cached) do not return state changes during the current transaction
*
* @param {Function} callback
*/
async mappingsLocation () {
if (!this.completeMapingsLocationPromise) {
this.completeMapingsLocationPromise = new Promise((resolve, reject) => {
if (this.completeMappingsLocation) {
return this.completeMappingsLocation
}
async initialMappingsLocation () {
if (!this.initialMappingsLocationPromise) {
this.initialMappingsLocationPromise = new Promise((resolve, reject) => {
this.storageResolver.initialPreimagesMappings(this.context.tx, this.context.stepIndex, this.context.address, (error, initialMappingsLocation) => {
if (error) {
reject(error)
} else {
this.extractMappingsLocationChanges(this.storageChanges, (error, mappingsLocationChanges) => {
if (error) {
return reject(error)
}
this.completeMappingsLocation = Object.assign({}, initialMappingsLocation)
for (var key in mappingsLocationChanges) {
if (!initialMappingsLocation[key]) {
initialMappingsLocation[key] = {}
}
this.completeMappingsLocation[key] = Object.assign({}, initialMappingsLocation[key], mappingsLocationChanges[key])
}
resolve(this.completeMappingsLocation)
})
resolve(initialMappingsLocation)
}
})
})
}
return this.completeMapingsLocationPromise
return this.initialMappingsLocationPromise
}
/**
* return all the possible mappings locations for the current context (cached) and current mapping slot. returns state changes during the current transaction
*
* @param {Function} callback
*/
async mappingsLocation () {
if (!this.currentMappingsLocationPromise) {
this.currentMappingsLocationPromise = new Promise((resolve, reject) => {
this.extractMappingsLocationChanges(this.storageChanges, (error, mappingsLocationChanges) => {
if (error) {
reject(error)
} else {
resolve(mappingsLocationChanges)
}
})
})
}
return this.currentMappingsLocationPromise
}
/**
@ -121,6 +127,4 @@ class StorageViewer {
}
}
module.exports = StorageViewer

@ -18,6 +18,7 @@ function SolidityState (_parent, _traceManager, _codeManager, _solidityProxy) {
})
this.init()
this.view
this.stateVariablesByAddresses = {}
}
SolidityState.prototype.render = function () {
@ -54,26 +55,35 @@ SolidityState.prototype.init = function () {
self.basicPanel.update({})
console.log(error)
} else {
self.solidityProxy.extractStateVariablesAt(index, function (error, stateVars) {
if (error) {
self.basicPanel.update({})
console.log(error)
} else {
var storageViewer = new StorageViewer({
stepIndex: self.parent.currentStepIndex,
tx: self.parent.tx,
address: address
}, self.storageResolver, self.traceManager)
stateDecoder.decodeState(stateVars, storageViewer).then((result) => {
if (!result.error) {
self.basicPanel.update(result)
}
})
}
})
if (self.stateVariablesByAddresses[address]) {
extractStateVariables(self, self.stateVariablesByAddresses[address], address)
} else {
self.solidityProxy.extractStateVariablesAt(index, function (error, stateVars) {
if (error) {
self.basicPanel.update({})
console.log(error)
} else {
self.stateVariablesByAddresses[address] = stateVars
extractStateVariables(self, stateVars, address)
}
})
}
}
})
})
}
function extractStateVariables (self, stateVars, address) {
var storageViewer = new StorageViewer({
stepIndex: self.parent.currentStepIndex,
tx: self.parent.tx,
address: address
}, self.storageResolver, self.traceManager)
stateDecoder.decodeState(stateVars, storageViewer).then((result) => {
if (!result.error) {
self.basicPanel.update(result)
}
})
}
module.exports = SolidityState

Loading…
Cancel
Save