Skip to content

Commit f168763

Browse files
authored
Merge pull request #3861 from NomicFoundation/fix-shanghai
Several shanghai fixes
2 parents 231f7c4 + 28c99a9 commit f168763

File tree

12 files changed

+392
-106
lines changed

12 files changed

+392
-106
lines changed

Diff for: packages/hardhat-core/package.json

+10-10
Original file line numberDiff line numberDiff line change
@@ -99,16 +99,16 @@
9999
"dependencies": {
100100
"@ethersproject/abi": "^5.1.2",
101101
"@metamask/eth-sig-util": "^4.0.0",
102-
"@nomicfoundation/ethereumjs-block": "5.0.0",
103-
"@nomicfoundation/ethereumjs-blockchain": "7.0.0",
104-
"@nomicfoundation/ethereumjs-common": "4.0.0",
105-
"@nomicfoundation/ethereumjs-evm": "2.0.0",
106-
"@nomicfoundation/ethereumjs-rlp": "5.0.0",
107-
"@nomicfoundation/ethereumjs-statemanager": "2.0.0",
108-
"@nomicfoundation/ethereumjs-trie": "6.0.0",
109-
"@nomicfoundation/ethereumjs-tx": "5.0.0",
110-
"@nomicfoundation/ethereumjs-util": "9.0.0",
111-
"@nomicfoundation/ethereumjs-vm": "7.0.0",
102+
"@nomicfoundation/ethereumjs-block": "5.0.1",
103+
"@nomicfoundation/ethereumjs-blockchain": "7.0.1",
104+
"@nomicfoundation/ethereumjs-common": "4.0.1",
105+
"@nomicfoundation/ethereumjs-evm": "2.0.1",
106+
"@nomicfoundation/ethereumjs-rlp": "5.0.1",
107+
"@nomicfoundation/ethereumjs-statemanager": "2.0.1",
108+
"@nomicfoundation/ethereumjs-trie": "6.0.1",
109+
"@nomicfoundation/ethereumjs-tx": "5.0.1",
110+
"@nomicfoundation/ethereumjs-util": "9.0.1",
111+
"@nomicfoundation/ethereumjs-vm": "7.0.1",
112112
"@nomicfoundation/solidity-analyzer": "^0.1.0",
113113
"@sentry/node": "^5.18.1",
114114
"@types/bn.js": "^5.1.0",

Diff for: packages/hardhat-core/src/internal/hardhat-network/provider/node.ts

+37
Original file line numberDiff line numberDiff line change
@@ -2387,6 +2387,30 @@ Hardhat Network's forking functionality only works with blocks from at least spu
23872387
// know anything about the txs in the current block
23882388
}
23892389

2390+
// If this VM is running without EIP4895, but the block has withdrawals,
2391+
// we remove them and the withdrawal root from the block
2392+
if (
2393+
!this.isEip4895Active(blockNumberOrPending) &&
2394+
blockContext.withdrawals !== undefined
2395+
) {
2396+
blockContext = Block.fromBlockData(
2397+
{
2398+
...blockContext,
2399+
withdrawals: undefined,
2400+
header: {
2401+
...blockContext.header,
2402+
withdrawalsRoot: undefined,
2403+
},
2404+
},
2405+
{
2406+
freeze: false,
2407+
common: this._vm._common,
2408+
2409+
skipConsensusFormatValidation: true,
2410+
}
2411+
);
2412+
}
2413+
23902414
// NOTE: This is a workaround of both an @nomicfoundation/ethereumjs-vm limitation, and
23912415
// a bug in Hardhat Network.
23922416
//
@@ -2550,6 +2574,19 @@ Hardhat Network's forking functionality only works with blocks from at least spu
25502574
return this._vm._common.gteHardfork("london");
25512575
}
25522576

2577+
public isEip4895Active(blockNumberOrPending?: bigint | "pending"): boolean {
2578+
if (
2579+
blockNumberOrPending !== undefined &&
2580+
blockNumberOrPending !== "pending"
2581+
) {
2582+
return this._vm._common.hardforkGteHardfork(
2583+
this._selectHardfork(blockNumberOrPending),
2584+
"shanghai"
2585+
);
2586+
}
2587+
return this._vm._common.gteHardfork("shanghai");
2588+
}
2589+
25532590
public isPostMergeHardfork(): boolean {
25542591
return hardforkGte(this.hardfork, HardforkName.MERGE);
25552592
}

