|
|
|
@ -25,8 +25,8 @@ class StorageResolver { |
|
|
|
|
* @param {String} - address - lookup address |
|
|
|
|
* @param {Function} - callback - contains a map: [hashedKey] = {key, hashedKey, value} |
|
|
|
|
*/ |
|
|
|
|
storageRange (tx, stepIndex, address, callback) { |
|
|
|
|
this.storageRangeInternal(this, this.zeroSlot, tx, stepIndex, address, callback) |
|
|
|
|
storageRange (tx, stepIndex, address) { |
|
|
|
|
return this.storageRangeInternal(this, this.zeroSlot, tx, stepIndex, address) |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/** |
|
|
|
@ -39,22 +39,16 @@ class StorageResolver { |
|
|
|
|
* @param {Array} corrections - used in case the calculated sha3 has been modifyed before SSTORE (notably used for struct in mapping). |
|
|
|
|
* @return {Function} - callback |
|
|
|
|
*/ |
|
|
|
|
initialPreimagesMappings (tx, stepIndex, address, corrections, callback) { |
|
|
|
|
if (this.preimagesMappingByAddress[address]) { |
|
|
|
|
return callback(null, this.preimagesMappingByAddress[address]) |
|
|
|
|
} |
|
|
|
|
this.storageRange(tx, stepIndex, address, (error, storage) => { |
|
|
|
|
if (error) { |
|
|
|
|
return callback(error) |
|
|
|
|
initialPreimagesMappings (tx, stepIndex, address, corrections) { |
|
|
|
|
return new Promise((resolve, reject) => { |
|
|
|
|
if (this.preimagesMappingByAddress[address]) { |
|
|
|
|
return resolve(this.preimagesMappingByAddress[address]) |
|
|
|
|
} |
|
|
|
|
mappingPreimages.decodeMappingsKeys(this.web3, storage, corrections, (error, mappings) => { |
|
|
|
|
if (error) { |
|
|
|
|
callback(error) |
|
|
|
|
} else { |
|
|
|
|
this.preimagesMappingByAddress[address] = mappings |
|
|
|
|
callback(null, mappings) |
|
|
|
|
} |
|
|
|
|
}) |
|
|
|
|
this.storageRange(tx, stepIndex, address).then((storage) => { |
|
|
|
|
const mappings = mappingPreimages.decodeMappingsKeys(this.web3, storage, corrections) |
|
|
|
|
this.preimagesMappingByAddress[address] = mappings |
|
|
|
|
resolve(mappings) |
|
|
|
|
}).catch(reject) |
|
|
|
|
}) |
|
|
|
|
} |
|
|
|
|
|
|
|
|
@ -67,13 +61,11 @@ class StorageResolver { |
|
|
|
|
* @param {String} - address - lookup address |
|
|
|
|
* @param {Function} - callback - {key, hashedKey, value} - |
|
|
|
|
*/ |
|
|
|
|
storageSlot (slot, tx, stepIndex, address, callback) { |
|
|
|
|
this.storageRangeInternal(this, slot, tx, stepIndex, address, (error, storage) => { |
|
|
|
|
if (error) { |
|
|
|
|
callback(error) |
|
|
|
|
} else { |
|
|
|
|
callback(null, storage[slot] !== undefined ? storage[slot] : null) |
|
|
|
|
} |
|
|
|
|
storageSlot (slot, tx, stepIndex, address) { |
|
|
|
|
return new Promise((resolve, reject) => { |
|
|
|
|
this.storageRangeInternal(this, slot, tx, stepIndex, address).then((storage) => { |
|
|
|
|
resolve(storage[slot] !== undefined ? storage[slot] : null) |
|
|
|
|
}).catch(reject) |
|
|
|
|
}) |
|
|
|
|
} |
|
|
|
|
|
|
|
|
@ -93,26 +85,26 @@ class StorageResolver { |
|
|
|
|
* even if the next 1000 items are not in the cache. |
|
|
|
|
* - If @arg slot is not cached, the corresponding value will be resolved and the next 1000 slots. |
|
|
|
|
*/ |
|
|
|
|
storageRangeInternal (self, slotKey, tx, stepIndex, address, callback) { |
|
|
|
|
var cached = this.fromCache(self, address) |
|
|
|
|
if (cached && cached.storage[slotKey]) { // we have the current slot in the cache and maybe the next 1000...
|
|
|
|
|
return callback(null, cached.storage) |
|
|
|
|
} |
|
|
|
|
this.storageRangeWeb3Call(tx, address, slotKey, self.maxSize, (error, storage, nextKey) => { |
|
|
|
|
if (error) { |
|
|
|
|
return callback(error) |
|
|
|
|
storageRangeInternal (self, slotKey, tx, stepIndex, address) { |
|
|
|
|
return new Promise((resolve, reject) => { |
|
|
|
|
var cached = this.fromCache(self, address) |
|
|
|
|
if (cached && cached.storage[slotKey]) { // we have the current slot in the cache and maybe the next 1000...
|
|
|
|
|
return resolve(cached.storage) |
|
|
|
|
} |
|
|
|
|
if (!storage[slotKey] && slotKey !== self.zeroSlot) { // we don't cache the zero slot (could lead to inconsistency)
|
|
|
|
|
storage[slotKey] = { |
|
|
|
|
key: slotKey, |
|
|
|
|
value: self.zeroSlot |
|
|
|
|
this.storageRangeWeb3Call(tx, address, slotKey, self.maxSize).then((result) => { |
|
|
|
|
const [storage, nextKey] = result |
|
|
|
|
if (!storage[slotKey] && slotKey !== self.zeroSlot) { // we don't cache the zero slot (could lead to inconsistency)
|
|
|
|
|
storage[slotKey] = { |
|
|
|
|
key: slotKey, |
|
|
|
|
value: self.zeroSlot |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
self.toCache(self, address, storage) |
|
|
|
|
if (slotKey === self.zeroSlot && !nextKey) { // only working if keys are sorted !!
|
|
|
|
|
self.storageByAddress[address].complete = true |
|
|
|
|
} |
|
|
|
|
callback(null, storage) |
|
|
|
|
self.toCache(self, address, storage) |
|
|
|
|
if (slotKey === self.zeroSlot && !nextKey) { // only working if keys are sorted !!
|
|
|
|
|
self.storageByAddress[address].complete = true |
|
|
|
|
} |
|
|
|
|
return resolve(storage) |
|
|
|
|
}).catch(reject) |
|
|
|
|
}) |
|
|
|
|
} |
|
|
|
|
|
|
|
|
@ -142,25 +134,27 @@ class StorageResolver { |
|
|
|
|
self.storageByAddress[address].storage = Object.assign(self.storageByAddress[address].storage || {}, storage) |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
storageRangeWeb3Call (tx, address, start, maxSize, callback) { |
|
|
|
|
if (traceHelper.isContractCreation(address)) { |
|
|
|
|
callback(null, {}, null) |
|
|
|
|
} else { |
|
|
|
|
this.web3.debug.storageRangeAt( |
|
|
|
|
tx.blockHash, tx.transactionIndex === undefined ? tx.hash : tx.transactionIndex, |
|
|
|
|
address, |
|
|
|
|
start, |
|
|
|
|
maxSize, |
|
|
|
|
(error, result) => { |
|
|
|
|
if (error) { |
|
|
|
|
callback(error) |
|
|
|
|
} else if (result.storage) { |
|
|
|
|
callback(null, result.storage, result.nextKey) |
|
|
|
|
} else { |
|
|
|
|
callback('the storage has not been provided') |
|
|
|
|
} |
|
|
|
|
}) |
|
|
|
|
} |
|
|
|
|
storageRangeWeb3Call (tx, address, start, maxSize) { |
|
|
|
|
return new Promise((resolve, reject) => { |
|
|
|
|
if (traceHelper.isContractCreation(address)) { |
|
|
|
|
resolve([{}, null]) |
|
|
|
|
} else { |
|
|
|
|
this.web3.debug.storageRangeAt( |
|
|
|
|
tx.blockHash, tx.transactionIndex === undefined ? tx.hash : tx.transactionIndex, |
|
|
|
|
address, |
|
|
|
|
start, |
|
|
|
|
maxSize, |
|
|
|
|
(error, result) => { |
|
|
|
|
if (error) { |
|
|
|
|
reject(error) |
|
|
|
|
} else if (result.storage) { |
|
|
|
|
resolve([result.storage, result.nextKey]) |
|
|
|
|
} else { |
|
|
|
|
reject('the storage has not been provided') |
|
|
|
|
} |
|
|
|
|
}) |
|
|
|
|
} |
|
|
|
|
}) |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|