Skip to content

Commit fc38bb3

Browse files
committed
test: CrossStore.sol
1 parent e134954 commit fc38bb3

File tree

2 files changed

+206
-4
lines changed

2 files changed

+206
-4
lines changed

src/core/CrossStore.sol

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -127,10 +127,14 @@ abstract contract CrossStore {
127127

128128
uint32[] memory arr = new uint32[](count);
129129
uint256 idx = 0;
130-
if ((mask & 0x01) != 0) arr[idx] = 0;
131-
++idx;
132-
if ((mask & 0x02) != 0) arr[idx] = 1;
133-
++idx;
130+
if ((mask & 0x01) != 0) {
131+
arr[idx] = 0;
132+
++idx;
133+
}
134+
if ((mask & 0x02) != 0) {
135+
arr[idx] = 1;
136+
++idx;
137+
}
134138
return arr;
135139
}
136140

test/CrossStore.t.sol

Lines changed: 198 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,35 @@ contract CrossStoreHarness is CrossStore {
4040
CoordStorage storage s = _getCoordStorage();
4141
return s.compactStates[txID].phase;
4242
}
43+
44+
//--- Coord Storage Logic Exposers ---
45+
function exposed_loadCoordinatorState(bytes32 txID) public view returns (CoordinatorState.Data memory) {
46+
return _loadCoordinatorState(txID);
47+
}
48+
49+
function exposed_saveCoordinatorState(bytes32 txID, CoordinatorState.Data memory data) public {
50+
_saveCoordinatorState(txID, data);
51+
}
52+
53+
function exposed_confirmParticipant(bytes32 txID) public {
54+
_confirmParticipant(txID);
55+
}
56+
57+
function exposed_completeSimpleProtocol(
58+
bytes32 txID,
59+
CoordinatorState.CoordinatorPhase phase,
60+
CoordinatorState.CoordinatorDecision decision
61+
) public {
62+
_completeSimpleProtocol(txID, phase, decision);
63+
}
64+
65+
function exposed_maskToUint32Array(uint8 mask) public pure returns (uint32[] memory) {
66+
return _maskToUint32Array(mask);
67+
}
68+
69+
function exposed_uint32ArrayToMask(uint32[] memory arr) public pure returns (uint8 mask) {
70+
return _uint32ArrayToMask(arr);
71+
}
4372
}
4473

