diff --git a/src/bitcoin/mod.rs b/src/bitcoin/mod.rs index 6c41c40c..a278d33a 100644 --- a/src/bitcoin/mod.rs +++ b/src/bitcoin/mod.rs @@ -40,6 +40,8 @@ impl fmt::Display for BlockChainTip { /// Our Bitcoin backend. pub trait BitcoinInterface: Send { + fn genesis_block_timestamp(&self) -> u32; + fn genesis_block(&self) -> BlockChainTip; /// Get the progress of the block chain synchronization. @@ -124,6 +126,15 @@ pub trait BitcoinInterface: Send { } impl BitcoinInterface for d::BitcoinD { + fn genesis_block_timestamp(&self) -> u32 { + self.get_block_stats( + self.get_block_hash(0) + .expect("Genesis block hash must always be there"), + ) + .expect("Genesis block must always be there") + .time + } + fn genesis_block(&self) -> BlockChainTip { let height = 0; let hash = self @@ -379,6 +390,10 @@ impl BitcoinInterface for d::BitcoinD { // FIXME: do we need to repeat the entire trait implemenation? Isn't there a nicer way? impl BitcoinInterface for sync::Arc> { + fn genesis_block_timestamp(&self) -> u32 { + self.lock().unwrap().genesis_block_timestamp() + } + fn genesis_block(&self) -> BlockChainTip { self.lock().unwrap().genesis_block() } diff --git a/src/commands/mod.rs b/src/commands/mod.rs index e3814be7..8648d519 100644 --- a/src/commands/mod.rs +++ b/src/commands/mod.rs @@ -33,9 +33,6 @@ use miniscript::{ }; use serde::{Deserialize, Serialize}; -// Timestamp in the header of the genesis block. Used for sanity checks. -const MAINNET_GENESIS_TIME: u32 = 1231006505; - #[derive(Debug, Clone, PartialEq, Eq)] pub enum CommandError { NoOutpointForSelfSend, @@ -953,13 +950,14 @@ impl DaemonControl { /// The date must be after the genesis block time and before the current tip blocktime. pub fn start_rescan(&self, timestamp: u32) -> Result<(), CommandError> { let mut db_conn = self.db.connection(); + let genesis_timestamp = self.bitcoin.genesis_block_timestamp(); let future_timestamp = self .bitcoin .tip_time() .map(|t| timestamp >= t) .unwrap_or(false); - if timestamp < MAINNET_GENESIS_TIME || future_timestamp { + if timestamp < genesis_timestamp || future_timestamp { return Err(CommandError::InsaneRescanTimestamp(timestamp)); } if db_conn.rescan_timestamp().is_some() || self.bitcoin.rescan_progress().is_some() { diff --git a/src/testutils.rs b/src/testutils.rs index 8359b75d..c7e2f077 100644 --- a/src/testutils.rs +++ b/src/testutils.rs @@ -34,6 +34,10 @@ impl DummyBitcoind { } impl BitcoinInterface for DummyBitcoind { + fn genesis_block_timestamp(&self) -> u32 { + 1231006505 + } + fn genesis_block(&self) -> BlockChainTip { let hash = bitcoin::BlockHash::from_str( "000000000019d6689c085ae165831e934ff763ae46a2a6c172b3f1b60a8ce26f", diff --git a/tests/test_rpc.py b/tests/test_rpc.py index 5157f87d..87e74af9 100644 --- a/tests/test_rpc.py +++ b/tests/test_rpc.py @@ -628,10 +628,15 @@ def test_start_rescan(lianad, bitcoind): with pytest.raises(RpcError, match="Insane timestamp.*"): lianad.rpc.startrescan(future_timestamp) assert lianad.rpc.getinfo()["rescan_progress"] is None - prebitcoin_timestamp = 1231006505 - 1 + block_hash = bitcoind.rpc.getblockhash(0) + genesis_timestamp = bitcoind.rpc.getblock(block_hash)["time"] + prebitcoin_timestamp = genesis_timestamp - 1 with pytest.raises(RpcError, match="Insane timestamp."): lianad.rpc.startrescan(prebitcoin_timestamp) assert lianad.rpc.getinfo()["rescan_progress"] is None + # we can rescan from genesis block + lianad.rpc.startrescan(genesis_timestamp) + wait_for(lambda: lianad.rpc.getinfo()["rescan_progress"] is None) # First, get some coins for _ in range(10):