Skip to content

Commit 48c7dcb

Browse files
Mirror storage on both networks
1 parent 5b93acb commit 48c7dcb

File tree

1 file changed

+55
-49
lines changed

1 file changed

+55
-49
lines changed

test/utils/cryptography/TrieProof.test.js

Lines changed: 55 additions & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@ const { ethers } = require('hardhat');
22
const { expect } = require('chai');
33
const { spawn } = require('child_process');
44

5+
const hardhat = 'hardhat';
6+
const anvil = 'anvil';
57
const anvilPort = 8546;
68
const ProofError = {
79
NO_ERROR: 0,
@@ -20,26 +22,44 @@ const ProofError = {
2022
};
2123

2224
async function fixture() {
23-
const anvil = spawn('anvil', ['--port', anvilPort], {
25+
const anvilProcess = spawn('anvil', ['--port', anvilPort], {
2426
timeout: 30000,
2527
}); // Method eth_getProof is not supported with default Hardhat Network
2628
await new Promise(resolve => {
27-
anvil.stdout.once('data', resolve);
29+
anvilProcess.stdout.once('data', resolve);
2830
});
2931
if (process.env.ANVIL_LOGS === 'true') {
30-
anvil.stdout.on('data', function (data) {
32+
anvilProcess.stdout.on('data', function (data) {
3133
console.log(data.toString());
3234
});
3335
}
34-
const provider = new ethers.JsonRpcProvider(`http://localhost:${anvilPort}`);
35-
const account = await provider.getSigner(0);
36-
const mock = (await ethers.deployContract('$TrieProof', account)).connect(account);
37-
const storage = (await ethers.deployContract('StorageSlotMock', account)).connect(account);
36+
const [provider, account, storage] = [{}, {}, {}];
37+
for (const providerType of [hardhat, anvil]) {
38+
provider[providerType] =
39+
providerType === anvil ? new ethers.JsonRpcProvider(`http://localhost:${anvilPort}`) : ethers.provider;
40+
account[providerType] = await provider[providerType].getSigner(0);
41+
storage[providerType] = (await ethers.deployContract('StorageSlotMock', account[providerType])).connect(
42+
account[providerType],
43+
);
44+
}
45+
const mock = (await ethers.deployContract('$TrieProof', account[hardhat])).connect(account[hardhat]); // only required on hardhat network
46+
const getProof = async function (contract, slot, tx) {
47+
const { storageHash, storageProof } = await this.provider[anvil].send('eth_getProof', [
48+
contract[anvil].target,
49+
[slot],
50+
tx ? ethers.toBeHex(tx[anvil].blockNumber) : 'latest',
51+
]);
52+
const { key, value, proof } = storageProof[0];
53+
return { key, value, proof, storageHash };
54+
};
55+
3856
return {
39-
anvil,
57+
anvilProcess,
4058
provider,
41-
mock,
59+
account,
4260
storage,
61+
mock,
62+
getProof,
4363
};
4464
}
4565

@@ -49,36 +69,24 @@ describe('TrieProof', function () {
4969
});
5070

5171
afterEach(async function () {
52-
this.anvil.kill();
72+
this.anvilProcess.kill();
5373
});
5474

5575
describe('verify', function () {
5676
it('returns true for a valid proof with leaf', async function () {
5777
const slot = ethers.ZeroHash;
58-
const tx = await this.storage.setUint256Slot(slot, 42);
59-
const response = await this.provider.send('eth_getProof', [
60-
this.storage.target,
61-
[slot],
62-
ethers.toBeHex(tx.blockNumber),
63-
]);
64-
const { storageHash, storageProof } = response;
65-
const { key, value, proof } = storageProof[0];
78+
const tx = await call(this.storage, 'setUint256Slot', [slot, 42]);
79+
const { key, value, proof, storageHash } = await this.getProof(this.storage, slot, tx);
6680
const result = await this.mock.$verify(key, value, proof, storageHash);
6781
expect(result).is.true;
6882
});
6983

7084
it('returns true for a valid proof with extension', async function () {
7185
const slot0 = ethers.ZeroHash;
7286
const slot1 = '0x0000000000000000000000000000000000000000000000000000000000000001';
73-
await this.storage.setUint256Slot(slot0, 42);
74-
const tx = await this.storage.setUint256Slot(slot1, 43);
75-
const response = await this.provider.send('eth_getProof', [
76-
this.storage.target,
77-
[slot1],
78-
ethers.toBeHex(tx.blockNumber),
79-
]);
80-
const { storageHash, storageProof } = response;
81-
const { key, value, proof } = storageProof[0];
87+
await call(this.storage, 'setUint256Slot', [slot0, 42]);
88+
const tx = await call(this.storage, 'setUint256Slot', [slot1, 43]);
89+
const { key, value, proof, storageHash } = await this.getProof(this.storage, slot1, tx);
8290
const result = await this.mock.$verify(key, value, proof, storageHash);
8391
expect(result).is.true;
8492
});
@@ -93,13 +101,8 @@ describe('TrieProof', function () {
93101

94102
it('fails to process proof with invalid root hash', async function () {
95103
const slot = ethers.ZeroHash;
96-
const tx = await this.storage.setUint256Slot(slot, 42);
97-
const { storageHash, storageProof } = await this.provider.send('eth_getProof', [
98-
this.storage.target,
99-
[slot],
100-
ethers.toBeHex(tx.blockNumber),
101-
]);
102-
const { key, proof } = storageProof[0];
104+
const tx = await call(this.storage, 'setUint256Slot', [slot, 42]);
105+
const { key, proof, storageHash } = await this.getProof(this.storage, slot, tx);
103106
const [processedValue, error] = await this.mock.$processProof(key, proof, ethers.keccak256(storageHash)); // Corrupt root hash
104107
expect(processedValue).to.equal('0x');
105108
expect(error).to.equal(ProofError.INVALID_ROOT_HASH);
@@ -108,14 +111,9 @@ describe('TrieProof', function () {
108111
it('fails to process proof with invalid internal large hash', async function () {
109112
const slot0 = ethers.ZeroHash;
110113
const slot1 = '0x0000000000000000000000000000000000000000000000000000000000000001';
111-
await this.storage.setUint256Slot(slot0, 42);
112-
const tx = await this.storage.setUint256Slot(slot1, 43);
113-
const { storageHash, storageProof } = await this.provider.send('eth_getProof', [
114-
this.storage.target,
115-
[slot1],
116-
ethers.toBeHex(tx.blockNumber),
117-
]);
118-
const { key, proof } = storageProof[0];
114+
await call(this.storage, 'setUint256Slot', [slot0, 42]);
115+
const tx = await call(this.storage, 'setUint256Slot', [slot1, 43]);
116+
const { key, proof, storageHash } = await this.getProof(this.storage, slot1, tx);
119117
proof[1] = ethers.toBeHex(BigInt(proof[1]) + 1n); // Corrupt internal large node hash
120118
const [processedValue, error] = await this.mock.$processProof(key, proof, storageHash);
121119
expect(processedValue).to.equal('0x');
@@ -133,13 +131,8 @@ describe('TrieProof', function () {
133131

134132
it('fails to process proof with invalid extra proof', async function () {
135133
const slot0 = ethers.ZeroHash;
136-
const tx = await this.storage.setUint256Slot(slot0, 42);
137-
const { storageHash, storageProof } = await this.provider.send('eth_getProof', [
138-
this.storage.target,
139-
[slot0],
140-
ethers.toBeHex(tx.blockNumber),
141-
]);
142-
const { key, proof } = storageProof[0];
134+
const tx = await call(this.storage, 'setUint256Slot', [slot0, 42]);
135+
const { key, proof, storageHash } = await this.getProof(this.storage, slot0, tx);
143136
proof[1] = ethers.encodeRlp([]); // extra proof element
144137
const [processedValue, error] = await this.mock.$processProof(key, proof, storageHash);
145138
expect(processedValue).to.equal('0x');
@@ -176,3 +169,16 @@ describe('TrieProof', function () {
176169
});
177170
});
178171
});
172+
173+
/**
174+
* Call a method on both Hardhat and Anvil networks
175+
* @returns txs on both networks
176+
*/
177+
async function call(contract, method, args) {
178+
const hardhatTx = await contract[hardhat][method](...args);
179+
const anvilTx = await contract[anvil][method](...args);
180+
return {
181+
[hardhat]: hardhatTx,
182+
[anvil]: anvilTx,
183+
};
184+
}

0 commit comments

Comments
 (0)