diff --git a/Cargo.lock b/Cargo.lock index 1e03e49d..a5198c77 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2008,6 +2008,19 @@ dependencies = [ "tokio-rustls", ] +[[package]] +name = "hyper-tls" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d6183ddfa99b85da61a140bea0efc93fdf56ceaa041b37d553518030827f9905" +dependencies = [ + "bytes", + "hyper", + "native-tls", + "tokio", + "tokio-native-tls", +] + [[package]] name = "ident_case" version = "1.0.1" @@ -3530,11 +3543,13 @@ dependencies = [ "http-body", "hyper", "hyper-rustls", + "hyper-tls", "ipnet", "js-sys", "lazy_static", "log", "mime", + "native-tls", "percent-encoding", "pin-project-lite", "rustls", @@ -3543,6 +3558,7 @@ dependencies = [ "serde_json", "serde_urlencoded", "tokio", + "tokio-native-tls", "tokio-rustls", "url", "wasm-bindgen", @@ -6047,6 +6063,7 @@ dependencies = [ "dirs", "futures", "gumdrop", + "hex", "hyper", "indexmap", "inferno", @@ -6060,6 +6077,7 @@ dependencies = [ "proptest-derive", "rand 0.8.5", "regex", + "reqwest", "semver 1.0.7", "sentry", "sentry-tracing", diff --git a/zebrad/Cargo.toml b/zebrad/Cargo.toml index 9bcbbcba..a61150da 100644 --- a/zebrad/Cargo.toml +++ b/zebrad/Cargo.toml @@ -71,8 +71,10 @@ vergen = { version = "7.0.0", default-features = false, features = ["cargo", "gi [dev-dependencies] abscissa_core = { version = "0.5", features = ["testing"] } +hex = "0.4.3" once_cell = "1.10.0" regex = "1.5.5" +reqwest = "0.11" semver = "1.0.7" # zebra-rpc needs the preserve_order feature, it also makes test results more stable serde_json = { version = "1.0.79", features = ["preserve_order"] } diff --git a/zebrad/tests/acceptance.rs b/zebrad/tests/acceptance.rs index 41bde2ed..1cfb5c68 100644 --- a/zebrad/tests/acceptance.rs +++ b/zebrad/tests/acceptance.rs @@ -21,7 +21,9 @@ //! or you have poor network connectivity, //! skip all the network tests by setting the `ZEBRA_SKIP_NETWORK_TESTS` environmental variable. -use std::{collections::HashSet, convert::TryInto, env, path::PathBuf, time::Duration}; +use std::{ + collections::HashSet, convert::TryInto, env, net::SocketAddr, path::PathBuf, time::Duration, +}; use color_eyre::{ eyre::{Result, WrapErr}, @@ -1473,3 +1475,84 @@ where Ok(()) } + +#[tokio::test] +#[ignore] +async fn fully_synced_rpc_test() -> Result<()> { + zebra_test::init(); + + // TODO: reuse code from https://github.com/ZcashFoundation/zebra/pull/4177/ + // to get the cached_state_path + const CACHED_STATE_PATH_VAR: &str = "ZEBRA_CACHED_STATE_PATH"; + let cached_state_path = match env::var_os(CACHED_STATE_PATH_VAR) { + Some(argument) => PathBuf::from(argument), + None => { + tracing::info!( + "skipped send transactions using lightwalletd test, \ + set the {CACHED_STATE_PATH_VAR:?} environment variable to run the test", + ); + return Ok(()); + } + }; + + let network = Network::Mainnet; + + let (_zebrad, zebra_rpc_address) = + spawn_zebrad_for_rpc_without_initial_peers(network, cached_state_path)?; + + // Make a getblock test that works only on synced node (high block number). + // The block is before the mandatory checkpoint, so the checkpoint cached state can be used + // if desired. + let client = reqwest::Client::new(); + let res = client + .post(format!("http://{}", &zebra_rpc_address.to_string())) + // Manually constructed request to avoid encoding it, for simplicity + .body(r#"{"jsonrpc": "2.0", "method": "getblock", "params": ["1180900", 0], "id":123 }"#) + .header("Content-Type", "application/json") + .send() + .await? + .text() + .await?; + + // Simple textual check to avoid fully parsing the response, for simplicity + let expected_bytes = zebra_test::vectors::MAINNET_BLOCKS + .get(&1_180_900) + .expect("test block must exist"); + let expected_hex = hex::encode(expected_bytes); + assert!( + res.contains(&expected_hex), + "response did not contain the desired block: {}", + res + ); + + Ok(()) +} + +/// Spawns a zebrad instance to interact with lightwalletd, but without an internet connection. +/// +/// This prevents it from downloading blocks. Instead, the `zebra_directory` parameter allows +/// providing an initial state to the zebrad instance. +fn spawn_zebrad_for_rpc_without_initial_peers( + network: Network, + zebra_directory: PathBuf, +) -> Result<(TestChild, SocketAddr)> { + let mut config = random_known_rpc_port_config() + .expect("Failed to create a config file with a known RPC listener port"); + + config.state.ephemeral = false; + config.network.initial_mainnet_peers = HashSet::new(); + config.network.initial_testnet_peers = HashSet::new(); + config.network.network = network; + + let mut zebrad = zebra_directory + .with_config(&mut config)? + .spawn_child(args!["start"])? + .with_timeout(Duration::from_secs(60 * 60)) + .bypass_test_capture(true); + + let rpc_address = config.rpc.listen_addr.unwrap(); + + zebrad.expect_stdout_line_matches(&format!("Opened RPC endpoint at {}", rpc_address))?; + + Ok((zebrad, rpc_address)) +}