diff --git a/Cargo.lock b/Cargo.lock index 1df6b95..6549b59 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -613,6 +613,7 @@ dependencies = [ "monero-wire", "reqwest", "tar", + "tempfile", "tokio", "zip", ] diff --git a/Cargo.toml b/Cargo.toml index c1e46a7..3bf700a 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -70,6 +70,7 @@ tracing-subscriber = { version = "0.3.17", default-features = false } tracing = { version = "0.1.40", default-features = false } ## workspace.dev-dependencies +tempfile = { version = "3" } reqwest = { version = "0.11.24" } proptest = { version = "1" } proptest-derive = { version = "0.4.0" } diff --git a/p2p/monero-p2p/Cargo.toml b/p2p/monero-p2p/Cargo.toml index 53ca330..5c39035 100644 --- a/p2p/monero-p2p/Cargo.toml +++ b/p2p/monero-p2p/Cargo.toml @@ -29,6 +29,6 @@ borsh = { workspace = true, default-features = false, features = ["derive", "std [dev-dependencies] cuprate-test-utils = {path = "../../test-utils"} -hex = { workspace = true } +hex = { workspace = true, features = ["std"] } tokio = { workspace = true, features = ["net", "rt-multi-thread", "rt", "macros"]} tracing-subscriber = { workspace = true } diff --git a/p2p/monero-p2p/src/network_zones/clear.rs b/p2p/monero-p2p/src/network_zones/clear.rs index a246cef..508b0ab 100644 --- a/p2p/monero-p2p/src/network_zones/clear.rs +++ b/p2p/monero-p2p/src/network_zones/clear.rs @@ -26,7 +26,7 @@ impl NetZoneAddress for SocketAddr { } pub struct ClearNetServerCfg { - addr: SocketAddr, + pub addr: SocketAddr, } #[derive(Clone, Copy)] diff --git a/p2p/monero-p2p/tests/handshake.rs b/p2p/monero-p2p/tests/handshake.rs index 541713a..dacc150 100644 --- a/p2p/monero-p2p/tests/handshake.rs +++ b/p2p/monero-p2p/tests/handshake.rs @@ -1,23 +1,25 @@ -use std::sync::Arc; +use std::{sync::Arc, time::Duration}; use futures::{channel::mpsc, StreamExt}; -use tokio::sync::{broadcast, Semaphore}; +use tokio::{ + sync::{broadcast, Semaphore}, + time::timeout, +}; use tower::{Service, ServiceExt}; use cuprate_helper::network::Network; use monero_wire::{common::PeerSupportFlags, BasicNodeData}; use monero_p2p::{ - client::{ConnectRequest, Connector, DoHandshakeRequest, HandShaker}, - network_zones::ClearNet, - ConnectionDirection, + client::{ConnectRequest, Connector, DoHandshakeRequest, HandShaker, InternalPeerID}, + network_zones::{ClearNet, ClearNetServerCfg}, + ConnectionDirection, NetworkZone, }; use cuprate_test_utils::{ monerod::monerod, test_netzone::{TestNetZone, TestNetZoneAddr}, }; -use monero_p2p::client::InternalPeerID; mod utils; use utils::*; @@ -143,3 +145,56 @@ async fn handshake_cuprate_to_monerod() { .await .unwrap(); } + +#[tokio::test] +async fn handshake_monerod_to_cuprate() { + let (broadcast_tx, _) = broadcast::channel(1); // this isn't actually used in this test. + let semaphore = Arc::new(Semaphore::new(10)); + let permit = semaphore.acquire_owned().await.unwrap(); + + let our_basic_node_data = BasicNodeData { + my_port: 18081, + network_id: Network::Mainnet.network_id().into(), + peer_id: 87980, + support_flags: PeerSupportFlags::from(1_u32), + rpc_port: 0, + rpc_credits_per_hash: 0, + }; + + let mut handshaker = HandShaker::::new( + DummyAddressBook, + DummyCoreSyncSvc, + DummyPeerRequestHandlerSvc, + broadcast_tx, + our_basic_node_data, + ); + + let addr = "127.0.0.1:18081".parse().unwrap(); + + let mut listener = ClearNet::incoming_connection_listener(ClearNetServerCfg { addr }) + .await + .unwrap(); + + let _monerod = monerod(["--add-exclusive-node=127.0.0.1:18081"]).await; + + // Put a timeout on this just in case monerod doesn't make the connection to us. + let next_connection_fut = timeout(Duration::from_secs(30), listener.next()); + + if let Some(Ok((addr, stream, sink))) = next_connection_fut.await.unwrap() { + let _ = handshaker + .ready() + .await + .unwrap() + .call(DoHandshakeRequest { + addr: InternalPeerID::KnownAddr(addr.unwrap()), // This is clear net all addresses are known. + peer_stream: stream, + peer_sink: sink, + direction: ConnectionDirection::InBound, + permit, + }) + .await + .unwrap(); + } else { + panic!("Failed to receive connection from monerod."); + }; +} diff --git a/test-utils/Cargo.toml b/test-utils/Cargo.toml index 4b71095..7e0110b 100644 --- a/test-utils/Cargo.toml +++ b/test-utils/Cargo.toml @@ -12,6 +12,7 @@ async-trait = { workspace = true } tokio = { workspace = true, features = ["full"] } reqwest = { workspace = true } bytes = { workspace = true, features = ["std"] } +tempfile = { workspace = true } borsh = { workspace = true, features = ["derive"]} diff --git a/test-utils/src/monerod.rs b/test-utils/src/monerod.rs index 620534b..d377c49 100644 --- a/test-utils/src/monerod.rs +++ b/test-utils/src/monerod.rs @@ -34,16 +34,18 @@ pub async fn monerod>(flags: impl IntoIterator) -> Spa let p2p_port = get_available_port(&[rpc_port]); let zmq_port = get_available_port(&[rpc_port, p2p_port]); - // TODO: set a random DB location + let data_dir = tempfile::tempdir().unwrap(); + let mut monerod = Command::new(path_to_monerod) .stdout(Stdio::piped()) .stderr(Stdio::piped()) .args(flags) .arg("--regtest") .arg("--log-level=2") - .arg(format!("--p2p-bind-port={}", p2p_port)) - .arg(format!("--rpc-bind-port={}", rpc_port)) - .arg(format!("--zmq-rpc-bind-port={}", zmq_port)) + .arg(format!("--p2p-bind-port={p2p_port}")) + .arg(format!("--rpc-bind-port={rpc_port}")) + .arg(format!("--zmq-rpc-bind-port={zmq_port}")) + .arg(format!("--data-dir={}", data_dir.path().display())) .arg("--non-interactive") .spawn() .unwrap(); @@ -81,6 +83,7 @@ pub async fn monerod>(flags: impl IntoIterator) -> Spa process: monerod, rpc_port, p2p_port, + _data_dir: data_dir, start_up_logs: logs, } } @@ -108,7 +111,9 @@ pub struct SpawnedMoneroD { rpc_port: u16, /// The P2P port of the monerod instance. p2p_port: u16, - + /// The data dir for monerod - when this is dropped the dir will be deleted. + _data_dir: tempfile::TempDir, + /// The logs upto [`MONEROD_STARTUP_TEXT`]. start_up_logs: String, } @@ -126,7 +131,10 @@ impl SpawnedMoneroD { impl Drop for SpawnedMoneroD { fn drop(&mut self) { + let mut error = false; + if self.process.kill().is_err() { + error = true; println!("Failed to kill monerod, process id: {}", self.process.id()) } @@ -150,5 +158,12 @@ impl Drop for SpawnedMoneroD { println!("{}{out}", self.start_up_logs); println!("------END-MONEROD-LOGS------"); } + + if error && !panicking() { + // `println` only outputs in a test when panicking so if there is an error while + // dropping monerod but not an error in the test then we need to panic to make sure + // the println!s are output. + panic!("Error while dropping monerod"); + } } }