#[allow(dead_code)]
mod common;
use crate::common::{
CurrentNetwork,
primary::new_test_committee,
test_peer::TestPeer,
utils::{sample_gateway, sample_ledger, sample_storage},
};
use snarkos_account::Account;
use snarkos_node_bft::{Gateway, helpers::init_primary_channels};
use snarkos_node_bft_events::{ChallengeRequest, ChallengeResponse, Event};
use snarkos_node_network::PeerPoolHandling;
use snarkos_node_tcp::{P2P, protocols::Handshake};
use snarkvm::{ledger::narwhal::Data, prelude::TestRng};
use std::time::Duration;
use deadline::deadline;
use rand::Rng;
use tokio::task;
async fn new_test_gateway(
num_nodes: u16,
rng: &mut TestRng,
) -> (Vec<Account<CurrentNetwork>>, Gateway<CurrentNetwork>) {
let (accounts, committee) = new_test_committee(num_nodes, rng);
let accounts_ = accounts.clone();
let mut rng_ = TestRng::fixed(rng.r#gen());
let ledger = task::spawn_blocking(move || sample_ledger(&accounts_, &committee, &mut rng_)).await.unwrap();
let storage = sample_storage(ledger.clone());
let gateway = sample_gateway(accounts[0].clone(), storage, ledger);
let (primary_tx, _primary_rx) = init_primary_channels();
gateway.run(primary_tx, [].into(), None).await;
(accounts, gateway)
}
#[tokio::test(flavor = "multi_thread")]
async fn handshake_responder_side_timeout() {
const NUM_NODES: u16 = 4;
let mut rng = TestRng::default();
let (_accounts, gateway) = new_test_gateway(NUM_NODES, &mut rng).await;
let test_peer = TestPeer::new().await;
dbg!(test_peer.listening_addr());
assert!(test_peer.connect(gateway.local_ip()).await.is_ok());
let gateway_clone = gateway.clone();
deadline!(Duration::from_secs(1), move || gateway_clone.tcp().num_connecting() == 1);
let gateway_clone = gateway.clone();
deadline!(Duration::from_millis(<Gateway<CurrentNetwork> as Handshake>::TIMEOUT_MS + 2_000), move || gateway_clone
.tcp()
.num_connecting()
== 0);
assert!(gateway.connected_peers().is_empty());
assert_eq!(gateway.tcp().num_connected(), 0);
}
#[tokio::test(flavor = "multi_thread")]
async fn handshake_responder_side_invalid_challenge_request() {
const NUM_NODES: u16 = 4;
let mut rng = TestRng::default();
let (accounts, gateway) = new_test_gateway(NUM_NODES, &mut rng).await;
let test_peer = TestPeer::new().await;
assert!(test_peer.connect(gateway.local_ip()).await.is_ok());
let gateway_clone = gateway.clone();
deadline!(Duration::from_secs(1), move || gateway_clone.tcp().num_connecting() == 1);
let listener_port = test_peer.listening_addr().port();
let address = accounts.get(1).unwrap().address();
let nonce = rng.r#gen();
let snarkos_sha = None;
let challenge_request = ChallengeRequest { version: 0, listener_port, address, nonce, snarkos_sha };
let _ = test_peer.unicast(gateway.local_ip(), Event::ChallengeRequest(challenge_request));
let gateway_clone = gateway.clone();
deadline!(Duration::from_secs(1), move || gateway_clone.tcp().num_connecting() == 0);
assert!(gateway.connected_peers().is_empty());
assert_eq!(gateway.tcp().num_connected(), 0);
}
#[tokio::test(flavor = "multi_thread")]
async fn handshake_responder_side_invalid_challenge_response() {
const NUM_NODES: u16 = 4;
let mut rng = TestRng::default();
let (accounts, gateway) = new_test_gateway(NUM_NODES, &mut rng).await;
let mut test_peer = TestPeer::new().await;
assert!(test_peer.connect(gateway.local_ip()).await.is_ok());
let gateway_clone = gateway.clone();
deadline!(Duration::from_secs(1), move || gateway_clone.tcp().num_connecting() == 1);
let listener_port = test_peer.listening_addr().port();
let address = accounts.get(1).unwrap().address();
let our_nonce = rng.r#gen();
let snarkos_sha = None;
let version = Event::<CurrentNetwork>::VERSION;
let challenge_request = ChallengeRequest { version, listener_port, address, nonce: our_nonce, snarkos_sha };
let _ = test_peer.unicast(gateway.local_ip(), Event::ChallengeRequest(challenge_request));
let (peer_addr, Event::ChallengeResponse(ChallengeResponse { restrictions_id, signature, nonce })) =
test_peer.recv_timeout(Duration::from_secs(1)).await
else {
panic!("Expected challenge response")
};
assert_eq!(peer_addr, gateway.local_ip());
assert!(
signature.deserialize_blocking().unwrap().verify_bytes(
&accounts.first().unwrap().address(),
&[our_nonce.to_le_bytes(), nonce.to_le_bytes()].concat()
)
);
let (peer_addr, Event::ChallengeRequest(challenge_request)) = test_peer.recv_timeout(Duration::from_secs(1)).await
else {
panic!("Expected challenge request")
};
assert_eq!(peer_addr, gateway.local_ip());
assert_eq!(challenge_request.version, version);
assert_eq!(challenge_request.listener_port, gateway.local_ip().port());
assert_eq!(challenge_request.address, accounts.first().unwrap().address());
let response_nonce = rng.r#gen();
let _ = test_peer.unicast(
gateway.local_ip(),
Event::ChallengeResponse(ChallengeResponse {
restrictions_id,
signature: Data::Object(
accounts.get(2).unwrap().sign_bytes(&challenge_request.nonce.to_le_bytes(), &mut rng).unwrap(),
),
nonce: response_nonce,
}),
);
let gateway_clone = gateway.clone();
deadline!(Duration::from_secs(1), move || gateway_clone.tcp().num_connecting() == 0);
assert!(gateway.connected_peers().is_empty());
assert_eq!(gateway.tcp().num_connected(), 0);
}