Compare commits
27 Commits
0.10.0
...
release/0.
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
9e508748a3 | ||
|
|
84b8579df5 | ||
|
|
7cb0116c44 | ||
|
|
6e12468b12 | ||
|
|
5694b98304 | ||
|
|
aa786fbb21 | ||
|
|
8c570ae7eb | ||
|
|
56a7bc9874 | ||
|
|
cf1815a1c0 | ||
|
|
721748e98f | ||
|
|
976e641ba6 | ||
|
|
7117557dea | ||
|
|
fa013aeb83 | ||
|
|
38d1d0b0e2 | ||
|
|
582d2f3814 | ||
|
|
5e0011e1a8 | ||
|
|
39d2bd0d21 | ||
|
|
0e10952b80 | ||
|
|
19d74955e2 | ||
|
|
73a7faf144 | ||
|
|
ea56a87b4b | ||
|
|
67f5f45e07 | ||
|
|
b8680b299d | ||
|
|
e80be49d1e | ||
|
|
fe30716fa2 | ||
|
|
e52550cfec | ||
|
|
f57c0ca98e |
14
.github/workflows/cont_integration.yml
vendored
14
.github/workflows/cont_integration.yml
vendored
@@ -78,15 +78,20 @@ jobs:
|
|||||||
run: cargo test --features test-md-docs --no-default-features -- doctest::ReadmeDoctests
|
run: cargo test --features test-md-docs --no-default-features -- doctest::ReadmeDoctests
|
||||||
|
|
||||||
test-blockchains:
|
test-blockchains:
|
||||||
name: Test ${{ matrix.blockchain.name }}
|
name: Blockchain ${{ matrix.blockchain.features }}
|
||||||
runs-on: ubuntu-20.04
|
runs-on: ubuntu-20.04
|
||||||
strategy:
|
strategy:
|
||||||
fail-fast: false
|
fail-fast: false
|
||||||
matrix:
|
matrix:
|
||||||
blockchain:
|
blockchain:
|
||||||
- name: electrum
|
- name: electrum
|
||||||
|
features: test-electrum
|
||||||
- name: rpc
|
- name: rpc
|
||||||
|
features: test-rpc
|
||||||
- name: esplora
|
- name: esplora
|
||||||
|
features: test-esplora,use-esplora-reqwest
|
||||||
|
- name: esplora
|
||||||
|
features: test-esplora,use-esplora-ureq
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout
|
- name: Checkout
|
||||||
uses: actions/checkout@v2
|
uses: actions/checkout@v2
|
||||||
@@ -95,8 +100,6 @@ jobs:
|
|||||||
with:
|
with:
|
||||||
path: |
|
path: |
|
||||||
~/.cargo/registry
|
~/.cargo/registry
|
||||||
~/.cargo/bitcoin
|
|
||||||
~/.cargo/electrs
|
|
||||||
~/.cargo/git
|
~/.cargo/git
|
||||||
target
|
target
|
||||||
key: ${{ runner.os }}-cargo-${{ github.job }}-${{ hashFiles('**/Cargo.toml','**/Cargo.lock') }}
|
key: ${{ runner.os }}-cargo-${{ github.job }}-${{ hashFiles('**/Cargo.toml','**/Cargo.lock') }}
|
||||||
@@ -106,8 +109,8 @@ jobs:
|
|||||||
toolchain: stable
|
toolchain: stable
|
||||||
override: true
|
override: true
|
||||||
- name: Test
|
- name: Test
|
||||||
run: cargo test --features test-${{ matrix.blockchain.name }} ${{ matrix.blockchain.name }}::bdk_blockchain_tests
|
run: cargo test --no-default-features --features ${{ matrix.blockchain.features }} ${{ matrix.blockchain.name }}::bdk_blockchain_tests
|
||||||
|
|
||||||
check-wasm:
|
check-wasm:
|
||||||
name: Check WASM
|
name: Check WASM
|
||||||
runs-on: ubuntu-16.04
|
runs-on: ubuntu-16.04
|
||||||
@@ -141,7 +144,6 @@ jobs:
|
|||||||
- name: Check
|
- name: Check
|
||||||
run: cargo check --target wasm32-unknown-unknown --features use-esplora-reqwest --no-default-features
|
run: cargo check --target wasm32-unknown-unknown --features use-esplora-reqwest --no-default-features
|
||||||
|
|
||||||
|
|
||||||
fmt:
|
fmt:
|
||||||
name: Rust fmt
|
name: Rust fmt
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
|
|||||||
@@ -6,6 +6,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|||||||
|
|
||||||
## [Unreleased]
|
## [Unreleased]
|
||||||
|
|
||||||
|
## [v0.11.0] - [v0.10.0]
|
||||||
|
|
||||||
|
- Added `flush` method to the `Database` trait to explicitly flush to disk latest changes on the db.
|
||||||
|
|
||||||
## [v0.10.0] - [v0.9.0]
|
## [v0.10.0] - [v0.9.0]
|
||||||
|
|
||||||
- Added `RpcBlockchain` in the `AnyBlockchain` struct to allow using Rpc backend where `AnyBlockchain` is used (eg `bdk-cli`)
|
- Added `RpcBlockchain` in the `AnyBlockchain` struct to allow using Rpc backend where `AnyBlockchain` is used (eg `bdk-cli`)
|
||||||
@@ -360,7 +364,7 @@ final transaction is created by calling `finish` on the builder.
|
|||||||
- Use `MemoryDatabase` in the compiler example
|
- Use `MemoryDatabase` in the compiler example
|
||||||
- Make the REPL return JSON
|
- Make the REPL return JSON
|
||||||
|
|
||||||
[unreleased]: https://github.com/bitcoindevkit/bdk/compare/v0.9.0...HEAD
|
[unreleased]: https://github.com/bitcoindevkit/bdk/compare/v0.11.0...HEAD
|
||||||
[0.1.0-beta.1]: https://github.com/bitcoindevkit/bdk/compare/96c87ea5...0.1.0-beta.1
|
[0.1.0-beta.1]: https://github.com/bitcoindevkit/bdk/compare/96c87ea5...0.1.0-beta.1
|
||||||
[v0.2.0]: https://github.com/bitcoindevkit/bdk/compare/0.1.0-beta.1...v0.2.0
|
[v0.2.0]: https://github.com/bitcoindevkit/bdk/compare/0.1.0-beta.1...v0.2.0
|
||||||
[v0.3.0]: https://github.com/bitcoindevkit/bdk/compare/v0.2.0...v0.3.0
|
[v0.3.0]: https://github.com/bitcoindevkit/bdk/compare/v0.2.0...v0.3.0
|
||||||
@@ -372,3 +376,4 @@ final transaction is created by calling `finish` on the builder.
|
|||||||
[v0.8.0]: https://github.com/bitcoindevkit/bdk/compare/v0.7.0...v0.8.0
|
[v0.8.0]: https://github.com/bitcoindevkit/bdk/compare/v0.7.0...v0.8.0
|
||||||
[v0.9.0]: https://github.com/bitcoindevkit/bdk/compare/v0.8.0...v0.9.0
|
[v0.9.0]: https://github.com/bitcoindevkit/bdk/compare/v0.8.0...v0.9.0
|
||||||
[v0.10.0]: https://github.com/bitcoindevkit/bdk/compare/v0.9.0...v0.10.0
|
[v0.10.0]: https://github.com/bitcoindevkit/bdk/compare/v0.9.0...v0.10.0
|
||||||
|
[v0.11.0]: https://github.com/bitcoindevkit/bdk/compare/v0.10.0...v0.11.0
|
||||||
@@ -57,6 +57,21 @@ comment suggesting that you're working on it. If someone is already assigned,
|
|||||||
don't hesitate to ask if the assigned party or previous commenters are still
|
don't hesitate to ask if the assigned party or previous commenters are still
|
||||||
working on it if it has been awhile.
|
working on it if it has been awhile.
|
||||||
|
|
||||||
|
Deprecation policy
|
||||||
|
------------------
|
||||||
|
|
||||||
|
Where possible, breaking existing APIs should be avoided. Instead, add new APIs and
|
||||||
|
use [`#[deprecated]`](https://github.com/rust-lang/rfcs/blob/master/text/1270-deprecation.md)
|
||||||
|
to discourage use of the old one.
|
||||||
|
|
||||||
|
Deprecated APIs are typically maintained for one release cycle. In other words, an
|
||||||
|
API that has been deprecated with the 0.10 release can be expected to be removed in the
|
||||||
|
0.11 release. This allows for smoother upgrades without incurring too much technical
|
||||||
|
debt inside this library.
|
||||||
|
|
||||||
|
If you deprecated an API as part of a contribution, we encourage you to "own" that API
|
||||||
|
and send a follow-up to remove it as part of the next release cycle.
|
||||||
|
|
||||||
Peer review
|
Peer review
|
||||||
-----------
|
-----------
|
||||||
|
|
||||||
|
|||||||
28
Cargo.toml
28
Cargo.toml
@@ -1,6 +1,6 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "bdk"
|
name = "bdk"
|
||||||
version = "0.10.0"
|
version = "0.11.1-dev"
|
||||||
edition = "2018"
|
edition = "2018"
|
||||||
authors = ["Alekos Filini <alekos.filini@gmail.com>", "Riccardo Casatta <riccardo@casatta.it>"]
|
authors = ["Alekos Filini <alekos.filini@gmail.com>", "Riccardo Casatta <riccardo@casatta.it>"]
|
||||||
homepage = "https://bitcoindevkit.org"
|
homepage = "https://bitcoindevkit.org"
|
||||||
@@ -12,22 +12,22 @@ readme = "README.md"
|
|||||||
license = "MIT OR Apache-2.0"
|
license = "MIT OR Apache-2.0"
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
bdk-macros = "0.5"
|
bdk-macros = { path = "macros"} # TODO: Change this to version number after next release.
|
||||||
log = "^0.4"
|
log = "^0.4"
|
||||||
miniscript = "5.1"
|
miniscript = "^6.0"
|
||||||
bitcoin = { version = "~0.26.2", features = ["use-serde", "base64"] }
|
bitcoin = { version = "^0.27", features = ["use-serde", "base64"] }
|
||||||
serde = { version = "^1.0", features = ["derive"] }
|
serde = { version = "^1.0", features = ["derive"] }
|
||||||
serde_json = { version = "^1.0" }
|
serde_json = { version = "^1.0" }
|
||||||
rand = "^0.7"
|
rand = "^0.7"
|
||||||
|
|
||||||
# Optional dependencies
|
# Optional dependencies
|
||||||
sled = { version = "0.34", optional = true }
|
sled = { version = "0.34", optional = true }
|
||||||
electrum-client = { version = "0.7", optional = true }
|
electrum-client = { version = "0.8", optional = true }
|
||||||
reqwest = { version = "0.11", optional = true, features = ["json"] }
|
reqwest = { version = "0.11", optional = true, features = ["json"] }
|
||||||
ureq = { version = "2.1", default-features = false, features = ["json"], optional = true }
|
ureq = { version = "2.1", default-features = false, features = ["json"], optional = true }
|
||||||
futures = { version = "0.3", optional = true }
|
futures = { version = "0.3", optional = true }
|
||||||
async-trait = { version = "0.1", optional = true }
|
async-trait = { version = "0.1", optional = true }
|
||||||
rocksdb = { version = "0.14", optional = true }
|
rocksdb = { version = "0.14", default-features = false, features = ["snappy"], optional = true }
|
||||||
cc = { version = ">=1.0.64", optional = true }
|
cc = { version = ">=1.0.64", optional = true }
|
||||||
socks = { version = "0.3", optional = true }
|
socks = { version = "0.3", optional = true }
|
||||||
lazy_static = { version = "1.4", optional = true }
|
lazy_static = { version = "1.4", optional = true }
|
||||||
@@ -36,7 +36,11 @@ zeroize = { version = "<1.4.0", optional = true }
|
|||||||
bitcoinconsensus = { version = "0.19.0-3", optional = true }
|
bitcoinconsensus = { version = "0.19.0-3", optional = true }
|
||||||
|
|
||||||
# Needed by bdk_blockchain_tests macro
|
# Needed by bdk_blockchain_tests macro
|
||||||
bitcoincore-rpc = { version = "0.13", optional = true }
|
core-rpc = { version = "0.14", optional = true }
|
||||||
|
|
||||||
|
# Platform-specific dependencies
|
||||||
|
[target.'cfg(not(target_arch = "wasm32"))'.dependencies]
|
||||||
|
tokio = { version = "1", features = ["rt"] }
|
||||||
|
|
||||||
[target.'cfg(target_arch = "wasm32")'.dependencies]
|
[target.'cfg(target_arch = "wasm32")'.dependencies]
|
||||||
async-trait = "0.1"
|
async-trait = "0.1"
|
||||||
@@ -52,7 +56,7 @@ compact_filters = ["rocksdb", "socks", "lazy_static", "cc"]
|
|||||||
key-value-db = ["sled"]
|
key-value-db = ["sled"]
|
||||||
all-keys = ["keys-bip39"]
|
all-keys = ["keys-bip39"]
|
||||||
keys-bip39 = ["tiny-bip39", "zeroize"]
|
keys-bip39 = ["tiny-bip39", "zeroize"]
|
||||||
rpc = ["bitcoincore-rpc"]
|
rpc = ["core-rpc"]
|
||||||
|
|
||||||
# We currently provide mulitple implementations of `Blockchain`, all are
|
# We currently provide mulitple implementations of `Blockchain`, all are
|
||||||
# blocking except for the `EsploraBlockchain` which can be either async or
|
# blocking except for the `EsploraBlockchain` which can be either async or
|
||||||
@@ -70,24 +74,24 @@ rpc = ["bitcoincore-rpc"]
|
|||||||
async-interface = ["async-trait"]
|
async-interface = ["async-trait"]
|
||||||
electrum = ["electrum-client"]
|
electrum = ["electrum-client"]
|
||||||
# MUST ALSO USE `--no-default-features`.
|
# MUST ALSO USE `--no-default-features`.
|
||||||
use-esplora-reqwest = ["async-interface", "esplora", "reqwest", "futures"]
|
use-esplora-reqwest = ["esplora", "reqwest", "futures"]
|
||||||
use-esplora-ureq = ["esplora", "ureq"]
|
use-esplora-ureq = ["esplora", "ureq"]
|
||||||
# Typical configurations will not need to use `esplora` feature directly.
|
# Typical configurations will not need to use `esplora` feature directly.
|
||||||
esplora = []
|
esplora = []
|
||||||
|
|
||||||
|
|
||||||
# Debug/Test features
|
# Debug/Test features
|
||||||
test-blockchains = ["bitcoincore-rpc", "electrum-client"]
|
test-blockchains = ["core-rpc", "electrum-client"]
|
||||||
test-electrum = ["electrum", "electrsd/electrs_0_8_10", "test-blockchains"]
|
test-electrum = ["electrum", "electrsd/electrs_0_8_10", "test-blockchains"]
|
||||||
test-rpc = ["rpc", "electrsd/electrs_0_8_10", "test-blockchains"]
|
test-rpc = ["rpc", "electrsd/electrs_0_8_10", "test-blockchains"]
|
||||||
test-esplora = ["esplora", "ureq", "electrsd/legacy", "electrsd/esplora_a33e97e1", "test-blockchains"]
|
test-esplora = ["electrsd/legacy", "electrsd/esplora_a33e97e1", "test-blockchains"]
|
||||||
test-md-docs = ["electrum"]
|
test-md-docs = ["electrum"]
|
||||||
|
|
||||||
[dev-dependencies]
|
[dev-dependencies]
|
||||||
lazy_static = "1.4"
|
lazy_static = "1.4"
|
||||||
env_logger = "0.7"
|
env_logger = "0.7"
|
||||||
clap = "2.33"
|
clap = "2.33"
|
||||||
electrsd = { version= "0.8", features = ["trigger", "bitcoind_0_21_1"] }
|
electrsd = { version= "0.10", features = ["trigger", "bitcoind_0_21_1"] }
|
||||||
|
|
||||||
[[example]]
|
[[example]]
|
||||||
name = "address_validator"
|
name = "address_validator"
|
||||||
|
|||||||
@@ -121,3 +121,26 @@ pub fn maybe_await(expr: TokenStream) -> TokenStream {
|
|||||||
|
|
||||||
quoted.into()
|
quoted.into()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Awaits if target_arch is "wasm32", uses `tokio::Runtime::block_on()` otherwise
|
||||||
|
///
|
||||||
|
/// Requires the `tokio` crate as a dependecy with `rt-core` or `rt-threaded` to build on non-wasm32 platforms.
|
||||||
|
#[proc_macro]
|
||||||
|
pub fn await_or_block(expr: TokenStream) -> TokenStream {
|
||||||
|
let expr: proc_macro2::TokenStream = expr.into();
|
||||||
|
let quoted = quote! {
|
||||||
|
{
|
||||||
|
#[cfg(all(not(target_arch = "wasm32"), not(feature = "async-interface")))]
|
||||||
|
{
|
||||||
|
tokio::runtime::Builder::new_current_thread().enable_all().build().unwrap().block_on(#expr)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(any(target_arch = "wasm32", feature = "async-interface"))]
|
||||||
|
{
|
||||||
|
#expr.await
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
quoted.into()
|
||||||
|
}
|
||||||
|
|||||||
@@ -29,38 +29,16 @@ use bitcoin::{BlockHash, Txid};
|
|||||||
use crate::error::Error;
|
use crate::error::Error;
|
||||||
use crate::FeeRate;
|
use crate::FeeRate;
|
||||||
|
|
||||||
#[cfg(all(
|
#[cfg(feature = "reqwest")]
|
||||||
feature = "esplora",
|
|
||||||
feature = "reqwest",
|
|
||||||
any(feature = "async-interface", target_arch = "wasm32"),
|
|
||||||
))]
|
|
||||||
mod reqwest;
|
mod reqwest;
|
||||||
|
|
||||||
#[cfg(all(
|
#[cfg(feature = "reqwest")]
|
||||||
feature = "esplora",
|
|
||||||
feature = "reqwest",
|
|
||||||
any(feature = "async-interface", target_arch = "wasm32"),
|
|
||||||
))]
|
|
||||||
pub use self::reqwest::*;
|
pub use self::reqwest::*;
|
||||||
|
|
||||||
#[cfg(all(
|
#[cfg(feature = "ureq")]
|
||||||
feature = "esplora",
|
|
||||||
not(any(
|
|
||||||
feature = "async-interface",
|
|
||||||
feature = "reqwest",
|
|
||||||
target_arch = "wasm32"
|
|
||||||
)),
|
|
||||||
))]
|
|
||||||
mod ureq;
|
mod ureq;
|
||||||
|
|
||||||
#[cfg(all(
|
#[cfg(feature = "ureq")]
|
||||||
feature = "esplora",
|
|
||||||
not(any(
|
|
||||||
feature = "async-interface",
|
|
||||||
feature = "reqwest",
|
|
||||||
target_arch = "wasm32"
|
|
||||||
)),
|
|
||||||
))]
|
|
||||||
pub use self::ureq::*;
|
pub use self::ureq::*;
|
||||||
|
|
||||||
fn into_fee_rate(target: usize, estimates: HashMap<String, f64>) -> Result<FeeRate, Error> {
|
fn into_fee_rate(target: usize, estimates: HashMap<String, f64>) -> Result<FeeRate, Error> {
|
||||||
@@ -141,3 +119,11 @@ impl_error!(io::Error, Io, EsploraError);
|
|||||||
impl_error!(std::num::ParseIntError, Parsing, EsploraError);
|
impl_error!(std::num::ParseIntError, Parsing, EsploraError);
|
||||||
impl_error!(consensus::encode::Error, BitcoinEncoding, EsploraError);
|
impl_error!(consensus::encode::Error, BitcoinEncoding, EsploraError);
|
||||||
impl_error!(bitcoin::hashes::hex::Error, Hex, EsploraError);
|
impl_error!(bitcoin::hashes::hex::Error, Hex, EsploraError);
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
#[cfg(feature = "test-esplora")]
|
||||||
|
crate::bdk_blockchain_tests! {
|
||||||
|
fn test_instance(test_client: &TestClient) -> EsploraBlockchain {
|
||||||
|
EsploraBlockchain::new(&format!("http://{}",test_client.electrsd.esplora_url.as_ref().unwrap()), 20)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -106,19 +106,19 @@ impl Blockchain for EsploraBlockchain {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn get_tx(&self, txid: &Txid) -> Result<Option<Transaction>, Error> {
|
fn get_tx(&self, txid: &Txid) -> Result<Option<Transaction>, Error> {
|
||||||
Ok(self.url_client._get_tx(txid).await?)
|
Ok(await_or_block!(self.url_client._get_tx(txid))?)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn broadcast(&self, tx: &Transaction) -> Result<(), Error> {
|
fn broadcast(&self, tx: &Transaction) -> Result<(), Error> {
|
||||||
Ok(self.url_client._broadcast(tx).await?)
|
Ok(await_or_block!(self.url_client._broadcast(tx))?)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_height(&self) -> Result<u32, Error> {
|
fn get_height(&self) -> Result<u32, Error> {
|
||||||
Ok(self.url_client._get_height().await?)
|
Ok(await_or_block!(self.url_client._get_height())?)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn estimate_fee(&self, target: usize) -> Result<FeeRate, Error> {
|
fn estimate_fee(&self, target: usize) -> Result<FeeRate, Error> {
|
||||||
let estimates = self.url_client._get_fee_estimates().await?;
|
let estimates = await_or_block!(self.url_client._get_fee_estimates())?;
|
||||||
super::into_fee_rate(target, estimates)
|
super::into_fee_rate(target, estimates)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -287,10 +287,10 @@ impl ElectrumLikeSync for UrlClient {
|
|||||||
for script in chunk {
|
for script in chunk {
|
||||||
futs.push(self._script_get_history(script));
|
futs.push(self._script_get_history(script));
|
||||||
}
|
}
|
||||||
let partial_results: Vec<Vec<ElsGetHistoryRes>> = futs.try_collect().await?;
|
let partial_results: Vec<Vec<ElsGetHistoryRes>> = await_or_block!(futs.try_collect())?;
|
||||||
results.extend(partial_results);
|
results.extend(partial_results);
|
||||||
}
|
}
|
||||||
Ok(stream::iter(results).collect().await)
|
Ok(await_or_block!(stream::iter(results).collect()))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn els_batch_transaction_get<'s, I: IntoIterator<Item = &'s Txid>>(
|
fn els_batch_transaction_get<'s, I: IntoIterator<Item = &'s Txid>>(
|
||||||
@@ -303,10 +303,10 @@ impl ElectrumLikeSync for UrlClient {
|
|||||||
for txid in chunk {
|
for txid in chunk {
|
||||||
futs.push(self._get_tx_no_opt(txid));
|
futs.push(self._get_tx_no_opt(txid));
|
||||||
}
|
}
|
||||||
let partial_results: Vec<Transaction> = futs.try_collect().await?;
|
let partial_results: Vec<Transaction> = await_or_block!(futs.try_collect())?;
|
||||||
results.extend(partial_results);
|
results.extend(partial_results);
|
||||||
}
|
}
|
||||||
Ok(stream::iter(results).collect().await)
|
Ok(await_or_block!(stream::iter(results).collect()))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn els_batch_block_header<I: IntoIterator<Item = u32>>(
|
fn els_batch_block_header<I: IntoIterator<Item = u32>>(
|
||||||
@@ -319,10 +319,10 @@ impl ElectrumLikeSync for UrlClient {
|
|||||||
for height in chunk {
|
for height in chunk {
|
||||||
futs.push(self._get_header(height));
|
futs.push(self._get_header(height));
|
||||||
}
|
}
|
||||||
let partial_results: Vec<BlockHeader> = futs.try_collect().await?;
|
let partial_results: Vec<BlockHeader> = await_or_block!(futs.try_collect())?;
|
||||||
results.extend(partial_results);
|
results.extend(partial_results);
|
||||||
}
|
}
|
||||||
Ok(stream::iter(results).collect().await)
|
Ok(await_or_block!(stream::iter(results).collect()))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -350,11 +350,3 @@ impl ConfigurableBlockchain for EsploraBlockchain {
|
|||||||
Ok(blockchain)
|
Ok(blockchain)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
|
||||||
#[cfg(feature = "test-esplora")]
|
|
||||||
crate::bdk_blockchain_tests! {
|
|
||||||
fn test_instance(test_client: &TestClient) -> EsploraBlockchain {
|
|
||||||
EsploraBlockchain::new(&format!("http://{}",test_client.electrsd.esplora_url.as_ref().unwrap()), None, 20)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -38,13 +38,13 @@ use crate::database::{BatchDatabase, DatabaseUtils};
|
|||||||
use crate::descriptor::{get_checksum, IntoWalletDescriptor};
|
use crate::descriptor::{get_checksum, IntoWalletDescriptor};
|
||||||
use crate::wallet::utils::SecpCtx;
|
use crate::wallet::utils::SecpCtx;
|
||||||
use crate::{ConfirmationTime, Error, FeeRate, KeychainKind, LocalUtxo, TransactionDetails};
|
use crate::{ConfirmationTime, Error, FeeRate, KeychainKind, LocalUtxo, TransactionDetails};
|
||||||
use bitcoincore_rpc::json::{
|
use core_rpc::json::{
|
||||||
GetAddressInfoResultLabel, ImportMultiOptions, ImportMultiRequest,
|
GetAddressInfoResultLabel, ImportMultiOptions, ImportMultiRequest,
|
||||||
ImportMultiRequestScriptPubkey, ImportMultiRescanSince,
|
ImportMultiRequestScriptPubkey, ImportMultiRescanSince,
|
||||||
};
|
};
|
||||||
use bitcoincore_rpc::jsonrpc::serde_json::Value;
|
use core_rpc::jsonrpc::serde_json::Value;
|
||||||
use bitcoincore_rpc::Auth as RpcAuth;
|
use core_rpc::Auth as RpcAuth;
|
||||||
use bitcoincore_rpc::{Client, RpcApi};
|
use core_rpc::{Client, RpcApi};
|
||||||
use log::debug;
|
use log::debug;
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
use std::collections::{HashMap, HashSet};
|
use std::collections::{HashMap, HashSet};
|
||||||
@@ -82,7 +82,7 @@ pub struct RpcConfig {
|
|||||||
pub skip_blocks: Option<u32>,
|
pub skip_blocks: Option<u32>,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// This struct is equivalent to [bitcoincore_rpc::Auth] but it implements [serde::Serialize]
|
/// This struct is equivalent to [core_rpc::Auth] but it implements [serde::Serialize]
|
||||||
/// To be removed once upstream equivalent is implementing Serialize (json serialization format
|
/// To be removed once upstream equivalent is implementing Serialize (json serialization format
|
||||||
/// should be the same) https://github.com/rust-bitcoin/rust-bitcoincore-rpc/pull/181
|
/// should be the same) https://github.com/rust-bitcoin/rust-bitcoincore-rpc/pull/181
|
||||||
#[derive(Clone, Debug, Hash, Eq, PartialEq, Ord, PartialOrd, Serialize, Deserialize)]
|
#[derive(Clone, Debug, Hash, Eq, PartialEq, Ord, PartialOrd, Serialize, Deserialize)]
|
||||||
@@ -357,7 +357,7 @@ impl ConfigurableBlockchain for RpcBlockchain {
|
|||||||
let wallet_url = format!("{}/wallet/{}", config.url, &wallet_name);
|
let wallet_url = format!("{}/wallet/{}", config.url, &wallet_name);
|
||||||
debug!("connecting to {} auth:{:?}", wallet_url, config.auth);
|
debug!("connecting to {} auth:{:?}", wallet_url, config.auth);
|
||||||
|
|
||||||
let client = Client::new(wallet_url, config.auth.clone().into())?;
|
let client = Client::new(wallet_url.as_str(), config.auth.clone().into())?;
|
||||||
let loaded_wallets = client.list_wallets()?;
|
let loaded_wallets = client.list_wallets()?;
|
||||||
if loaded_wallets.contains(&wallet_name) {
|
if loaded_wallets.contains(&wallet_name) {
|
||||||
debug!("wallet already loaded {:?}", wallet_name);
|
debug!("wallet already loaded {:?}", wallet_name);
|
||||||
|
|||||||
@@ -233,6 +233,10 @@ impl Database for AnyDatabase {
|
|||||||
fn increment_last_index(&mut self, keychain: KeychainKind) -> Result<u32, Error> {
|
fn increment_last_index(&mut self, keychain: KeychainKind) -> Result<u32, Error> {
|
||||||
impl_inner_method!(AnyDatabase, self, increment_last_index, keychain)
|
impl_inner_method!(AnyDatabase, self, increment_last_index, keychain)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn flush(&mut self) -> Result<(), Error> {
|
||||||
|
impl_inner_method!(AnyDatabase, self, flush)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl BatchOperations for AnyBatch {
|
impl BatchOperations for AnyBatch {
|
||||||
|
|||||||
@@ -367,6 +367,10 @@ impl Database for Tree {
|
|||||||
Ok(val)
|
Ok(val)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn flush(&mut self) -> Result<(), Error> {
|
||||||
|
Ok(Tree::flush(self).map(|_| ())?)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl BatchDatabase for Tree {
|
impl BatchDatabase for Tree {
|
||||||
|
|||||||
@@ -419,6 +419,10 @@ impl Database for MemoryDatabase {
|
|||||||
|
|
||||||
Ok(*value)
|
Ok(*value)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn flush(&mut self) -> Result<(), Error> {
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl BatchDatabase for MemoryDatabase {
|
impl BatchDatabase for MemoryDatabase {
|
||||||
|
|||||||
@@ -134,6 +134,9 @@ pub trait Database: BatchOperations {
|
|||||||
///
|
///
|
||||||
/// It should insert and return `0` if not present in the database
|
/// It should insert and return `0` if not present in the database
|
||||||
fn increment_last_index(&mut self, keychain: KeychainKind) -> Result<u32, Error>;
|
fn increment_last_index(&mut self, keychain: KeychainKind) -> Result<u32, Error>;
|
||||||
|
|
||||||
|
/// Force changes to be written to disk
|
||||||
|
fn flush(&mut self) -> Result<(), Error>;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Trait for a database that supports batch operations
|
/// Trait for a database that supports batch operations
|
||||||
|
|||||||
@@ -139,7 +139,7 @@ pub enum Error {
|
|||||||
Sled(sled::Error),
|
Sled(sled::Error),
|
||||||
#[cfg(feature = "rpc")]
|
#[cfg(feature = "rpc")]
|
||||||
/// Rpc client error
|
/// Rpc client error
|
||||||
Rpc(bitcoincore_rpc::Error),
|
Rpc(core_rpc::Error),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl fmt::Display for Error {
|
impl fmt::Display for Error {
|
||||||
@@ -193,7 +193,7 @@ impl_error!(electrum_client::Error, Electrum);
|
|||||||
#[cfg(feature = "key-value-db")]
|
#[cfg(feature = "key-value-db")]
|
||||||
impl_error!(sled::Error, Sled);
|
impl_error!(sled::Error, Sled);
|
||||||
#[cfg(feature = "rpc")]
|
#[cfg(feature = "rpc")]
|
||||||
impl_error!(bitcoincore_rpc::Error, Rpc);
|
impl_error!(core_rpc::Error, Rpc);
|
||||||
|
|
||||||
#[cfg(feature = "compact_filters")]
|
#[cfg(feature = "compact_filters")]
|
||||||
impl From<crate::blockchain::compact_filters::CompactFiltersError> for Error {
|
impl From<crate::blockchain::compact_filters::CompactFiltersError> for Error {
|
||||||
|
|||||||
@@ -40,7 +40,7 @@
|
|||||||
//! interact with the bitcoin P2P network.
|
//! interact with the bitcoin P2P network.
|
||||||
//!
|
//!
|
||||||
//! ```toml
|
//! ```toml
|
||||||
//! bdk = "0.10.0"
|
//! bdk = "0.11.0"
|
||||||
//! ```
|
//! ```
|
||||||
#![cfg_attr(
|
#![cfg_attr(
|
||||||
feature = "electrum",
|
feature = "electrum",
|
||||||
@@ -236,7 +236,7 @@ extern crate bdk_macros;
|
|||||||
extern crate lazy_static;
|
extern crate lazy_static;
|
||||||
|
|
||||||
#[cfg(feature = "rpc")]
|
#[cfg(feature = "rpc")]
|
||||||
pub extern crate bitcoincore_rpc;
|
pub extern crate core_rpc;
|
||||||
|
|
||||||
#[cfg(feature = "electrum")]
|
#[cfg(feature = "electrum")]
|
||||||
pub extern crate electrum_client;
|
pub extern crate electrum_client;
|
||||||
|
|||||||
@@ -43,8 +43,8 @@ impl PsbtUtils for Psbt {
|
|||||||
mod test {
|
mod test {
|
||||||
use crate::bitcoin::TxIn;
|
use crate::bitcoin::TxIn;
|
||||||
use crate::psbt::Psbt;
|
use crate::psbt::Psbt;
|
||||||
use crate::wallet::test::{get_funded_wallet, get_test_wpkh};
|
|
||||||
use crate::wallet::AddressIndex;
|
use crate::wallet::AddressIndex;
|
||||||
|
use crate::wallet::{get_funded_wallet, test::get_test_wpkh};
|
||||||
use crate::SignOptions;
|
use crate::SignOptions;
|
||||||
use std::str::FromStr;
|
use std::str::FromStr;
|
||||||
|
|
||||||
|
|||||||
@@ -3,14 +3,14 @@ use bitcoin::consensus::encode::{deserialize, serialize};
|
|||||||
use bitcoin::hashes::hex::{FromHex, ToHex};
|
use bitcoin::hashes::hex::{FromHex, ToHex};
|
||||||
use bitcoin::hashes::sha256d;
|
use bitcoin::hashes::sha256d;
|
||||||
use bitcoin::{Address, Amount, Script, Transaction, Txid};
|
use bitcoin::{Address, Amount, Script, Transaction, Txid};
|
||||||
pub use bitcoincore_rpc::bitcoincore_rpc_json::AddressType;
|
|
||||||
pub use bitcoincore_rpc::{Auth, Client as RpcClient, RpcApi};
|
|
||||||
use core::str::FromStr;
|
use core::str::FromStr;
|
||||||
|
pub use core_rpc::core_rpc_json::AddressType;
|
||||||
|
pub use core_rpc::{Auth, Client as RpcClient, RpcApi};
|
||||||
use electrsd::bitcoind::BitcoinD;
|
use electrsd::bitcoind::BitcoinD;
|
||||||
use electrsd::{bitcoind, Conf, ElectrsD};
|
use electrsd::{bitcoind, Conf, ElectrsD};
|
||||||
pub use electrum_client::{Client as ElectrumClient, ElectrumApi};
|
pub use electrum_client::{Client as ElectrumClient, ElectrumApi};
|
||||||
#[allow(unused_imports)]
|
#[allow(unused_imports)]
|
||||||
use log::{debug, error, info, trace};
|
use log::{debug, error, info, log_enabled, trace, Level};
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
use std::env;
|
use std::env;
|
||||||
use std::ops::Deref;
|
use std::ops::Deref;
|
||||||
@@ -24,12 +24,17 @@ pub struct TestClient {
|
|||||||
impl TestClient {
|
impl TestClient {
|
||||||
pub fn new(bitcoind_exe: String, electrs_exe: String) -> Self {
|
pub fn new(bitcoind_exe: String, electrs_exe: String) -> Self {
|
||||||
debug!("launching {} and {}", &bitcoind_exe, &electrs_exe);
|
debug!("launching {} and {}", &bitcoind_exe, &electrs_exe);
|
||||||
let bitcoind = BitcoinD::new(bitcoind_exe).unwrap();
|
let conf = bitcoind::Conf {
|
||||||
|
view_stdout: log_enabled!(Level::Debug),
|
||||||
|
..Default::default()
|
||||||
|
};
|
||||||
|
let bitcoind = BitcoinD::with_conf(bitcoind_exe, &conf).unwrap();
|
||||||
|
|
||||||
let http_enabled = cfg!(feature = "test-esplora");
|
let http_enabled = cfg!(feature = "test-esplora");
|
||||||
|
|
||||||
let conf = Conf {
|
let conf = Conf {
|
||||||
http_enabled,
|
http_enabled,
|
||||||
|
view_stderr: log_enabled!(Level::Debug),
|
||||||
..Default::default()
|
..Default::default()
|
||||||
};
|
};
|
||||||
let electrsd = ElectrsD::with_conf(electrs_exe, &bitcoind, &conf).unwrap();
|
let electrsd = ElectrsD::with_conf(electrs_exe, &bitcoind, &conf).unwrap();
|
||||||
|
|||||||
@@ -115,8 +115,8 @@ mod test {
|
|||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
|
|
||||||
use super::*;
|
use super::*;
|
||||||
use crate::wallet::test::{get_funded_wallet, get_test_wpkh};
|
|
||||||
use crate::wallet::AddressIndex::New;
|
use crate::wallet::AddressIndex::New;
|
||||||
|
use crate::wallet::{get_funded_wallet, test::get_test_wpkh};
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
struct TestValidator;
|
struct TestValidator;
|
||||||
|
|||||||
@@ -18,6 +18,7 @@ use std::collections::HashMap;
|
|||||||
use std::collections::{BTreeMap, HashSet};
|
use std::collections::{BTreeMap, HashSet};
|
||||||
use std::fmt;
|
use std::fmt;
|
||||||
use std::ops::{Deref, DerefMut};
|
use std::ops::{Deref, DerefMut};
|
||||||
|
use std::str::FromStr;
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
|
|
||||||
use bitcoin::secp256k1::Secp256k1;
|
use bitcoin::secp256k1::Secp256k1;
|
||||||
@@ -55,6 +56,7 @@ use tx_builder::{BumpFee, CreateTx, FeePolicy, TxBuilder, TxParams};
|
|||||||
use utils::{check_nlocktime, check_nsequence_rbf, After, Older, SecpCtx, DUST_LIMIT_SATOSHI};
|
use utils::{check_nlocktime, check_nsequence_rbf, After, Older, SecpCtx, DUST_LIMIT_SATOSHI};
|
||||||
|
|
||||||
use crate::blockchain::{Blockchain, Progress};
|
use crate::blockchain::{Blockchain, Progress};
|
||||||
|
use crate::database::memory::MemoryDatabase;
|
||||||
use crate::database::{BatchDatabase, BatchOperations, DatabaseUtils};
|
use crate::database::{BatchDatabase, BatchOperations, DatabaseUtils};
|
||||||
use crate::descriptor::derived::AsDerived;
|
use crate::descriptor::derived::AsDerived;
|
||||||
use crate::descriptor::policy::BuildSatisfaction;
|
use crate::descriptor::policy::BuildSatisfaction;
|
||||||
@@ -66,6 +68,7 @@ use crate::descriptor::{
|
|||||||
use crate::error::Error;
|
use crate::error::Error;
|
||||||
use crate::psbt::PsbtUtils;
|
use crate::psbt::PsbtUtils;
|
||||||
use crate::signer::SignerError;
|
use crate::signer::SignerError;
|
||||||
|
use crate::testutils;
|
||||||
use crate::types::*;
|
use crate::types::*;
|
||||||
|
|
||||||
const CACHE_ADDR_BATCH_SIZE: u32 = 100;
|
const CACHE_ADDR_BATCH_SIZE: u32 = 100;
|
||||||
@@ -167,6 +170,11 @@ where
|
|||||||
secp,
|
secp,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Get the Bitcoin network the wallet is using.
|
||||||
|
pub fn network(&self) -> Network {
|
||||||
|
self.network
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// The address index selection strategy to use to derived an address from the wallet's external
|
/// The address index selection strategy to use to derived an address from the wallet's external
|
||||||
@@ -1534,11 +1542,6 @@ where
|
|||||||
&self.client
|
&self.client
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Get the Bitcoin network the wallet is using.
|
|
||||||
pub fn network(&self) -> Network {
|
|
||||||
self.network
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Broadcast a transaction to the network
|
/// Broadcast a transaction to the network
|
||||||
#[maybe_async]
|
#[maybe_async]
|
||||||
pub fn broadcast(&self, tx: Transaction) -> Result<Txid, Error> {
|
pub fn broadcast(&self, tx: Transaction) -> Result<Txid, Error> {
|
||||||
@@ -1548,19 +1551,60 @@ where
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Return a fake wallet that appears to be funded for testing.
|
||||||
|
pub fn get_funded_wallet(
|
||||||
|
descriptor: &str,
|
||||||
|
) -> (
|
||||||
|
Wallet<(), MemoryDatabase>,
|
||||||
|
(String, Option<String>),
|
||||||
|
bitcoin::Txid,
|
||||||
|
) {
|
||||||
|
let descriptors = testutils!(@descriptors (descriptor));
|
||||||
|
let wallet = Wallet::new_offline(
|
||||||
|
&descriptors.0,
|
||||||
|
None,
|
||||||
|
Network::Regtest,
|
||||||
|
MemoryDatabase::new(),
|
||||||
|
)
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
let funding_address_kix = 0;
|
||||||
|
|
||||||
|
let tx_meta = testutils! {
|
||||||
|
@tx ( (@external descriptors, funding_address_kix) => 50_000 ) (@confirmations 1)
|
||||||
|
};
|
||||||
|
|
||||||
|
wallet
|
||||||
|
.database
|
||||||
|
.borrow_mut()
|
||||||
|
.set_script_pubkey(
|
||||||
|
&bitcoin::Address::from_str(&tx_meta.output.get(0).unwrap().to_address)
|
||||||
|
.unwrap()
|
||||||
|
.script_pubkey(),
|
||||||
|
KeychainKind::External,
|
||||||
|
funding_address_kix,
|
||||||
|
)
|
||||||
|
.unwrap();
|
||||||
|
wallet
|
||||||
|
.database
|
||||||
|
.borrow_mut()
|
||||||
|
.set_last_index(KeychainKind::External, funding_address_kix)
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
let txid = crate::populate_test_db!(wallet.database.borrow_mut(), tx_meta, Some(100));
|
||||||
|
|
||||||
|
(wallet, descriptors, txid)
|
||||||
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
pub(crate) mod test {
|
pub(crate) mod test {
|
||||||
use std::str::FromStr;
|
|
||||||
|
|
||||||
use bitcoin::{util::psbt, Network};
|
use bitcoin::{util::psbt, Network};
|
||||||
|
|
||||||
use crate::database::memory::MemoryDatabase;
|
|
||||||
use crate::database::Database;
|
use crate::database::Database;
|
||||||
use crate::types::KeychainKind;
|
use crate::types::KeychainKind;
|
||||||
|
|
||||||
use super::*;
|
use super::*;
|
||||||
use crate::signer::{SignOptions, SignerError};
|
use crate::signer::{SignOptions, SignerError};
|
||||||
use crate::testutils;
|
|
||||||
use crate::wallet::AddressIndex::{LastUnused, New, Peek, Reset};
|
use crate::wallet::AddressIndex::{LastUnused, New, Peek, Reset};
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
@@ -1672,50 +1716,6 @@ pub(crate) mod test {
|
|||||||
"wsh(and_v(v:pk(cVpPVruEDdmutPzisEsYvtST1usBR3ntr8pXSyt6D2YYqXRyPcFW),after(100000)))"
|
"wsh(and_v(v:pk(cVpPVruEDdmutPzisEsYvtST1usBR3ntr8pXSyt6D2YYqXRyPcFW),after(100000)))"
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn get_funded_wallet(
|
|
||||||
descriptor: &str,
|
|
||||||
) -> (
|
|
||||||
Wallet<(), MemoryDatabase>,
|
|
||||||
(String, Option<String>),
|
|
||||||
bitcoin::Txid,
|
|
||||||
) {
|
|
||||||
let descriptors = testutils!(@descriptors (descriptor));
|
|
||||||
let wallet = Wallet::new_offline(
|
|
||||||
&descriptors.0,
|
|
||||||
None,
|
|
||||||
Network::Regtest,
|
|
||||||
MemoryDatabase::new(),
|
|
||||||
)
|
|
||||||
.unwrap();
|
|
||||||
|
|
||||||
let funding_address_kix = 0;
|
|
||||||
|
|
||||||
let tx_meta = testutils! {
|
|
||||||
@tx ( (@external descriptors, funding_address_kix) => 50_000 ) (@confirmations 1)
|
|
||||||
};
|
|
||||||
|
|
||||||
wallet
|
|
||||||
.database
|
|
||||||
.borrow_mut()
|
|
||||||
.set_script_pubkey(
|
|
||||||
&bitcoin::Address::from_str(&tx_meta.output.get(0).unwrap().to_address)
|
|
||||||
.unwrap()
|
|
||||||
.script_pubkey(),
|
|
||||||
KeychainKind::External,
|
|
||||||
funding_address_kix,
|
|
||||||
)
|
|
||||||
.unwrap();
|
|
||||||
wallet
|
|
||||||
.database
|
|
||||||
.borrow_mut()
|
|
||||||
.set_last_index(KeychainKind::External, funding_address_kix)
|
|
||||||
.unwrap();
|
|
||||||
|
|
||||||
let txid = crate::populate_test_db!(wallet.database.borrow_mut(), tx_meta, Some(100));
|
|
||||||
|
|
||||||
(wallet, descriptors, txid)
|
|
||||||
}
|
|
||||||
|
|
||||||
macro_rules! assert_fee_rate {
|
macro_rules! assert_fee_rate {
|
||||||
($tx:expr, $fees:expr, $fee_rate:expr $( ,@dust_change $( $dust_change:expr )* )* $( ,@add_signature $( $add_signature:expr )* )* ) => ({
|
($tx:expr, $fees:expr, $fee_rate:expr $( ,@dust_change $( $dust_change:expr )* )* $( ,@add_signature $( $add_signature:expr )* )* ) => ({
|
||||||
let mut tx = $tx.clone();
|
let mut tx = $tx.clone();
|
||||||
|
|||||||
Reference in New Issue
Block a user