@@ -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
4574contract 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