Diff for: packages/hardhat-core/test/internal/hardhat-network/helpers/providers.ts

+5-5
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ import { ALCHEMY_URL, INFURA_URL } from "../../../setup";
1212

1313
import { useProvider, UseProviderOptions } from "./useProvider";
1414

15-
export const DEFAULT_HARDFORK = "london";
15+
export const DEFAULT_HARDFORK = "shanghai";
1616
export const DEFAULT_CHAIN_ID = 123;
1717
export const DEFAULT_NETWORK_ID = 234;
1818
export const DEFAULT_BLOCK_GAS_LIMIT = 6000000n;
@@ -139,7 +139,7 @@ if (INFURA_URL !== undefined) {
139139
useProvider({
140140
useJsonRpc: false,
141141
loggerEnabled: true,
142-
forkConfig: { jsonRpcUrl: url },
142+
forkConfig: { jsonRpcUrl: url, blockNumber: options.forkBlockNumber },
143143
...options,
144144
});
145145
},
@@ -153,7 +153,7 @@ if (INFURA_URL !== undefined) {
153153
useProvider({
154154
useJsonRpc: false,
155155
loggerEnabled: true,
156-
forkConfig: { jsonRpcUrl: url },
156+
forkConfig: { jsonRpcUrl: url, blockNumber: options.forkBlockNumber },
157157
mining: {
158158
auto: false,
159159
interval: 10000,
@@ -171,7 +171,7 @@ if (INFURA_URL !== undefined) {
171171
useProvider({
172172
useJsonRpc: false,
173173
loggerEnabled: true,
174-
forkConfig: { jsonRpcUrl: url },
174+
forkConfig: { jsonRpcUrl: url, blockNumber: options.forkBlockNumber },
175175
...options,
176176
});
177177
},
@@ -188,7 +188,7 @@ if (ALCHEMY_URL !== undefined) {
188188
useProvider({
189189
useJsonRpc: false,
190190
loggerEnabled: true,
191-
forkConfig: { jsonRpcUrl: url },
191+
forkConfig: { jsonRpcUrl: url, blockNumber: options.forkBlockNumber },
192192
...options,
193193
});
194194
},

Diff for: packages/hardhat-core/test/internal/hardhat-network/helpers/useProvider.ts

+1
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,7 @@ export interface UseProviderOptions {
5252
mempool?: HardhatNetworkMempoolConfig;
5353
coinbase?: string;
5454
chains?: HardhatNetworkChainsConfig;
55+
forkBlockNumber?: number;
5556
}
5657

5758
export function useProvider({

Diff for: packages/hardhat-core/test/internal/hardhat-network/provider/baseFeePerGas.ts

+6-1
Original file line numberDiff line numberDiff line change
@@ -122,13 +122,18 @@ describe("Block's baseFeePerGas", function () {
122122
);
123123
});
124124

125-
for (const hardfork of ["london", "arrowGlacier"]) {
125+
for (const hardfork of ["london", "arrowGlacier", "shanghai"]) {
126126
it(`should compute the next base fee correctly when ${hardfork} is activated`, async function () {
127127
const latestBlockRpc = await this.provider.send(
128128
"eth_getBlockByNumber",
129129
["latest", false]
130130
);
131131

132+
if (hardfork !== "shanghai") {
133+
delete latestBlockRpc.withdrawals;
134+
delete latestBlockRpc.withdrawalsRoot;
135+
}
136+
132137
const latestBlockData = rpcToBlockData({
133138
...latestBlockRpc,
134139
transactions: [],
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,234 @@
1+
import { assert } from "chai";
2+
3+
import {
4+
numberToRpcQuantity,
5+
rpcDataToBigInt,
6+
} from "../../../../src/internal/core/jsonrpc/types/base-types";
7+
import { workaroundWindowsCiFailures } from "../../../utils/workaround-windows-ci-failures";
8+
import { DAI_ADDRESS } from "../helpers/constants";
9+
import { setCWD } from "../helpers/cwd";
10+
import {
11+
DEFAULT_ACCOUNTS_ADDRESSES,
12+
FORKED_PROVIDERS,
13+
} from "../helpers/providers";
14+
15+
const TOTAL_SUPPLY_SELECTOR = "0x18160ddd";
16+
17+
const SHANGHAI_HARDFORK_BLOCK_NUMBER = 17_034_870;
18+
const MERGE_HARDFORK_BLOCK_NUMBER = 15_537_394;
19+
20+
describe("Forking a block with a different hardfork", function () {
21+
FORKED_PROVIDERS.forEach(({ rpcProvider, useProvider }) => {
22+
workaroundWindowsCiFailures.call(this, { isFork: true });
23+
24+
describe(`Using ${rpcProvider}`, function () {
25+
setCWD();
26+
27+
describe("shanghai hardfork", function () {
28+
const hardfork = "shanghai";
29+
30+
describe("forking a 'shanghai' block", function () {
31+
const forkBlockNumber = SHANGHAI_HARDFORK_BLOCK_NUMBER + 100;
32+
33+
useProvider({
34+
hardfork,
35+
forkBlockNumber,
36+
});
37+
38+
it("should mine transactions", async function () {
39+
await this.provider.send("eth_sendTransaction", [
40+
{
41+
from: DEFAULT_ACCOUNTS_ADDRESSES[0],
42+
to: DEFAULT_ACCOUNTS_ADDRESSES[1],
43+
},
44+
]);
45+
});
46+
47+
it("should make calls in the forked block", async function () {
48+
const daiSupply = await this.provider.send("eth_call", [
49+
{
50+
from: DEFAULT_ACCOUNTS_ADDRESSES[0],
51+
to: DAI_ADDRESS.toString(),
52+
data: TOTAL_SUPPLY_SELECTOR,
53+
},
54+
numberToRpcQuantity(forkBlockNumber),
55+
]);
56+
57+
assert.equal(
58+
rpcDataToBigInt(daiSupply),
59+
5022305384218217259061852351n
60+
);
61+
});
62+
63+
it("should make calls in blocks before the forked block", async function () {
64+
const daiSupply = await this.provider.send("eth_call", [
65+
{
66+
from: DEFAULT_ACCOUNTS_ADDRESSES[0],
67+
to: DAI_ADDRESS.toString(),
68+
data: TOTAL_SUPPLY_SELECTOR,
69+
},
70+
numberToRpcQuantity(forkBlockNumber - 1),
71+
]);
72+
73+
assert.equal(
74+
rpcDataToBigInt(daiSupply),
75+
5022305384218217259061852351n
76+
);
77+
});
78+
});
79+
80+
describe("forking a 'merge' block", function () {
81+
const forkBlockNumber = MERGE_HARDFORK_BLOCK_NUMBER + 100;
82+
83+
useProvider({
84+
forkBlockNumber,
85+
});
86+
87+
it("should mine transactions", async function () {
88+
await this.provider.send("eth_sendTransaction", [
89+
{
90+
from: DEFAULT_ACCOUNTS_ADDRESSES[0],
91+
to: DEFAULT_ACCOUNTS_ADDRESSES[1],
92+
},
93+
]);
94+
});
95+
96+
it("should make calls in the forked block", async function () {
97+
const daiSupply = await this.provider.send("eth_call", [
98+
{
99+
from: DEFAULT_ACCOUNTS_ADDRESSES[0],
100+
to: DAI_ADDRESS.toString(),
101+
data: TOTAL_SUPPLY_SELECTOR,
102+
},
103+
numberToRpcQuantity(forkBlockNumber),
104+
]);
105+
106+
assert.equal(
107+
rpcDataToBigInt(daiSupply),
108+
6378560137543824474512862351n
109+
);
110+
});
111+
112+
it("should make calls in blocks before the forked block", async function () {
113+
const daiSupply = await this.provider.send("eth_call", [
114+
{
115+
from: DEFAULT_ACCOUNTS_ADDRESSES[0],
116+
to: DAI_ADDRESS.toString(),
117+
data: TOTAL_SUPPLY_SELECTOR,
118+
},
119+
numberToRpcQuantity(forkBlockNumber - 1),
120+
]);
121+
122+
assert.equal(
123+
rpcDataToBigInt(daiSupply),
124+
6378560137543824474512862351n
125+
);
126+
});
127+
});
128+
});
129+
130+
describe("merge hardfork", function () {
131+
const hardfork = "merge";
132+
133+
describe("forking a 'shanghai' block", function () {
134+
const forkBlockNumber = SHANGHAI_HARDFORK_BLOCK_NUMBER + 100;
135+
136+
useProvider({
137+
forkBlockNumber,
138+
hardfork,
139+
});
140+
141+
it("should mine transactions", async function () {
142+
await this.provider.send("eth_sendTransaction", [
143+
{
144+
from: DEFAULT_ACCOUNTS_ADDRESSES[0],
145+
to: DEFAULT_ACCOUNTS_ADDRESSES[1],
146+
},
147+
]);
148+
});
149+
150+
it("should make calls in the forked block", async function () {
151+
const daiSupply = await this.provider.send("eth_call", [
152+
{
153+
from: DEFAULT_ACCOUNTS_ADDRESSES[0],
154+
to: DAI_ADDRESS.toString(),
155+
data: TOTAL_SUPPLY_SELECTOR,
156+
},
157+
numberToRpcQuantity(forkBlockNumber),
158+
]);
159+
160+
assert.equal(
161+
rpcDataToBigInt(daiSupply),
162+
5022305384218217259061852351n
163+
);
164+
});
165+
166+
it("should make calls in blocks before the forked block", async function () {
167+
const daiSupply = await this.provider.send("eth_call", [
168+
{
169+
from: DEFAULT_ACCOUNTS_ADDRESSES[0],
170+
to: DAI_ADDRESS.toString(),
171+
data: TOTAL_SUPPLY_SELECTOR,
172+
},
173+
numberToRpcQuantity(forkBlockNumber - 1),
174+
]);
175+
176+
assert.equal(
177+
rpcDataToBigInt(daiSupply),
178+
5022305384218217259061852351n
179+
);
180+
});
181+
});
182+
183+
describe("forking a 'merge' block", function () {
184+
const forkBlockNumber = MERGE_HARDFORK_BLOCK_NUMBER + 100;
185+
186+
useProvider({
187+
forkBlockNumber,
188+
});
189+
190+
it("should mine transactions", async function () {
191+
await this.provider.send("eth_sendTransaction", [
192+
{
193+
from: DEFAULT_ACCOUNTS_ADDRESSES[0],
194+
to: DEFAULT_ACCOUNTS_ADDRESSES[1],
195+
},
196+
]);
197+
});
198+
199+
it("should make calls in the forked block", async function () {
200+
const daiSupply = await this.provider.send("eth_call", [
201+
{
202+
from: DEFAULT_ACCOUNTS_ADDRESSES[0],
203+
to: DAI_ADDRESS.toString(),
204+
data: TOTAL_SUPPLY_SELECTOR,
205+
},
206+
numberToRpcQuantity(forkBlockNumber),
207+
]);
208+
209+
assert.equal(
210+
rpcDataToBigInt(daiSupply),
211+
6378560137543824474512862351n
212+
);
213+
});
214+
215+
it("should make calls in blocks before the forked block", async function () {
216+
const daiSupply = await this.provider.send("eth_call", [
217+
{
218+
from: DEFAULT_ACCOUNTS_ADDRESSES[0],
219+
to: DAI_ADDRESS.toString(),
220+
data: TOTAL_SUPPLY_SELECTOR,
221+
},
222+
numberToRpcQuantity(forkBlockNumber - 1),
223+
]);
224+
225+
assert.equal(
226+
rpcDataToBigInt(daiSupply),
227+
6378560137543824474512862351n
228+
);
229+
});
230+
});
231+
});
232+
});
233+
});
234+
});

Diff for: packages/hardhat-core/test/internal/hardhat-network/provider/modules/eth/methods/getBlockByNumber.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ describe("Eth module", function () {
2828

2929
describe(`${name} provider`, function () {
3030
setCWD();
31-
useProvider();
31+
useProvider({ hardfork: "london" });
3232

3333
const getFirstBlock = async () =>
3434
isFork ? retrieveForkBlockNumber(this.ctx.hardhatNetworkProvider) : 0;

0 commit comments

Comments
 (0)