Merge #957: Get genesis timestamp from bitcoind

f2c418f79a6fe8f1d6138b12af9fdc7303b4725d get genesis timestamp from bitcoind (pythcoiner)

Pull request description:

  fixes #904

ACKs for top commit:
  jp1ac4:
    ACK f2c418f79a.

Tree-SHA512: 7b1b7c13c21b657109ab0aab0d89deb47f5f6693f95687b86c219fc109ee304c38e3ebe865d071ebbbfa890a6a754c615f5dd70f2fe8c492bdea35d0394f36eb
This commit is contained in:
Antoine Poinsot 2024-03-09 19:03:33 +01:00
commit cf299b997b
No known key found for this signature in database
GPG Key ID: E13FC145CD3F4304
4 changed files with 27 additions and 5 deletions

View File

@ -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<sync::Mutex<dyn BitcoinInterface + 'static>> {
fn genesis_block_timestamp(&self) -> u32 {
self.lock().unwrap().genesis_block_timestamp()
}
fn genesis_block(&self) -> BlockChainTip {
self.lock().unwrap().genesis_block()
}

View File

@ -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() {

View File

@ -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",

View File

@ -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):