diff --git a/gui/src/app/state/settings/bitcoind.rs b/gui/src/app/state/settings/bitcoind.rs index eeeb3409..cf944660 100644 --- a/gui/src/app/state/settings/bitcoind.rs +++ b/gui/src/app/state/settings/bitcoind.rs @@ -1,4 +1,4 @@ -use std::convert::From; +use std::convert::{From, TryInto}; use std::net::SocketAddr; use std::path::PathBuf; use std::str::FromStr; @@ -8,7 +8,10 @@ use chrono::prelude::*; use iced::Command; use tracing::info; -use liana::config::{BitcoinConfig, BitcoindConfig, BitcoindRpcAuth, Config}; +use liana::{ + config::{BitcoinConfig, BitcoindConfig, BitcoindRpcAuth, Config}, + miniscript::bitcoin::Network, +}; use liana_ui::{component::form, widget::Element}; @@ -40,7 +43,7 @@ impl BitcoindSettingsState { node_settings: config.map(|config| { BitcoindSettings::new( config.bitcoin_config.clone(), - config.bitcoind_config.clone().unwrap(), + config.bitcoind_config.unwrap(), daemon_is_external, bitcoind_is_internal, ) @@ -315,6 +318,7 @@ pub struct RescanSetting { month: form::Value, day: form::Value, invalid_date: bool, + future_date: bool, past_possible_height: bool, } @@ -340,12 +344,14 @@ impl RescanSetting { fn update( &mut self, daemon: Arc, - _cache: &Cache, + cache: &Cache, message: view::SettingsEditMessage, ) -> Command { match message { view::SettingsEditMessage::FieldEdited(field, value) => { self.invalid_date = false; + self.future_date = false; + self.past_possible_height = false; if !self.processing && (value.is_empty() || u32::from_str(&value).is_ok()) { match field { "rescan_year" => self.year.value = value, @@ -356,27 +362,66 @@ impl RescanSetting { } } view::SettingsEditMessage::Confirm => { - let date_time = if let Some(date) = NaiveDate::from_ymd_opt( + let t = if let Some(date) = NaiveDate::from_ymd_opt( i32::from_str(&self.year.value).unwrap_or(1), u32::from_str(&self.month.value).unwrap_or(1), u32::from_str(&self.day.value).unwrap_or(1), - ) { - if date < NaiveDate::from_str("2009-01-03").unwrap() { - self.past_possible_height = true; - return Command::none(); - } else { - self.past_possible_height = false; - date + ) + .and_then(|d| d.and_hms_opt(0, 0, 0)) + .map(|d| d.timestamp()) + { + match cache.network { + Network::Bitcoin => { + if date < MAINNET_GENESIS_BLOCK_TIMESTAMP { + info!("Date {} prior to genesis block, using genesis block timestamp {}", date, MAINNET_GENESIS_BLOCK_TIMESTAMP); + + MAINNET_GENESIS_BLOCK_TIMESTAMP + } else { + date + } + } + Network::Testnet => { + if date < TESTNET3_GENESIS_BLOCK_TIMESTAMP { + info!("Date {} prior to genesis block, using genesis block timestamp {}", date, TESTNET3_GENESIS_BLOCK_TIMESTAMP); + TESTNET3_GENESIS_BLOCK_TIMESTAMP + } else { + date + } + } + Network::Signet => { + if date < SIGNET_GENESIS_BLOCK_TIMESTAMP { + info!("Date {} prior to genesis block, using genesis block timestamp {}", date, SIGNET_GENESIS_BLOCK_TIMESTAMP); + SIGNET_GENESIS_BLOCK_TIMESTAMP + } else { + date + } + } + // We expect regtest user to not use genesis block timestamp inferior to + // the mainnet one. + // Network is a non exhaustive enum, that is why the _. + _ => { + if date < MAINNET_GENESIS_BLOCK_TIMESTAMP { + info!("Date {} prior to genesis block, using genesis block timestamp {}", date, MAINNET_GENESIS_BLOCK_TIMESTAMP); + MAINNET_GENESIS_BLOCK_TIMESTAMP + } else { + date + } + } } } else { self.invalid_date = true; return Command::none(); }; - let t = date_time.and_hms_opt(0, 0, 0).unwrap().timestamp() as u32; + if t > Utc::now().timestamp() { + self.future_date = true; + return Command::none(); + } self.processing = true; info!("Asking deamon to rescan with timestamp: {}", t); return Command::perform( - async move { daemon.start_rescan(t).map_err(|e| e.into()) }, + async move { + daemon.start_rescan(t.try_into().expect("t cannot be inferior to 0 otherwise genesis block timestam is chosen")).map_err(|e| e.into()) + }, Message::StartRescan, ); } @@ -396,6 +441,12 @@ impl RescanSetting { can_edit, self.invalid_date, self.past_possible_height, + self.future_date, ) } } + +/// Use bitcoin-cli getblock $(bitcoin-cli getblockhash 0) | jq .time +const MAINNET_GENESIS_BLOCK_TIMESTAMP: i64 = 1231006505; +const TESTNET3_GENESIS_BLOCK_TIMESTAMP: i64 = 1296688602; +const SIGNET_GENESIS_BLOCK_TIMESTAMP: i64 = 1598918400; diff --git a/gui/src/app/view/settings.rs b/gui/src/app/view/settings.rs index e44bc7f8..73658922 100644 --- a/gui/src/app/view/settings.rs +++ b/gui/src/app/view/settings.rs @@ -476,6 +476,7 @@ pub fn rescan<'a>( can_edit: bool, invalid_date: bool, past_possible_height: bool, + future_date: bool, ) -> Element<'a, SettingsEditMessage> { card::simple(Container::new( Column::new() @@ -534,21 +535,23 @@ pub fn rescan<'a>( .spacing(10), ) .push_maybe(if invalid_date { - Some( - p1_regular("Provided date is invalid") - .style(color::RED), - ) + Some(p1_regular("Provided date is invalid").style(color::RED)) } else { None }) .push_maybe(if past_possible_height { Some( - p1_regular("Provided date earlier than the genesis block's timestamp or the node prune height") + p1_regular("Provided date earlier than the node prune height") .style(color::RED), ) } else { None }) + .push_maybe(if future_date { + Some(p1_regular("Provided date is in the future").style(color::RED)) + } else { + None + }) .push( if can_edit && !invalid_date