From f2c418f79a6fe8f1d6138b12af9fdc7303b4725d Mon Sep 17 00:00:00 2001 From: pythcoiner Date: Sat, 3 Feb 2024 06:38:39 +0100 Subject: [PATCH] get genesis timestamp from bitcoind --- src/bitcoin/mod.rs | 15 +++++++++++++++ src/commands/mod.rs | 6 ++---- src/testutils.rs | 4 ++++ tests/test_rpc.py | 13 ++++++++----- 4 files changed, 29 insertions(+), 9 deletions(-) diff --git a/src/bitcoin/mod.rs b/src/bitcoin/mod.rs index 60388c1e..914525cf 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. @@ -119,6 +121,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 @@ -370,6 +381,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 bf473bf6..28a0620e 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, @@ -888,13 +885,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 9034aaec..7fe3141d 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 904d17b8..9144ad88 100644 --- a/tests/test_rpc.py +++ b/tests/test_rpc.py @@ -22,7 +22,7 @@ from test_framework.utils import ( def test_getinfo(lianad): res = lianad.rpc.getinfo() - assert 'timestamp' in res.keys() + assert "timestamp" in res.keys() assert res["version"] == "4.0.0-dev" assert res["network"] == "regtest" wait_for(lambda: lianad.rpc.getinfo()["block_height"] == 101) @@ -599,10 +599,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): @@ -1232,9 +1237,7 @@ def test_rbfpsbt_cancel(lianad, bitcoind): # But we can't set the feerate explicitly. with pytest.raises( RpcError, - match=re.escape( - "A feerate must not be provided if creating a cancel." - ), + match=re.escape("A feerate must not be provided if creating a cancel."), ): rbf_1_res = lianad.rpc.rbfpsbt(first_txid, True, 2) rbf_1_psbt = PSBT.from_base64(rbf_1_res["psbt"])