Compare commits
31 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
f3e479fa7f | ||
|
|
5698c683c6 | ||
|
|
a83aa0461c | ||
|
|
fcf422752b | ||
|
|
6fb42fdea1 | ||
|
|
3f65e8c64b | ||
|
|
3f0101d317 | ||
|
|
b1346d4ccf | ||
|
|
5107ff80c1 | ||
|
|
5ac51dfe74 | ||
|
|
04d58f7903 | ||
|
|
380a4f2588 | ||
|
|
9e30a79027 | ||
|
|
fdb272e039 | ||
|
|
d2b6b5545e | ||
|
|
db6ffb90f0 | ||
|
|
947a9c29db | ||
|
|
61ee2a9c1c | ||
|
|
44e4c5dac5 | ||
|
|
e09aaf055a | ||
|
|
c40898ba08 | ||
|
|
2f98db8549 | ||
|
|
a0c140bb29 | ||
|
|
bf5994b14a | ||
|
|
ca682819b3 | ||
|
|
ee41d88f25 | ||
|
|
beb1e4114d | ||
|
|
af047f90db | ||
|
|
d01ec6d259 | ||
|
|
77bce06caf | ||
|
|
1a907f8a53 |
10
.github/workflows/nightly_docs.yml
vendored
10
.github/workflows/nightly_docs.yml
vendored
@@ -18,7 +18,7 @@ jobs:
|
||||
target
|
||||
key: nightly-docs-${{ hashFiles('**/Cargo.toml','**/Cargo.lock') }}
|
||||
- name: Set default toolchain
|
||||
run: rustup default nightly
|
||||
run: rustup default nightly-2022-01-25
|
||||
- name: Set profile
|
||||
run: rustup set profile minimal
|
||||
- name: Update toolchain
|
||||
@@ -44,18 +44,18 @@ jobs:
|
||||
repository: bitcoindevkit/bitcoindevkit.org
|
||||
ref: master
|
||||
- name: Create directories
|
||||
run: mkdir -p ./static/docs-rs/bdk/nightly
|
||||
run: mkdir -p ./docs/.vuepress/public/docs-rs/bdk/nightly
|
||||
- name: Remove old latest
|
||||
run: rm -rf ./static/docs-rs/bdk/nightly/latest
|
||||
run: rm -rf ./docs/.vuepress/public/docs-rs/bdk/nightly/latest
|
||||
- name: Download built docs
|
||||
uses: actions/download-artifact@v1
|
||||
with:
|
||||
name: built-docs
|
||||
path: ./static/docs-rs/bdk/nightly/latest
|
||||
path: ./docs/.vuepress/public/docs-rs/bdk/nightly/latest
|
||||
- name: Configure git
|
||||
run: git config user.email "github-actions@github.com" && git config user.name "github-actions"
|
||||
- name: Commit
|
||||
continue-on-error: true # If there's nothing to commit this step fails, but it's fine
|
||||
run: git add ./static && git commit -m "Publish autogenerated nightly docs"
|
||||
run: git add ./docs/.vuepress/public/docs-rs && git commit -m "Publish autogenerated nightly docs"
|
||||
- name: Push
|
||||
run: git push origin master
|
||||
|
||||
14
CHANGELOG.md
14
CHANGELOG.md
@@ -6,6 +6,17 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
||||
|
||||
## [Unreleased]
|
||||
|
||||
## [v0.16.1] - [v0.16.0]
|
||||
|
||||
- Pin tokio dependency version to ~1.14 to prevent errors due to their new MSRV 1.49.0
|
||||
|
||||
## [v0.16.0] - [v0.15.0]
|
||||
|
||||
- Disable `reqwest` default features.
|
||||
- Added `reqwest-default-tls` feature: Use this to restore the TLS defaults of reqwest if you don't want to add a dependency to it in your own manifest.
|
||||
- Use dust_value from rust-bitcoin
|
||||
- Fixed generating WIF in the correct network format.
|
||||
|
||||
## [v0.15.0] - [v0.14.0]
|
||||
|
||||
- Overhauled sync logic for electrum and esplora.
|
||||
@@ -403,3 +414,6 @@ final transaction is created by calling `finish` on the builder.
|
||||
[v0.12.0]: https://github.com/bitcoindevkit/bdk/compare/v0.11.0...v0.12.0
|
||||
[v0.13.0]: https://github.com/bitcoindevkit/bdk/compare/v0.12.0...v0.13.0
|
||||
[v0.14.0]: https://github.com/bitcoindevkit/bdk/compare/v0.13.0...v0.14.0
|
||||
[v0.15.0]: https://github.com/bitcoindevkit/bdk/compare/v0.14.0...v0.15.0
|
||||
[v0.16.0]: https://github.com/bitcoindevkit/bdk/compare/v0.15.0...v0.16.0
|
||||
[v0.16.1]: https://github.com/bitcoindevkit/bdk/compare/v0.16.0...v0.16.1
|
||||
@@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "bdk"
|
||||
version = "0.15.0"
|
||||
version = "0.16.1"
|
||||
edition = "2018"
|
||||
authors = ["Alekos Filini <alekos.filini@gmail.com>", "Riccardo Casatta <riccardo@casatta.it>"]
|
||||
homepage = "https://bitcoindevkit.org"
|
||||
@@ -25,7 +25,7 @@ sled = { version = "0.34", optional = true }
|
||||
electrum-client = { version = "0.8", optional = true }
|
||||
rusqlite = { version = "0.25.3", optional = true }
|
||||
ahash = { version = "=0.7.4", optional = true }
|
||||
reqwest = { version = "0.11", optional = true, features = ["json"] }
|
||||
reqwest = { version = "0.11", optional = true, default-features = false, features = ["json"] }
|
||||
ureq = { version = "~2.2.0", features = ["json"], optional = true }
|
||||
futures = { version = "0.3", optional = true }
|
||||
async-trait = { version = "0.1", optional = true }
|
||||
@@ -42,7 +42,7 @@ bitcoincore-rpc = { version = "0.14", optional = true }
|
||||
|
||||
# Platform-specific dependencies
|
||||
[target.'cfg(not(target_arch = "wasm32"))'.dependencies]
|
||||
tokio = { version = "1", features = ["rt"] }
|
||||
tokio = { version = "~1.14", features = ["rt"] }
|
||||
|
||||
[target.'cfg(target_arch = "wasm32")'.dependencies]
|
||||
async-trait = "0.1"
|
||||
@@ -82,6 +82,8 @@ use-esplora-ureq = ["esplora", "ureq", "ureq/socks"]
|
||||
# Typical configurations will not need to use `esplora` feature directly.
|
||||
esplora = []
|
||||
|
||||
# Use below feature with `use-esplora-reqwest` to enable reqwest default TLS support
|
||||
reqwest-default-tls = ["reqwest/default-tls"]
|
||||
|
||||
# Debug/Test features
|
||||
test-blockchains = ["bitcoincore-rpc", "electrum-client"]
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
<div align="center">
|
||||
<h1>BDK</h1>
|
||||
|
||||
<img src="./static/bdk.svg" width="220" />
|
||||
<img src="./static/bdk.png" width="220" />
|
||||
|
||||
<p>
|
||||
<strong>A modern, lightweight, descriptor-based wallet library written in Rust!</strong>
|
||||
|
||||
@@ -319,6 +319,7 @@ impl<Ctx: ScriptContext> ExtendedKey<Ctx> {
|
||||
match self {
|
||||
ExtendedKey::Private((mut xprv, _)) => {
|
||||
xprv.network = network;
|
||||
xprv.private_key.network = network;
|
||||
Some(xprv)
|
||||
}
|
||||
ExtendedKey::Public(_) => None,
|
||||
@@ -931,4 +932,43 @@ pub mod test {
|
||||
"L2wTu6hQrnDMiFNWA5na6jB12ErGQqtXwqpSL7aWquJaZG8Ai3ch"
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_keys_wif_network() {
|
||||
// test mainnet wif
|
||||
let generated_xprv: GeneratedKey<_, miniscript::Segwitv0> =
|
||||
bip32::ExtendedPrivKey::generate_with_entropy_default(TEST_ENTROPY).unwrap();
|
||||
let xkey = generated_xprv.into_extended_key().unwrap();
|
||||
|
||||
let network = Network::Bitcoin;
|
||||
let xprv = xkey.into_xprv(network).unwrap();
|
||||
let wif = PrivateKey::from_wif(&xprv.private_key.to_wif()).unwrap();
|
||||
assert_eq!(wif.network, network);
|
||||
|
||||
// test testnet wif
|
||||
let generated_xprv: GeneratedKey<_, miniscript::Segwitv0> =
|
||||
bip32::ExtendedPrivKey::generate_with_entropy_default(TEST_ENTROPY).unwrap();
|
||||
let xkey = generated_xprv.into_extended_key().unwrap();
|
||||
|
||||
let network = Network::Testnet;
|
||||
let xprv = xkey.into_xprv(network).unwrap();
|
||||
let wif = PrivateKey::from_wif(&xprv.private_key.to_wif()).unwrap();
|
||||
assert_eq!(wif.network, network);
|
||||
}
|
||||
|
||||
#[cfg(feature = "keys-bip39")]
|
||||
#[test]
|
||||
fn test_keys_wif_network_bip39() {
|
||||
let xkey: ExtendedKey = bip39::Mnemonic::parse_in(
|
||||
bip39::Language::English,
|
||||
"jelly crash boy whisper mouse ecology tuna soccer memory million news short",
|
||||
)
|
||||
.unwrap()
|
||||
.into_extended_key()
|
||||
.unwrap();
|
||||
let xprv = xkey.into_xprv(Network::Testnet).unwrap();
|
||||
let wif = PrivateKey::from_wif(&xprv.private_key.to_wif()).unwrap();
|
||||
|
||||
assert_eq!(wif.network, Network::Testnet);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -14,6 +14,10 @@
|
||||
// only enables the `doc_cfg` feature when
|
||||
// the `docsrs` configuration attribute is defined
|
||||
#![cfg_attr(docsrs, feature(doc_cfg))]
|
||||
#![cfg_attr(
|
||||
docsrs,
|
||||
doc(html_logo_url = "https://github.com/bitcoindevkit/bdk/raw/master/static/bdk.png")
|
||||
)]
|
||||
|
||||
//! A modern, lightweight, descriptor-based wallet library written in Rust.
|
||||
//!
|
||||
@@ -40,7 +44,7 @@
|
||||
//! interact with the bitcoin P2P network.
|
||||
//!
|
||||
//! ```toml
|
||||
//! bdk = "0.15.0"
|
||||
//! bdk = "0.16.1"
|
||||
//! ```
|
||||
#![cfg_attr(
|
||||
feature = "electrum",
|
||||
|
||||
@@ -843,7 +843,7 @@ macro_rules! bdk_blockchain_tests {
|
||||
assert_eq!(wallet.get_balance().unwrap(), details.received, "incorrect received after send");
|
||||
|
||||
let mut builder = wallet.build_fee_bump(details.txid).unwrap();
|
||||
builder.fee_rate(FeeRate::from_sat_per_vb(5.0));
|
||||
builder.fee_rate(FeeRate::from_sat_per_vb(5.1));
|
||||
let (mut new_psbt, new_details) = builder.finish().unwrap();
|
||||
let finalized = wallet.sign(&mut new_psbt, Default::default()).unwrap();
|
||||
assert!(finalized, "Cannot finalize transaction");
|
||||
|
||||
@@ -53,7 +53,7 @@ use address_validator::AddressValidator;
|
||||
use coin_selection::DefaultCoinSelectionAlgorithm;
|
||||
use signer::{SignOptions, Signer, SignerOrdering, SignersContainer};
|
||||
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};
|
||||
|
||||
use crate::blockchain::{Blockchain, Progress};
|
||||
use crate::database::memory::MemoryDatabase;
|
||||
@@ -601,7 +601,7 @@ where
|
||||
let recipients = params.recipients.iter().map(|(r, v)| (r, *v));
|
||||
|
||||
for (index, (script_pubkey, value)) in recipients.enumerate() {
|
||||
if value.is_dust() && !script_pubkey.is_provably_unspendable() {
|
||||
if value.is_dust(script_pubkey) && !script_pubkey.is_provably_unspendable() {
|
||||
return Err(Error::OutputBelowDustLimit(index));
|
||||
}
|
||||
|
||||
@@ -677,9 +677,9 @@ where
|
||||
|
||||
if tx.output.is_empty() {
|
||||
if params.drain_to.is_some() {
|
||||
if drain_val.is_dust() {
|
||||
if drain_val.is_dust(&drain_output.script_pubkey) {
|
||||
return Err(Error::InsufficientFunds {
|
||||
needed: DUST_LIMIT_SATOSHI,
|
||||
needed: drain_output.script_pubkey.dust_value().as_sat(),
|
||||
available: drain_val,
|
||||
});
|
||||
}
|
||||
@@ -688,7 +688,7 @@ where
|
||||
}
|
||||
}
|
||||
|
||||
if drain_val.is_dust() {
|
||||
if drain_val.is_dust(&drain_output.script_pubkey) {
|
||||
fee_amount += drain_val;
|
||||
} else {
|
||||
drain_output.value = drain_val;
|
||||
@@ -3424,7 +3424,7 @@ pub(crate) mod test {
|
||||
.unwrap();
|
||||
|
||||
let mut builder = wallet.build_fee_bump(txid).unwrap();
|
||||
builder.fee_rate(FeeRate::from_sat_per_vb(140.0));
|
||||
builder.fee_rate(FeeRate::from_sat_per_vb(141.0));
|
||||
let (psbt, details) = builder.finish().unwrap();
|
||||
|
||||
assert_eq!(
|
||||
|
||||
@@ -9,13 +9,11 @@
|
||||
// You may not use this file except in accordance with one or both of these
|
||||
// licenses.
|
||||
|
||||
use bitcoin::blockdata::script::Script;
|
||||
use bitcoin::secp256k1::{All, Secp256k1};
|
||||
|
||||
use miniscript::{MiniscriptKey, Satisfier, ToPublicKey};
|
||||
|
||||
// De-facto standard "dust limit" (even though it should change based on the output type)
|
||||
pub const DUST_LIMIT_SATOSHI: u64 = 546;
|
||||
|
||||
// MSB of the nSequence. If set there's no consensus-constraint, so it must be disabled when
|
||||
// spending using CSV in order to enforce CSV rules
|
||||
pub(crate) const SEQUENCE_LOCKTIME_DISABLE_FLAG: u32 = 1 << 31;
|
||||
@@ -28,18 +26,19 @@ pub(crate) const SEQUENCE_LOCKTIME_MASK: u32 = 0x0000FFFF;
|
||||
// Threshold for nLockTime to be considered a block-height-based timelock rather than time-based
|
||||
pub(crate) const BLOCKS_TIMELOCK_THRESHOLD: u32 = 500000000;
|
||||
|
||||
/// Trait to check if a value is below the dust limit
|
||||
/// Trait to check if a value is below the dust limit.
|
||||
/// We are performing dust value calculation for a given script public key using rust-bitcoin to
|
||||
/// keep it compatible with network dust rate
|
||||
// we implement this trait to make sure we don't mess up the comparison with off-by-one like a <
|
||||
// instead of a <= etc. The constant value for the dust limit is not public on purpose, to
|
||||
// encourage the usage of this trait.
|
||||
// instead of a <= etc.
|
||||
pub trait IsDust {
|
||||
/// Check whether or not a value is below dust limit
|
||||
fn is_dust(&self) -> bool;
|
||||
fn is_dust(&self, script: &Script) -> bool;
|
||||
}
|
||||
|
||||
impl IsDust for u64 {
|
||||
fn is_dust(&self) -> bool {
|
||||
*self <= DUST_LIMIT_SATOSHI
|
||||
fn is_dust(&self, script: &Script) -> bool {
|
||||
*self < script.dust_value().as_sat()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -141,10 +140,29 @@ pub(crate) type SecpCtx = Secp256k1<All>;
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
use super::{
|
||||
check_nlocktime, check_nsequence_rbf, BLOCKS_TIMELOCK_THRESHOLD,
|
||||
check_nlocktime, check_nsequence_rbf, IsDust, BLOCKS_TIMELOCK_THRESHOLD,
|
||||
SEQUENCE_LOCKTIME_TYPE_FLAG,
|
||||
};
|
||||
use crate::bitcoin::Address;
|
||||
use crate::types::FeeRate;
|
||||
use std::str::FromStr;
|
||||
|
||||
#[test]
|
||||
fn test_is_dust() {
|
||||
let script_p2pkh = Address::from_str("1GNgwA8JfG7Kc8akJ8opdNWJUihqUztfPe")
|
||||
.unwrap()
|
||||
.script_pubkey();
|
||||
assert!(script_p2pkh.is_p2pkh());
|
||||
assert!(545.is_dust(&script_p2pkh));
|
||||
assert!(!546.is_dust(&script_p2pkh));
|
||||
|
||||
let script_p2wpkh = Address::from_str("bc1qxlh2mnc0yqwas76gqq665qkggee5m98t8yskd8")
|
||||
.unwrap()
|
||||
.script_pubkey();
|
||||
assert!(script_p2wpkh.is_v0_p2wpkh());
|
||||
assert!(293.is_dust(&script_p2wpkh));
|
||||
assert!(!294.is_dust(&script_p2wpkh));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_fee_from_btc_per_kb() {
|
||||
|
||||
BIN
static/bdk.png
Normal file
BIN
static/bdk.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 5.5 KiB |
Reference in New Issue
Block a user