Skip to content
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
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- Fee sniping discouraging through nLockTime - if the user specifies a `current_height`, we use that as a nlocktime, otherwise we use the last sync height (or 0 if we never synced)
- Fix hang when `ElectrumBlockchainConfig::stop_gap` is zero.
- Set coin type in BIP44, BIP49, and BIP84 templates
- Get block hash given a block height - A `get_block_hash` method is now defined on the `GetBlockHash` trait and implemented on every blockchain backend. This method expects a block height and returns the corresponding block hash.

## [v0.19.0] - [v0.18.0]

Expand Down
7 changes: 7 additions & 0 deletions src/blockchain/any.rs
Original file line number Diff line number Diff line change
Expand Up @@ -120,6 +120,13 @@ impl GetTx for AnyBlockchain {
}
}

#[maybe_async]
impl GetBlockHash for AnyBlockchain {
fn get_block_hash(&self, height: u64) -> Result<BlockHash, Error> {
maybe_await!(impl_inner_method!(self, get_block_hash, height))
}
}

#[maybe_async]
impl WalletSync for AnyBlockchain {
fn wallet_sync<D: BatchDatabase>(
Expand Down
12 changes: 12 additions & 0 deletions src/blockchain/compact_filters/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -260,6 +260,16 @@ impl GetTx for CompactFiltersBlockchain {
}
}

impl GetBlockHash for CompactFiltersBlockchain {
fn get_block_hash(&self, height: u64) -> Result<BlockHash, Error> {
self.headers
.get_block_hash(height as usize)?
.ok_or(Error::CompactFilters(
CompactFiltersError::BlockHashNotFound,
))
}
}

impl WalletSync for CompactFiltersBlockchain {
#[allow(clippy::mutex_atomic)] // Mutex is easier to understand than a CAS loop.
fn wallet_setup<D: BatchDatabase>(
Expand Down Expand Up @@ -536,6 +546,8 @@ pub enum CompactFiltersError {
InvalidFilter,
/// The peer is missing a block in the valid chain
MissingBlock,
/// Block hash at specified height not found
BlockHashNotFound,
/// The data stored in the block filters storage are corrupted
DataCorruption,

Expand Down
7 changes: 7 additions & 0 deletions src/blockchain/electrum.rs
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,13 @@ impl GetTx for ElectrumBlockchain {
}
}

impl GetBlockHash for ElectrumBlockchain {
fn get_block_hash(&self, height: u64) -> Result<BlockHash, Error> {
let block_header = self.client.block_header(height as usize)?;
Ok(block_header.block_hash())
}
}

impl WalletSync for ElectrumBlockchain {
fn wallet_setup<D: BatchDatabase>(
&self,
Expand Down
8 changes: 8 additions & 0 deletions src/blockchain/esplora/reqwest.rs
Original file line number Diff line number Diff line change
Expand Up @@ -117,6 +117,14 @@ impl GetTx for EsploraBlockchain {
}
}

#[maybe_async]
impl GetBlockHash for EsploraBlockchain {
fn get_block_hash(&self, height: u64) -> Result<BlockHash, Error> {
let block_header = await_or_block!(self.url_client._get_header(height as u32))?;
Ok(block_header.block_hash())
}
}

#[maybe_async]
impl WalletSync for EsploraBlockchain {
fn wallet_setup<D: BatchDatabase>(
Expand Down
7 changes: 7 additions & 0 deletions src/blockchain/esplora/ureq.rs
Original file line number Diff line number Diff line change
Expand Up @@ -112,6 +112,13 @@ impl GetTx for EsploraBlockchain {
}
}

impl GetBlockHash for EsploraBlockchain {
fn get_block_hash(&self, height: u64) -> Result<BlockHash, Error> {
let block_header = self.url_client._get_header(height as u32)?;
Ok(block_header.block_hash())
}
}

impl WalletSync for EsploraBlockchain {
fn wallet_setup<D: BatchDatabase>(
&self,
Expand Down
18 changes: 16 additions & 2 deletions src/blockchain/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ use std::ops::Deref;
use std::sync::mpsc::{channel, Receiver, Sender};
use std::sync::Arc;

use bitcoin::{Transaction, Txid};
use bitcoin::{BlockHash, Transaction, Txid};

use crate::database::BatchDatabase;
use crate::error::Error;
Expand Down Expand Up @@ -87,7 +87,7 @@ pub enum Capability {

/// Trait that defines the actions that must be supported by a blockchain backend
#[maybe_async]
pub trait Blockchain: WalletSync + GetHeight + GetTx {
pub trait Blockchain: WalletSync + GetHeight + GetTx + GetBlockHash {
/// Return the set of [`Capability`] supported by this backend
fn get_capabilities(&self) -> HashSet<Capability>;
/// Broadcast a transaction
Expand All @@ -110,6 +110,13 @@ pub trait GetTx {
fn get_tx(&self, txid: &Txid) -> Result<Option<Transaction>, Error>;
}

#[maybe_async]
/// Trait for getting block hash by block height
pub trait GetBlockHash {
/// fetch block hash given its height
fn get_block_hash(&self, height: u64) -> Result<BlockHash, Error>;
}

/// Trait for blockchains that can sync by updating the database directly.
#[maybe_async]
pub trait WalletSync {
Expand Down Expand Up @@ -359,6 +366,13 @@ impl<T: GetHeight> GetHeight for Arc<T> {
}
}

#[maybe_async]
impl<T: GetBlockHash> GetBlockHash for Arc<T> {
fn get_block_hash(&self, height: u64) -> Result<BlockHash, Error> {
maybe_await!(self.deref().get_block_hash(height))
}
}

#[maybe_async]
impl<T: WalletSync> WalletSync for Arc<T> {
fn wallet_setup<D: BatchDatabase>(
Expand Down
6 changes: 6 additions & 0 deletions src/blockchain/rpc.rs
Original file line number Diff line number Diff line change
Expand Up @@ -169,6 +169,12 @@ impl GetHeight for RpcBlockchain {
}
}

impl GetBlockHash for RpcBlockchain {
fn get_block_hash(&self, height: u64) -> Result<BlockHash, Error> {
Ok(self.client.get_block_hash(height)?)
}
}

impl WalletSync for RpcBlockchain {
fn wallet_setup<D: BatchDatabase>(
&self,
Expand Down
29 changes: 29 additions & 0 deletions src/testutils/blockchain_tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1361,6 +1361,35 @@ macro_rules! bdk_blockchain_tests {
let finalized = wallet.sign(&mut psbt, Default::default()).unwrap();
assert_eq!(finalized, true);
}

#[test]
fn test_get_block_hash() {
use bitcoincore_rpc::{ RpcApi };
use crate::blockchain::GetBlockHash;

// create wallet with init_wallet
let (_, blockchain, _descriptors, mut test_client) = init_single_sig();

let height = test_client.bitcoind.client.get_blockchain_info().unwrap().blocks as u64;
let best_hash = test_client.bitcoind.client.get_best_block_hash().unwrap();

// use get_block_hash to get best block hash and compare with best_hash above
let block_hash = blockchain.get_block_hash(height).unwrap();
assert_eq!(best_hash, block_hash);

// generate blocks to address
let node_addr = test_client.get_node_address(None);
test_client.generate(10, Some(node_addr));

let height = test_client.bitcoind.client.get_blockchain_info().unwrap().blocks as u64;
let best_hash = test_client.bitcoind.client.get_best_block_hash().unwrap();

let block_hash = blockchain.get_block_hash(height).unwrap();
assert_eq!(best_hash, block_hash);

// try to get hash for block that has not yet been created.
assert!(blockchain.get_block_hash(height + 1).is_err());
}
}
};

Expand Down