Skip to content

Commit

Permalink
validate network name when connecting RPC client
Browse files Browse the repository at this point in the history
  • Loading branch information
Maciej Wójcik committed Nov 14, 2024
1 parent 06c1e68 commit bc1323a
Show file tree
Hide file tree
Showing 2 changed files with 92 additions and 13 deletions.
86 changes: 73 additions & 13 deletions rpc_sidecar/src/node_client.rs
Original file line number Diff line number Diff line change
Expand Up @@ -835,17 +835,29 @@ impl FramedNodeClient {
Arc::clone(&reconnect),
);

Ok((
Self {
client: Arc::clone(&stream),
request_limit: Semaphore::new(config.request_limit as usize),
reconnect,
shutdown,
config,
current_request_id: AtomicU16::new(INITIAL_REQUEST_ID),
},
reconnect_loop,
))
// clone network name for validation later
let maybe_network_name = config.network_name.clone();

let node_client = Self {
client: Arc::clone(&stream),
request_limit: Semaphore::new(config.request_limit as usize),
reconnect,
shutdown,
config,
current_request_id: AtomicU16::new(INITIAL_REQUEST_ID),
};

// validate network name
if let Some(network_name) = maybe_network_name {
let node_status = node_client.read_node_status().await?;
if network_name != node_status.chainspec_name {
let msg = format!("Network name {} does't match name {network_name} configured for node RPC connection", node_status.chainspec_name);
error!("{msg}");
return Err(AnyhowError::msg(msg));
}
}

Ok((node_client, reconnect_loop))
}

fn next_id(&self) -> u16 {
Expand Down Expand Up @@ -1165,13 +1177,14 @@ where
mod tests {
use crate::testing::{
get_dummy_request, get_dummy_request_payload, get_port, start_mock_binary_port,
start_mock_binary_port_responding_with_given_response,
start_mock_binary_port_responding_with_stored_value,
};

use super::*;
use casper_binary_port::BinaryRequestHeader;
use casper_binary_port::{BinaryRequestHeader, ReactorStateName};
use casper_types::testing::TestRng;
use casper_types::{CLValue, SemVer};
use casper_types::{BlockSynchronizerStatus, CLValue, SemVer, TimeDiff, Timestamp};
use futures::FutureExt;
use tokio::time::sleep;

Expand Down Expand Up @@ -1317,6 +1330,53 @@ mod tests {
assert_eq!(res, StoredValue::CLValue(CLValue::from_t("Foo").unwrap()))
}

#[tokio::test]
async fn should_fail_to_connect_if_network_name_does_not_match() {
// prepare node status response with network name
let mut rng = TestRng::new();
let protocol_version = ProtocolVersion::from_parts(2, 0, 0);
let value = NodeStatus {
protocol_version,
peers: Peers::random(&mut rng),
build_version: rng.random_string(5..10),
chainspec_name: "network-1".into(),
starting_state_root_hash: Digest::random(&mut rng),
last_added_block_info: None,
our_public_signing_key: None,
round_length: None,
next_upgrade: None,
uptime: TimeDiff::from_millis(0),
reactor_state: ReactorStateName::new(rng.random_string(5..10)),
last_progress: Timestamp::random(&mut rng),
available_block_range: AvailableBlockRange::random(&mut rng),
block_sync: BlockSynchronizerStatus::random(&mut rng),
latest_switch_block_hash: None,
};
let response = BinaryResponse::from_value(value, protocol_version);

// setup mock binary port with node status response
let port = get_port();
let shutdown = Arc::new(tokio::sync::Notify::new());
let request_id = Some(INITIAL_REQUEST_ID);
let _mock_server_handle = start_mock_binary_port_responding_with_given_response(
port,
request_id,
None,
Arc::clone(&shutdown),
response,
)
.await;

let mut config = NodeClientConfig::new_with_port_and_retries(port, 2);
config.network_name = Some("not-network-1".into());
let res = FramedNodeClient::new(config).await;

assert!(res.is_err());
let error_message = res.err().unwrap().to_string();

assert_eq!(error_message, "Network name network-1 does't match name not-network-1 configured for node RPC connection");
}

async fn query_global_state_for_string_value(
rng: &mut TestRng,
client: &FramedNodeClient,
Expand Down
19 changes: 19 additions & 0 deletions rpc_sidecar/src/testing/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,25 @@ pub async fn start_mock_binary_port_responding_with_stored_value(
.await
}

pub async fn start_mock_binary_port_responding_with_given_response(
port: u16,
request_id: Option<u16>,
number_of_responses: Option<u8>,
shutdown: Arc<Notify>,
binary_response: BinaryResponse,
) -> JoinHandle<()> {
let request = get_dummy_request_payload(request_id);
let response =
BinaryResponseAndRequest::new(binary_response, &request, request_id.unwrap_or_default());
start_mock_binary_port(
port,
response.to_bytes().unwrap(),
number_of_responses.unwrap_or(1), // Single response by default
shutdown,
)
.await
}

pub async fn start_mock_binary_port(
port: u16,
data: Vec<u8>,
Expand Down

0 comments on commit bc1323a

Please sign in to comment.