@@ -378,8 +378,8 @@ func TestMultiNode_selectNode(t *testing.T) {
378378 activeNode , err := mn .selectNode (ctx )
379379 require .NoError (t , err )
380380 require .Equal (t , oldBest .String (), activeNode .String ())
381- // old best is out-of-sync, a new alive node is available via selector
382- oldBest .On ("State" ).Return (nodeStateOutOfSync ).Maybe ()
381+ // old best died, so we should replace it
382+ oldBest .On ("State" ).Return (nodeStateOutOfSync ).Twice ()
383383 nodeSelector .On ("Select" ).Return (newBest ).Once ()
384384 newActiveNode , err := mn .selectNode (ctx )
385385 require .NoError (t , err )
@@ -404,143 +404,6 @@ func TestMultiNode_selectNode(t *testing.T) {
404404 require .Nil (t , node )
405405 tests .RequireLogMessage (t , observedLogs , "No live RPC nodes available" )
406406 })
407- t .Run ("Falls back to out-of-sync node when no alive nodes available" , func (t * testing.T ) {
408- t .Parallel ()
409- ctx := tests .Context (t )
410- chainID := RandomID ()
411- lggr , observedLogs := logger .TestObserved (t , zap .WarnLevel )
412- oosNode := newMockNode [ID , multiNodeRPCClient ](t )
413- oosNode .On ("State" ).Return (nodeStateOutOfSync ).Maybe ()
414- oosNode .On ("StateAndLatest" ).Return (nodeStateOutOfSync , ChainInfo {BlockNumber : 50 }).Maybe ()
415- oosNode .On ("String" ).Return ("oosNode" ).Maybe ()
416- unreachableNode := newMockNode [ID , multiNodeRPCClient ](t )
417- unreachableNode .On ("State" ).Return (nodeStateUnreachable ).Maybe ()
418- unreachableNode .On ("String" ).Return ("unreachableNode" ).Maybe ()
419- mn := newTestMultiNode (t , multiNodeOpts {
420- selectionMode : NodeSelectionModeRoundRobin ,
421- chainID : chainID ,
422- nodes : []Node [ID , multiNodeRPCClient ]{oosNode , unreachableNode },
423- logger : lggr ,
424- })
425- nodeSelector := newMockNodeSelector [ID , multiNodeRPCClient ](t )
426- nodeSelector .On ("Select" ).Return (nil )
427- mn .nodeSelector = nodeSelector
428- selected , err := mn .selectNode (ctx )
429- require .NoError (t , err )
430- assert .Equal (t , oosNode , selected )
431- tests .RequireLogMessage (t , observedLogs , "No alive RPC nodes available, falling back to out-of-sync node" )
432- })
433- t .Run ("Does not fall back to FinalizedBlockOutOfSync node" , func (t * testing.T ) {
434- t .Parallel ()
435- ctx := tests .Context (t )
436- chainID := RandomID ()
437- lggr , observedLogs := logger .TestObserved (t , zap .WarnLevel )
438- fbOosNode := newMockNode [ID , multiNodeRPCClient ](t )
439- fbOosNode .On ("State" ).Return (nodeStateFinalizedBlockOutOfSync ).Maybe ()
440- fbOosNode .On ("String" ).Return ("fbOosNode" ).Maybe ()
441- mn := newTestMultiNode (t , multiNodeOpts {
442- selectionMode : NodeSelectionModeRoundRobin ,
443- chainID : chainID ,
444- nodes : []Node [ID , multiNodeRPCClient ]{fbOosNode },
445- logger : lggr ,
446- })
447- nodeSelector := newMockNodeSelector [ID , multiNodeRPCClient ](t )
448- nodeSelector .On ("Select" ).Return (nil )
449- nodeSelector .On ("Name" ).Return ("MockedNodeSelector" )
450- mn .nodeSelector = nodeSelector
451- selected , err := mn .selectNode (ctx )
452- require .EqualError (t , err , ErrNodeError .Error ())
453- require .Nil (t , selected )
454- tests .RequireLogMessage (t , observedLogs , "No live RPC nodes available" )
455- })
456- t .Run ("Selects best out-of-sync node by highest block number" , func (t * testing.T ) {
457- t .Parallel ()
458- ctx := tests .Context (t )
459- chainID := RandomID ()
460- lggr , _ := logger .TestObserved (t , zap .WarnLevel )
461- oosLow := newMockNode [ID , multiNodeRPCClient ](t )
462- oosLow .On ("State" ).Return (nodeStateOutOfSync ).Maybe ()
463- oosLow .On ("StateAndLatest" ).Return (nodeStateOutOfSync , ChainInfo {BlockNumber : 30 }).Maybe ()
464- oosLow .On ("String" ).Return ("oosLow" ).Maybe ()
465- oosHigh := newMockNode [ID , multiNodeRPCClient ](t )
466- oosHigh .On ("State" ).Return (nodeStateOutOfSync ).Maybe ()
467- oosHigh .On ("StateAndLatest" ).Return (nodeStateOutOfSync , ChainInfo {BlockNumber : 90 }).Maybe ()
468- oosHigh .On ("String" ).Return ("oosHigh" ).Maybe ()
469- mn := newTestMultiNode (t , multiNodeOpts {
470- selectionMode : NodeSelectionModeRoundRobin ,
471- chainID : chainID ,
472- nodes : []Node [ID , multiNodeRPCClient ]{oosLow , oosHigh },
473- logger : lggr ,
474- })
475- nodeSelector := newMockNodeSelector [ID , multiNodeRPCClient ](t )
476- nodeSelector .On ("Select" ).Return (nil )
477- mn .nodeSelector = nodeSelector
478- selected , err := mn .selectNode (ctx )
479- require .NoError (t , err )
480- assert .Equal (t , oosHigh , selected )
481- })
482- t .Run ("Keeps out-of-sync active node when no alive node becomes available" , func (t * testing.T ) {
483- t .Parallel ()
484- ctx := tests .Context (t )
485- chainID := RandomID ()
486- oosNode := newMockNode [ID , multiNodeRPCClient ](t )
487- oosNode .On ("State" ).Return (nodeStateOutOfSync ).Maybe ()
488- oosNode .On ("StateAndLatest" ).Return (nodeStateOutOfSync , ChainInfo {BlockNumber : 50 }).Maybe ()
489- oosNode .On ("String" ).Return ("oosNode" ).Maybe ()
490- oosNode2 := newMockNode [ID , multiNodeRPCClient ](t )
491- oosNode2 .On ("State" ).Return (nodeStateOutOfSync ).Maybe ()
492- oosNode2 .On ("StateAndLatest" ).Return (nodeStateOutOfSync , ChainInfo {BlockNumber : 40 }).Maybe ()
493- oosNode2 .On ("String" ).Return ("oosNode2" ).Maybe ()
494- mn := newTestMultiNode (t , multiNodeOpts {
495- selectionMode : NodeSelectionModeRoundRobin ,
496- chainID : chainID ,
497- nodes : []Node [ID , multiNodeRPCClient ]{oosNode , oosNode2 },
498- })
499- nodeSelector := newMockNodeSelector [ID , multiNodeRPCClient ](t )
500- nodeSelector .On ("Select" ).Return (nil )
501- mn .nodeSelector = nodeSelector
502- // First call falls back to best out-of-sync (oosNode has higher block)
503- first , err := mn .selectNode (ctx )
504- require .NoError (t , err )
505- assert .Equal (t , oosNode , first )
506- // Second call: still no alive, keeps the same out-of-sync node (no switch to oosNode2)
507- second , err := mn .selectNode (ctx )
508- require .NoError (t , err )
509- assert .Equal (t , oosNode , second )
510- })
511- t .Run ("Upgrades from out-of-sync active to alive node when one becomes available" , func (t * testing.T ) {
512- t .Parallel ()
513- ctx := tests .Context (t )
514- chainID := RandomID ()
515- lggr , _ := logger .TestObserved (t , zap .DebugLevel )
516- oosNode := newMockNode [ID , multiNodeRPCClient ](t )
517- oosNode .On ("State" ).Return (nodeStateOutOfSync ).Maybe ()
518- oosNode .On ("StateAndLatest" ).Return (nodeStateOutOfSync , ChainInfo {BlockNumber : 50 }).Maybe ()
519- oosNode .On ("String" ).Return ("oosNode" ).Maybe ()
520- oosNode .On ("UnsubscribeAllExceptAliveLoop" ).Maybe ()
521- aliveNode := newMockNode [ID , multiNodeRPCClient ](t )
522- aliveNode .On ("State" ).Return (nodeStateAlive ).Maybe ()
523- aliveNode .On ("String" ).Return ("aliveNode" ).Maybe ()
524- mn := newTestMultiNode (t , multiNodeOpts {
525- selectionMode : NodeSelectionModeRoundRobin ,
526- chainID : chainID ,
527- nodes : []Node [ID , multiNodeRPCClient ]{oosNode , aliveNode },
528- logger : lggr ,
529- })
530- nodeSelector := newMockNodeSelector [ID , multiNodeRPCClient ](t )
531- // First select returns nil (no alive), second returns alive
532- nodeSelector .On ("Select" ).Return (nil ).Once ()
533- mn .nodeSelector = nodeSelector
534- // First selection falls back to out-of-sync
535- first , err := mn .selectNode (ctx )
536- require .NoError (t , err )
537- assert .Equal (t , oosNode , first )
538- // Now an alive node becomes available
539- nodeSelector .On ("Select" ).Return (aliveNode ).Once ()
540- second , err := mn .selectNode (ctx )
541- require .NoError (t , err )
542- assert .Equal (t , aliveNode , second )
543- })
544407}
545408
546409func TestMultiNode_RandomRPC (t * testing.T ) {
@@ -617,36 +480,6 @@ func TestMultiNode_RandomRPC(t *testing.T) {
617480 node1 .AssertNotCalled (t , "UnsubscribeAllExceptAliveLoop" )
618481 node2 .AssertNotCalled (t , "UnsubscribeAllExceptAliveLoop" )
619482 })
620- t .Run ("RandomRPC falls back to out-of-sync node when no alive nodes available" , func (t * testing.T ) {
621- t .Parallel ()
622- ctx := t .Context ()
623- chainID := RandomID ()
624- lggr , observedLogs := logger .TestObserved (t , zap .WarnLevel )
625- oosNode := newMockNode [ID , multiNodeRPCClient ](t )
626- oosNode .On ("State" ).Return (nodeStateOutOfSync ).Maybe ()
627- oosNode .On ("StateAndLatest" ).Return (nodeStateOutOfSync , ChainInfo {BlockNumber : 50 }).Maybe ()
628- oosNode .On ("String" ).Return ("oosNode" ).Maybe ()
629- mn := newTestMultiNode (t , multiNodeOpts {
630- selectionMode : NodeSelectionModeRandomRPC ,
631- chainID : chainID ,
632- nodes : []Node [ID , multiNodeRPCClient ]{oosNode },
633- logger : lggr ,
634- })
635- nodeSelector := newMockNodeSelector [ID , multiNodeRPCClient ](t )
636- nodeSelector .On ("Select" ).Return (nil )
637- mn .nodeSelector = nodeSelector
638-
639- first , err := mn .selectNode (ctx )
640- require .NoError (t , err )
641- assert .Equal (t , oosNode , first )
642- tests .RequireLogMessage (t , observedLogs , "No alive RPC nodes available, falling back to out-of-sync node" )
643-
644- second , err := mn .selectNode (ctx )
645- require .NoError (t , err )
646- assert .Equal (t , oosNode , second )
647-
648- oosNode .AssertNotCalled (t , "UnsubscribeAllExceptAliveLoop" )
649- })
650483 t .Run ("RandomRPC reports error when no nodes available" , func (t * testing.T ) {
651484 t .Parallel ()
652485 ctx := t .Context ()
0 commit comments