Skip to content

Commit ab47282

Browse files
committed
Add ckb-onion integration test
Signed-off-by: Eval EXEC <[email protected]>
1 parent 67985d5 commit ab47282

File tree

16 files changed

+742
-13
lines changed

16 files changed

+742
-13
lines changed

ckb-bin/src/subcommand/run.rs

+1
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ use ckb_build_info::Version;
77
use ckb_launcher::Launcher;
88
use ckb_logger::info;
99
use ckb_logger::warn;
10+
use ckb_network::multiaddr::Multiaddr;
1011
use ckb_resource::{Resource, TemplateContext};
1112

1213
use ckb_stop_handler::{broadcast_exit_signals, wait_all_ckb_services_exit};

network/src/network.rs

+18-5
Original file line numberDiff line numberDiff line change
@@ -122,7 +122,8 @@ impl NetworkState {
122122
config.peer_store_path(),
123123
));
124124
info!("Loaded the peer store.");
125-
if let Some(ref proxy_url) = config.proxy_config.proxy_url {
125+
126+
if let Some(ref proxy_url) = config.proxy.proxy_url {
126127
proxy::check_proxy_url(proxy_url).map_err(|reason| Error::Config(reason))?;
127128
}
128129

@@ -348,6 +349,12 @@ impl NetworkState {
348349
.collect()
349350
}
350351

352+
/// After onion service created,
353+
/// ckb use this method to add onion address to public_addr
354+
pub fn add_public_addr(&self, addr: Multiaddr) {
355+
self.public_addrs.write().insert(addr);
356+
}
357+
351358
pub(crate) fn connection_status(&self) -> ConnectionStatus {
352359
self.peer_registry.read().connection_status()
353360
}
@@ -954,7 +961,7 @@ impl NetworkService {
954961
.max_connection_number(1024)
955962
.set_send_buffer_size(config.max_send_buffer())
956963
.set_channel_size(config.channel_size())
957-
.timeout(Duration::from_secs(5));
964+
.timeout(Duration::from_secs(50));
958965

959966
#[cfg(not(target_family = "wasm"))]
960967
{
@@ -996,10 +1003,11 @@ impl NetworkService {
9961003
if init.is_ready() {
9971004
break;
9981005
}
999-
let proxy_config_enable = config.proxy_config.proxy_url.is_some();
1006+
let proxy_config_enable =
1007+
config.proxy.proxy_url.is_some() || config.onion.onion_server.is_some();
10001008
service_builder = service_builder
1001-
.tcp_proxy_config(config.proxy_config.proxy_url.clone())
1002-
.tcp_onion_config(config.onion_config.onion_server.clone());
1009+
.tcp_proxy_config(config.proxy.proxy_url.clone())
1010+
.tcp_onion_config(config.onion.onion_server.clone());
10031011

10041012
match find_type(multi_addr) {
10051013
TransportType::Tcp => {
@@ -1329,6 +1337,11 @@ impl NetworkController {
13291337
self.network_state.add_node(&self.p2p_control, address)
13301338
}
13311339

1340+
/// Add a public_addr to NetworkState.public_addrs
1341+
pub fn add_public_addr(&self, public_addr: Multiaddr) {
1342+
self.network_state.add_public_addr(public_addr)
1343+
}
1344+
13321345
/// Disconnect session with peer id
13331346
pub fn remove_node(&self, peer_id: &PeerId) {
13341347
if let Some(session_id) = self

network/src/peer_store/addr_manager.rs

+6-2
Original file line numberDiff line numberDiff line change
@@ -71,8 +71,12 @@ impl AddrManager {
7171
}
7272
}
7373
None => {
74-
if addr_info.is_connectable(now_ms) && filter(&addr_info) {
75-
addr_infos.push(addr_info);
74+
if filter(&addr_info) {
75+
if addr_info.is_connectable(now_ms) {
76+
addr_infos.push(addr_info);
77+
} else if addr_info.addr.to_string().starts_with("/onion3/") {
78+
addr_infos.push(addr_info);
79+
}
7680
}
7781
}
7882
}

network/src/protocols/identify/mod.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -228,7 +228,7 @@ impl<T: Callback> ServiceProtocol for IdentifyProtocol<T> {
228228
.filter(|addr| {
229229
multiaddr_to_socketaddr(addr)
230230
.map(|socket_addr| !self.global_ip_only || is_reachable(socket_addr.ip()))
231-
.unwrap_or(false)
231+
.unwrap_or(true)
232232
})
233233
.take(MAX_ADDRS)
234234
.cloned()

test/Cargo.toml

+1-1
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ ckb-db = { path = "../db", version = "= 0.121.0-pre" }
3333
ckb-store = { path = "../store", version = "= 0.121.0-pre" }
3434
ckb-shared = { path = "../shared", version = "= 0.121.0-pre" }
3535
tempfile = "3"
36-
reqwest = { version = "0.12", features = ["blocking", "json"] }
36+
reqwest = { version = "0.12", features = ["blocking", "json", "socks"] }
3737
rand = "0.8"
3838
ckb-systemtime = { path = "../util/systemtime", version = "= 0.121.0-pre" }
3939
serde_json = "1.0"

test/src/main.rs

+2
Original file line numberDiff line numberDiff line change
@@ -606,6 +606,8 @@ fn all_specs() -> Vec<Box<dyn Spec>> {
606606
Box::new(CheckVmBExtension),
607607
Box::new(RandomlyKill),
608608
Box::new(SyncChurn),
609+
Box::new(TorServiceContainsPublicAddr),
610+
Box::new(TorConnect::new()),
609611
];
610612
specs.shuffle(&mut thread_rng());
611613
specs

test/src/node.rs

+39
Original file line numberDiff line numberDiff line change
@@ -216,6 +216,19 @@ impl Node {
216216
self.inner.rpc_listen.clone()
217217
}
218218

219+
pub fn get_onion_public_addr(&self) -> Option<String> {
220+
let onion_public_addr = self
221+
.rpc_client()
222+
.local_node_info()
223+
.addresses
224+
.iter()
225+
.filter(|addr| addr.address.contains("/onion3/"))
226+
.collect::<Vec<_>>()
227+
.first()
228+
.map(|addr| addr.address.clone());
229+
onion_public_addr
230+
}
231+
219232
pub fn p2p_address(&self) -> String {
220233
format!("{}/p2p/{}", self.p2p_listen(), self.node_id())
221234
}
@@ -290,6 +303,32 @@ impl Node {
290303
}
291304
}
292305

306+
pub fn connect_onion(&self, peer: &Self) {
307+
wait_until(30, || peer.get_onion_public_addr().is_some());
308+
309+
let onion_pub_address = peer
310+
.get_onion_public_addr()
311+
.expect("peer onion address is not found");
312+
313+
info!(
314+
"got peer:{}'s onion address: {}",
315+
peer.node_id(),
316+
onion_pub_address
317+
);
318+
319+
self.rpc_client()
320+
.add_node(peer.node_id(), onion_pub_address);
321+
let connected = wait_until(6000, || {
322+
self.rpc_client()
323+
.get_peers()
324+
.iter()
325+
.any(|p| p.node_id == peer.node_id())
326+
});
327+
if !connected {
328+
panic!("Connect outbound peer timeout, node id: {}", peer.node_id());
329+
}
330+
}
331+
293332
pub fn connect_uncheck(&self, peer: &Self) {
294333
self.rpc_client()
295334
.add_node(peer.node_id(), peer.p2p_listen());

test/src/specs/mod.rs

+2
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ mod p2p;
88
mod relay;
99
mod rpc;
1010
mod sync;
11+
mod tor;
1112
mod tx_pool;
1213

1314
pub use alert::*;
@@ -20,6 +21,7 @@ pub use p2p::*;
2021
pub use relay::*;
2122
pub use rpc::*;
2223
pub use sync::*;
24+
pub use tor::*;
2325
pub use tx_pool::*;
2426

2527
use crate::Node;

test/src/specs/tor/mod.rs

+46
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
mod tor_basic;
2+
mod tor_connect;
3+
4+
use std::process::Child;
5+
6+
use ckb_logger::info;
7+
pub use tor_basic::*;
8+
pub use tor_connect::*;
9+
10+
use crate::utils::find_available_port;
11+
12+
#[derive(Clone, Debug)]
13+
struct TorServer {
14+
tor_command_path: String,
15+
socks_port: u16,
16+
control_port: u16,
17+
}
18+
19+
impl TorServer {
20+
pub fn new() -> Self {
21+
TorServer {
22+
tor_command_path: std::option_env!("TOR_COMMAND_PATH")
23+
.unwrap_or("tor")
24+
.to_string(),
25+
socks_port: find_available_port(),
26+
control_port: find_available_port(),
27+
}
28+
}
29+
30+
fn build_tor_args(&self) -> Vec<String> {
31+
vec![
32+
"--SocksPort".to_string(),
33+
self.socks_port.to_string(),
34+
"--ControlPort".to_string(),
35+
self.control_port.to_string(),
36+
]
37+
}
38+
39+
fn tor_start(&self) -> Child {
40+
let mut cmd = std::process::Command::new(&self.tor_command_path);
41+
let cmd = cmd.args(self.build_tor_args().clone());
42+
let child = cmd.spawn().unwrap();
43+
info!("tor started:({:?}) ; pid: {}", &self, child.id());
44+
child
45+
}
46+
}

test/src/specs/tor/tor_basic.rs

+86
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,86 @@
1+
use crate::utils::find_available_port;
2+
use crate::{Node, Spec};
3+
use ckb_logger::{error, info};
4+
use std::process::Child;
5+
6+
use super::TorServer;
7+
8+
// create a sender and receiver for tor_server signal
9+
static TOR_SERVER_PROCESS: std::sync::LazyLock<std::sync::Mutex<Option<Child>>> =
10+
std::sync::LazyLock::new(|| std::sync::Mutex::new(None));
11+
12+
static TOR_SERVER: std::sync::OnceLock<TorServer> = std::sync::OnceLock::new();
13+
14+
struct TorServerGuard {}
15+
16+
impl Drop for TorServerGuard {
17+
fn drop(&mut self) {
18+
let mut child = TOR_SERVER_PROCESS.lock().unwrap();
19+
let child = child.as_mut().unwrap();
20+
info!("killing tor server... {}", child.id());
21+
match child.kill() {
22+
Ok(_) => {
23+
info!("tor server exit success");
24+
}
25+
Err(e) => {
26+
error!("tor server exit failed: {:?}", e);
27+
}
28+
};
29+
}
30+
}
31+
32+
pub struct TorServiceContainsPublicAddr;
33+
34+
impl Spec for TorServiceContainsPublicAddr {
35+
crate::setup!(num_nodes: 1);
36+
37+
fn before_run(&self) -> Vec<Node> {
38+
let tor_server = TorServer::new();
39+
40+
TOR_SERVER.set(tor_server.clone());
41+
42+
let tor_server_process = tor_server.tor_start();
43+
*TOR_SERVER_PROCESS.lock().unwrap() = Some(tor_server_process);
44+
45+
std::thread::sleep(std::time::Duration::from_secs(5));
46+
47+
let mut node0 = Node::new(self.name(), "node0");
48+
node0.modify_app_config(|config: &mut ckb_app_config::CKBAppConfig| {
49+
config.network.onion.listen_on_onion = true;
50+
config.network.onion.onion_server =
51+
Some(format!("127.0.0.1:{}", tor_server.socks_port));
52+
config.network.onion.tor_controller = format!("127.0.0.1:{}", tor_server.control_port);
53+
});
54+
55+
node0.start();
56+
57+
vec![node0]
58+
}
59+
60+
fn run(&self, nodes: &mut Vec<Node>) {
61+
// when _tor_server_guard dropped, the tor server will be killed by Drop
62+
let _tor_server_guard = TorServerGuard {};
63+
64+
let node = &nodes[0];
65+
66+
let rpc_client = node.rpc_client();
67+
let node_info = rpc_client.local_node_info();
68+
69+
let node_onion_addrs: Vec<_> = node_info
70+
.addresses
71+
.iter()
72+
.filter(|addr| {
73+
// check contains the onion address
74+
info!("addr: {:?}", addr.address);
75+
addr.address.contains("/onion3")
76+
})
77+
.collect();
78+
assert!(
79+
!node_onion_addrs.is_empty(),
80+
"node should contains onion address"
81+
);
82+
83+
let node_onion_p2p_addr: String = node_onion_addrs.first().unwrap().address.clone();
84+
info!("node_onion_p2p_addr: {}", node_onion_p2p_addr);
85+
}
86+
}

0 commit comments

Comments
 (0)