Merge pull request #905 from ethereum/fixStructinMapping

Fix Decoding struct in mapping
pull/5370/head
yann300 6 years ago committed by GitHub
commit 77ede5f588
  1. 5
      remix-debug/src/solidity-decoder/types/Mapping.js
  2. 5
      remix-debug/src/solidity-decoder/types/util.js
  3. 12
      remix-debug/src/storage/mappingPreimages.js
  4. 8
      remix-debug/src/storage/storageResolver.js
  5. 20
      remix-debug/src/storage/storageViewer.js

@ -12,10 +12,11 @@ class Mapping extends RefType {
} }
async decodeFromStorage (location, storageResolver) { async decodeFromStorage (location, storageResolver) {
var corrections = this.valueType.members ? this.valueType.members.map((value) => { return value.storagelocation }) : []
if (!this.initialDecodedState) { // cache the decoded initial storage if (!this.initialDecodedState) { // cache the decoded initial storage
var mappingsInitialPreimages var mappingsInitialPreimages
try { try {
mappingsInitialPreimages = await storageResolver.initialMappingsLocation() mappingsInitialPreimages = await storageResolver.initialMappingsLocation(corrections)
this.initialDecodedState = await this.decodeMappingsLocation(mappingsInitialPreimages, location, storageResolver) this.initialDecodedState = await this.decodeMappingsLocation(mappingsInitialPreimages, location, storageResolver)
} catch (e) { } catch (e) {
return { return {
@ -24,7 +25,7 @@ class Mapping extends RefType {
} }
} }
} }
var mappingPreimages = await storageResolver.mappingsLocation() var mappingPreimages = await storageResolver.mappingsLocation(corrections)
var ret = await this.decodeMappingsLocation(mappingPreimages, location, storageResolver) // fetch mapping storage changes var ret = await this.decodeMappingsLocation(mappingPreimages, location, storageResolver) // fetch mapping storage changes
ret = Object.assign({}, this.initialDecodedState, ret) // merge changes ret = Object.assign({}, this.initialDecodedState, ret) // merge changes
return { return {

@ -9,6 +9,7 @@ module.exports = {
extractHexByteSlice: extractHexByteSlice, extractHexByteSlice: extractHexByteSlice,
toBN: toBN, toBN: toBN,
add: add, add: add,
sub: sub,
extractLocation: extractLocation, extractLocation: extractLocation,
removeLocation: removeLocation, removeLocation: removeLocation,
normalizeHex: normalizeHex, normalizeHex: normalizeHex,
@ -88,6 +89,10 @@ function add (value1, value2) {
return toBN(value1).add(toBN(value2)) return toBN(value1).add(toBN(value2))
} }
function sub (value1, value2) {
return toBN(value1).sub(toBN(value2))
}
function removeLocation (type) { function removeLocation (type) {
return type.replace(/( storage ref| storage pointer| memory| calldata)/g, '') return type.replace(/( storage ref| storage pointer| memory| calldata)/g, '')
} }

@ -1,3 +1,4 @@
var util = require('../solidity-decoder/types/util')
module.exports = { module.exports = {
decodeMappingsKeys: decodeMappingsKeys decodeMappingsKeys: decodeMappingsKeys
@ -8,15 +9,22 @@ module.exports = {
* like { "<mapping_slot>" : { "<mapping-key1>": preimageOf1 }, { "<mapping-key2>": preimageOf2 }, ... } * like { "<mapping_slot>" : { "<mapping-key1>": preimageOf1 }, { "<mapping-key2>": preimageOf2 }, ... }
* *
* @param {Object} storage - storage given by storage Viewer (basically a mapping hashedkey : {key, value}) * @param {Object} storage - storage given by storage Viewer (basically a mapping hashedkey : {key, value})
* @param {Array} corrections - used in case the calculated sha3 has been modifyed before SSTORE (notably used for struct in mapping).
* @param {Function} callback - calback * @param {Function} callback - calback
* @return {Map} - solidity mapping location (e.g { "<mapping_slot>" : { "<mapping-key1>": preimageOf1 }, { "<mapping-key2>": preimageOf2 }, ... }) * @return {Map} - solidity mapping location (e.g { "<mapping_slot>" : { "<mapping-key1>": preimageOf1 }, { "<mapping-key2>": preimageOf2 }, ... })
*/ */
async function decodeMappingsKeys (web3, storage, callback) { async function decodeMappingsKeys (web3, storage, corrections, callback) {
var ret = {} var ret = {}
if (!corrections.length) corrections.push({offset: 0, slot: 0})
for (var hashedLoc in storage) { for (var hashedLoc in storage) {
var preimage var preimage
try { try {
preimage = await getPreimage(web3, storage[hashedLoc].key) var key = storage[hashedLoc].key
for (var k in corrections) {
var corrected = util.sub(key, corrections[k].slot).toString(16)
preimage = await getPreimage(web3, '0x' + corrected)
if (preimage) break
}
} catch (e) { } catch (e) {
} }
if (preimage) { if (preimage) {

@ -33,11 +33,13 @@ class StorageResolver {
* compute the mappgings type locations for the current address (cached for a debugging session) * compute the mappgings type locations for the current address (cached for a debugging session)
* note: that only retrieve the first 100 items. * note: that only retrieve the first 100 items.
* *
* @param {String} address - contract address * @param {Object} tx
* @param {Int} stepIndex
* @param {Object} address - storage * @param {Object} address - storage
* @param {Array} corrections - used in case the calculated sha3 has been modifyed before SSTORE (notably used for struct in mapping).
* @return {Function} - callback * @return {Function} - callback
*/ */
initialPreimagesMappings (tx, stepIndex, address, callback) { initialPreimagesMappings (tx, stepIndex, address, corrections, callback) {
const self = this const self = this
if (this.preimagesMappingByAddress[address]) { if (this.preimagesMappingByAddress[address]) {
return callback(null, this.preimagesMappingByAddress[address]) return callback(null, this.preimagesMappingByAddress[address])
@ -46,7 +48,7 @@ class StorageResolver {
if (error) { if (error) {
return callback(error) return callback(error)
} }
mappingPreimages.decodeMappingsKeys(self.web3, storage, (error, mappings) => { mappingPreimages.decodeMappingsKeys(self.web3, storage, corrections, (error, mappings) => {
if (error) { if (error) {
callback(error) callback(error)
} else { } else {

@ -72,12 +72,12 @@ class StorageViewer {
/** /**
* return all the possible mappings locations for the current context (cached) do not return state changes during the current transaction * return all the possible mappings locations for the current context (cached) do not return state changes during the current transaction
* *
* @param {Function} callback * @param {Array} corrections - used in case the calculated sha3 has been modifyed before SSTORE (notably used for struct in mapping).
*/ */
async initialMappingsLocation () { async initialMappingsLocation (corrections) {
if (!this.initialMappingsLocationPromise) { if (!this.initialMappingsLocationPromise) {
this.initialMappingsLocationPromise = new Promise((resolve, reject) => { this.initialMappingsLocationPromise = new Promise((resolve, reject) => {
this.storageResolver.initialPreimagesMappings(this.context.tx, this.context.stepIndex, this.context.address, (error, initialMappingsLocation) => { this.storageResolver.initialPreimagesMappings(this.context.tx, this.context.stepIndex, this.context.address, corrections, (error, initialMappingsLocation) => {
if (error) { if (error) {
reject(error) reject(error)
} else { } else {
@ -92,12 +92,12 @@ class StorageViewer {
/** /**
* return all the possible mappings locations for the current context (cached) and current mapping slot. returns state changes during the current transaction * 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 * @param {Array} corrections - used in case the calculated sha3 has been modifyed before SSTORE (notably used for struct in mapping).
*/ */
async mappingsLocation () { async mappingsLocation (corrections) {
if (!this.currentMappingsLocationPromise) { if (!this.currentMappingsLocationPromise) {
this.currentMappingsLocationPromise = new Promise((resolve, reject) => { this.currentMappingsLocationPromise = new Promise((resolve, reject) => {
this.extractMappingsLocationChanges(this.storageChanges, (error, mappingsLocationChanges) => { this.extractMappingsLocationChanges(this.storageChanges, corrections, (error, mappingsLocationChanges) => {
if (error) { if (error) {
reject(error) reject(error)
} else { } else {
@ -111,14 +111,14 @@ class StorageViewer {
/** /**
* retrieve mapping location changes from the storage changes. * retrieve mapping location changes from the storage changes.
* * @param {Map} storageChanges
* @param {Function} callback * @param {Array} corrections - used in case the calculated sha3 has been modifyed before SSTORE (notably used for struct in mapping).
*/ */
extractMappingsLocationChanges (storageChanges, callback) { extractMappingsLocationChanges (storageChanges, corrections, callback) {
if (this.mappingsLocationChanges) { if (this.mappingsLocationChanges) {
return callback(null, this.mappingsLocationChanges) return callback(null, this.mappingsLocationChanges)
} }
mappingPreimages.decodeMappingsKeys(this.web3, storageChanges, (error, mappings) => { mappingPreimages.decodeMappingsKeys(this.web3, storageChanges, corrections, (error, mappings) => {
if (!error) { if (!error) {
this.mappingsLocationChanges = mappings this.mappingsLocationChanges = mappings
return callback(null, this.mappingsLocationChanges) return callback(null, this.mappingsLocationChanges)

Loading…
Cancel
Save