@@ -15,6 +15,8 @@ use ledger::proofs::{VerifierIndex, VerifierSRS};
15
15
use libp2p:: futures:: { stream:: FuturesUnordered , StreamExt } ;
16
16
use node:: core:: channels:: mpsc;
17
17
use node:: core:: requests:: RpcId ;
18
+ use node:: p2p:: connection:: outgoing:: P2pConnectionOutgoingInitOpts ;
19
+ use node:: p2p:: { P2pConnectionEvent , P2pDiscoveryEvent , PeerId } ;
18
20
use node:: {
19
21
account:: { AccountPublicKey , AccountSecretKey } ,
20
22
event_source:: Event ,
@@ -38,7 +40,7 @@ use openmina_node_native::{http_server, rpc::RpcService, NodeService, RpcSender}
38
40
use rand:: { rngs:: StdRng , SeedableRng } ;
39
41
use serde:: Serialize ;
40
42
41
- use crate :: node:: { DaemonJson , OcamlStep , TestPeerId } ;
43
+ use crate :: node:: { DaemonJson , NonDeterministicEvent , OcamlStep , TestPeerId } ;
42
44
use crate :: {
43
45
network_debugger:: Debugger ,
44
46
node:: {
@@ -277,6 +279,9 @@ impl Cluster {
277
279
if self . config . all_rust_to_rust_use_webrtc ( ) {
278
280
service. set_rust_to_rust_use_webrtc ( ) ;
279
281
}
282
+ if self . config . is_replay ( ) {
283
+ service. set_replay ( ) ;
284
+ }
280
285
281
286
let state = node:: State :: new ( config) ;
282
287
fn effects ( store : & mut node:: Store < NodeTestingService > , action : node:: ActionWithMeta ) {
@@ -409,6 +414,12 @@ impl Cluster {
409
414
self . nodes . get ( node_id. index ( ) )
410
415
}
411
416
417
+ pub fn node_by_peer_id ( & self , peer_id : PeerId ) -> Option < & Node > {
418
+ self . nodes_iter ( )
419
+ . find ( |( _, node) | node. peer_id ( ) == peer_id)
420
+ . map ( |( _, node) | node)
421
+ }
422
+
412
423
pub fn node_mut ( & mut self , node_id : ClusterNodeId ) -> Option < & mut Node > {
413
424
self . nodes . get_mut ( node_id. index ( ) )
414
425
}
@@ -419,6 +430,12 @@ impl Cluster {
419
430
. map ( |opt| opt. as_ref ( ) . expect ( "tried to access removed ocaml node" ) )
420
431
}
421
432
433
+ pub fn ocaml_node_by_peer_id ( & self , peer_id : PeerId ) -> Option < & OcamlNode > {
434
+ self . ocaml_nodes_iter ( )
435
+ . find ( |( _, node) | node. peer_id ( ) == peer_id)
436
+ . map ( |( _, node) | node)
437
+ }
438
+
422
439
pub fn pending_events (
423
440
& mut self ,
424
441
) -> impl Iterator <
@@ -471,6 +488,35 @@ impl Cluster {
471
488
}
472
489
}
473
490
491
+ pub async fn wait_for_pending_event (
492
+ & mut self ,
493
+ node_id : ClusterNodeId ,
494
+ event_pattern : & str ,
495
+ ) -> anyhow:: Result < PendingEventId > {
496
+ let node = self
497
+ . nodes
498
+ . get_mut ( node_id. index ( ) )
499
+ . ok_or_else ( || anyhow:: anyhow!( "node {node_id:?} not found" ) ) ?;
500
+ let timeout = tokio:: time:: sleep ( Duration :: from_secs ( 60 ) ) ;
501
+ tokio:: select! {
502
+ opt = node. wait_for_event( & event_pattern) => opt. ok_or_else( || anyhow:: anyhow!( "wait_for_event: None" ) ) ,
503
+ _ = timeout => {
504
+ let pending_events = node. pending_events( ) . map( |( _, event) | event. to_string( ) ) . collect:: <Vec <_>>( ) ;
505
+ return Err ( anyhow:: anyhow!( "waiting for event timed out! node {node_id:?}, event: \" {event_pattern}\" \n {pending_events:?}" ) ) ;
506
+ }
507
+ }
508
+ }
509
+
510
+ pub async fn wait_for_event_and_dispatch (
511
+ & mut self ,
512
+ node_id : ClusterNodeId ,
513
+ event_pattern : & str ,
514
+ ) -> anyhow:: Result < bool > {
515
+ let event_id = self . wait_for_pending_event ( node_id, event_pattern) . await ?;
516
+ let node = self . nodes . get_mut ( node_id. index ( ) ) . unwrap ( ) ;
517
+ Ok ( node. take_event_and_dispatch ( event_id) )
518
+ }
519
+
474
520
pub async fn add_steps_and_save ( & mut self , steps : impl IntoIterator < Item = ScenarioStep > ) {
475
521
let scenario = self . scenario . chain . back_mut ( ) . unwrap ( ) ;
476
522
steps
@@ -480,10 +526,14 @@ impl Cluster {
480
526
}
481
527
482
528
pub async fn exec_to_end ( & mut self ) -> Result < ( ) , anyhow:: Error > {
529
+ let mut i = 0 ;
530
+ let total = self . scenario . cur_scenario ( ) . steps . len ( ) ;
483
531
loop {
532
+ eprintln ! ( "[step]: {i}/{total}" ) ;
484
533
if !self . exec_next ( ) . await ? {
485
534
break Ok ( ( ) ) ;
486
535
}
536
+ i += 1 ;
487
537
}
488
538
}
489
539
@@ -545,29 +595,129 @@ impl Cluster {
545
595
Ok ( dispatched)
546
596
}
547
597
548
- pub async fn exec_step ( & mut self , step : ScenarioStep ) -> Result < bool , anyhow:: Error > {
598
+ pub async fn exec_step ( & mut self , step : ScenarioStep ) -> anyhow:: Result < bool > {
599
+ fn node_addr_by_peer_id (
600
+ cluster : & Cluster ,
601
+ peer_id : PeerId ,
602
+ ) -> anyhow:: Result < P2pConnectionOutgoingInitOpts > {
603
+ cluster
604
+ . node_by_peer_id ( peer_id)
605
+ . map ( |node| node. dial_addr ( ) )
606
+ . or_else ( || {
607
+ cluster
608
+ . ocaml_node_by_peer_id ( peer_id)
609
+ . map ( |node| node. dial_addr ( ) )
610
+ } )
611
+ . ok_or_else ( || anyhow:: anyhow!( "node with peer_id: '{peer_id}' not found" ) )
612
+ }
613
+
549
614
Ok ( match step {
615
+ ScenarioStep :: Event { node_id, event } => {
616
+ return self . wait_for_event_and_dispatch ( node_id, & event) . await ;
617
+ }
550
618
ScenarioStep :: ManualEvent { node_id, event } => self
551
619
. nodes
552
620
. get_mut ( node_id. index ( ) )
553
621
. ok_or_else ( || anyhow:: anyhow!( "node {node_id:?} not found" ) ) ?
554
622
. dispatch_event ( * event) ,
555
- ScenarioStep :: Event { node_id, event } => {
556
- let node = self
557
- . nodes
558
- . get_mut ( node_id. index ( ) )
559
- . ok_or_else ( || anyhow:: anyhow!( "node {node_id:?} not found" ) ) ?;
560
- let timeout = tokio:: time:: sleep ( Duration :: from_secs ( 60 ) ) ;
561
- tokio:: select! {
562
- res = node. wait_for_event_and_dispatch( & event) => res,
563
- _ = timeout => {
564
- return Err ( anyhow:: anyhow!( "waiting for event timed out! node {node_id:?}, event: \" {event}\" " ) ) ;
623
+ ScenarioStep :: NonDeterministicEvent { node_id, event } => {
624
+ let event = match * event {
625
+ NonDeterministicEvent :: P2pListen => return Ok ( true ) ,
626
+ NonDeterministicEvent :: P2pConnectionClosed ( peer_id) => {
627
+ let node = self
628
+ . nodes
629
+ . get_mut ( node_id. index ( ) )
630
+ . ok_or_else ( || anyhow:: anyhow!( "node {node_id:?} not found" ) ) ?;
631
+ node. p2p_disconnect ( peer_id) ;
632
+ let event =
633
+ Event :: P2p ( P2pEvent :: Connection ( P2pConnectionEvent :: Closed ( peer_id) ) ) ;
634
+ return self
635
+ . wait_for_event_and_dispatch ( node_id, & event. to_string ( ) )
636
+ . await ;
565
637
}
566
- }
638
+ NonDeterministicEvent :: P2pConnectionFinalized ( peer_id, res) => {
639
+ let node = self
640
+ . nodes
641
+ . get ( node_id. index ( ) )
642
+ . ok_or_else ( || anyhow:: anyhow!( "node {node_id:?} not found" ) ) ?;
643
+ let res_is_ok = res. is_ok ( ) ;
644
+ let event = Event :: P2p ( P2pEvent :: Connection (
645
+ P2pConnectionEvent :: Finalized ( peer_id, res) ,
646
+ ) ) ;
647
+
648
+ if res_is_ok {
649
+ let is_peer_connected =
650
+ node. state ( ) . p2p . get_ready_peer ( & peer_id) . is_some ( ) ;
651
+ // deduce if kad initiated this conn.
652
+ if !node. state ( ) . p2p . is_peer_connected_or_connecting ( & peer_id) {
653
+ let my_addr = node. dial_addr ( ) ;
654
+ let peer = self
655
+ . nodes
656
+ . iter_mut ( )
657
+ . find ( |node| node. peer_id ( ) == peer_id)
658
+ . ok_or_else ( || {
659
+ anyhow:: anyhow!( "node with peer_id: '{peer_id}' not found" )
660
+ } ) ?;
661
+
662
+ if !peer. state ( ) . p2p . is_peer_connecting ( my_addr. peer_id ( ) ) {
663
+ // kad initiated this connection so replay that.
664
+ eprintln ! (
665
+ "p2p_kad_outgoing_init({:?}) -> {:?} - {}" ,
666
+ peer. node_id( ) ,
667
+ node_id,
668
+ my_addr
669
+ ) ;
670
+ peer. p2p_kad_outgoing_init ( my_addr) ;
671
+ }
672
+ }
673
+ if is_peer_connected {
674
+ // we are already connected, so skip the extra event.
675
+ return Ok ( true ) ;
676
+ }
677
+ eprintln ! ( "non_deterministic_wait_for_event_and_dispatch({node_id:?}): {event}" ) ;
678
+ return self
679
+ . wait_for_event_and_dispatch ( node_id, & event. to_string ( ) )
680
+ . await ;
681
+ } else {
682
+ event
683
+ }
684
+ }
685
+ NonDeterministicEvent :: P2pLibp2pIdentify ( peer_id) => {
686
+ let addr = match node_addr_by_peer_id ( self , peer_id) ? {
687
+ P2pConnectionOutgoingInitOpts :: LibP2P ( v) => ( & v) . into ( ) ,
688
+ _ => unreachable ! ( ) ,
689
+ } ;
690
+ P2pEvent :: Libp2pIdentify ( peer_id, addr) . into ( )
691
+ }
692
+ NonDeterministicEvent :: P2pDiscoveryReady => {
693
+ P2pEvent :: Discovery ( P2pDiscoveryEvent :: Ready ) . into ( )
694
+ }
695
+ NonDeterministicEvent :: P2pDiscoveryDidFindPeers ( ids) => {
696
+ P2pEvent :: Discovery ( P2pDiscoveryEvent :: DidFindPeers ( ids) ) . into ( )
697
+ }
698
+ NonDeterministicEvent :: P2pDiscoveryDidFindPeersError ( err) => {
699
+ P2pEvent :: Discovery ( P2pDiscoveryEvent :: DidFindPeersError ( err) ) . into ( )
700
+ }
701
+ NonDeterministicEvent :: P2pDiscoveryAddRoute ( id, ids) => {
702
+ let addrs = ids
703
+ . into_iter ( )
704
+ . map ( |id| node_addr_by_peer_id ( & self , id) )
705
+ . collect :: < Result < Vec < _ > , _ > > ( ) ?;
706
+ P2pEvent :: Discovery ( P2pDiscoveryEvent :: AddRoute ( id, addrs) ) . into ( )
707
+ }
708
+ NonDeterministicEvent :: RpcReadonly ( id, req) => Event :: Rpc ( id, req) . into ( ) ,
709
+ } ;
710
+ eprintln ! ( "non_deterministic_event_dispatch({node_id:?}): {event}" ) ;
711
+ self . nodes
712
+ . get_mut ( node_id. index ( ) )
713
+ . ok_or_else ( || anyhow:: anyhow!( "node {node_id:?} not found" ) ) ?
714
+ . dispatch_event ( event)
567
715
}
568
716
ScenarioStep :: AddNode { config } => match config {
569
717
NodeTestingConfig :: Rust ( config) => {
570
718
self . add_rust_node ( config) ;
719
+ // TODO(binier): wait for node ports to be opened instead.
720
+ tokio:: time:: sleep ( Duration :: from_secs ( 2 ) ) . await ;
571
721
true
572
722
}
573
723
NodeTestingConfig :: Ocaml ( config) => {
0 commit comments