@@ -63,9 +63,7 @@ func MerkleUpdater(
6363
6464 ethClient := ethereumNetwork .EthClient
6565 _ , ethFundedKey := ethereumNetwork .GetFundedAccountInfo ()
66- chainID := ethereumNetwork .ChainID
6766 fundedAddress , fundedKey := avalancheNetwork .GetFundedAccountInfo ()
68- _ = chainID
6967
7068 // =========================================================================
7169 // Setup: Fetch P-chain validators and compute the genesis Merkle root
@@ -144,7 +142,7 @@ func MerkleUpdater(
144142
145143 initialCommitment , err := contract .GetValidatorSetCommitment (callOpts , l1BlockchainID )
146144 Expect (err ).Should (BeNil ())
147- Expect (initialCommitment .TotalWeight ).Should (Equal ( uint64 ( 0 ) ),
145+ Expect (initialCommitment .TotalWeight ).Should (BeZero ( ),
148146 "L1 commitment should start empty" )
149147
150148 log .Info ("Contract state verified: P-chain initialized, L1 not yet registered" )
@@ -193,37 +191,22 @@ func MerkleUpdater(
193191 // Wait for the relayer to register the initial L1 validator set.
194192 // totalWeight == 0 always triggers an immediate registration.
195193 // =========================================================================
196- pollCtx , pollCancel := context .WithTimeout (ctx , 120 * time .Second )
197- defer pollCancel ()
198-
199- ticker := time .NewTicker (2 * time .Second )
200- defer ticker .Stop ()
201-
202- var firstTotalWeight uint64
203- var firstPChainHeight uint64
204-
205- for done := false ; ! done ; {
206- select {
207- case <- pollCtx .Done ():
208- Expect (pollCtx .Err ()).ShouldNot (HaveOccurred (),
209- "Timed out waiting for relayer to register L1 validator set" )
210- case <- ticker .C :
211- cmt , err := contract .GetValidatorSetCommitment (callOpts , l1BlockchainID )
212- if err != nil {
213- log .Warn ("Failed to query on-chain commitment" , zap .Error (err ))
214- continue
215- }
194+ firstCmt := pollForCommitmentUpdate (
195+ ctx , log , contract , callOpts , l1BlockchainID , 120 * time .Second ,
196+ "Timed out waiting for relayer to register L1 validator set" ,
197+ func (cmt merkleregistry.ValidatorSetMerkleCommitment ) bool {
216198 if cmt .TotalWeight == 0 {
217199 log .Debug ("Validator set not yet registered, waiting..." )
218- continue
200+ return false
219201 }
220-
202+ return true
203+ },
204+ func (cmt merkleregistry.ValidatorSetMerkleCommitment ) {
221205 log .Info ("Initial validator set registered" ,
222206 zap .Uint64 ("totalWeight" , cmt .TotalWeight ),
223207 zap .Uint64 ("pChainHeight" , cmt .PChainHeight ),
224208 zap .String ("root" , hex .EncodeToString (cmt .Root [:])),
225209 )
226-
227210 Expect (cmt .PChainHeight ).Should (BeNumerically (">" , 0 ),
228211 "P-chain height should be positive" )
229212 Expect (cmt .PChainTimestamp ).Should (BeNumerically (">" , 0 ),
@@ -246,17 +229,13 @@ func MerkleUpdater(
246229 "Merkle root should match the P-chain validator set at the recorded height" )
247230 Expect (cmt .TotalWeight ).Should (Equal (expectedWeight ),
248231 "Total weight should match the sum of validator weights" )
249-
250- firstTotalWeight = cmt .TotalWeight
251- firstPChainHeight = cmt .PChainHeight
252- done = true
253- }
254- }
232+ },
233+ )
255234
256235 firstRegistrationTime := time .Now ()
257236 log .Info ("Initial registration complete" ,
258- zap .Uint64 ("firstTotalWeight" , firstTotalWeight ),
259- zap .Uint64 ("firstPChainHeight" , firstPChainHeight ),
237+ zap .Uint64 ("firstTotalWeight" , firstCmt . TotalWeight ),
238+ zap .Uint64 ("firstPChainHeight" , firstCmt . PChainHeight ),
260239 )
261240
262241 // =========================================================================
@@ -314,43 +293,26 @@ func MerkleUpdater(
314293
315294 // 90s timeout — well under the staleness cap. If the update arrives in this window
316295 // it was triggered by the root change, not by staleness.
317- rootChangeCtx , rootChangeCancel := context .WithTimeout (ctx , 90 * time .Second )
318- defer rootChangeCancel ()
319-
320- rootChangeTicker := time .NewTicker (2 * time .Second )
321- defer rootChangeTicker .Stop ()
322-
323- var secondPChainHeight uint64
324- var secondTotalWeight uint64
325- var secondRoot [32 ]byte
326-
327- for {
328- select {
329- case <- rootChangeCtx .Done ():
330- Expect (false ).Should (BeTrue (),
331- "Phase 1: Timed out waiting for root-change-triggered update" )
332- case <- rootChangeTicker .C :
333- cmt , err := contract .GetValidatorSetCommitment (callOpts , l1BlockchainID )
334- if err != nil {
335- log .Warn ("Failed to query on-chain commitment" , zap .Error (err ))
336- continue
337- }
338-
339- if cmt .PChainHeight <= firstPChainHeight {
296+ secondCmt := pollForCommitmentUpdate (
297+ ctx , log , contract , callOpts , l1BlockchainID , 90 * time .Second ,
298+ "Phase 1: Timed out waiting for root-change-triggered update" ,
299+ func (cmt merkleregistry.ValidatorSetMerkleCommitment ) bool {
300+ if cmt .PChainHeight <= firstCmt .PChainHeight {
340301 log .Debug ("Phase 1: Waiting for root-change update..." ,
341302 zap .Uint64 ("currentPChainHeight" , cmt .PChainHeight ),
342303 )
343- continue
304+ return false
344305 }
345-
306+ return true
307+ },
308+ func (cmt merkleregistry.ValidatorSetMerkleCommitment ) {
346309 log .Info ("Phase 1: Root-change update detected!" ,
347310 zap .Uint64 ("totalWeight" , cmt .TotalWeight ),
348311 zap .Uint64 ("pChainHeight" , cmt .PChainHeight ),
349312 zap .String ("root" , hex .EncodeToString (cmt .Root [:])),
350313 )
351-
352- Expect (cmt .PChainHeight ).Should (BeNumerically (">" , firstPChainHeight ))
353- Expect (cmt .TotalWeight ).Should (BeNumerically (">" , firstTotalWeight ),
314+ Expect (cmt .PChainHeight ).Should (BeNumerically (">" , firstCmt .PChainHeight ))
315+ Expect (cmt .TotalWeight ).Should (BeNumerically (">" , firstCmt .TotalWeight ),
354316 "Phase 1: New commitment should include the added validator's weight" )
355317 Expect (cmt .Root ).ShouldNot (Equal ([32 ]byte {}))
356318
@@ -361,18 +323,13 @@ func MerkleUpdater(
361323 expectedRoot := validatorupdater .BuildMerkleRoot (expectedValidators )
362324 Expect (cmt .Root ).Should (Equal (expectedRoot ),
363325 "Phase 1: Merkle root should match the updated P-chain validator set" )
364-
365- secondPChainHeight = cmt .PChainHeight
366- secondTotalWeight = cmt .TotalWeight
367- secondRoot = cmt .Root
368- }
369- break
370- }
326+ },
327+ )
371328
372329 secondUpdateTime := time .Now ()
373330 log .Info ("Phase 1 PASSED: Root-change-triggered update confirmed" ,
374- zap .Uint64 ("secondTotalWeight" , secondTotalWeight ),
375- zap .Uint64 ("secondPChainHeight" , secondPChainHeight ),
331+ zap .Uint64 ("secondTotalWeight" , secondCmt . TotalWeight ),
332+ zap .Uint64 ("secondPChainHeight" , secondCmt . PChainHeight ),
376333 )
377334
378335 // =========================================================================
@@ -400,49 +357,73 @@ func MerkleUpdater(
400357 zap .Duration ("remainingWait" , remainingWait ),
401358 )
402359
403- stalenessCtx , stalenessCancel := context .WithTimeout (ctx , remainingWait )
404- defer stalenessCancel ()
405-
406- stalenessTicker := time .NewTicker (2 * time .Second )
407- defer stalenessTicker .Stop ()
408-
409- for {
410- select {
411- case <- stalenessCtx .Done ():
412- Expect (false ).Should (BeTrue (),
413- "Phase 2: Timed out waiting for staleness-forced update" )
414- case <- stalenessTicker .C :
415- cmt , err := contract .GetValidatorSetCommitment (callOpts , l1BlockchainID )
416- if err != nil {
417- log .Warn ("Failed to query on-chain commitment" , zap .Error (err ))
418- continue
419- }
420-
421- if cmt .PChainHeight <= secondPChainHeight {
360+ pollForCommitmentUpdate (
361+ ctx , log , contract , callOpts , l1BlockchainID , remainingWait ,
362+ "Phase 2: Timed out waiting for staleness-forced update" ,
363+ func (cmt merkleregistry.ValidatorSetMerkleCommitment ) bool {
364+ if cmt .PChainHeight <= secondCmt .PChainHeight {
422365 log .Debug ("Phase 2: Still waiting for staleness update..." ,
423366 zap .Duration ("elapsed" , time .Since (secondUpdateTime )),
424367 )
425- continue
368+ return false
426369 }
427-
370+ return true
371+ },
372+ func (cmt merkleregistry.ValidatorSetMerkleCommitment ) {
428373 log .Info ("Phase 2: Staleness-forced update detected!" ,
429374 zap .Uint64 ("totalWeight" , cmt .TotalWeight ),
430375 zap .Uint64 ("pChainHeight" , cmt .PChainHeight ),
431376 zap .String ("root" , hex .EncodeToString (cmt .Root [:])),
432377 )
433-
434- Expect (cmt .PChainHeight ).Should (BeNumerically (">" , secondPChainHeight ))
435- Expect (cmt .TotalWeight ).Should (Equal (secondTotalWeight ),
378+ Expect (cmt .PChainHeight ).Should (BeNumerically (">" , secondCmt .PChainHeight ))
379+ Expect (cmt .TotalWeight ).Should (Equal (secondCmt .TotalWeight ),
436380 "Phase 2: Total weight should be unchanged (no new validators)" )
437- Expect (cmt .Root ).Should (Equal (secondRoot ),
381+ Expect (cmt .Root ).Should (Equal (secondCmt . Root ),
438382 "Phase 2: Merkle root should be unchanged (no new validators)" )
439383
440384 log .Info ("Phase 2 PASSED: Staleness-forced update confirmed" )
385+ },
386+ )
387+
388+ log .Info ("MerkleUpdater e2e test PASSED" )
389+ }
390+
391+ func pollForCommitmentUpdate (
392+ ctx context.Context ,
393+ log logging.Logger ,
394+ contract * merkleregistry.MerkleValidatorSetRegistry ,
395+ callOpts * bind.CallOpts ,
396+ l1BlockchainID ids.ID ,
397+ timeout time.Duration ,
398+ timeoutMsg string ,
399+ isUpdated func (cmt merkleregistry.ValidatorSetMerkleCommitment ) bool ,
400+ validate func (cmt merkleregistry.ValidatorSetMerkleCommitment ),
401+ ) merkleregistry.ValidatorSetMerkleCommitment {
402+ pollCtx , pollCancel := context .WithTimeout (ctx , timeout )
403+ defer pollCancel ()
404+
405+ ticker := time .NewTicker (2 * time .Second )
406+ defer ticker .Stop ()
407+
408+ for {
409+ select {
410+ case <- pollCtx .Done ():
411+ Expect (false ).Should (BeTrue (), timeoutMsg )
412+ case <- ticker .C :
413+ cmt , err := contract .GetValidatorSetCommitment (callOpts , l1BlockchainID )
414+ if err != nil {
415+ log .Warn ("Failed to query on-chain commitment" , zap .Error (err ))
416+ continue
417+ }
418+ if ! isUpdated (cmt ) {
419+ continue
420+ }
421+ validate (cmt )
422+ return cmt
441423 }
442424 break
443425 }
444-
445- log .Info ("MerkleUpdater e2e test PASSED" )
426+ panic ("unreachable" )
446427}
447428
448429func createMerkleUpdaterRelayerConfig (
0 commit comments