Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(scanner): Don't scan and log if we are below sapling height #8121

Merged
merged 2 commits into from
Dec 21, 2023
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
30 changes: 28 additions & 2 deletions zebra-scan/src/scan.rs
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,8 @@ pub async fn start(
.await;
let key_heights = Arc::new(key_heights);

let mut height = get_min_height(&key_heights).unwrap_or(storage.min_sapling_birthday_height());
let sapling_activation_height = storage.min_sapling_birthday_height();
let mut height = get_min_height(&key_heights).unwrap_or(sapling_activation_height);

// Parse and convert keys once, then use them to scan all blocks.
// There is some cryptography here, but it should be fast even with thousands of keys.
Expand All @@ -90,6 +91,14 @@ pub async fn start(
tokio::time::sleep(INITIAL_WAIT).await;

loop {
// Do not scan and notify if we are below sapling activation height.
let tip_height = tip_height(state.clone()).await?;
if tip_height < sapling_activation_height {
info!("scanner is waiting for sapling activation. Current tip: {}, Sapling activation: {}", tip_height.0, sapling_activation_height.0);
tokio::time::sleep(CHECK_INTERVAL).await;
continue;
}

let scanned_height = scan_height_and_store_results(
height,
state.clone(),
Expand Down Expand Up @@ -149,7 +158,7 @@ pub async fn scan_height_and_store_results(
let block = match block {
zebra_state::Response::Block(Some(block)) => block,
zebra_state::Response::Block(None) => return Ok(None),
_ => unreachable!("unmatched response to a state::Tip request"),
_ => unreachable!("unmatched response to a state::Block request"),
};

// Scan it with all the keys.
Expand Down Expand Up @@ -400,3 +409,20 @@ fn scanned_block_to_db_result<Nf>(
fn get_min_height(map: &HashMap<String, Height>) -> Option<Height> {
map.values().cloned().min()
}

/// Get tip height or return genesis block height if no tip is available.
async fn tip_height(mut state: State) -> Result<Height, Report> {
let tip = state
.ready()
.await
.map_err(|e| eyre!(e))?
.call(zebra_state::Request::Tip)
.await
.map_err(|e| eyre!(e))?;

match tip {
zebra_state::Response::Tip(Some((height, _hash))) => Ok(height),
zebra_state::Response::Tip(None) => Ok(Height(0)),
_ => unreachable!("unmatched response to a state::Tip request"),
}
}
42 changes: 19 additions & 23 deletions zebrad/tests/acceptance.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2820,39 +2820,36 @@ async fn fully_synced_rpc_z_getsubtreesbyindex_snapshot_test() -> Result<()> {
#[cfg(feature = "shielded-scan")]
fn scan_task_starts() -> Result<()> {
use indexmap::IndexMap;

use zebra_scan::tests::ZECPAGES_SAPLING_VIEWING_KEY;

let _init_guard = zebra_test::init();

let test_type = TestType::LaunchWithEmptyState {
launches_lightwalletd: false,
};
let mut config = default_test_config(Mainnet)?;
let mut keys = IndexMap::new();
keys.insert(ZECPAGES_SAPLING_VIEWING_KEY.to_string(), 1);
config.shielded_scan.sapling_keys_to_scan = keys;

let testdir = testdir()?.with_config(&mut config)?;
let testdir = &testdir;
// Start zebra with the config.
let mut zebrad = testdir()?
.with_exact_config(&config)?
.spawn_child(args!["start"])?
.with_timeout(test_type.zebrad_timeout());

let mut child = testdir.spawn_child(args!["start"])?;
// Check scanner was started.
zebrad.expect_stdout_line_matches("loaded Zebra scanner cache")?;

// Run the program and kill it after the scanner starts and the first scanning is done.
std::thread::sleep(LAUNCH_DELAY * 2);
child.kill(false)?;
// Look for 2 scanner notices indicating we are below sapling activation.
zebrad.expect_stdout_line_matches("scanner is waiting for sapling activation. Current tip: [0-9]{1,4}, Sapling activation: 419200")?;
zebrad.expect_stdout_line_matches("scanner is waiting for sapling activation. Current tip: [0-9]{1,4}, Sapling activation: 419200")?;

// Check that scan task started and the first scanning is done.
let output = child.wait_with_output()?;
// Kill the node.
zebrad.kill(false)?;

output.stdout_line_contains("spawning shielded scanner with configured viewing keys")?;
/*
TODO: these lines only happen when we reach sapling activation height
output.stdout_line_contains("Scanning the blockchain: now at block")?;
output.stdout_line_contains(
format!(
"Scanning the blockchain for key 0, started at block",
)
.as_str(),
)?;
*/
// Check that scan task started and the first scanning is done.
let output = zebrad.wait_with_output()?;

// Make sure the command was killed
output.assert_was_killed()?;
Expand All @@ -2878,18 +2875,17 @@ fn scan_task_starts() -> Result<()> {
#[cfg(feature = "shielded-scan")]
fn scan_start_where_left() -> Result<()> {
use indexmap::IndexMap;
use zebra_scan::storage::db::SCANNER_DATABASE_KIND;
use zebra_scan::{storage::db::SCANNER_DATABASE_KIND, tests::ZECPAGES_SAPLING_VIEWING_KEY};

let _init_guard = zebra_test::init();

// use `UpdateZebraCachedStateNoRpc` as the test type to make sure a zebrad cache state is available.
let test_type = TestType::UpdateZebraCachedStateNoRpc;
if let Some(cache_dir) = test_type.zebrad_state_path("scan test") {
// Add a key to the config
const ZECPAGES_VIEWING_KEY: &str = "zxviews1q0duytgcqqqqpqre26wkl45gvwwwd706xw608hucmvfalr759ejwf7qshjf5r9aa7323zulvz6plhttp5mltqcgs9t039cx2d09mgq05ts63n8u35hyv6h9nc9ctqqtue2u7cer2mqegunuulq2luhq3ywjcz35yyljewa4mgkgjzyfwh6fr6jd0dzd44ghk0nxdv2hnv4j5nxfwv24rwdmgllhe0p8568sgqt9ckt02v2kxf5ahtql6s0ltjpkckw8gtymxtxuu9gcr0swvz";
let mut config = default_test_config(Mainnet)?;
let mut keys = IndexMap::new();
keys.insert(ZECPAGES_VIEWING_KEY.to_string(), 1);
keys.insert(ZECPAGES_SAPLING_VIEWING_KEY.to_string(), 1);
config.shielded_scan.sapling_keys_to_scan = keys;

// Add the cache dir to shielded scan, make it the same as the zebrad cache state.
Expand Down
Loading