2021-09-08 00:36:52 +10:00
// Copyright 2021 COMIT Network.
//
// Permission is hereby granted, free of charge, to any person obtaining a
// copy of this software and associated documentation files (the "Software"),
// to deal in the Software without restriction, including without limitation
// the rights to use, copy, modify, merge, publish, distribute, sublicense,
// and/or sell copies of the Software, and to permit persons to whom the
// Software is furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE.
use futures ::stream ::FuturesUnordered ;
use futures ::StreamExt ;
2023-10-15 04:40:13 -04:00
use libp2p_core ::multiaddr ::Protocol ;
use libp2p_core ::Multiaddr ;
2023-03-13 01:46:58 +11:00
use libp2p_identity as identity ;
2022-12-13 07:58:01 +11:00
use libp2p_rendezvous as rendezvous ;
2023-06-17 14:19:41 +03:00
use libp2p_rendezvous ::client ::RegisterError ;
2022-12-13 07:58:01 +11:00
use libp2p_swarm ::{ DialError , Swarm , SwarmEvent } ;
2023-03-08 20:36:35 +11:00
use libp2p_swarm_test ::SwarmExt ;
2021-09-08 00:36:52 +10:00
use std ::convert ::TryInto ;
use std ::time ::Duration ;
#[ tokio::test ]
async fn given_successful_registration_then_successful_discovery ( ) {
let _ = env_logger ::try_init ( ) ;
let namespace = rendezvous ::Namespace ::from_static ( " some-namespace " ) ;
let ( [ mut alice , mut bob ] , mut robert ) =
new_server_with_connected_clients ( rendezvous ::server ::Config ::default ( ) ) . await ;
2022-10-04 18:24:38 +11:00
alice
2021-09-08 00:36:52 +10:00
. behaviour_mut ( )
2023-06-17 14:19:41 +03:00
. register ( namespace . clone ( ) , * robert . local_peer_id ( ) , None )
. unwrap ( ) ;
2021-09-08 00:36:52 +10:00
2023-03-08 20:36:35 +11:00
match libp2p_swarm_test ::drive ( & mut alice , & mut robert ) . await {
(
[ rendezvous ::client ::Event ::Registered {
rendezvous_node ,
ttl ,
namespace : register_node_namespace ,
} ] ,
[ rendezvous ::server ::Event ::PeerRegistered { peer , registration } ] ,
) = > {
2021-09-08 00:36:52 +10:00
assert_eq! ( & peer , alice . local_peer_id ( ) ) ;
assert_eq! ( & rendezvous_node , robert . local_peer_id ( ) ) ;
assert_eq! ( registration . namespace , namespace ) ;
assert_eq! ( register_node_namespace , namespace ) ;
assert_eq! ( ttl , rendezvous ::DEFAULT_TTL ) ;
}
2023-03-08 20:36:35 +11:00
events = > panic! ( " Unexpected events: {events:?} " ) ,
}
2021-09-08 00:36:52 +10:00
bob . behaviour_mut ( )
. discover ( Some ( namespace . clone ( ) ) , None , None , * robert . local_peer_id ( ) ) ;
2023-03-08 20:36:35 +11:00
match libp2p_swarm_test ::drive ( & mut bob , & mut robert ) . await {
(
[ rendezvous ::client ::Event ::Discovered { registrations , .. } ] ,
[ rendezvous ::server ::Event ::DiscoverServed { .. } ] ,
) = > match registrations . as_slice ( ) {
[ rendezvous ::Registration {
namespace : registered_namespace ,
record ,
ttl ,
} ] = > {
assert_eq! ( * ttl , rendezvous ::DEFAULT_TTL ) ;
assert_eq! ( record . peer_id ( ) , * alice . local_peer_id ( ) ) ;
assert_eq! ( * registered_namespace , namespace ) ;
2021-09-08 00:36:52 +10:00
}
2023-03-08 20:36:35 +11:00
_ = > panic! ( " Expected exactly one registration to be returned from discover " ) ,
} ,
events = > panic! ( " Unexpected events: {events:?} " ) ,
}
2021-09-08 00:36:52 +10:00
}
2023-06-17 14:19:41 +03:00
#[ tokio::test ]
async fn should_return_error_when_no_external_addresses ( ) {
let _ = env_logger ::try_init ( ) ;
let namespace = rendezvous ::Namespace ::from_static ( " some-namespace " ) ;
let server = new_server ( rendezvous ::server ::Config ::default ( ) ) . await ;
let mut client = Swarm ::new_ephemeral ( rendezvous ::client ::Behaviour ::new ) ;
let actual = client
. behaviour_mut ( )
. register ( namespace . clone ( ) , * server . local_peer_id ( ) , None )
. unwrap_err ( ) ;
assert! ( matches! ( actual , RegisterError ::NoExternalAddresses ) )
}
2021-09-08 00:36:52 +10:00
#[ tokio::test ]
async fn given_successful_registration_then_refresh_ttl ( ) {
let _ = env_logger ::try_init ( ) ;
let namespace = rendezvous ::Namespace ::from_static ( " some-namespace " ) ;
let ( [ mut alice , mut bob ] , mut robert ) =
new_server_with_connected_clients ( rendezvous ::server ::Config ::default ( ) ) . await ;
let roberts_peer_id = * robert . local_peer_id ( ) ;
let refresh_ttl = 10_000 ;
2022-10-04 18:24:38 +11:00
alice
2021-09-08 00:36:52 +10:00
. behaviour_mut ( )
2023-06-17 14:19:41 +03:00
. register ( namespace . clone ( ) , roberts_peer_id , None )
. unwrap ( ) ;
2021-09-08 00:36:52 +10:00
2023-03-08 20:36:35 +11:00
match libp2p_swarm_test ::drive ( & mut alice , & mut robert ) . await {
(
[ rendezvous ::client ::Event ::Registered { .. } ] ,
[ rendezvous ::server ::Event ::PeerRegistered { .. } ] ,
) = > { }
events = > panic! ( " Unexpected events: {events:?} " ) ,
}
2021-09-08 00:36:52 +10:00
bob . behaviour_mut ( )
. discover ( Some ( namespace . clone ( ) ) , None , None , roberts_peer_id ) ;
2023-03-08 20:36:35 +11:00
match libp2p_swarm_test ::drive ( & mut bob , & mut robert ) . await {
(
[ rendezvous ::client ::Event ::Discovered { .. } ] ,
[ rendezvous ::server ::Event ::DiscoverServed { .. } ] ,
) = > { }
events = > panic! ( " Unexpected events: {events:?} " ) ,
}
2021-09-08 00:36:52 +10:00
alice
. behaviour_mut ( )
2023-06-17 14:19:41 +03:00
. register ( namespace . clone ( ) , roberts_peer_id , Some ( refresh_ttl ) )
. unwrap ( ) ;
2021-09-08 00:36:52 +10:00
2023-03-08 20:36:35 +11:00
match libp2p_swarm_test ::drive ( & mut alice , & mut robert ) . await {
(
[ rendezvous ::client ::Event ::Registered { ttl , .. } ] ,
[ rendezvous ::server ::Event ::PeerRegistered { .. } ] ,
) = > {
2021-09-08 00:36:52 +10:00
assert_eq! ( ttl , refresh_ttl ) ;
}
2023-03-08 20:36:35 +11:00
events = > panic! ( " Unexpected events: {events:?} " ) ,
}
2021-09-08 00:36:52 +10:00
bob . behaviour_mut ( )
. discover ( Some ( namespace . clone ( ) ) , None , None , * robert . local_peer_id ( ) ) ;
2023-03-08 20:36:35 +11:00
match libp2p_swarm_test ::drive ( & mut bob , & mut robert ) . await {
(
[ rendezvous ::client ::Event ::Discovered { registrations , .. } ] ,
[ rendezvous ::server ::Event ::DiscoverServed { .. } ] ,
) = > match registrations . as_slice ( ) {
[ rendezvous ::Registration { ttl , .. } ] = > {
assert_eq! ( * ttl , refresh_ttl ) ;
2021-09-08 00:36:52 +10:00
}
2023-03-08 20:36:35 +11:00
_ = > panic! ( " Expected exactly one registration to be returned from discover " ) ,
} ,
events = > panic! ( " Unexpected events: {events:?} " ) ,
}
2021-09-08 00:36:52 +10:00
}
2023-10-15 04:40:13 -04:00
#[ tokio::test ]
async fn given_successful_registration_then_refresh_external_addrs ( ) {
let _ = env_logger ::try_init ( ) ;
let namespace = rendezvous ::Namespace ::from_static ( " some-namespace " ) ;
let ( [ mut alice ] , mut robert ) =
new_server_with_connected_clients ( rendezvous ::server ::Config ::default ( ) ) . await ;
let roberts_peer_id = * robert . local_peer_id ( ) ;
alice
. behaviour_mut ( )
. register ( namespace . clone ( ) , roberts_peer_id , None )
. unwrap ( ) ;
match libp2p_swarm_test ::drive ( & mut alice , & mut robert ) . await {
(
[ rendezvous ::client ::Event ::Registered { .. } ] ,
[ rendezvous ::server ::Event ::PeerRegistered { .. } ] ,
) = > { }
events = > panic! ( " Unexpected events: {events:?} " ) ,
}
let external_addr = Multiaddr ::empty ( ) . with ( Protocol ::Memory ( 0 ) ) ;
alice . add_external_address ( external_addr . clone ( ) ) ;
match libp2p_swarm_test ::drive ( & mut alice , & mut robert ) . await {
(
[ rendezvous ::client ::Event ::Registered { .. } ] ,
[ rendezvous ::server ::Event ::PeerRegistered { registration , .. } ] ,
) = > {
let record = registration . record ;
assert! ( record . addresses ( ) . contains ( & external_addr ) ) ;
}
events = > panic! ( " Unexpected events: {events:?} " ) ,
}
alice . remove_external_address ( & external_addr ) ;
match libp2p_swarm_test ::drive ( & mut alice , & mut robert ) . await {
(
[ rendezvous ::client ::Event ::Registered { .. } ] ,
[ rendezvous ::server ::Event ::PeerRegistered { registration , .. } ] ,
) = > {
let record = registration . record ;
assert! ( ! record . addresses ( ) . contains ( & external_addr ) ) ;
}
events = > panic! ( " Unexpected events: {events:?} " ) ,
}
}
2021-09-08 00:36:52 +10:00
#[ tokio::test ]
async fn given_invalid_ttl_then_unsuccessful_registration ( ) {
let _ = env_logger ::try_init ( ) ;
let namespace = rendezvous ::Namespace ::from_static ( " some-namespace " ) ;
let ( [ mut alice ] , mut robert ) =
new_server_with_connected_clients ( rendezvous ::server ::Config ::default ( ) ) . await ;
2023-06-17 14:19:41 +03:00
alice
. behaviour_mut ( )
. register (
namespace . clone ( ) ,
* robert . local_peer_id ( ) ,
Some ( 100_000_000 ) ,
)
. unwrap ( ) ;
2021-09-08 00:36:52 +10:00
2023-03-08 20:36:35 +11:00
match libp2p_swarm_test ::drive ( & mut alice , & mut robert ) . await {
(
2023-06-17 14:19:41 +03:00
[ rendezvous ::client ::Event ::RegisterFailed { error , .. } ] ,
2023-03-08 20:36:35 +11:00
[ rendezvous ::server ::Event ::PeerNotRegistered { .. } ] ,
) = > {
2021-09-08 00:36:52 +10:00
assert_eq! ( error , rendezvous ::ErrorCode ::InvalidTtl ) ;
}
2023-03-08 20:36:35 +11:00
events = > panic! ( " Unexpected events: {events:?} " ) ,
}
2021-09-08 00:36:52 +10:00
}
#[ tokio::test ]
async fn discover_allows_for_dial_by_peer_id ( ) {
let _ = env_logger ::try_init ( ) ;
let namespace = rendezvous ::Namespace ::from_static ( " some-namespace " ) ;
let ( [ mut alice , mut bob ] , robert ) =
new_server_with_connected_clients ( rendezvous ::server ::Config ::default ( ) ) . await ;
let roberts_peer_id = * robert . local_peer_id ( ) ;
2023-03-08 20:36:35 +11:00
tokio ::spawn ( robert . loop_on_next ( ) ) ;
2021-09-08 00:36:52 +10:00
alice
. behaviour_mut ( )
2023-06-17 14:19:41 +03:00
. register ( namespace . clone ( ) , roberts_peer_id , None )
. unwrap ( ) ;
2023-03-08 20:36:35 +11:00
match alice . next_behaviour_event ( ) . await {
rendezvous ::client ::Event ::Registered { .. } = > { }
event = > panic! ( " Unexpected event: {event:?} " ) ,
}
2021-09-08 00:36:52 +10:00
2021-10-14 18:05:07 +02:00
bob . behaviour_mut ( )
. discover ( Some ( namespace . clone ( ) ) , None , None , roberts_peer_id ) ;
2023-03-08 20:36:35 +11:00
match bob . next_behaviour_event ( ) . await {
rendezvous ::client ::Event ::Discovered { registrations , .. } = > {
2021-10-14 18:05:07 +02:00
assert! ( ! registrations . is_empty ( ) ) ;
}
2023-03-08 20:36:35 +11:00
event = > panic! ( " Unexpected event: {event:?} " ) ,
}
2021-10-14 18:05:07 +02:00
2021-09-08 00:36:52 +10:00
let alices_peer_id = * alice . local_peer_id ( ) ;
let bobs_peer_id = * bob . local_peer_id ( ) ;
2021-11-15 14:17:23 +01:00
bob . dial ( alices_peer_id ) . unwrap ( ) ;
2021-09-08 00:36:52 +10:00
let alice_connected_to = tokio ::spawn ( async move {
loop {
if let SwarmEvent ::ConnectionEstablished { peer_id , .. } =
alice . select_next_some ( ) . await
{
break peer_id ;
}
}
} ) ;
let bob_connected_to = tokio ::spawn ( async move {
loop {
if let SwarmEvent ::ConnectionEstablished { peer_id , .. } = bob . select_next_some ( ) . await
{
break peer_id ;
}
}
} ) ;
assert_eq! ( alice_connected_to . await . unwrap ( ) , bobs_peer_id ) ;
assert_eq! ( bob_connected_to . await . unwrap ( ) , alices_peer_id ) ;
}
#[ tokio::test ]
async fn eve_cannot_register ( ) {
let _ = env_logger ::try_init ( ) ;
let namespace = rendezvous ::Namespace ::from_static ( " some-namespace " ) ;
let mut robert = new_server ( rendezvous ::server ::Config ::default ( ) ) . await ;
let mut eve = new_impersonating_client ( ) . await ;
2023-03-08 20:36:35 +11:00
eve . connect ( & mut robert ) . await ;
2021-09-08 00:36:52 +10:00
eve . behaviour_mut ( )
2023-06-17 14:19:41 +03:00
. register ( namespace . clone ( ) , * robert . local_peer_id ( ) , None )
. unwrap ( ) ;
2021-09-08 00:36:52 +10:00
2023-03-08 20:36:35 +11:00
match libp2p_swarm_test ::drive ( & mut eve , & mut robert ) . await {
(
2023-06-17 14:19:41 +03:00
[ rendezvous ::client ::Event ::RegisterFailed {
error : err_code , ..
} ] ,
2023-03-08 20:36:35 +11:00
[ rendezvous ::server ::Event ::PeerNotRegistered { .. } ] ,
) = > {
2021-09-08 00:36:52 +10:00
assert_eq! ( err_code , rendezvous ::ErrorCode ::NotAuthorized ) ;
}
2023-03-08 20:36:35 +11:00
events = > panic! ( " Unexpected events: {events:?} " ) ,
}
2021-09-08 00:36:52 +10:00
}
// test if charlie can operate as client and server simultaneously
#[ tokio::test ]
async fn can_combine_client_and_server ( ) {
let _ = env_logger ::try_init ( ) ;
let namespace = rendezvous ::Namespace ::from_static ( " some-namespace " ) ;
let ( [ mut alice ] , mut robert ) =
new_server_with_connected_clients ( rendezvous ::server ::Config ::default ( ) ) . await ;
let mut charlie = new_combined_node ( ) . await ;
2023-03-08 20:36:35 +11:00
charlie . connect ( & mut robert ) . await ;
alice . connect ( & mut charlie ) . await ;
2021-09-08 00:36:52 +10:00
charlie
. behaviour_mut ( )
. client
2023-06-17 14:19:41 +03:00
. register ( namespace . clone ( ) , * robert . local_peer_id ( ) , None )
. unwrap ( ) ;
2023-03-08 20:36:35 +11:00
match libp2p_swarm_test ::drive ( & mut charlie , & mut robert ) . await {
(
[ CombinedEvent ::Client ( rendezvous ::client ::Event ::Registered { .. } ) ] ,
[ rendezvous ::server ::Event ::PeerRegistered { .. } ] ,
) = > { }
events = > panic! ( " Unexpected events: {events:?} " ) ,
}
2021-09-08 00:36:52 +10:00
alice
. behaviour_mut ( )
2023-06-17 14:19:41 +03:00
. register ( namespace , * charlie . local_peer_id ( ) , None )
. unwrap ( ) ;
2023-03-08 20:36:35 +11:00
match libp2p_swarm_test ::drive ( & mut charlie , & mut alice ) . await {
(
[ CombinedEvent ::Server ( rendezvous ::server ::Event ::PeerRegistered { .. } ) ] ,
[ rendezvous ::client ::Event ::Registered { .. } ] ,
) = > { }
events = > panic! ( " Unexpected events: {events:?} " ) ,
}
2021-09-08 00:36:52 +10:00
}
#[ tokio::test ]
async fn registration_on_clients_expire ( ) {
let _ = env_logger ::try_init ( ) ;
let namespace = rendezvous ::Namespace ::from_static ( " some-namespace " ) ;
let ( [ mut alice , mut bob ] , robert ) =
new_server_with_connected_clients ( rendezvous ::server ::Config ::default ( ) . with_min_ttl ( 1 ) )
. await ;
let roberts_peer_id = * robert . local_peer_id ( ) ;
2023-03-08 20:36:35 +11:00
tokio ::spawn ( robert . loop_on_next ( ) ) ;
2021-09-08 00:36:52 +10:00
let registration_ttl = 3 ;
alice
. behaviour_mut ( )
2023-06-17 14:19:41 +03:00
. register ( namespace . clone ( ) , roberts_peer_id , Some ( registration_ttl ) )
. unwrap ( ) ;
2023-03-08 20:36:35 +11:00
match alice . next_behaviour_event ( ) . await {
rendezvous ::client ::Event ::Registered { .. } = > { }
event = > panic! ( " Unexpected event: {event:?} " ) ,
}
2021-10-14 18:05:07 +02:00
bob . behaviour_mut ( )
. discover ( Some ( namespace ) , None , None , roberts_peer_id ) ;
2023-03-08 20:36:35 +11:00
match bob . next_behaviour_event ( ) . await {
rendezvous ::client ::Event ::Discovered { registrations , .. } = > {
2021-10-14 18:05:07 +02:00
assert! ( ! registrations . is_empty ( ) ) ;
}
2023-03-08 20:36:35 +11:00
event = > panic! ( " Unexpected event: {event:?} " ) ,
}
2021-09-08 00:36:52 +10:00
tokio ::time ::sleep ( Duration ::from_secs ( registration_ttl + 5 ) ) . await ;
let event = bob . select_next_some ( ) . await ;
2021-11-15 14:17:23 +01:00
let error = bob . dial ( * alice . local_peer_id ( ) ) . unwrap_err ( ) ;
2021-09-08 00:36:52 +10:00
assert! ( matches! (
event ,
SwarmEvent ::Behaviour ( rendezvous ::client ::Event ::Expired { .. } )
) ) ;
assert! ( matches! ( error , DialError ::NoAddresses ) ) ;
}
async fn new_server_with_connected_clients < const N : usize > (
config : rendezvous ::server ::Config ,
) -> (
[ Swarm < rendezvous ::client ::Behaviour > ; N ] ,
Swarm < rendezvous ::server ::Behaviour > ,
) {
let mut server = new_server ( config ) . await ;
let mut clients : [ Swarm < _ > ; N ] = match ( 0 usize .. N )
. map ( | _ | new_client ( ) )
. collect ::< FuturesUnordered < _ > > ( )
. collect ::< Vec < _ > > ( )
. await
. try_into ( )
{
Ok ( clients ) = > clients ,
Err ( _ ) = > panic! ( " Vec is of size N " ) ,
} ;
for client in & mut clients {
2023-03-08 20:36:35 +11:00
client . connect ( & mut server ) . await ;
2021-09-08 00:36:52 +10:00
}
( clients , server )
}
async fn new_client ( ) -> Swarm < rendezvous ::client ::Behaviour > {
2023-03-08 20:36:35 +11:00
let mut client = Swarm ::new_ephemeral ( rendezvous ::client ::Behaviour ::new ) ;
client . listen ( ) . await ; // we need to listen otherwise we don't have addresses to register
2021-09-08 00:36:52 +10:00
client
}
async fn new_server ( config : rendezvous ::server ::Config ) -> Swarm < rendezvous ::server ::Behaviour > {
2023-03-08 20:36:35 +11:00
let mut server = Swarm ::new_ephemeral ( | _ | rendezvous ::server ::Behaviour ::new ( config ) ) ;
2021-09-08 00:36:52 +10:00
2023-03-08 20:36:35 +11:00
server . listen ( ) . await ;
2021-09-08 00:36:52 +10:00
server
}
2023-03-08 20:36:35 +11:00
async fn new_combined_node ( ) -> Swarm < Combined > {
let mut node = Swarm ::new_ephemeral ( | identity | Combined {
2021-09-08 00:36:52 +10:00
client : rendezvous ::client ::Behaviour ::new ( identity ) ,
server : rendezvous ::server ::Behaviour ::new ( rendezvous ::server ::Config ::default ( ) ) ,
} ) ;
2023-03-08 20:36:35 +11:00
node . listen ( ) . await ;
2021-09-08 00:36:52 +10:00
node
}
async fn new_impersonating_client ( ) -> Swarm < rendezvous ::client ::Behaviour > {
// In reality, if Eve were to try and fake someones identity, she would obviously only know the public key.
// Due to the type-safe API of the `Rendezvous` behaviour and `PeerRecord`, we actually cannot construct a bad `PeerRecord` (i.e. one that is claims to be someone else).
// As such, the best we can do is hand eve a completely different keypair from what she is using to authenticate her connection.
let someone_else = identity ::Keypair ::generate_ed25519 ( ) ;
2023-03-08 20:36:35 +11:00
let mut eve = Swarm ::new_ephemeral ( move | _ | rendezvous ::client ::Behaviour ::new ( someone_else ) ) ;
eve . listen ( ) . await ;
2021-09-08 00:36:52 +10:00
eve
}
2022-12-13 07:58:01 +11:00
#[ derive(libp2p_swarm::NetworkBehaviour) ]
2023-03-08 20:36:35 +11:00
#[ behaviour(prelude = " libp2p_swarm::derive_prelude " ) ]
struct Combined {
2021-09-08 00:36:52 +10:00
client : rendezvous ::client ::Behaviour ,
server : rendezvous ::server ::Behaviour ,
}