Skip to content

Commit

Permalink
test(network): add private overlay test
Browse files Browse the repository at this point in the history
  • Loading branch information
Rexagon committed Feb 23, 2024
1 parent 89bb432 commit 2661bb7
Show file tree
Hide file tree
Showing 5 changed files with 193 additions and 8 deletions.
4 changes: 2 additions & 2 deletions network/src/overlay/overlay_id.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,10 @@ use tl_proto::{TlRead, TlWrite};

#[derive(Clone, Copy, Hash, PartialEq, Eq, PartialOrd, Ord, TlRead, TlWrite)]
#[repr(transparent)]
pub struct OverlayId([u8; 32]);
pub struct OverlayId(pub [u8; 32]);

impl OverlayId {
pub fn wrap(bytes: &[u8; 32]) -> &Self {
pub const fn wrap(bytes: &[u8; 32]) -> &Self {
// SAFETY: `[u8; 32]` has the same layout as `OverlayId`.
unsafe { &*(bytes as *const [u8; 32]).cast::<Self>() }
}
Expand Down
2 changes: 1 addition & 1 deletion network/src/types/peer_id.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ use tl_proto::{TlRead, TlWrite};
pub struct PeerId(pub [u8; 32]);

impl PeerId {
pub fn wrap(bytes: &[u8; 32]) -> &Self {
pub const fn wrap(bytes: &[u8; 32]) -> &Self {
// SAFETY: `[u8; 32]` has the same layout as `PeerId`.
unsafe { &*(bytes as *const [u8; 32]).cast::<Self>() }
}
Expand Down
11 changes: 10 additions & 1 deletion network/src/types/request.rs
Original file line number Diff line number Diff line change
Expand Up @@ -95,7 +95,7 @@ impl Response {
}
}

pub fn parse_tl<T>(self) -> tl_proto::TlResult<T>
pub fn parse_tl<T>(&self) -> tl_proto::TlResult<T>
where
for<'a> T: tl_proto::TlRead<'a, Repr = tl_proto::Boxed>,
{
Expand All @@ -115,6 +115,15 @@ pub struct ServiceRequest {
pub body: Bytes,
}

impl ServiceRequest {
pub fn parse_tl<T>(&self) -> tl_proto::TlResult<T>
where
for<'a> T: tl_proto::TlRead<'a, Repr = tl_proto::Boxed>,
{
tl_proto::deserialize(self.body.as_ref())
}
}

impl AsRef<[u8]> for ServiceRequest {
#[inline]
fn as_ref(&self) -> &[u8] {
Expand Down
8 changes: 4 additions & 4 deletions network/tests/dht.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,8 +20,8 @@ struct Node {
}

impl Node {
fn new(key: &ed25519::SecretKey) -> Result<Self> {
let keypair = everscale_crypto::ed25519::KeyPair::from(key);
fn new(key: &ed25519::SecretKey) -> Self {
let keypair = ed25519::KeyPair::from(key);

let (dht_client, dht) = DhtService::builder(keypair.public_key.into()).build();

Expand All @@ -35,7 +35,7 @@ impl Node {

let dht = dht_client.build(network.clone());

Ok(Self { network, dht })
Self { network, dht }
}

fn make_peer_info(key: &ed25519::SecretKey, address: Address) -> PeerInfo {
Expand Down Expand Up @@ -151,7 +151,7 @@ async fn connect_new_node_to_bootstrap() -> Result<()> {

let (bootstrap_nodes, global_config) = make_network(5);

let node = Node::new(&ed25519::SecretKey::generate(&mut rand::thread_rng()))?;
let node = Node::new(&ed25519::SecretKey::generate(&mut rand::thread_rng()));
for peer_info in &global_config {
node.dht.add_peer(peer_info.clone())?;
}
Expand Down
176 changes: 176 additions & 0 deletions network/tests/overlay.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,176 @@
//! Run tests with this env:
//! ```text
//! RUST_LOG=info,tycho_network=trace
//! ```
use anyhow::Result;
use everscale_crypto::ed25519;
use std::net::Ipv4Addr;
use std::sync::Arc;
use tl_proto::{TlRead, TlWrite};
use tycho_network::{
Address, Network, OverlayId, OverlayService, PeerAffinity, PeerId, PeerInfo, PrivateOverlay,
Request, Response, Router, Service, ServiceRequest,
};
use tycho_util::time::now_sec;

struct Node {
network: Network,
private_overlay: PrivateOverlay,
}

impl Node {
fn new(key: &ed25519::SecretKey) -> Self {
let keypair = ed25519::KeyPair::from(key);
let local_id = PeerId::from(keypair.public_key);

let private_overlay = PrivateOverlay::builder(PRIVATE_OVERLAY_ID).build(PingPongService);

let (overlay_tasks, overlay_service) = OverlayService::builder(local_id)
.with_private_overlay(&private_overlay)
.build();

let router = Router::builder().route(overlay_service).build();

let network = Network::builder()
.with_private_key(key.to_bytes())
.with_service_name("test-service")
.build((Ipv4Addr::LOCALHOST, 0), router)
.unwrap();

overlay_tasks.spawn(network.clone());

Self {
network,
private_overlay,
}
}

fn make_peer_info(key: &ed25519::SecretKey, address: Address) -> PeerInfo {
let keypair = ed25519::KeyPair::from(key);
let peer_id = PeerId::from(keypair.public_key);

let now = now_sec();
let mut node_info = PeerInfo {
id: peer_id,
address_list: vec![address].into_boxed_slice(),
created_at: now,
expires_at: u32::MAX,
signature: Box::new([0; 64]),
};
*node_info.signature = keypair.sign(&node_info);
node_info
}

async fn private_overlay_query<Q, A>(&self, peer_id: &PeerId, req: Q) -> Result<A>
where
Q: tl_proto::TlWrite<Repr = tl_proto::Boxed>,
for<'a> A: tl_proto::TlRead<'a, Repr = tl_proto::Boxed>,
{
self.private_overlay
.query(&self.network, peer_id, Request::from_tl(req))
.await?
.parse_tl::<A>()
.map_err(Into::into)
}
}

fn make_network(node_count: usize) -> Vec<Node> {
let keys = (0..node_count)
.map(|_| ed25519::SecretKey::generate(&mut rand::thread_rng()))
.collect::<Vec<_>>();

let nodes = keys.iter().map(Node::new).collect::<Vec<_>>();

let bootstrap_info = std::iter::zip(&keys, &nodes)
.map(|(key, node)| Arc::new(Node::make_peer_info(key, node.network.local_addr().into())))
.collect::<Vec<_>>();

for node in &nodes {
let mut private_overlay_entries = node.private_overlay.write_entries();

for info in &bootstrap_info {
node.network
.known_peers()
.insert(info.clone(), PeerAffinity::Allowed);

private_overlay_entries.insert(&info.id);
}
}

nodes
}

#[tokio::test]
async fn private_overlays_accessible() -> Result<()> {
tracing_subscriber::fmt::try_init().ok();
tracing::info!("bootstrap_nodes_accessible");

let nodes = make_network(5);

for i in 0..nodes.len() {
for j in 0..nodes.len() {
if i == j {
continue;
}

let left = &nodes[i];
let right = &nodes[j];

let value = (i * 1000 + j) as u64;
let Pong { value: received } = left
.private_overlay_query(right.network.peer_id(), Ping { value })
.await?;
assert_eq!(received, value);
}
}

Ok(())
}

struct PingPongService;

impl Service<ServiceRequest> for PingPongService {
type QueryResponse = Response;
type OnQueryFuture = futures_util::future::Ready<Option<Self::QueryResponse>>;
type OnMessageFuture = futures_util::future::Ready<()>;
type OnDatagramFuture = futures_util::future::Ready<()>;

fn on_query(&self, req: ServiceRequest) -> Self::OnQueryFuture {
futures_util::future::ready(match req.parse_tl() {
Ok(Ping { value }) => Some(Response::from_tl(Pong { value })),
Err(e) => {
tracing::error!(
peer_id = %req.metadata.peer_id,
addr = %req.metadata.remote_address,
"invalid request: {e:?}",
);
None
}
})
}

#[inline]
fn on_message(&self, _req: ServiceRequest) -> Self::OnMessageFuture {
futures_util::future::ready(())
}

#[inline]
fn on_datagram(&self, _req: ServiceRequest) -> Self::OnDatagramFuture {
futures_util::future::ready(())
}
}

#[derive(Debug, Copy, Clone, TlRead, TlWrite)]
#[tl(boxed, id = 0x11223344)]
struct Ping {
value: u64,
}

#[derive(Debug, Copy, Clone, TlRead, TlWrite)]
#[tl(boxed, id = 0x55667788)]
struct Pong {
value: u64,
}

static PRIVATE_OVERLAY_ID: OverlayId = OverlayId([0; 32]);

0 comments on commit 2661bb7

Please sign in to comment.