From 0d3a26a54b3f94d21de6e5b8f72ff2f79a0b73ea Mon Sep 17 00:00:00 2001 From: yann300 Date: Tue, 11 Apr 2017 13:41:59 +0200 Subject: [PATCH] refactor storageResolver --- src/storage/storageResolver.js | 138 +++++++++++++++++---------------- 1 file changed, 73 insertions(+), 65 deletions(-) diff --git a/src/storage/storageResolver.js b/src/storage/storageResolver.js index 07ecd45a15..8fd2ae5d5d 100644 --- a/src/storage/storageResolver.js +++ b/src/storage/storageResolver.js @@ -7,28 +7,31 @@ class StorageResolver { constructor (_traceManager) { this.traceManager = _traceManager this.storageByAddress = {} + this.maxSize = 100 } /** - * return the storage for the current context (address and vm trace index) - * by default now returns the range 0 => 1000 + * return the storage for the given context (address and vm trace index) + * returns the range 0 => this.maxSize + * * @param {Object} - tx - transaction * @param {Int} - stepIndex - Index of the stop in the vm trace * @param {Function} - callback - contains a map: [hashedKey] = {key, hashedKey, value} */ storageRange (tx, stepIndex, callback) { - storageRangeInternal(this, '0x0', true, tx, stepIndex, callback) + storageRangeInternal(this, '0x0', tx, stepIndex, true, callback) } /** - * return a slot value for the current context (address and vm trace index) + * return a slot value for the given context (address and vm trace index) + * * @param {String} - slot - slot key * @param {Object} - tx - transaction * @param {Int} - stepIndex - Index of the stop in the vm trace * @param {Function} - callback - {key, hashedKey, value} - */ storageSlot (slot, tx, stepIndex, callback) { - storageRangeInternal(this, slot, false, tx, stepIndex, function (error, storage) { + storageRangeInternal(this, slot, tx, stepIndex, false, function (error, storage) { if (error) { callback(error) } else { @@ -49,71 +52,49 @@ class StorageResolver { } } -function resolveAddress (self, stepIndex, callback) { - self.traceManager.getCurrentCalledAddressAt(stepIndex, (error, result) => { +/** + * retrieve the storage and ensure at least @arg slot is cached. + * - If @arg slot is already cached, the storage will be returned from the cache + * 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. + */ +function storageRangeInternal (self, slot, tx, stepIndex, fullStorage, callback) { + resolveAddress(self, stepIndex, (error, address) => { if (error) { - callback(error) - } else { - callback(null, result) + return callback(error) } - }) -} - -function storageRangeWeb3Call (tx, address, start, fullStorage, callback) { - var maxSize = fullStorage ? 1000 : 100 - util.web3.debug.storageRangeAt( - tx.blockHash, tx.transactionIndex === undefined ? tx.hash : tx.transactionIndex, - address, - start, - maxSize, - (error, result) => { + self.traceManager.accumulateStorageChanges(stepIndex, address, {}, (error, storageChanges) => { if (error) { - callback(error) - } else if (result.storage) { - callback(null, result.storage, result.complete) - } else { - callback('the storage has not been provided') + return callback(error) } - }) -} - -function storageRangeInternal (self, start, fullStorage, tx, stepIndex, callback) { - resolveAddress(self, stepIndex, (error, address) => { - if (error) { - callback(error) - } else { - if (traceHelper.isContractCreation(address)) { - callback(null, {}) - } else { - if (!util.web3.debug.storageRangeAt) { - callback('no storageRangeAt endpoint found') - } else { - var cached = fromCache(self, address, start) - if (cached) { - self.traceManager.accumulateStorageChanges(stepIndex, address, cached, callback) - } else { - storageRangeWeb3Call(tx, address, start, fullStorage, (error, storage, complete) => { - if (error) { - callback(error) - } else { - toCache(self, address, storage, fullStorage, complete) - self.traceManager.accumulateStorageChanges(stepIndex, address, storage, callback) - } - }) - } - } + if (!fullStorage && storageChanges[slot]) { + return callback(null, storageChanges) } - } + var cached = fromCache(self, address, slot) + if (cached && cached[slot]) { // we have the current slot in the cache and maybe the next 1000 ... + return callback(null, Object.assign(cached, storageChanges)) + } + storageRangeWeb3Call(tx, address, slot, self.maxSize, (error, storage, complete) => { + if (error) { + return callback(error) + } + toCache(self, address, storage) + if (slot === '0x0' && Object.keys(storage).length < self.maxSize) { + self.storageByAddress[address].complete = true + } + callback(null, Object.assign(storage, storageChanges)) + }) + }) }) } /** - * retrieve the storage from the cache. if @arg slot is defined, return only the desired slot, if not return the entire known storage - * - * @param {String} address - contract address - * @param {String} slotKey - key of the value to return - * @return {String} - either the entire known storage or a single value - */ + * retrieve the storage from the cache. if @arg slot is defined, return only the desired slot, if not return the entire known storage + * + * @param {String} address - contract address + * @param {String} slotKey - key of the value to return + * @return {String} - either the entire known storage or a single value + */ function fromCache (self, address, hashedKey) { if (!self.storageByAddress[address]) { return null @@ -126,16 +107,43 @@ function fromCache (self, address, hashedKey) { * * @param {String} address - contract address * @param {Object} storage - result of `storageRangeAtInternal`, contains {key, hashedKey, value} - * @param {Bool} complete - True if the storage is complete */ -function toCache (self, address, storage, fullStorageRequest, complete) { +function toCache (self, address, storage) { if (!self.storageByAddress[address]) { self.storageByAddress[address] = {} } self.storageByAddress[address].storage = Object.assign(self.storageByAddress[address].storage || {}, storage) - if (Object.keys(storage).length < 1000 && fullStorageRequest && complete) { - self.storageByAddress[address].complete = complete +} + +function storageRangeWeb3Call (tx, address, start, maxSize, callback) { + if (traceHelper.isContractCreation(address)) { + callback(null, {}, true) + } else { + util.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.complete) + } else { + callback('the storage has not been provided') + } + }) } } +function resolveAddress (self, stepIndex, callback) { + self.traceManager.getCurrentCalledAddressAt(stepIndex, (error, result) => { + if (error) { + callback(error) + } else { + callback(null, result) + } + }) +} + module.exports = StorageResolver