4574
contract CrossStoreTest is Test {
@@ -98,4 +127,173 @@ contract CrossStoreTest is Test {
98127
"Coord storage collision with Tx"
99128
);
100129
}
130+
131+
function test_maskToUint32Array_Empty() public view {
132+
uint32[] memory res = harness.exposed_maskToUint32Array(0x00);
133+
assertEq(res.length, 0, "Should return empty array for mask 0x00");
134+
}
135+
136+
function test_maskToUint32Array_CoordinatorOnly() public view {
137+
uint32[] memory res = harness.exposed_maskToUint32Array(0x01);
138+
assertEq(res.length, 1, "Array length mismatch");
139+
assertEq(res[0], 0, "Index 0 should be TX_INDEX_COORDINATOR (0)");
140+
}
141+
142+
function test_maskToUint32Array_ParticipantOnly() public view {
143+
uint32[] memory res = harness.exposed_maskToUint32Array(0x02);
144+
assertEq(res.length, 1, "Array length mismatch");
145+
assertEq(res[0], 1, "Index 0 should be TX_INDEX_PARTICIPANT (1)");
146+
}
147+
148+
function test_maskToUint32Array_Both() public view {
149+
uint32[] memory res = harness.exposed_maskToUint32Array(0x03);
150+
assertEq(res.length, 2, "Array length mismatch");
151+
assertEq(res[0], 0, "First element mismatch");
152+
assertEq(res[1], 1, "Second element mismatch");
153+
}
154+
155+
function test_uint32ArrayToMask_Empty() public view {
156+
uint32[] memory arr = new uint32[](0);
157+
assertEq(harness.exposed_uint32ArrayToMask(arr), 0x00, "Empty array should yield mask 0x00");
158+
}
159+
160+
function test_uint32ArrayToMask_CoordinatorOnly() public view {
161+
uint32[] memory arr = new uint32[](1);
162+
arr[0] = 0;
163+
assertEq(harness.exposed_uint32ArrayToMask(arr), 0x01, "Mask mismatch for Coordinator");
164+
}
165+
166+
function test_uint32ArrayToMask_ParticipantOnly() public view {
167+
uint32[] memory arr = new uint32[](1);
168+
arr[0] = 1;
169+
assertEq(harness.exposed_uint32ArrayToMask(arr), 0x02, "Mask mismatch for Participant");
170+
}
171+
172+
function test_uint32ArrayToMask_Both() public view {
173+
uint32[] memory arr = new uint32[](2);
174+
arr[0] = 0;
175+
arr[1] = 1;
176+
assertEq(harness.exposed_uint32ArrayToMask(arr), 0x03, "Mask mismatch for Both");
177+
}
178+
179+
function test_uint32ArrayToMask_BothReversedOrder() public view {
180+
uint32[] memory arr = new uint32[](2);
181+
arr[0] = 1;
182+
arr[1] = 0;
183+
assertEq(harness.exposed_uint32ArrayToMask(arr), 0x03, "Mask should be 0x03 regardless of order");
184+
}
185+
186+
function test_SaveAndLoad_CoordinatorState() public {
187+
bytes32 txId = keccak256("tx.save.load");
188+
189+
CoordinatorState.Data memory original;
190+
original.commit_protocol = Tx.CommitProtocol.COMMIT_PROTOCOL_SIMPLE;
191+
original.phase = CoordinatorState.CoordinatorPhase.COORDINATOR_PHASE_PREPARE;
192+
original.decision = CoordinatorState.CoordinatorDecision.COORDINATOR_DECISION_UNKNOWN;
193+
194+
original.channels = new ChannelInfo.Data[](2);
195+
original.channels[0] = ChannelInfo.Data("", "");
196+
original.channels[1] = ChannelInfo.Data("port-1", "channel-1");
197+
198+
original.confirmed_txs = new uint32[](1);
199+
original.confirmed_txs[0] = 0;
200+
201+
harness.exposed_saveCoordinatorState(txId, original);
202+
203+
CoordinatorState.Data memory loaded = harness.exposed_loadCoordinatorState(txId);
204+
assertEq(uint256(loaded.commit_protocol), uint256(original.commit_protocol));
205+
assertEq(loaded.channels[1].port, "port-1");
206+
assertEq(loaded.confirmed_txs.length, 1);
207+
assertEq(loaded.confirmed_txs[0], 0);
208+
}
209+
210+
function test_SaveLoad_DataLossChannel0() public {
211+
bytes32 txId = keccak256("tx.dataloss.ch0");
212+
CoordinatorState.Data memory data = _createEmptyData();
213+
214+
data.channels = new ChannelInfo.Data[](2);
215+
data.channels[0] = ChannelInfo.Data("should-be-lost", "lost-channel");
216+
data.channels[1] = ChannelInfo.Data("port-1", "channel-1");
217+
218+
harness.exposed_saveCoordinatorState(txId, data);
219+
220+
CoordinatorState.Data memory loaded = harness.exposed_loadCoordinatorState(txId);
221+
222+
assertEq(loaded.channels[0].port, "", "Channel0 port should be lost");
223+
assertEq(loaded.channels[0].channel, "", "Channel0 channel should be lost");
224+
assertEq(loaded.channels[1].port, "port-1");
225+
}
226+
227+
function test_SaveLoad_DataLossExtraChannels() public {
228+
bytes32 txId = keccak256("tx.dataloss.extra_ch");
229+
CoordinatorState.Data memory data = _createEmptyData();
230+
231+
data.channels = new ChannelInfo.Data[](3);
232+
data.channels[0] = ChannelInfo.Data("", "");
233+
data.channels[1] = ChannelInfo.Data("port-1", "channel-1");
234+
data.channels[2] = ChannelInfo.Data("port-2", "channel-2");
235+
236+
harness.exposed_saveCoordinatorState(txId, data);
237+
238+
CoordinatorState.Data memory loaded = harness.exposed_loadCoordinatorState(txId);
239+
240+
assertEq(loaded.channels.length, 2, "Extra channels should be truncated to 2");
241+
}
242+
243+
function test_SaveLoad_DataLossUnsupportedIndices() public {
244+
bytes32 txId = keccak256("tx.dataloss.indices");
245+
CoordinatorState.Data memory data = _createEmptyData();
246+
247+
data.confirmed_txs = new uint32[](3);
248+
data.confirmed_txs[0] = 0;
249+
data.confirmed_txs[1] = 1;
250+
data.confirmed_txs[2] = 2;
251+
252+
harness.exposed_saveCoordinatorState(txId, data);
253+
254+
CoordinatorState.Data memory loaded = harness.exposed_loadCoordinatorState(txId);
255+
256+
assertEq(loaded.confirmed_txs.length, 2, "Index 2 should be lost");
257+
assertEq(loaded.confirmed_txs[0], 0);
258+
assertEq(loaded.confirmed_txs[1], 1);
259+
}
260+
261+
function _createEmptyData() internal pure returns (CoordinatorState.Data memory) {
262+
return CoordinatorState.Data({
263+
commit_protocol: Tx.CommitProtocol.COMMIT_PROTOCOL_SIMPLE,
264+
phase: CoordinatorState.CoordinatorPhase.COORDINATOR_PHASE_PREPARE,
265+
decision: CoordinatorState.CoordinatorDecision.COORDINATOR_DECISION_UNKNOWN,
266+
channels: new ChannelInfo.Data[](0),
267+
confirmed_txs: new uint32[](0),
268+
acks: new uint32[](0)
269+
});
270+
}
271+
272+
function test_confirmParticipant_UpdatesMask() public {
273+
bytes32 txId = keccak256("tx.confirm");
274+
275+
test_SaveAndLoad_CoordinatorState();
276+
txId = keccak256("tx.save.load");
277+
278+
harness.exposed_confirmParticipant(txId);
279+
280+
CoordinatorState.Data memory loaded = harness.exposed_loadCoordinatorState(txId);
281+
assertEq(loaded.confirmed_txs.length, 2, "Should have 2 confirmed txs");
282+
assertEq(loaded.confirmed_txs[1], 1, "Participant should be confirmed");
283+
}
284+
285+
function test_completeSimpleProtocol_SetsCorrectValues() public {
286+
bytes32 txId = keccak256("tx.complete");
287+
288+
harness.exposed_completeSimpleProtocol(
289+
txId,
290+
CoordinatorState.CoordinatorPhase.COORDINATOR_PHASE_COMMIT,
291+
CoordinatorState.CoordinatorDecision.COORDINATOR_DECISION_COMMIT
292+
);
293+
294+
CoordinatorState.Data memory loaded = harness.exposed_loadCoordinatorState(txId);
295+
assertEq(uint256(loaded.phase), uint256(CoordinatorState.CoordinatorPhase.COORDINATOR_PHASE_COMMIT));
296+
assertEq(uint256(loaded.decision), uint256(CoordinatorState.CoordinatorDecision.COORDINATOR_DECISION_COMMIT));
297+
assertEq(loaded.acks.length, 2, "Both Coord and Participant should be in ACKs");
298+
}
101299
}

0 commit comments

Comments
 (0)