Add a test for an inbound handshake from monerod (#75)

* monerod: set a random DB and remove dir when done

* add a test for an inbound monerod handshake

* don't fail if can't remove dir on windows

* Update test-utils/src/monerod.rs

Co-authored-by: hinto-janai <hinto.janai@protonmail.com>

* use `temp_dir`

* use `tempfile`

---------

Co-authored-by: hinto-janai <hinto.janai@protonmail.com>
This commit is contained in:
Boog900 2024-02-25 21:21:25 +00:00 committed by GitHub
parent 34bfe37673
commit e560ecc2ee
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
7 changed files with 86 additions and 13 deletions

1
Cargo.lock generated
View file

@ -613,6 +613,7 @@ dependencies = [
"monero-wire", "monero-wire",
"reqwest", "reqwest",
"tar", "tar",
"tempfile",
"tokio", "tokio",
"zip", "zip",
] ]

View file

@ -70,6 +70,7 @@ tracing-subscriber = { version = "0.3.17", default-features = false }
tracing = { version = "0.1.40", default-features = false } tracing = { version = "0.1.40", default-features = false }
## workspace.dev-dependencies ## workspace.dev-dependencies
tempfile = { version = "3" }
reqwest = { version = "0.11.24" } reqwest = { version = "0.11.24" }
proptest = { version = "1" } proptest = { version = "1" }
proptest-derive = { version = "0.4.0" } proptest-derive = { version = "0.4.0" }

View file

@ -29,6 +29,6 @@ borsh = { workspace = true, default-features = false, features = ["derive", "std
[dev-dependencies] [dev-dependencies]
cuprate-test-utils = {path = "../../test-utils"} cuprate-test-utils = {path = "../../test-utils"}
hex = { workspace = true } hex = { workspace = true, features = ["std"] }
tokio = { workspace = true, features = ["net", "rt-multi-thread", "rt", "macros"]} tokio = { workspace = true, features = ["net", "rt-multi-thread", "rt", "macros"]}
tracing-subscriber = { workspace = true } tracing-subscriber = { workspace = true }

View file

@ -26,7 +26,7 @@ impl NetZoneAddress for SocketAddr {
} }
pub struct ClearNetServerCfg { pub struct ClearNetServerCfg {
addr: SocketAddr, pub addr: SocketAddr,
} }
#[derive(Clone, Copy)] #[derive(Clone, Copy)]

View file

@ -1,23 +1,25 @@
use std::sync::Arc; use std::{sync::Arc, time::Duration};
use futures::{channel::mpsc, StreamExt}; use futures::{channel::mpsc, StreamExt};
use tokio::sync::{broadcast, Semaphore}; use tokio::{
sync::{broadcast, Semaphore},
time::timeout,
};
use tower::{Service, ServiceExt}; use tower::{Service, ServiceExt};
use cuprate_helper::network::Network; use cuprate_helper::network::Network;
use monero_wire::{common::PeerSupportFlags, BasicNodeData}; use monero_wire::{common::PeerSupportFlags, BasicNodeData};
use monero_p2p::{ use monero_p2p::{
client::{ConnectRequest, Connector, DoHandshakeRequest, HandShaker}, client::{ConnectRequest, Connector, DoHandshakeRequest, HandShaker, InternalPeerID},
network_zones::ClearNet, network_zones::{ClearNet, ClearNetServerCfg},
ConnectionDirection, ConnectionDirection, NetworkZone,
}; };
use cuprate_test_utils::{ use cuprate_test_utils::{
monerod::monerod, monerod::monerod,
test_netzone::{TestNetZone, TestNetZoneAddr}, test_netzone::{TestNetZone, TestNetZoneAddr},
}; };
use monero_p2p::client::InternalPeerID;
mod utils; mod utils;
use utils::*; use utils::*;
@ -143,3 +145,56 @@ async fn handshake_cuprate_to_monerod() {
.await .await
.unwrap(); .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::<ClearNet, _, _, _>::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.");
};
}

View file

@ -12,6 +12,7 @@ async-trait = { workspace = true }
tokio = { workspace = true, features = ["full"] } tokio = { workspace = true, features = ["full"] }
reqwest = { workspace = true } reqwest = { workspace = true }
bytes = { workspace = true, features = ["std"] } bytes = { workspace = true, features = ["std"] }
tempfile = { workspace = true }
borsh = { workspace = true, features = ["derive"]} borsh = { workspace = true, features = ["derive"]}

View file

@ -34,16 +34,18 @@ pub async fn monerod<T: AsRef<OsStr>>(flags: impl IntoIterator<Item = T>) -> Spa
let p2p_port = get_available_port(&[rpc_port]); let p2p_port = get_available_port(&[rpc_port]);
let zmq_port = get_available_port(&[rpc_port, p2p_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) let mut monerod = Command::new(path_to_monerod)
.stdout(Stdio::piped()) .stdout(Stdio::piped())
.stderr(Stdio::piped()) .stderr(Stdio::piped())
.args(flags) .args(flags)
.arg("--regtest") .arg("--regtest")
.arg("--log-level=2") .arg("--log-level=2")
.arg(format!("--p2p-bind-port={}", p2p_port)) .arg(format!("--p2p-bind-port={p2p_port}"))
.arg(format!("--rpc-bind-port={}", rpc_port)) .arg(format!("--rpc-bind-port={rpc_port}"))
.arg(format!("--zmq-rpc-bind-port={}", zmq_port)) .arg(format!("--zmq-rpc-bind-port={zmq_port}"))
.arg(format!("--data-dir={}", data_dir.path().display()))
.arg("--non-interactive") .arg("--non-interactive")
.spawn() .spawn()
.unwrap(); .unwrap();
@ -81,6 +83,7 @@ pub async fn monerod<T: AsRef<OsStr>>(flags: impl IntoIterator<Item = T>) -> Spa
process: monerod, process: monerod,
rpc_port, rpc_port,
p2p_port, p2p_port,
_data_dir: data_dir,
start_up_logs: logs, start_up_logs: logs,
} }
} }
@ -108,7 +111,9 @@ pub struct SpawnedMoneroD {
rpc_port: u16, rpc_port: u16,
/// The P2P port of the monerod instance. /// The P2P port of the monerod instance.
p2p_port: u16, 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, start_up_logs: String,
} }
@ -126,7 +131,10 @@ impl SpawnedMoneroD {
impl Drop for SpawnedMoneroD { impl Drop for SpawnedMoneroD {
fn drop(&mut self) { fn drop(&mut self) {
let mut error = false;
if self.process.kill().is_err() { if self.process.kill().is_err() {
error = true;
println!("Failed to kill monerod, process id: {}", self.process.id()) 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!("{}{out}", self.start_up_logs);
println!("------END-MONEROD-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");
}
} }
} }