diff --git a/ledger-tool/src/main.rs b/ledger-tool/src/main.rs index e5617d2e7f..e498b23268 100644 --- a/ledger-tool/src/main.rs +++ b/ledger-tool/src/main.rs @@ -15,6 +15,7 @@ use solana_ledger::{ rooted_slot_iterator::RootedSlotIterator, snapshot_utils, }; +use solana_runtime::bank::Bank; use solana_sdk::{ clock::Slot, genesis_config::GenesisConfig, native_token::lamports_to_sol, pubkey::Pubkey, shred_version::compute_shred_version, @@ -29,6 +30,7 @@ use std::{ path::{Path, PathBuf}, process::{exit, Command, Stdio}, str::FromStr, + sync::Arc, }; use log::*; @@ -787,6 +789,17 @@ fn main() { .takes_value(true) .help("Output directory for the snapshot"), ) + .arg( + Arg::with_name("warp_slot") + .required(false) + .long("warp-slot") + .takes_value(true) + .value_name("WARP_SLOT") + .validator(is_slot) + .help("After loading the snapshot slot warp the ledger to WARP_SLOT, \ + which could be a slot in a galaxy far far away"), + ) + ).subcommand( SubCommand::with_name("accounts") .about("Print account contents after processing in the ledger") @@ -1034,6 +1047,7 @@ fn main() { ("create-snapshot", Some(arg_matches)) => { let snapshot_slot = value_t_or_exit!(arg_matches, "snapshot_slot", Slot); let output_directory = value_t_or_exit!(arg_matches, "output_directory", String); + let warp_slot = value_t!(arg_matches, "warp_slot", Slot).ok(); let process_options = ProcessOptions { dev_halt_at_slot: Some(snapshot_slot), @@ -1050,12 +1064,26 @@ fn main() { AccessType::TryPrimaryThenSecondary, ) { Ok((bank_forks, _leader_schedule_cache, _snapshot_hash)) => { - let bank = bank_forks.get(snapshot_slot).unwrap_or_else(|| { - eprintln!("Error: Slot {} is not available", snapshot_slot); - exit(1); - }); + let bank = bank_forks + .get(snapshot_slot) + .unwrap_or_else(|| { + eprintln!("Error: Slot {} is not available", snapshot_slot); + exit(1); + }) + .clone(); + + let bank = if let Some(warp_slot) = warp_slot { + Arc::new(Bank::warp_from_parent( + &bank, + bank.collector_id(), + warp_slot, + )) + } else { + bank + }; println!("Creating a snapshot of slot {}", bank.slot()); + assert!(bank.is_complete()); bank.squash(); bank.clean_accounts(); bank.update_accounts_hash(); @@ -1082,7 +1110,8 @@ fn main() { snapshot_utils::archive_snapshot_package(&package).map(|ok| { println!( "Successfully created snapshot for slot {}: {:?}", - snapshot_slot, package.tar_output_file + bank.slot(), + package.tar_output_file ); println!( "Shred version: {}", diff --git a/multinode-demo/bootstrap-validator.sh b/multinode-demo/bootstrap-validator.sh index 80731b2923..fe8d4bc786 100755 --- a/multinode-demo/bootstrap-validator.sh +++ b/multinode-demo/bootstrap-validator.sh @@ -33,6 +33,9 @@ while [[ -n $1 ]]; do elif [[ $1 = --gossip-port ]]; then args+=("$1" "$2") shift 2 + elif [[ $1 = --dev-halt-at-slot ]]; then + args+=("$1" "$2") + shift 2 elif [[ $1 = --dynamic-port-range ]]; then args+=("$1" "$2") shift 2 diff --git a/runtime/src/bank.rs b/runtime/src/bank.rs index 9e1708daa2..23d3e0f946 100644 --- a/runtime/src/bank.rs +++ b/runtime/src/bank.rs @@ -483,6 +483,20 @@ impl Bank { new } + /// Like `new_from_parent` but additionally: + /// * Doesn't assume that the parent is anywhere near `slot`, parent could be millions of slots + /// in the past + /// * Adjusts the new bank's tick height to avoid having to run PoH for millions of slots + /// * Freezes the new bank, assuming that the user will `Bank::new_from_parent` from this bank + pub fn warp_from_parent(parent: &Arc, collector_id: &Pubkey, slot: Slot) -> Self { + let mut new = Bank::new_from_parent(parent, collector_id, slot); + new.update_epoch_stakes(new.epoch_schedule().get_epoch(slot)); + new.tick_height + .store(new.max_tick_height(), Ordering::Relaxed); + new.freeze(); + new + } + pub fn collector_id(&self) -> &Pubkey { &self.collector_id }