Skip to content
This repository has been archived by the owner on Feb 26, 2024. It is now read-only.

Commit

Permalink
leverage the requested blocknumber when getting forked storage
Browse files Browse the repository at this point in the history
  • Loading branch information
mikeseese committed Aug 20, 2020
1 parent c5e31cf commit 3f56085
Show file tree
Hide file tree
Showing 2 changed files with 69 additions and 8 deletions.
25 changes: 23 additions & 2 deletions lib/forking/forked_blockchain.js
Original file line number Diff line number Diff line change
Expand Up @@ -403,11 +403,32 @@ ForkedBlockchain.prototype.getStorage = function(address, key, number, callback)
if (err) {
return callback(err);
}
this.getEffectiveBlockNumber(number, (err, number) => {
this.getEffectiveBlockNumber(number, (err, blockNumber) => {
if (err) {
return callback(err);
}
trie.get(utils.setLengthLeft(utils.toBuffer(key), 32), number, callback);

if (blockNumber > this.forkBlockNumber) {
// only hit the ForkedStorageTrieBase if we're not looking
// for something that's on the forked chain
trie.get(utils.setLengthLeft(utils.toBuffer(key), 32), blockNumber, callback);
} else {
// we're looking for something prior to forking, so let's
// hit eth_getStorageAt
const queryBlockNumber = blockNumber > this.forkBlockNumber ? this.forkBlockNumber : blockNumber;
this.web3.eth.getStorageAt(to.rpcDataHexString(address), to.rpcDataHexString(key), queryBlockNumber, function(
err,
value
) {
if (err) {
return callback(err);
}

value = utils.rlp.encode(value);

callback(null, value);
});
}
});
});
};
Expand Down
52 changes: 46 additions & 6 deletions lib/forking/forked_storage_trie.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ const Sublevel = require("level-sublevel");
const MerklePatriciaTree = require("merkle-patricia-tree");
const BaseTrie = require("merkle-patricia-tree/baseTrie");
const checkpointInterface = require("merkle-patricia-tree/checkpoint-interface");
const Account = require("ethereumjs-account").default;
var utils = require("ethereumjs-util");
var inherits = require("util").inherits;
var Web3 = require("web3");
Expand All @@ -24,11 +25,13 @@ function ForkedStorageBaseTrie(db, root, options) {
// Note: This overrides a standard method whereas the other methods do not.
ForkedStorageBaseTrie.prototype.get = function(key, blockNumber, callback) {
var self = this;
let blockNumberProvided = true;

// Allow an optional blockNumber
if (typeof blockNumber === "function") {
callback = blockNumber;
blockNumber = this.forkBlockNumber;
blockNumberProvided = false;
}

key = utils.toBuffer(key);
Expand All @@ -40,12 +43,49 @@ ForkedStorageBaseTrie.prototype.get = function(key, blockNumber, callback) {
}

if (exists) {
// TODO: just because we have the key doesn't mean we're at the right
// block number/root to send it. We need to check the block number
// before using the data in our own trie.
MerklePatriciaTree.prototype.get.call(self, key, function(err, r) {
callback(err, r);
});
// I'm checking to see if a blockNumber is provided because the below
// logic breaks for things like nonce lookup, in which we should just
// use the root trie as is. I'm guessing there's a cleaner architecture
// that doesn't require such checks
if (blockNumberProvided) {
// this logic is heavily influenced by BlockchainDouble.prototype.getStorage
// but some adjustments were necessary due to the ForkedStorageTrieBase context
self.blockchain.getBlock(blockNumber, function(err, block) {
if (err) {
return callback(err);
}

// Manipulate the state root in place to maintain checkpoints
const currentStateRoot = self.root;
self.root = block.header.stateRoot;

MerklePatriciaTree.prototype.get.call(self, utils.toBuffer(self.address), function(err, data) {
if (err != null) {
// Put the stateRoot back if there's an error
self.root = currentStateRoot;
return callback(err);
}

const account = new Account(data);

self.root = account.stateRoot;
MerklePatriciaTree.prototype.get.call(self, key, function(err, value) {
// Finally, put the stateRoot back for good
self.root = currentStateRoot;

if (err != null) {
return callback(err, value);
}

callback(null, value);
});
});
});
} else {
MerklePatriciaTree.prototype.get.call(self, key, function(err, r) {
callback(err, r);
});
}
} else {
self.keyIsDeleted(key, (err, deleted) => {
if (err) {
Expand Down

0 comments on commit 3f56085

Please sign in to comment.