Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Get genesis timestamp from bitcoind #957

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 15 additions & 0 deletions src/bitcoin/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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<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()
}
Expand Down
6 changes: 2 additions & 4 deletions src/commands/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down Expand Up @@ -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() {
Expand Down
4 changes: 4 additions & 0 deletions src/testutils.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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",
Expand Down
13 changes: 8 additions & 5 deletions tests/test_rpc.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@

def test_getinfo(lianad):
res = lianad.rpc.getinfo()
assert 'timestamp' in res.keys()
assert "timestamp" in res.keys()
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

black doing is job here

assert res["version"] == "4.0.0-dev"
assert res["network"] == "regtest"
wait_for(lambda: lianad.rpc.getinfo()["block_height"] == 101)
Expand Down Expand Up @@ -599,10 +599,15 @@ def all_spent(coins):
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):
Expand Down Expand Up @@ -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."),
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

black doing his job

):
rbf_1_res = lianad.rpc.rbfpsbt(first_txid, True, 2)
rbf_1_psbt = PSBT.from_base64(rbf_1_res["psbt"])
Expand Down
Loading