Skip to content

Commit 5ca4dbd

Browse files
committed
evm: add fork upgrade slot test
1 parent ea14e8d commit 5ca4dbd

File tree

4 files changed

+465
-1
lines changed

4 files changed

+465
-1
lines changed

evm/forge/tests/ForkSlots.t.sol

+358
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,358 @@
1+
// SPDX-License-Identifier: Apache 2
2+
pragma solidity ^0.8.22;
3+
4+
import "forge-std/Test.sol";
5+
import "forge-std/console.sol";
6+
7+
import {IWormhole} from "src/interfaces/IWormhole.sol";
8+
import {ICircleIntegration} from "src/interfaces/ICircleIntegration.sol";
9+
10+
import {Utils} from "src/libraries/Utils.sol";
11+
12+
import {Implementation} from "src/contracts/CircleIntegration/Implementation.sol";
13+
14+
import {
15+
CircleIntegrationOverride,
16+
CraftedCctpMessageParams,
17+
CraftedVaaParams
18+
} from "test-helpers/libraries/CircleIntegrationOverride.sol";
19+
import {SlotCheck} from "test-helpers/libraries/SlotCheck.sol";
20+
import {WormholeOverride} from "test-helpers/libraries/WormholeOverride.sol";
21+
22+
contract ForkSlots is Test {
23+
using CircleIntegrationOverride for *;
24+
using WormholeOverride for *;
25+
using Utils for address;
26+
using SlotCheck for *;
27+
28+
bytes32 constant GOVERNANCE_MODULE =
29+
0x000000000000000000000000000000436972636c65496e746567726174696f6e;
30+
31+
address constant FORKED_CIRCLE_INTEGRATION_ADDRESS = 0x2703483B1a5a7c577e8680de9Df8Be03c6f30e3c;
32+
33+
ICircleIntegration forked;
34+
address forkedAddress;
35+
36+
IWormhole wormhole;
37+
38+
// Expected at slot 0x0.
39+
40+
uint16 expectedChainId;
41+
uint8 expectedWormholeFinality;
42+
uint32 expectedLocalDomain;
43+
address expectedWormholeAddress;
44+
uint16 expectedGovernanceChainId;
45+
46+
// Expected at slot 0x1.
47+
bytes32 expectedGovernanceContract;
48+
49+
// Expected at slot 0x2.
50+
address expectedCircleBridgeAddress;
51+
52+
// Expected at slot 0x3.
53+
address expectedCircleTransmitterAddress;
54+
55+
// Expected at slot 0x4.
56+
address expectedCircleTokenMinterAddress;
57+
58+
// Expected at slot 0xa.
59+
uint256 expectedEvmChain;
60+
61+
function setUp() public {
62+
forked = ICircleIntegration(FORKED_CIRCLE_INTEGRATION_ADDRESS);
63+
forked.setUpOverride(uint256(vm.envBytes32("TESTING_DEVNET_GUARDIAN")));
64+
forkedAddress = address(forked);
65+
66+
wormhole = forked.wormhole();
67+
68+
// Set expected values.
69+
expectedChainId = forked.chainId();
70+
expectedWormholeFinality = forked.wormholeFinality();
71+
expectedLocalDomain = forked.localDomain();
72+
expectedWormholeAddress = address(forked.wormhole());
73+
expectedGovernanceChainId = forked.governanceChainId();
74+
expectedGovernanceContract = forked.governanceContract();
75+
expectedCircleBridgeAddress = address(forked.circleBridge());
76+
expectedCircleTransmitterAddress = address(forked.circleTransmitter());
77+
expectedCircleTokenMinterAddress = address(forked.circleTokenMinter());
78+
expectedEvmChain = forked.evmChain();
79+
}
80+
81+
function test_UpgradeForkAndCheckSlots() public {
82+
// Deploy new implementation.
83+
Implementation implementation = new Implementation(
84+
address(wormhole),
85+
vm.envAddress("TESTING_CIRCLE_BRIDGE_ADDRESS") // tokenMessenger
86+
);
87+
88+
// Should not be initialized yet.
89+
bool isInitialized = forked.isInitialized(address(implementation));
90+
assertFalse(isInitialized, "already initialized");
91+
92+
(IWormhole.VM memory vaa, bytes memory encodedVaa) = wormhole.craftGovernanceVaa(
93+
GOVERNANCE_MODULE,
94+
3, // action
95+
forked.chainId(),
96+
69, // sequence
97+
abi.encodePacked(address(implementation).toUniversalAddress())
98+
);
99+
100+
// This VAA should not have been consumed yet.
101+
bool isVaaConsumed = forked.isMessageConsumed(vaa.hash);
102+
assertFalse(isVaaConsumed, "VAA already consumed");
103+
104+
// Before upgrading, fetch some expected values.
105+
uint16 expectedRegisteredChainId = 2;
106+
bytes32 expectedEmitter = forked.getRegisteredEmitter(expectedRegisteredChainId);
107+
uint32 expectedCctpDomain = forked.getDomainFromChainId(expectedRegisteredChainId);
108+
109+
// Check slots before upgrade.
110+
{
111+
bytes32 slotZeroData = vm.load(address(forked), bytes32(0));
112+
113+
// If the data is already zeroed, check the remaining zeroed slots. Otherwise check that
114+
// the slots are the expected values from the existing getters.
115+
if (slotZeroData != 0) {
116+
// Now check slots that will be zeroed.
117+
uint256 bitOffset;
118+
119+
// First 2 bytes is chain ID.
120+
assertEq(
121+
uint16(uint256(slotZeroData >> bitOffset)),
122+
expectedChainId,
123+
"slot 0x0 not equal to expected before upgrade"
124+
);
125+
bitOffset += 16;
126+
127+
// Next byte is wormhole finality.
128+
assertEq(
129+
uint8(uint256(slotZeroData >> bitOffset)),
130+
expectedWormholeFinality,
131+
"slot 0x0 not equal to expected before upgrade"
132+
);
133+
bitOffset += 8;
134+
135+
// Next 4 bytes is local domain.
136+
assertEq(
137+
uint32(uint256(slotZeroData >> bitOffset)),
138+
expectedLocalDomain,
139+
"slot 0x0 not equal to expected before upgrade"
140+
);
141+
bitOffset += 32;
142+
143+
// Next 20 bytes is wormhole address.
144+
assertEq(
145+
address(uint160(uint256(slotZeroData >> bitOffset))),
146+
expectedWormholeAddress,
147+
"slot 0x0 not equal to expected before upgrade"
148+
);
149+
bitOffset += 160;
150+
151+
// Next 2 bytes is governance chain ID.
152+
assertEq(
153+
uint16(uint256(slotZeroData >> bitOffset)),
154+
expectedGovernanceChainId,
155+
"slot 0x0 not equal to expected before upgrade"
156+
);
157+
bitOffset += 16;
158+
159+
// Remaining bytes are zero.
160+
assertEq(
161+
uint256(slotZeroData >> bitOffset),
162+
0,
163+
"slot 0x0 not equal to expected before upgrade"
164+
);
165+
}
166+
if (slotZeroData == 0) {
167+
assertTrue(
168+
forkedAddress.slotValueZero(0x1),
169+
"slot 0x1 not equal to expected before upgrade"
170+
);
171+
assertTrue(
172+
forkedAddress.slotValueZero(0x2),
173+
"slot 0x2 not equal to expected before upgrade"
174+
);
175+
assertTrue(
176+
forkedAddress.slotValueZero(0x3),
177+
"slot 0x3 not equal to expected before upgrade"
178+
);
179+
assertTrue(
180+
forkedAddress.slotValueZero(0x4),
181+
"slot 0x4 not equal to expected before upgrade"
182+
);
183+
} else {
184+
assertTrue(
185+
forkedAddress.slotValueEquals(0x1, expectedGovernanceContract),
186+
"slot 0x1 not equal to expected before upgrade"
187+
);
188+
assertTrue(
189+
forkedAddress.slotValueEquals(0x2, expectedCircleBridgeAddress),
190+
"slot 0x2 not equal to expected before upgrade"
191+
);
192+
assertTrue(
193+
forkedAddress.slotValueEquals(0x3, expectedCircleTransmitterAddress),
194+
"slot 0x3 not equal to expected before upgrade"
195+
);
196+
assertTrue(
197+
forkedAddress.slotValueEquals(0x4, expectedCircleTokenMinterAddress),
198+
"slot 0x4 not equal to expected before upgrade"
199+
);
200+
}
201+
assertTrue(
202+
forkedAddress.slotValueEquals(
203+
keccak256(abi.encode(address(implementation), uint256(0x5))), isInitialized
204+
),
205+
"mapped slot 0x5 not equal to expected before upgrade"
206+
);
207+
assertTrue(
208+
forkedAddress.slotValueEquals(
209+
keccak256(abi.encode(expectedRegisteredChainId, uint256(0x6))), expectedEmitter
210+
),
211+
"mapped slot 0x6 not equal to expected before upgrade"
212+
);
213+
assertTrue(
214+
forkedAddress.slotValueEquals(
215+
keccak256(abi.encode(expectedRegisteredChainId, uint256(0x7))),
216+
expectedCctpDomain
217+
),
218+
"mapped slot 0x7 not equal to expected before upgrade"
219+
);
220+
assertTrue(
221+
forkedAddress.slotValueEquals(
222+
keccak256(abi.encode(expectedCctpDomain, uint256(0x8))),
223+
expectedRegisteredChainId
224+
),
225+
"mapped slot 0x8 not equal to expected before upgrade"
226+
);
227+
assertTrue(
228+
forkedAddress.slotValueEquals(
229+
keccak256(abi.encode(vaa.hash, uint256(0x9))), isVaaConsumed
230+
),
231+
"mapped slot 0x9 not equal to expected before upgrade"
232+
);
233+
if (slotZeroData == 0) {
234+
assertTrue(
235+
forkedAddress.slotValueZero(0xa),
236+
"slot 0xa not equal to expected before upgrade"
237+
);
238+
} else {
239+
assertTrue(
240+
forkedAddress.slotValueEquals(0xa, expectedEvmChain),
241+
"slot 0xa not equal to expected before upgrade"
242+
);
243+
}
244+
}
245+
246+
// Upgrade contract.
247+
forked.upgradeContract(encodedVaa);
248+
249+
// Now initialized.
250+
isInitialized = forked.isInitialized(address(implementation));
251+
assertTrue(isInitialized, "implementation not initialized");
252+
253+
// VAA now consumed.
254+
isVaaConsumed = forked.isMessageConsumed(vaa.hash);
255+
assertTrue(isVaaConsumed, "VAA not consumed");
256+
257+
// Now check all slots that were checked before.
258+
{
259+
assertTrue(
260+
forkedAddress.slotValueZero(bytes32(0)),
261+
"slot 0x0 not equal to expected after upgrade"
262+
);
263+
assertTrue(
264+
forkedAddress.slotValueZero(0x1), "slot 0x1 not equal to expected after upgrade"
265+
);
266+
assertTrue(
267+
forkedAddress.slotValueZero(0x2), "slot 0x2 not equal to expected after upgrade"
268+
);
269+
assertTrue(
270+
forkedAddress.slotValueZero(0x3), "slot 0x3 not equal to expected after upgrade"
271+
);
272+
assertTrue(
273+
forkedAddress.slotValueZero(0x4), "slot 0x4 not equal to expected after upgrade"
274+
);
275+
assertTrue(
276+
forkedAddress.slotValueEquals(
277+
keccak256(abi.encode(address(implementation), uint256(0x5))), isInitialized
278+
),
279+
"mapped slot 0x5 not equal to expected after upgrade"
280+
);
281+
assertTrue(
282+
forkedAddress.slotValueEquals(
283+
keccak256(abi.encode(expectedRegisteredChainId, uint256(0x6))), expectedEmitter
284+
),
285+
"mapped slot 0x6 not equal to expected after upgrade"
286+
);
287+
assertTrue(
288+
forkedAddress.slotValueEquals(
289+
keccak256(abi.encode(expectedRegisteredChainId, uint256(0x7))),
290+
expectedCctpDomain
291+
),
292+
"mapped slot 0x7 not equal to expected after upgrade"
293+
);
294+
assertTrue(
295+
forkedAddress.slotValueEquals(
296+
keccak256(abi.encode(expectedCctpDomain, uint256(0x8))),
297+
expectedRegisteredChainId
298+
),
299+
"mapped slot 0x8 not equal to expected after upgrade"
300+
);
301+
assertTrue(
302+
forkedAddress.slotValueEquals(
303+
keccak256(abi.encode(vaa.hash, uint256(0x9))), isVaaConsumed
304+
),
305+
"mapped slot 0x9 not equal to expected after upgrade"
306+
);
307+
assertTrue(
308+
forkedAddress.slotValueZero(0xa), "slot 0xa not equal to expected after upgrade"
309+
);
310+
}
311+
312+
// Make sure getters still retrieve expected values.
313+
assertEq(forked.chainId(), expectedChainId, "chainId not equal to expected after upgrade");
314+
assertEq(
315+
forked.wormholeFinality(),
316+
expectedWormholeFinality,
317+
"wormholeFinality not equal to expected after upgrade"
318+
);
319+
assertEq(
320+
forked.localDomain(),
321+
expectedLocalDomain,
322+
"localDomain not equal to expected after upgrade"
323+
);
324+
assertEq(
325+
address(forked.wormhole()),
326+
expectedWormholeAddress,
327+
"wormholeAddress not equal to expected after upgrade"
328+
);
329+
assertEq(
330+
forked.governanceChainId(),
331+
expectedGovernanceChainId,
332+
"governanceChainId not equal to expected after upgrade"
333+
);
334+
assertEq(
335+
forked.governanceContract(),
336+
expectedGovernanceContract,
337+
"governanceContract not equal to expected after upgrade"
338+
);
339+
assertEq(
340+
address(forked.circleBridge()),
341+
expectedCircleBridgeAddress,
342+
"circleBridgeAddress not equal to expected after upgrade"
343+
);
344+
assertEq(
345+
address(forked.circleTransmitter()),
346+
expectedCircleTransmitterAddress,
347+
"circleTransmitterAddress not equal to expected after upgrade"
348+
);
349+
assertEq(
350+
address(forked.circleTokenMinter()),
351+
expectedCircleTokenMinterAddress,
352+
"circleTokenMinterAddress not equal to expected after upgrade"
353+
);
354+
assertEq(
355+
forked.evmChain(), expectedEvmChain, "evmChain not equal to expected after upgrade"
356+
);
357+
}
358+
}

evm/forge/tests/gas/CircleIntegrationComparison.t.sol

+1-1
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@ contract CircleIntegrationComparison is Test {
3838
bytes32 immutable FOREIGN_USDC_ADDRESS =
3939
bytes32(uint256(uint160(vm.envAddress("TESTING_FOREIGN_USDC_TOKEN_ADDRESS"))));
4040

41-
address immutable FORKED_CIRCLE_INTEGRATION_ADDRESS = 0x2703483B1a5a7c577e8680de9Df8Be03c6f30e3c;
41+
address constant FORKED_CIRCLE_INTEGRATION_ADDRESS = 0x2703483B1a5a7c577e8680de9Df8Be03c6f30e3c;
4242

4343
// dependencies
4444
IWormhole wormhole;

0 commit comments

Comments
 (0)