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

Commit

Permalink
fix(forking): invalidate _deleted in ForkedStorageTrie if a subse…
Browse files Browse the repository at this point in the history
…quent `put` happens (#612)
  • Loading branch information
mikeseese committed Aug 18, 2020
1 parent 93c2488 commit a8a4d8f
Show file tree
Hide file tree
Showing 3 changed files with 89 additions and 0 deletions.
17 changes: 17 additions & 0 deletions lib/forking/forked_storage_trie.js
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,23 @@ ForkedStorageBaseTrie.prototype.keyExists = function(key, callback) {
});
};

const originalPut = ForkedStorageBaseTrie.prototype.put;
ForkedStorageBaseTrie.prototype.put = function(key, value, callback) {
let rpcKey = to.rpcDataHexString(key);
if (this.address) {
rpcKey = `${to.rpcDataHexString(this.address)};${rpcKey}`;
}
this._deleted.get(rpcKey, (_, result) => {
if (result === 1) {
this._deleted.put(rpcKey, 0, () => {
originalPut.call(this, key, value, callback);
});
} else {
originalPut.call(this, key, value, callback);
}
});
};

ForkedStorageBaseTrie.prototype.keyIsDeleted = function(key, callback) {
let rpcKey = to.rpcDataHexString(key);
if (this.address) {
Expand Down
18 changes: 18 additions & 0 deletions test/contracts/forking/StorageDelete.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
pragma solidity ^0.6.0;

contract StorageDelete {
bool entered;

constructor() public {
entered = true;
}

function test() public nonReentrant {}

modifier nonReentrant() {
require(entered, "re-entered");
entered = false;
_;
entered = true;
}
}
54 changes: 54 additions & 0 deletions test/forking/delete.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
const assert = require("assert");
const bootstrap = require("../helpers/contract/bootstrap");
const intializeTestProvider = require("../helpers/web3/initializeTestProvider");

/**
* NOTE: Naming in these tests is a bit confusing. Here, the "main chain"
* is the main chain the tests interact with; and the "forked chain" is the
* chain that _was forked_. This is in contrast to general naming, where the
* main chain represents the main chain to be forked (like the Ethereum live
* network) and the fork chaing being "the fork".
*/

describe("Forking Deletion", () => {
let forkedContext;
let mainContext;
const logger = {
log: function(msg) {}
};

before("Set up forked provider with web3 instance and deploy a contract", async function() {
this.timeout(5000);

const contractRef = {
contractFiles: ["StorageDelete"],
contractSubdirectory: "forking"
};

const ganacheProviderOptions = {
logger,
seed: "main provider"
};

forkedContext = await bootstrap(contractRef, ganacheProviderOptions);
});

before("Set up main provider and web3 instance", async function() {
const { provider: forkedProvider } = forkedContext;
mainContext = await intializeTestProvider({
fork: forkedProvider,
logger,
seed: "forked provider"
});
});

it("successfully manages storage slot deletion", async() => {
const { instance: forkedInstance, abi } = forkedContext;
const { web3: mainWeb3 } = mainContext;

const instance = new mainWeb3.eth.Contract(abi, forkedInstance._address);

assert.ok(await instance.methods.test().call());
assert.ok(await instance.methods.test().call());
});
});

0 comments on commit a8a4d8f

Please sign in to comment.