Merge bitcoindevkit/bdk#1448: bump(deps): upgrade rust bitcoin to 0.32.0, miniscript to 0.12.0 and others

11200810d048abb8deb3c7961ca93c68011d41fd chore(wallet): rm dup code (志宇)
2a4564097bd70905ed9fa21b92cdf074a72f878e deps(bdk): bump `bitcoin` to `0.32.0`, miniscript to `12.0.0` (Leonardo Lima)

Pull request description:

  fixes #1422
  <!-- You can erase any parts of this template not applicable to your Pull Request. -->

  ### Description

  This PR focuses on upgrading the `rust-bitcoin` and `miniscript` versions, to `0.32.0` and `0.12.0`, respectively. It also bumps the versions of other BDK ecosystem crates that also rely on both `rust-bitcoin` and `miniscript`, being:

  - electrum-client https://github.com/bitcoindevkit/rust-electrum-client/pull/133
  - esplora-client https://github.com/bitcoindevkit/rust-esplora-client/pull/85
  - hwi https://github.com/bitcoindevkit/rust-hwi/pull/99

  <ins>I structured the PR in multiple commits, with closed scope, being one for each BDK crate being upgraded, and one for each kind of fix and upgrade required, it seems like a lot of commits (**that should be squashed before merging**), but I think it'll make it easier during review phase.</ins>

  In summary I can already mention some of the main changes:
  - using `compute_txid()` instead of deprecated `txid()`
  - using `minimal_non_dust()` instead of `dust_value()`
  - using the renamed `signature` and `sighash_type` fields
  - using proper `sighash::P2wpkhError`,  `sighash::TaprootError` instead of older `sighash::Error`
  - conversion from `Network` to new expected `NetworkKind` #1465
  - conversion from the new `Weight` type to current expected `usize` #1466
  - using `.into()` to convert from AbsLockTime and `RelLockTime` to `absolute::LockTime` and `relative::LockTime`
  - using Message::from_digest() instead of relying on deprecated `ThirtyTwoByteHash` trait.
  - updating the miniscript policy and dsl to proper expect and handle new `Threshold` type, instead of the previous two parameters.

  <!-- Describe the purpose of this PR, what's being adding and/or fixed -->

  ### Notes to the reviewers
  <ins>Again, I structured the PR in multiple commits, with closed scope, being one for each BDK crate being upgraded, and one for each kind of fix and upgrade required, it seems like a lot of commits (**that should be squashed before merging**), but I think it'll make it easier during review phase.</ins>

  It should definitely be carefully reviewed, especially the last commits for the wallet crate scope, the ones with the semantic `fix(wallet)`.

  I would also appreciate if @tcharding reviewed it, as he gave a try in the past (#1400 ), and I relied on some of it for the  policy part of it, other rust-bitcoin maintainers reviews are a definitely welcome 😁

  <!-- In this section you can include notes directed to the reviewers, like explaining why some parts
  of the PR were done in a specific way -->

  ### Changelog notice
  > // TODO(@oleonardolima): Do another pass and double check the changes
  - Use `compute_txid()` instead of deprecated `txid()`
  - Use `minimal_non_dust()` instead of `dust_value()`
  - Use `signature` and `sighash_type` fields, instead of previous `sig` and `hash_type`
  - Use `sighash::P2wpkhError`,  and `sighash::TaprootError` instead of older `sighash::Error`
  - Converts from `Network` to `NetworkKind`, where expected
  - Converts from `Weight` type to current used `usize`
  - Use `.into()` to convert from `AbsLockTime` and `RelLockTime` to `absolute::LockTime` and `relative::LockTime`
  - Remove use of  deprecated `ThirtyTwoByteHash` trait, use `Message::from_digest()`
  - Update the miniscript policy and dsl macros to proper expect and handle new `Threshold` type, instead of the previous two parameters.

  <!-- Notice the release manager should include in the release tag message changelog -->
  <!-- See https://keepachangelog.com/en/1.0.0/ for examples -->

  ### Checklists

  #### All Submissions:

  * [x] I've signed all my commits
  * [x] I followed the [contribution guidelines](https://github.com/bitcoindevkit/bdk/blob/master/CONTRIBUTING.md)
  * [x] I ran `cargo fmt` and `cargo clippy` before committing

  #### New Features:

  * [ ] I've added tests for the new feature
  * [ ] I've added docs for the new feature

  #### Bugfixes:

  * [ ] This pull request breaks the existing API
  * [ ] I've added tests to reproduce the issue which are now passing
  * [ ] I'm linking the issue being fixed by this PR

ACKs for top commit:
  notmandatory:
    ACK 11200810d048abb8deb3c7961ca93c68011d41fd

Tree-SHA512: ba1ab64603b41014d3f0866d846167f77d31959ca6f1d9c3181d5e543964f5d772e05651d63935ba7bbffeba41a66868d27de4c32129739b9ca50f3bbaf9f2a1
This commit is contained in:
Steve Myers 2024-06-12 23:05:27 -05:00
commit 3b040a7ee6
No known key found for this signature in database
GPG Key ID: 8105A46B22C2D051
41 changed files with 430 additions and 305 deletions

View File

@ -58,15 +58,15 @@ jobs:
- name: Check bdk_chain
working-directory: ./crates/chain
# TODO "--target thumbv6m-none-eabi" should work but currently does not
run: cargo check --no-default-features --features bitcoin/no-std,miniscript/no-std,hashbrown
run: cargo check --no-default-features --features miniscript/no-std,hashbrown
- name: Check bdk wallet
working-directory: ./crates/wallet
# TODO "--target thumbv6m-none-eabi" should work but currently does not
run: cargo check --no-default-features --features bitcoin/no-std,miniscript/no-std,bdk_chain/hashbrown
run: cargo check --no-default-features --features miniscript/no-std,bdk_chain/hashbrown
- name: Check esplora
working-directory: ./crates/esplora
# TODO "--target thumbv6m-none-eabi" should work but currently does not
run: cargo check --no-default-features --features bitcoin/no-std,miniscript/no-std,bdk_chain/hashbrown
run: cargo check --no-default-features --features miniscript/no-std,bdk_chain/hashbrown
check-wasm:
name: Check WASM
@ -92,10 +92,10 @@ jobs:
uses: Swatinem/rust-cache@v2.2.1
- name: Check bdk wallet
working-directory: ./crates/wallet
run: cargo check --target wasm32-unknown-unknown --no-default-features --features bitcoin/no-std,miniscript/no-std,bdk_chain/hashbrown,dev-getrandom-wasm
run: cargo check --target wasm32-unknown-unknown --no-default-features --features miniscript/no-std,bdk_chain/hashbrown,dev-getrandom-wasm
- name: Check esplora
working-directory: ./crates/esplora
run: cargo check --target wasm32-unknown-unknown --no-default-features --features bitcoin/no-std,miniscript/no-std,bdk_chain/hashbrown,async
run: cargo check --target wasm32-unknown-unknown --no-default-features --features miniscript/no-std,bdk_chain/hashbrown,async
fmt:
name: Rust fmt

View File

@ -13,9 +13,8 @@ readme = "README.md"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]
# For no-std, remember to enable the bitcoin/no-std feature
bitcoin = { version = "0.31", default-features = false }
bitcoincore-rpc = { version = "0.18" }
bitcoin = { version = "0.32.0", default-features = false }
bitcoincore-rpc = { version = "0.19.0" }
bdk_chain = { path = "../chain", version = "0.15", default-features = false }
[dev-dependencies]

View File

@ -197,7 +197,7 @@ fn test_into_tx_graph() -> anyhow::Result<()> {
.graph
.txs
.iter()
.map(|tx| tx.txid())
.map(|tx| tx.compute_txid())
.collect::<BTreeSet<Txid>>(),
exp_txids,
"changeset should have the 3 mempool transactions",
@ -440,7 +440,7 @@ fn mempool_avoids_re_emission() -> anyhow::Result<()> {
let emitted_txids = emitter
.mempool()?
.into_iter()
.map(|(tx, _)| tx.txid())
.map(|(tx, _)| tx.compute_txid())
.collect::<BTreeSet<Txid>>();
assert_eq!(
emitted_txids, exp_txids,
@ -509,7 +509,7 @@ fn mempool_re_emits_if_tx_introduction_height_not_reached() -> anyhow::Result<()
emitter
.mempool()?
.into_iter()
.map(|(tx, _)| tx.txid())
.map(|(tx, _)| tx.compute_txid())
.collect::<BTreeSet<_>>(),
tx_introductions.iter().map(|&(_, txid)| txid).collect(),
"first mempool emission should include all txs",
@ -518,7 +518,7 @@ fn mempool_re_emits_if_tx_introduction_height_not_reached() -> anyhow::Result<()
emitter
.mempool()?
.into_iter()
.map(|(tx, _)| tx.txid())
.map(|(tx, _)| tx.compute_txid())
.collect::<BTreeSet<_>>(),
tx_introductions.iter().map(|&(_, txid)| txid).collect(),
"second mempool emission should still include all txs",
@ -538,7 +538,7 @@ fn mempool_re_emits_if_tx_introduction_height_not_reached() -> anyhow::Result<()
let emitted_txids = emitter
.mempool()?
.into_iter()
.map(|(tx, _)| tx.txid())
.map(|(tx, _)| tx.compute_txid())
.collect::<BTreeSet<_>>();
assert_eq!(
emitted_txids, exp_txids,
@ -596,7 +596,7 @@ fn mempool_during_reorg() -> anyhow::Result<()> {
emitter
.mempool()?
.into_iter()
.map(|(tx, _)| tx.txid())
.map(|(tx, _)| tx.compute_txid())
.collect::<BTreeSet<_>>(),
env.rpc_client()
.get_raw_mempool()?
@ -633,7 +633,7 @@ fn mempool_during_reorg() -> anyhow::Result<()> {
let mempool = emitter
.mempool()?
.into_iter()
.map(|(tx, _)| tx.txid())
.map(|(tx, _)| tx.compute_txid())
.collect::<BTreeSet<_>>();
let exp_mempool = tx_introductions
.iter()
@ -648,7 +648,7 @@ fn mempool_during_reorg() -> anyhow::Result<()> {
let mempool = emitter
.mempool()?
.into_iter()
.map(|(tx, _)| tx.txid())
.map(|(tx, _)| tx.compute_txid())
.collect::<BTreeSet<_>>();
let exp_mempool = tx_introductions
.iter()

View File

@ -13,13 +13,12 @@ readme = "README.md"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]
# For no-std, remember to enable the bitcoin/no-std feature
bitcoin = { version = "0.31.0", default-features = false }
bitcoin = { version = "0.32.0", default-features = false }
serde_crate = { package = "serde", version = "1", optional = true, features = ["derive", "rc"] }
# Use hashbrown as a feature flag to have HashSet and HashMap from it.
hashbrown = { version = "0.9.1", optional = true, features = ["serde"] }
miniscript = { version = "11.0.0", optional = true, default-features = false }
miniscript = { version = "12.0.0", optional = true, default-features = false }
[dev-dependencies]
rand = "0.8"

View File

@ -31,7 +31,7 @@ impl DescriptorExt for Descriptor<DescriptorPublicKey> {
self.at_derivation_index(0)
.expect("descriptor can't have hardened derivation")
.script_pubkey()
.dust_value()
.minimal_non_dust()
.to_sat()
}

View File

@ -143,7 +143,7 @@ where
let mut graph = tx_graph::ChangeSet::default();
for (tx, anchors) in txs {
if self.index.is_tx_relevant(tx) {
let txid = tx.txid();
let txid = tx.compute_txid();
graph.append(self.graph.insert_tx(tx.clone()));
for anchor in anchors {
graph.append(self.graph.insert_anchor(txid, anchor));
@ -234,7 +234,7 @@ where
for (tx_pos, tx) in block.txdata.iter().enumerate() {
changeset.indexer.append(self.index.index_tx(tx));
if self.index.is_tx_relevant(tx) {
let txid = tx.txid();
let txid = tx.compute_txid();
let anchor = A::from_block_position(block, block_id, tx_pos);
changeset.graph.append(self.graph.insert_tx(tx.clone()));
changeset
@ -261,7 +261,7 @@ where
let mut graph = tx_graph::ChangeSet::default();
for (tx_pos, tx) in block.txdata.iter().enumerate() {
let anchor = A::from_block_position(&block, block_id, tx_pos);
graph.append(self.graph.insert_anchor(tx.txid(), anchor));
graph.append(self.graph.insert_anchor(tx.compute_txid(), anchor));
graph.append(self.graph.insert_tx(tx.clone()));
}
let indexer = self.index_tx_graph_changeset(&graph);

View File

@ -251,7 +251,7 @@ impl<K: Clone + Ord + Debug> Indexer for KeychainTxOutIndex<K> {
fn index_tx(&mut self, tx: &bitcoin::Transaction) -> Self::ChangeSet {
let mut changeset = super::ChangeSet::<K>::default();
for (op, txout) in tx.output.iter().enumerate() {
changeset.append(self.index_txout(OutPoint::new(tx.txid(), op as u32), txout));
changeset.append(self.index_txout(OutPoint::new(tx.compute_txid(), op as u32), txout));
}
changeset
}

View File

@ -86,7 +86,7 @@ impl<I: Clone + Ord> SpkTxOutIndex<I> {
/// 2. When getting new data from the chain, you usually scan it before incorporating it into your chain state.
pub fn scan(&mut self, tx: &Transaction) -> BTreeSet<I> {
let mut scanned_indices = BTreeSet::new();
let txid = tx.txid();
let txid = tx.compute_txid();
for (i, txout) in tx.output.iter().enumerate() {
let op = OutPoint::new(txid, i as u32);
if let Some(spk_i) = self.scan_txout(op, txout) {

View File

@ -43,7 +43,7 @@ use alloc::vec::Vec;
/// let mut graph_a = TxGraph::<BlockId>::default();
/// let _ = graph_a.insert_tx(tx.clone());
/// graph_a.insert_anchor(
/// tx.txid(),
/// tx.compute_txid(),
/// BlockId {
/// height: 1,
/// hash: Hash::hash("first".as_bytes()),
@ -58,7 +58,7 @@ use alloc::vec::Vec;
/// let mut graph_b = TxGraph::<ConfirmationHeightAnchor>::default();
/// let _ = graph_b.insert_tx(tx.clone());
/// graph_b.insert_anchor(
/// tx.txid(),
/// tx.compute_txid(),
/// ConfirmationHeightAnchor {
/// anchor_block: BlockId {
/// height: 2,
@ -76,7 +76,7 @@ use alloc::vec::Vec;
/// let mut graph_c = TxGraph::<ConfirmationTimeHeightAnchor>::default();
/// let _ = graph_c.insert_tx(tx.clone());
/// graph_c.insert_anchor(
/// tx.txid(),
/// tx.compute_txid(),
/// ConfirmationTimeHeightAnchor {
/// anchor_block: BlockId {
/// height: 2,

View File

@ -445,7 +445,7 @@ impl<A> TxGraph<A> {
&'g self,
tx: &'g Transaction,
) -> impl Iterator<Item = (usize, Txid)> + '_ {
let txid = tx.txid();
let txid = tx.compute_txid();
tx.input
.iter()
.enumerate()
@ -516,9 +516,10 @@ impl<A: Clone + Ord> TxGraph<A> {
pub fn insert_tx<T: Into<Arc<Transaction>>>(&mut self, tx: T) -> ChangeSet<A> {
let tx = tx.into();
let mut update = Self::default();
update
.txs
.insert(tx.txid(), (TxNodeInternal::Whole(tx), BTreeSet::new(), 0));
update.txs.insert(
tx.compute_txid(),
(TxNodeInternal::Whole(tx), BTreeSet::new(), 0),
);
self.apply_update(update)
}
@ -533,7 +534,7 @@ impl<A: Clone + Ord> TxGraph<A> {
) -> ChangeSet<A> {
let mut changeset = ChangeSet::<A>::default();
for (tx, seen_at) in txs {
changeset.append(self.insert_seen_at(tx.txid(), seen_at));
changeset.append(self.insert_seen_at(tx.compute_txid(), seen_at));
changeset.append(self.insert_tx(tx));
}
changeset
@ -642,7 +643,7 @@ impl<A: Clone + Ord> TxGraph<A> {
pub fn apply_changeset(&mut self, changeset: ChangeSet<A>) {
for wrapped_tx in changeset.txs {
let tx = wrapped_tx.as_ref();
let txid = tx.txid();
let txid = tx.compute_txid();
tx.input
.iter()
@ -660,7 +661,7 @@ impl<A: Clone + Ord> TxGraph<A> {
}
Some((TxNodeInternal::Whole(tx), _, _)) => {
debug_assert_eq!(
tx.as_ref().txid(),
tx.as_ref().compute_txid(),
txid,
"tx should produce txid that is same as key"
);
@ -825,7 +826,7 @@ impl<A: Anchor> TxGraph<A> {
// resulting array will also include `tx`
let unconfirmed_ancestor_txs =
TxAncestors::new_include_root(self, tx.clone(), |_, ancestor_tx: Arc<Transaction>| {
let tx_node = self.get_tx_node(ancestor_tx.as_ref().txid())?;
let tx_node = self.get_tx_node(ancestor_tx.as_ref().compute_txid())?;
// We're filtering the ancestors to keep only the unconfirmed ones (= no anchors in
// the best chain)
for block in tx_node.anchors {
@ -843,7 +844,7 @@ impl<A: Anchor> TxGraph<A> {
// and our unconf descendants' last seen.
let unconfirmed_descendants_txs = TxDescendants::new_include_root(
self,
tx.as_ref().txid(),
tx.as_ref().compute_txid(),
|_, descendant_txid: Txid| {
let tx_node = self.get_tx_node(descendant_txid)?;
// We're filtering the ancestors to keep only the unconfirmed ones (= no anchors in
@ -884,7 +885,7 @@ impl<A: Anchor> TxGraph<A> {
return Ok(None);
}
if conflicting_tx.last_seen_unconfirmed == *last_seen
&& conflicting_tx.as_ref().txid() > tx.as_ref().txid()
&& conflicting_tx.as_ref().compute_txid() > tx.as_ref().compute_txid()
{
// Conflicting tx has priority if txid of conflicting tx > txid of original tx
return Ok(None);
@ -1255,7 +1256,7 @@ impl<A> ChangeSet<A> {
tx.output
.iter()
.enumerate()
.map(move |(vout, txout)| (OutPoint::new(tx.txid(), vout as _), txout))
.map(move |(vout, txout)| (OutPoint::new(tx.compute_txid(), vout as _), txout))
})
.chain(self.txouts.iter().map(|(op, txout)| (*op, txout)))
}

View File

@ -125,14 +125,14 @@ pub fn init_graph<'a, A: Anchor + Clone + 'a>(
.collect(),
};
tx_ids.insert(tx_tmp.tx_name, tx.txid());
tx_ids.insert(tx_tmp.tx_name, tx.compute_txid());
spk_index.scan(&tx);
let _ = graph.insert_tx(tx.clone());
for anchor in tx_tmp.anchors.iter() {
let _ = graph.insert_anchor(tx.txid(), anchor.clone());
let _ = graph.insert_anchor(tx.compute_txid(), anchor.clone());
}
if let Some(seen_at) = tx_tmp.last_seen {
let _ = graph.insert_seen_at(tx.txid(), seen_at);
let _ = graph.insert_seen_at(tx.compute_txid(), seen_at);
}
}
(graph, spk_index, tx_ids)

View File

@ -52,7 +52,7 @@ fn insert_relevant_txs() {
let tx_b = Transaction {
input: vec![TxIn {
previous_output: OutPoint::new(tx_a.txid(), 0),
previous_output: OutPoint::new(tx_a.compute_txid(), 0),
..Default::default()
}],
..common::new_tx(1)
@ -60,7 +60,7 @@ fn insert_relevant_txs() {
let tx_c = Transaction {
input: vec![TxIn {
previous_output: OutPoint::new(tx_a.txid(), 1),
previous_output: OutPoint::new(tx_a.compute_txid(), 1),
..Default::default()
}],
..common::new_tx(2)
@ -196,7 +196,7 @@ fn test_list_owned_txouts() {
// tx3 spends tx2 and gives a change back in trusted keychain. Confirmed at Block 2.
let tx3 = Transaction {
input: vec![TxIn {
previous_output: OutPoint::new(tx2.txid(), 0),
previous_output: OutPoint::new(tx2.compute_txid(), 0),
..Default::default()
}],
output: vec![TxOut {
@ -340,16 +340,22 @@ fn test_list_owned_txouts() {
balance,
) = fetch(0, &graph);
assert_eq!(confirmed_txouts_txid, [tx1.txid()].into());
assert_eq!(confirmed_txouts_txid, [tx1.compute_txid()].into());
assert_eq!(
unconfirmed_txouts_txid,
[tx2.txid(), tx3.txid(), tx4.txid(), tx5.txid()].into()
[
tx2.compute_txid(),
tx3.compute_txid(),
tx4.compute_txid(),
tx5.compute_txid()
]
.into()
);
assert_eq!(confirmed_utxos_txid, [tx1.txid()].into());
assert_eq!(confirmed_utxos_txid, [tx1.compute_txid()].into());
assert_eq!(
unconfirmed_utxos_txid,
[tx3.txid(), tx4.txid(), tx5.txid()].into()
[tx3.compute_txid(), tx4.compute_txid(), tx5.compute_txid()].into()
);
assert_eq!(
@ -374,17 +380,20 @@ fn test_list_owned_txouts() {
) = fetch(1, &graph);
// tx2 gets into confirmed txout set
assert_eq!(confirmed_txouts_txid, [tx1.txid(), tx2.txid()].into());
assert_eq!(
confirmed_txouts_txid,
[tx1.compute_txid(), tx2.compute_txid()].into()
);
assert_eq!(
unconfirmed_txouts_txid,
[tx3.txid(), tx4.txid(), tx5.txid()].into()
[tx3.compute_txid(), tx4.compute_txid(), tx5.compute_txid()].into()
);
// tx2 doesn't get into confirmed utxos set
assert_eq!(confirmed_utxos_txid, [tx1.txid()].into());
assert_eq!(confirmed_utxos_txid, [tx1.compute_txid()].into());
assert_eq!(
unconfirmed_utxos_txid,
[tx3.txid(), tx4.txid(), tx5.txid()].into()
[tx3.compute_txid(), tx4.compute_txid(), tx5.compute_txid()].into()
);
assert_eq!(
@ -411,13 +420,22 @@ fn test_list_owned_txouts() {
// tx3 now gets into the confirmed txout set
assert_eq!(
confirmed_txouts_txid,
[tx1.txid(), tx2.txid(), tx3.txid()].into()
[tx1.compute_txid(), tx2.compute_txid(), tx3.compute_txid()].into()
);
assert_eq!(
unconfirmed_txouts_txid,
[tx4.compute_txid(), tx5.compute_txid()].into()
);
assert_eq!(unconfirmed_txouts_txid, [tx4.txid(), tx5.txid()].into());
// tx3 also gets into confirmed utxo set
assert_eq!(confirmed_utxos_txid, [tx1.txid(), tx3.txid()].into());
assert_eq!(unconfirmed_utxos_txid, [tx4.txid(), tx5.txid()].into());
assert_eq!(
confirmed_utxos_txid,
[tx1.compute_txid(), tx3.compute_txid()].into()
);
assert_eq!(
unconfirmed_utxos_txid,
[tx4.compute_txid(), tx5.compute_txid()].into()
);
assert_eq!(
balance,
@ -442,12 +460,21 @@ fn test_list_owned_txouts() {
assert_eq!(
confirmed_txouts_txid,
[tx1.txid(), tx2.txid(), tx3.txid()].into()
[tx1.compute_txid(), tx2.compute_txid(), tx3.compute_txid()].into()
);
assert_eq!(
unconfirmed_txouts_txid,
[tx4.compute_txid(), tx5.compute_txid()].into()
);
assert_eq!(unconfirmed_txouts_txid, [tx4.txid(), tx5.txid()].into());
assert_eq!(confirmed_utxos_txid, [tx1.txid(), tx3.txid()].into());
assert_eq!(unconfirmed_utxos_txid, [tx4.txid(), tx5.txid()].into());
assert_eq!(
confirmed_utxos_txid,
[tx1.compute_txid(), tx3.compute_txid()].into()
);
assert_eq!(
unconfirmed_utxos_txid,
[tx4.compute_txid(), tx5.compute_txid()].into()
);
// Coinbase is still immature
assert_eq!(

View File

@ -47,7 +47,7 @@ fn spk_txout_sent_and_received() {
lock_time: absolute::LockTime::ZERO,
input: vec![TxIn {
previous_output: OutPoint {
txid: tx1.txid(),
txid: tx1.compute_txid(),
vout: 0,
},
..Default::default()

View File

@ -130,11 +130,11 @@ fn insert_txouts() {
// Mark it as confirmed.
assert_eq!(
graph.insert_anchor(update_txs.txid(), conf_anchor),
graph.insert_anchor(update_txs.compute_txid(), conf_anchor),
ChangeSet {
txs: [].into(),
txouts: [].into(),
anchors: [(conf_anchor, update_txs.txid())].into(),
anchors: [(conf_anchor, update_txs.compute_txid())].into(),
last_seen: [].into()
}
);
@ -149,7 +149,11 @@ fn insert_txouts() {
ChangeSet {
txs: [Arc::new(update_txs.clone())].into(),
txouts: update_ops.clone().into(),
anchors: [(conf_anchor, update_txs.txid()), (unconf_anchor, h!("tx2"))].into(),
anchors: [
(conf_anchor, update_txs.compute_txid()),
(unconf_anchor, h!("tx2"))
]
.into(),
last_seen: [(h!("tx2"), 1000000)].into()
}
);
@ -183,7 +187,9 @@ fn insert_txouts() {
);
assert_eq!(
graph.tx_outputs(update_txs.txid()).expect("should exists"),
graph
.tx_outputs(update_txs.compute_txid())
.expect("should exists"),
[(
0u32,
&TxOut {
@ -200,7 +206,11 @@ fn insert_txouts() {
ChangeSet {
txs: [Arc::new(update_txs.clone())].into(),
txouts: update_ops.into_iter().chain(original_ops).collect(),
anchors: [(conf_anchor, update_txs.txid()), (unconf_anchor, h!("tx2"))].into(),
anchors: [
(conf_anchor, update_txs.compute_txid()),
(unconf_anchor, h!("tx2"))
]
.into(),
last_seen: [(h!("tx2"), 1000000)].into()
}
);
@ -235,7 +245,7 @@ fn insert_tx_graph_keeps_track_of_spend() {
};
let op = OutPoint {
txid: tx1.txid(),
txid: tx1.compute_txid(),
vout: 0,
};
@ -261,7 +271,7 @@ fn insert_tx_graph_keeps_track_of_spend() {
assert_eq!(
graph1.outspends(op),
&iter::once(tx2.txid()).collect::<HashSet<_>>()
&iter::once(tx2.compute_txid()).collect::<HashSet<_>>()
);
assert_eq!(graph2.outspends(op), graph1.outspends(op));
}
@ -281,7 +291,9 @@ fn insert_tx_can_retrieve_full_tx_from_graph() {
let mut graph = TxGraph::<()>::default();
let _ = graph.insert_tx(tx.clone());
assert_eq!(
graph.get_tx(tx.txid()).map(|tx| tx.as_ref().clone()),
graph
.get_tx(tx.compute_txid())
.map(|tx| tx.as_ref().clone()),
Some(tx)
);
}
@ -301,7 +313,7 @@ fn insert_tx_displaces_txouts() {
let changeset = tx_graph.insert_txout(
OutPoint {
txid: tx.txid(),
txid: tx.compute_txid(),
vout: 0,
},
TxOut {
@ -314,7 +326,7 @@ fn insert_tx_displaces_txouts() {
let _ = tx_graph.insert_txout(
OutPoint {
txid: tx.txid(),
txid: tx.compute_txid(),
vout: 0,
},
TxOut {
@ -328,7 +340,7 @@ fn insert_tx_displaces_txouts() {
assert_eq!(
tx_graph
.get_txout(OutPoint {
txid: tx.txid(),
txid: tx.compute_txid(),
vout: 0
})
.unwrap()
@ -337,7 +349,7 @@ fn insert_tx_displaces_txouts() {
);
assert_eq!(
tx_graph.get_txout(OutPoint {
txid: tx.txid(),
txid: tx.compute_txid(),
vout: 1
}),
None
@ -361,7 +373,7 @@ fn insert_txout_does_not_displace_tx() {
let _ = tx_graph.insert_txout(
OutPoint {
txid: tx.txid(),
txid: tx.compute_txid(),
vout: 0,
},
TxOut {
@ -372,7 +384,7 @@ fn insert_txout_does_not_displace_tx() {
let _ = tx_graph.insert_txout(
OutPoint {
txid: tx.txid(),
txid: tx.compute_txid(),
vout: 0,
},
TxOut {
@ -384,7 +396,7 @@ fn insert_txout_does_not_displace_tx() {
assert_eq!(
tx_graph
.get_txout(OutPoint {
txid: tx.txid(),
txid: tx.compute_txid(),
vout: 0
})
.unwrap()
@ -393,7 +405,7 @@ fn insert_txout_does_not_displace_tx() {
);
assert_eq!(
tx_graph.get_txout(OutPoint {
txid: tx.txid(),
txid: tx.compute_txid(),
vout: 1
}),
None
@ -443,14 +455,14 @@ fn test_calculate_fee() {
input: vec![
TxIn {
previous_output: OutPoint {
txid: intx1.txid(),
txid: intx1.compute_txid(),
vout: 0,
},
..Default::default()
},
TxIn {
previous_output: OutPoint {
txid: intx2.txid(),
txid: intx2.compute_txid(),
vout: 0,
},
..Default::default()
@ -543,7 +555,7 @@ fn test_walk_ancestors() {
// tx_b0 spends tx_a0
let tx_b0 = Transaction {
input: vec![TxIn {
previous_output: OutPoint::new(tx_a0.txid(), 0),
previous_output: OutPoint::new(tx_a0.compute_txid(), 0),
..TxIn::default()
}],
output: vec![TxOut::NULL, TxOut::NULL],
@ -553,7 +565,7 @@ fn test_walk_ancestors() {
// tx_b1 spends tx_a0
let tx_b1 = Transaction {
input: vec![TxIn {
previous_output: OutPoint::new(tx_a0.txid(), 1),
previous_output: OutPoint::new(tx_a0.compute_txid(), 1),
..TxIn::default()
}],
output: vec![TxOut::NULL],
@ -572,7 +584,7 @@ fn test_walk_ancestors() {
// tx_c0 spends tx_b0
let tx_c0 = Transaction {
input: vec![TxIn {
previous_output: OutPoint::new(tx_b0.txid(), 0),
previous_output: OutPoint::new(tx_b0.compute_txid(), 0),
..TxIn::default()
}],
output: vec![TxOut::NULL],
@ -582,7 +594,7 @@ fn test_walk_ancestors() {
// tx_c1 spends tx_b0
let tx_c1 = Transaction {
input: vec![TxIn {
previous_output: OutPoint::new(tx_b0.txid(), 1),
previous_output: OutPoint::new(tx_b0.compute_txid(), 1),
..TxIn::default()
}],
output: vec![TxOut::NULL],
@ -593,11 +605,11 @@ fn test_walk_ancestors() {
let tx_c2 = Transaction {
input: vec![
TxIn {
previous_output: OutPoint::new(tx_b1.txid(), 0),
previous_output: OutPoint::new(tx_b1.compute_txid(), 0),
..TxIn::default()
},
TxIn {
previous_output: OutPoint::new(tx_b2.txid(), 0),
previous_output: OutPoint::new(tx_b2.compute_txid(), 0),
..TxIn::default()
},
],
@ -617,7 +629,7 @@ fn test_walk_ancestors() {
// tx_d0 spends tx_c1
let tx_d0 = Transaction {
input: vec![TxIn {
previous_output: OutPoint::new(tx_c1.txid(), 0),
previous_output: OutPoint::new(tx_c1.compute_txid(), 0),
..TxIn::default()
}],
output: vec![TxOut::NULL],
@ -628,11 +640,11 @@ fn test_walk_ancestors() {
let tx_d1 = Transaction {
input: vec![
TxIn {
previous_output: OutPoint::new(tx_c2.txid(), 0),
previous_output: OutPoint::new(tx_c2.compute_txid(), 0),
..TxIn::default()
},
TxIn {
previous_output: OutPoint::new(tx_c3.txid(), 0),
previous_output: OutPoint::new(tx_c3.compute_txid(), 0),
..TxIn::default()
},
],
@ -643,7 +655,7 @@ fn test_walk_ancestors() {
// tx_e0 spends tx_d1
let tx_e0 = Transaction {
input: vec![TxIn {
previous_output: OutPoint::new(tx_d1.txid(), 0),
previous_output: OutPoint::new(tx_d1.compute_txid(), 0),
..TxIn::default()
}],
output: vec![TxOut::NULL],
@ -665,7 +677,7 @@ fn test_walk_ancestors() {
]);
[&tx_a0, &tx_b1].iter().for_each(|&tx| {
let changeset = graph.insert_anchor(tx.txid(), tip.block_id());
let changeset = graph.insert_anchor(tx.compute_txid(), tip.block_id());
assert!(!changeset.is_empty());
});
@ -682,7 +694,7 @@ fn test_walk_ancestors() {
// Only traverse unconfirmed ancestors of tx_e0 this time
graph
.walk_ancestors(tx_e0.clone(), |depth, tx| {
let tx_node = graph.get_tx_node(tx.txid())?;
let tx_node = graph.get_tx_node(tx.compute_txid())?;
for block in tx_node.anchors {
match local_chain.is_block_in_chain(block.anchor_block(), tip.block_id()) {
Ok(Some(true)) => return None,
@ -746,15 +758,15 @@ fn test_conflicting_descendants() {
// tx_b spends tx_a
let tx_b = Transaction {
input: vec![TxIn {
previous_output: OutPoint::new(tx_a.txid(), 0),
previous_output: OutPoint::new(tx_a.compute_txid(), 0),
..TxIn::default()
}],
output: vec![TxOut::NULL],
..common::new_tx(2)
};
let txid_a = tx_a.txid();
let txid_b = tx_b.txid();
let txid_a = tx_a.compute_txid();
let txid_b = tx_b.compute_txid();
let mut graph = TxGraph::<()>::default();
let _ = graph.insert_tx(tx_a);
@ -778,7 +790,7 @@ fn test_descendants_no_repeat() {
let txs_b = (0..3)
.map(|vout| Transaction {
input: vec![TxIn {
previous_output: OutPoint::new(tx_a.txid(), vout),
previous_output: OutPoint::new(tx_a.compute_txid(), vout),
..TxIn::default()
}],
output: vec![TxOut::NULL],
@ -789,7 +801,7 @@ fn test_descendants_no_repeat() {
let txs_c = (0..2)
.map(|vout| Transaction {
input: vec![TxIn {
previous_output: OutPoint::new(txs_b[vout as usize].txid(), vout),
previous_output: OutPoint::new(txs_b[vout as usize].compute_txid(), vout),
..TxIn::default()
}],
output: vec![TxOut::NULL],
@ -800,11 +812,11 @@ fn test_descendants_no_repeat() {
let tx_d = Transaction {
input: vec![
TxIn {
previous_output: OutPoint::new(txs_c[0].txid(), 0),
previous_output: OutPoint::new(txs_c[0].compute_txid(), 0),
..TxIn::default()
},
TxIn {
previous_output: OutPoint::new(txs_c[1].txid(), 0),
previous_output: OutPoint::new(txs_c[1].compute_txid(), 0),
..TxIn::default()
},
],
@ -814,7 +826,7 @@ fn test_descendants_no_repeat() {
let tx_e = Transaction {
input: vec![TxIn {
previous_output: OutPoint::new(tx_d.txid(), 0),
previous_output: OutPoint::new(tx_d.compute_txid(), 0),
..TxIn::default()
}],
output: vec![TxOut::NULL],
@ -848,11 +860,11 @@ fn test_descendants_no_repeat() {
.chain(core::iter::once(&tx_e))
{
let _ = graph.insert_tx(tx.clone());
expected_txids.push(tx.txid());
expected_txids.push(tx.compute_txid());
}
let descendants = graph
.walk_descendants(tx_a.txid(), |_, txid| Some(txid))
.walk_descendants(tx_a.compute_txid(), |_, txid| Some(txid))
.collect::<Vec<_>>();
assert_eq!(descendants, expected_txids);
@ -888,7 +900,7 @@ fn test_chain_spends() {
// The first confirmed transaction spends vout: 0. And is confirmed at block 98.
let tx_1 = Transaction {
input: vec![TxIn {
previous_output: OutPoint::new(tx_0.txid(), 0),
previous_output: OutPoint::new(tx_0.compute_txid(), 0),
..TxIn::default()
}],
output: vec![
@ -907,7 +919,7 @@ fn test_chain_spends() {
// The second transactions spends vout:1, and is unconfirmed.
let tx_2 = Transaction {
input: vec![TxIn {
previous_output: OutPoint::new(tx_0.txid(), 1),
previous_output: OutPoint::new(tx_0.compute_txid(), 1),
..TxIn::default()
}],
output: vec![
@ -931,7 +943,7 @@ fn test_chain_spends() {
for (ht, tx) in [(95, &tx_0), (98, &tx_1)] {
let _ = graph.insert_anchor(
tx.txid(),
tx.compute_txid(),
ConfirmationHeightAnchor {
anchor_block: tip.block_id(),
confirmation_height: ht,
@ -941,19 +953,23 @@ fn test_chain_spends() {
// Assert that confirmed spends are returned correctly.
assert_eq!(
graph.get_chain_spend(&local_chain, tip.block_id(), OutPoint::new(tx_0.txid(), 0)),
graph.get_chain_spend(
&local_chain,
tip.block_id(),
OutPoint::new(tx_0.compute_txid(), 0)
),
Some((
ChainPosition::Confirmed(&ConfirmationHeightAnchor {
anchor_block: tip.block_id(),
confirmation_height: 98
}),
tx_1.txid(),
tx_1.compute_txid(),
)),
);
// Check if chain position is returned correctly.
assert_eq!(
graph.get_chain_position(&local_chain, tip.block_id(), tx_0.txid()),
graph.get_chain_position(&local_chain, tip.block_id(), tx_0.compute_txid()),
// Some(ObservedAs::Confirmed(&local_chain.get_block(95).expect("block expected"))),
Some(ChainPosition::Confirmed(&ConfirmationHeightAnchor {
anchor_block: tip.block_id(),
@ -963,25 +979,33 @@ fn test_chain_spends() {
// Even if unconfirmed tx has a last_seen of 0, it can still be part of a chain spend.
assert_eq!(
graph.get_chain_spend(&local_chain, tip.block_id(), OutPoint::new(tx_0.txid(), 1)),
Some((ChainPosition::Unconfirmed(0), tx_2.txid())),
graph.get_chain_spend(
&local_chain,
tip.block_id(),
OutPoint::new(tx_0.compute_txid(), 1)
),
Some((ChainPosition::Unconfirmed(0), tx_2.compute_txid())),
);
// Mark the unconfirmed as seen and check correct ObservedAs status is returned.
let _ = graph.insert_seen_at(tx_2.txid(), 1234567);
let _ = graph.insert_seen_at(tx_2.compute_txid(), 1234567);
// Check chain spend returned correctly.
assert_eq!(
graph
.get_chain_spend(&local_chain, tip.block_id(), OutPoint::new(tx_0.txid(), 1))
.get_chain_spend(
&local_chain,
tip.block_id(),
OutPoint::new(tx_0.compute_txid(), 1)
)
.unwrap(),
(ChainPosition::Unconfirmed(1234567), tx_2.txid())
(ChainPosition::Unconfirmed(1234567), tx_2.compute_txid())
);
// A conflicting transaction that conflicts with tx_1.
let tx_1_conflict = Transaction {
input: vec![TxIn {
previous_output: OutPoint::new(tx_0.txid(), 0),
previous_output: OutPoint::new(tx_0.compute_txid(), 0),
..Default::default()
}],
..common::new_tx(0)
@ -990,13 +1014,13 @@ fn test_chain_spends() {
// Because this tx conflicts with an already confirmed transaction, chain position should return none.
assert!(graph
.get_chain_position(&local_chain, tip.block_id(), tx_1_conflict.txid())
.get_chain_position(&local_chain, tip.block_id(), tx_1_conflict.compute_txid())
.is_none());
// Another conflicting tx that conflicts with tx_2.
let tx_2_conflict = Transaction {
input: vec![TxIn {
previous_output: OutPoint::new(tx_0.txid(), 1),
previous_output: OutPoint::new(tx_0.compute_txid(), 1),
..Default::default()
}],
..common::new_tx(0)
@ -1004,12 +1028,12 @@ fn test_chain_spends() {
// Insert in graph and mark it as seen.
let _ = graph.insert_tx(tx_2_conflict.clone());
let _ = graph.insert_seen_at(tx_2_conflict.txid(), 1234568);
let _ = graph.insert_seen_at(tx_2_conflict.compute_txid(), 1234568);
// This should return a valid observation with correct last seen.
assert_eq!(
graph
.get_chain_position(&local_chain, tip.block_id(), tx_2_conflict.txid())
.get_chain_position(&local_chain, tip.block_id(), tx_2_conflict.compute_txid())
.expect("position expected"),
ChainPosition::Unconfirmed(1234568)
);
@ -1017,14 +1041,21 @@ fn test_chain_spends() {
// Chain_spend now catches the new transaction as the spend.
assert_eq!(
graph
.get_chain_spend(&local_chain, tip.block_id(), OutPoint::new(tx_0.txid(), 1))
.get_chain_spend(
&local_chain,
tip.block_id(),
OutPoint::new(tx_0.compute_txid(), 1)
)
.expect("expect observation"),
(ChainPosition::Unconfirmed(1234568), tx_2_conflict.txid())
(
ChainPosition::Unconfirmed(1234568),
tx_2_conflict.compute_txid()
)
);
// Chain position of the `tx_2` is now none, as it is older than `tx_2_conflict`
assert!(graph
.get_chain_position(&local_chain, tip.block_id(), tx_2.txid())
.get_chain_position(&local_chain, tip.block_id(), tx_2.compute_txid())
.is_none());
}
@ -1065,7 +1096,7 @@ fn test_changeset_last_seen_append() {
fn update_last_seen_unconfirmed() {
let mut graph = TxGraph::<()>::default();
let tx = new_tx(0);
let txid = tx.txid();
let txid = tx.compute_txid();
// insert a new tx
// initially we have a last_seen of 0, and no anchors

View File

@ -13,8 +13,8 @@ readme = "README.md"
[dependencies]
bdk_chain = { path = "../chain", version = "0.15.0" }
electrum-client = { version = "0.19" }
electrum-client = { version = "0.20" }
#rustls = { version = "=0.21.1", optional = true, features = ["dangerous_configuration"] }
[dev-dependencies]
bdk_testenv = { path = "../testenv", default-features = false }
bdk_testenv = { path = "../testenv", default-features = false }

View File

@ -310,7 +310,7 @@ impl<E: ElectrumApi> BdkElectrumClient<E> {
Some(txout) => txout,
None => continue,
};
debug_assert_eq!(op_tx.txid(), op_txid);
debug_assert_eq!(op_tx.compute_txid(), op_txid);
// attempt to find the following transactions (alongside their chain positions), and
// add to our sparsechain `update`:

View File

@ -13,13 +13,12 @@ readme = "README.md"
[dependencies]
bdk_chain = { path = "../chain", version = "0.15.0", default-features = false }
esplora-client = { version = "0.7.0", default-features = false }
esplora-client = { version = "0.8.0", default-features = false }
async-trait = { version = "0.1.66", optional = true }
futures = { version = "0.3.26", optional = true }
# use these dependencies if you need to enable their /no-std features
bitcoin = { version = "0.31.0", optional = true, default-features = false }
miniscript = { version = "11.0.0", optional = true, default-features = false }
bitcoin = { version = "0.32.0", optional = true, default-features = false }
miniscript = { version = "12.0.0", optional = true, default-features = false }
[dev-dependencies]
bdk_testenv = { path = "../testenv", default-features = false }
@ -27,7 +26,7 @@ tokio = { version = "1", features = ["rt", "rt-multi-thread", "macros"] }
[features]
default = ["std", "async-https", "blocking-https-rustls"]
std = ["bdk_chain/std"]
std = ["bdk_chain/std", "miniscript?/std"]
async = ["async-trait", "futures", "esplora-client/async"]
async-https = ["async", "esplora-client/async-https"]
async-https-rustls = ["async", "esplora-client/async-https-rustls"]

View File

@ -10,4 +10,4 @@ readme = "README.md"
[dependencies]
bdk_wallet = { path = "../wallet", version = "1.0.0-alpha.12" }
hwi = { version = "0.8.0", features = [ "miniscript"] }
hwi = { version = "0.9.0", features = [ "miniscript"] }

View File

@ -303,7 +303,7 @@ impl<K, A> Store<K, A> {
let insert_tx_stmt = &mut db_transaction
.prepare_cached("INSERT INTO tx (txid, whole_tx) VALUES (:txid, :whole_tx) ON CONFLICT (txid) DO UPDATE SET whole_tx = :whole_tx WHERE txid = :txid")
.expect("insert or update tx whole_tx statement");
let txid = tx.txid().to_string();
let txid = tx.compute_txid().to_string();
let whole_tx = serialize(&tx);
insert_tx_stmt
.execute(named_params! {":txid": txid, ":whole_tx": whole_tx })
@ -685,9 +685,9 @@ mod test {
let tx2_hex = Vec::<u8>::from_hex("01000000010000000000000000000000000000000000000000000000000000000000000000ffffffff0e0432e7494d010e062f503253482fffffffff0100f2052a010000002321038a7f6ef1c8ca0c588aa53fa860128077c9e6c11e6830f4d7ee4e763a56b7718fac00000000").unwrap();
let tx2: Arc<Transaction> = Arc::new(deserialize(tx2_hex.as_slice()).unwrap());
let outpoint0_0 = OutPoint::new(tx0.txid(), 0);
let outpoint0_0 = OutPoint::new(tx0.compute_txid(), 0);
let txout0_0 = tx0.output.first().unwrap().clone();
let outpoint1_0 = OutPoint::new(tx1.txid(), 0);
let outpoint1_0 = OutPoint::new(tx1.compute_txid(), 0);
let txout1_0 = tx1.output.first().unwrap().clone();
let anchor1 = anchor_fn(1, 1296667328, block_hash_1);
@ -696,11 +696,11 @@ mod test {
let tx_graph_changeset = tx_graph::ChangeSet::<A> {
txs: [tx0.clone(), tx1.clone()].into(),
txouts: [(outpoint0_0, txout0_0), (outpoint1_0, txout1_0)].into(),
anchors: [(anchor1, tx0.txid()), (anchor1, tx1.txid())].into(),
anchors: [(anchor1, tx0.compute_txid()), (anchor1, tx1.compute_txid())].into(),
last_seen: [
(tx0.txid(), 1598918400),
(tx1.txid(), 1598919121),
(tx2.txid(), 1608919121),
(tx0.compute_txid(), 1598918400),
(tx1.compute_txid(), 1598919121),
(tx2.compute_txid(), 1608919121),
]
.into(),
};
@ -730,7 +730,7 @@ mod test {
txs: [tx2.clone()].into(),
txouts: BTreeMap::default(),
anchors: BTreeSet::default(),
last_seen: [(tx2.txid(), 1708919121)].into(),
last_seen: [(tx2.compute_txid(), 1708919121)].into(),
};
let graph_changeset2: indexed_tx_graph::ChangeSet<A, keychain::ChangeSet<Keychain>> =
@ -749,7 +749,7 @@ mod test {
let tx_graph_changeset3 = tx_graph::ChangeSet::<A> {
txs: BTreeSet::default(),
txouts: BTreeMap::default(),
anchors: [(anchor2, tx0.txid()), (anchor2, tx1.txid())].into(),
anchors: [(anchor2, tx0.compute_txid()), (anchor2, tx1.compute_txid())].into(),
last_seen: BTreeMap::default(),
};

View File

@ -14,7 +14,7 @@ readme = "README.md"
[dependencies]
bdk_chain = { path = "../chain", version = "0.15", default-features = false }
electrsd = { version= "0.27.1", features = ["bitcoind_25_0", "esplora_a33e97e1", "legacy"] }
electrsd = { version = "0.28.0", features = ["bitcoind_25_0", "esplora_a33e97e1", "legacy"] }
[features]
default = ["std"]

View File

@ -15,8 +15,8 @@ rust-version = "1.63"
[dependencies]
anyhow = { version = "1", default-features = false }
rand = "^0.8"
miniscript = { version = "11.0.0", features = ["serde"], default-features = false }
bitcoin = { version = "0.31.0", features = ["serde", "base64", "rand-std"], default-features = false }
miniscript = { version = "12.0.0", features = ["serde"], default-features = false }
bitcoin = { version = "0.32.0", features = ["serde", "base64", "rand-std"], default-features = false }
serde = { version = "^1.0", features = ["derive"] }
serde_json = { version = "^1.0" }
bdk_chain = { path = "../chain", version = "0.15.0", features = ["miniscript", "serde"], default-features = false }

View File

@ -703,10 +703,10 @@ macro_rules! fragment {
$crate::keys::make_pkh($key, &secp)
});
( after ( $value:expr ) ) => ({
$crate::impl_leaf_opcode_value!(After, $crate::miniscript::AbsLockTime::from_consensus($value))
$crate::impl_leaf_opcode_value!(After, $crate::miniscript::AbsLockTime::from_consensus($value).expect("valid `AbsLockTime`"))
});
( older ( $value:expr ) ) => ({
$crate::impl_leaf_opcode_value!(Older, $crate::bitcoin::Sequence($value)) // TODO!!
$crate::impl_leaf_opcode_value!(Older, $crate::miniscript::RelLockTime::from_consensus($value).expect("valid `RelLockTime`")) // TODO!!
});
( sha256 ( $hash:expr ) ) => ({
$crate::impl_leaf_opcode_value!(Sha256, $hash)
@ -757,7 +757,8 @@ macro_rules! fragment {
(keys_acc, net_acc)
});
$crate::impl_leaf_opcode_value_two!(Thresh, $thresh, items)
let thresh = $crate::miniscript::Threshold::new($thresh, items).expect("valid threshold and pks collection");
$crate::impl_leaf_opcode_value!(Thresh, thresh)
.map(|(minisc, _, _)| (minisc, key_maps, valid_networks))
});
( thresh ( $thresh:expr, $( $inner:tt )* ) ) => ({
@ -769,7 +770,12 @@ macro_rules! fragment {
( multi_vec ( $thresh:expr, $keys:expr ) ) => ({
let secp = $crate::bitcoin::secp256k1::Secp256k1::new();
$crate::keys::make_multi($thresh, $crate::miniscript::Terminal::Multi, $keys, &secp)
let fun = |k, pks| {
let thresh = $crate::miniscript::Threshold::new(k, pks).expect("valid threshold and pks collection");
$crate::miniscript::Terminal::Multi(thresh)
};
$crate::keys::make_multi($thresh, fun, $keys, &secp)
});
( multi ( $thresh:expr $(, $key:expr )+ ) ) => ({
$crate::group_multi_keys!( $( $key ),* )
@ -778,7 +784,12 @@ macro_rules! fragment {
( multi_a_vec ( $thresh:expr, $keys:expr ) ) => ({
let secp = $crate::bitcoin::secp256k1::Secp256k1::new();
$crate::keys::make_multi($thresh, $crate::miniscript::Terminal::MultiA, $keys, &secp)
let fun = |k, pks| {
let thresh = $crate::miniscript::Threshold::new(k, pks).expect("valid threshold and pks collection");
$crate::miniscript::Terminal::MultiA(thresh)
};
$crate::keys::make_multi($thresh, fun, $keys, &secp)
});
( multi_a ( $thresh:expr $(, $key:expr )+ ) ) => ({
$crate::group_multi_keys!( $( $key ),* )

View File

@ -37,7 +37,7 @@ pub enum Error {
/// Error during base58 decoding
Base58(bitcoin::base58::Error),
/// Key-related error
Pk(bitcoin::key::Error),
Pk(bitcoin::key::ParsePublicKeyError),
/// Miniscript error
Miniscript(miniscript::Error),
/// Hex decoding error
@ -103,8 +103,8 @@ impl From<bitcoin::base58::Error> for Error {
}
}
impl From<bitcoin::key::Error> for Error {
fn from(err: bitcoin::key::Error) -> Self {
impl From<bitcoin::key::ParsePublicKeyError> for Error {
fn from(err: bitcoin::key::ParsePublicKeyError) -> Self {
Error::Pk(err)
}
}

View File

@ -229,7 +229,7 @@ impl IntoWalletDescriptor for DescriptorTemplateOut {
let pk = match pk {
DescriptorPublicKey::XPub(ref xpub) => {
let mut xpub = xpub.clone();
xpub.xkey.network = self.network;
xpub.xkey.network = self.network.into();
DescriptorPublicKey::XPub(xpub)
}
@ -264,11 +264,11 @@ impl IntoWalletDescriptor for DescriptorTemplateOut {
.map(|(mut k, mut v)| {
match (&mut k, &mut v) {
(DescriptorPublicKey::XPub(xpub), DescriptorSecretKey::XPrv(xprv)) => {
xpub.xkey.network = network;
xprv.xkey.network = network;
xpub.xkey.network = network.into();
xprv.xkey.network = network.into();
}
(_, DescriptorSecretKey::Single(key)) => {
key.key.network = network;
key.key.network = network.into();
}
_ => {}
}
@ -606,8 +606,8 @@ mod test {
use assert_matches::assert_matches;
use bitcoin::hex::FromHex;
use bitcoin::secp256k1::Secp256k1;
use bitcoin::ScriptBuf;
use bitcoin::{bip32, Psbt};
use bitcoin::{NetworkKind, ScriptBuf};
use super::*;
use crate::psbt::PsbtUtils;
@ -743,7 +743,7 @@ mod test {
.unwrap();
let mut xprv_testnet = xprv;
xprv_testnet.network = Network::Testnet;
xprv_testnet.network = NetworkKind::Test;
let xpub_testnet = bip32::Xpub::from_priv(&secp, &xprv_testnet);
let desc_pubkey = DescriptorPublicKey::XPub(DescriptorXKey {

View File

@ -40,6 +40,7 @@ use crate::collections::{BTreeMap, HashSet, VecDeque};
use alloc::string::String;
use alloc::vec::Vec;
use core::cmp::max;
use miniscript::miniscript::limits::{MAX_PUBKEYS_IN_CHECKSIGADD, MAX_PUBKEYS_PER_MULTISIG};
use core::fmt;
@ -48,12 +49,12 @@ use serde::{Serialize, Serializer};
use bitcoin::bip32::Fingerprint;
use bitcoin::hashes::{hash160, ripemd160, sha256};
use bitcoin::{absolute, key::XOnlyPublicKey, PublicKey, Sequence};
use bitcoin::{absolute, key::XOnlyPublicKey, relative, PublicKey, Sequence};
use miniscript::descriptor::{
DescriptorPublicKey, ShInner, SinglePub, SinglePubKey, SortedMultiVec, WshInner,
};
use miniscript::hash256;
use miniscript::{hash256, Threshold};
use miniscript::{
Descriptor, Miniscript, Satisfier, ScriptContext, SigType, Terminal, ToPublicKey,
};
@ -137,7 +138,7 @@ pub enum SatisfiableItem {
/// Relative timelock locktime
RelativeTimelock {
/// The timelock value
value: Sequence,
value: relative::LockTime,
},
/// Multi-signature public keys with threshold count
Multisig {
@ -586,30 +587,25 @@ impl Policy {
Ok(Some(policy))
}
fn make_multisig<Ctx: ScriptContext + 'static>(
keys: &[DescriptorPublicKey],
fn make_multi<Ctx: ScriptContext + 'static, const MAX: usize>(
threshold: &Threshold<DescriptorPublicKey, MAX>,
signers: &SignersContainer,
build_sat: BuildSatisfaction,
threshold: usize,
sorted: bool,
secp: &SecpCtx,
) -> Result<Option<Policy>, PolicyError> {
if threshold == 0 {
return Ok(None);
}
let parsed_keys = keys.iter().map(|k| PkOrF::from_key(k, secp)).collect();
let parsed_keys = threshold.iter().map(|k| PkOrF::from_key(k, secp)).collect();
let mut contribution = Satisfaction::Partial {
n: keys.len(),
m: threshold,
n: threshold.n(),
m: threshold.k(),
items: vec![],
conditions: Default::default(),
sorted: Some(sorted),
};
let mut satisfaction = contribution.clone();
for (index, key) in keys.iter().enumerate() {
for (index, key) in threshold.iter().enumerate() {
if signers.find(signer_id(key, secp)).is_some() {
contribution.add(
&Satisfaction::Complete {
@ -618,7 +614,6 @@ impl Policy {
index,
)?;
}
if let Some(psbt) = build_sat.psbt() {
if Ctx::find_signature(psbt, key, secp) {
satisfaction.add(
@ -635,12 +630,11 @@ impl Policy {
let mut policy: Policy = SatisfiableItem::Multisig {
keys: parsed_keys,
threshold,
threshold: threshold.k(),
}
.into();
policy.contribution = contribution;
policy.satisfaction = satisfaction;
Ok(Some(policy))
}
@ -725,7 +719,7 @@ impl Policy {
timelock: Some(*value),
}),
SatisfiableItem::RelativeTimelock { value } => Ok(Condition {
csv: Some(*value),
csv: Some((*value).into()),
timelock: None,
}),
_ => Ok(Condition::default()),
@ -952,11 +946,14 @@ impl<Ctx: ScriptContext + 'static> ExtractPolicy for Miniscript<DescriptorPublic
Some(policy)
}
Terminal::Older(value) => {
let mut policy: Policy = SatisfiableItem::RelativeTimelock { value: *value }.into();
let mut policy: Policy = SatisfiableItem::RelativeTimelock {
value: (*value).into(),
}
.into();
policy.contribution = Satisfaction::Complete {
condition: Condition {
timelock: None,
csv: Some(*value),
csv: Some((*value).into()),
},
};
if let BuildSatisfaction::PsbtTimelocks {
@ -966,9 +963,11 @@ impl<Ctx: ScriptContext + 'static> ExtractPolicy for Miniscript<DescriptorPublic
} = build_sat
{
let older = Older::new(Some(current_height), Some(input_max_height), false);
let older_sat = Satisfier::<bitcoin::PublicKey>::check_older(&older, *value);
let inputs_sat = psbt_inputs_sat(psbt)
.all(|sat| Satisfier::<bitcoin::PublicKey>::check_older(&sat, *value));
let older_sat =
Satisfier::<bitcoin::PublicKey>::check_older(&older, (*value).into());
let inputs_sat = psbt_inputs_sat(psbt).all(|sat| {
Satisfier::<bitcoin::PublicKey>::check_older(&sat, (*value).into())
});
if older_sat && inputs_sat {
policy.satisfaction = policy.contribution.clone();
}
@ -986,9 +985,12 @@ impl<Ctx: ScriptContext + 'static> ExtractPolicy for Miniscript<DescriptorPublic
Terminal::Hash160(hash) => {
Some(SatisfiableItem::Hash160Preimage { hash: *hash }.into())
}
Terminal::Multi(k, pks) | Terminal::MultiA(k, pks) => {
Policy::make_multisig::<Ctx>(pks, signers, build_sat, *k, false, secp)?
}
Terminal::Multi(threshold) => Policy::make_multi::<Ctx, MAX_PUBKEYS_PER_MULTISIG>(
threshold, signers, build_sat, false, secp,
)?,
Terminal::MultiA(threshold) => Policy::make_multi::<Ctx, MAX_PUBKEYS_IN_CHECKSIGADD>(
threshold, signers, build_sat, false, secp,
)?,
// Identities
Terminal::Alt(inner)
| Terminal::Swap(inner)
@ -1016,8 +1018,9 @@ impl<Ctx: ScriptContext + 'static> ExtractPolicy for Miniscript<DescriptorPublic
a.extract_policy(signers, build_sat, secp)?,
b.extract_policy(signers, build_sat, secp)?,
)?,
Terminal::Thresh(k, nodes) => {
let mut threshold = *k;
Terminal::Thresh(threshold) => {
let mut k = threshold.k();
let nodes = threshold.data();
let mapped: Vec<_> = nodes
.iter()
.map(|n| n.extract_policy(signers, build_sat, secp))
@ -1027,13 +1030,13 @@ impl<Ctx: ScriptContext + 'static> ExtractPolicy for Miniscript<DescriptorPublic
.collect();
if mapped.len() < nodes.len() {
threshold = match threshold.checked_sub(nodes.len() - mapped.len()) {
k = match k.checked_sub(nodes.len() - mapped.len()) {
None => return Ok(None),
Some(x) => x,
};
}
Policy::make_thresh(mapped, threshold)?
Policy::make_thresh(mapped, k)?
}
// Unsupported
@ -1087,13 +1090,10 @@ impl ExtractPolicy for Descriptor<DescriptorPublicKey> {
build_sat: BuildSatisfaction,
secp: &SecpCtx,
) -> Result<Option<Policy>, Error> {
Ok(Policy::make_multisig::<Ctx>(
keys.pks.as_ref(),
signers,
build_sat,
keys.k,
true,
secp,
let threshold = Threshold::new(keys.k(), keys.pks().to_vec())
.expect("valid threshold and pks collection");
Ok(Policy::make_multi::<Ctx, MAX_PUBKEYS_PER_MULTISIG>(
&threshold, signers, build_sat, true, secp,
)?)
}

View File

@ -583,7 +583,7 @@ mod test {
use bitcoin::bip32::ChildNumber::{self, Hardened};
let xprvkey = bitcoin::bip32::Xpriv::from_str("xprv9s21ZrQH143K2fpbqApQL69a4oKdGVnVN52R82Ft7d1pSqgKmajF62acJo3aMszZb6qQ22QsVECSFxvf9uyxFUvFYQMq3QbtwtRSMjLAhMf").unwrap();
assert_eq!(Network::Bitcoin, xprvkey.network);
assert!(xprvkey.network.is_mainnet());
let xdesc = Bip44(xprvkey, KeychainKind::Internal)
.build(Network::Bitcoin)
.unwrap();
@ -597,7 +597,7 @@ mod test {
}
let tprvkey = bitcoin::bip32::Xpriv::from_str("tprv8ZgxMBicQKsPcx5nBGsR63Pe8KnRUqmbJNENAfGftF3yuXoMMoVJJcYeUw5eVkm9WBPjWYt6HMWYJNesB5HaNVBaFc1M6dRjWSYnmewUMYy").unwrap();
assert_eq!(Network::Testnet, tprvkey.network);
assert!(!tprvkey.network.is_mainnet());
let tdesc = Bip44(tprvkey, KeychainKind::Internal)
.build(Network::Testnet)
.unwrap();

View File

@ -336,7 +336,7 @@ impl<Ctx: ScriptContext> ExtendedKey<Ctx> {
pub fn into_xprv(self, network: Network) -> Option<bip32::Xpriv> {
match self {
ExtendedKey::Private((mut xprv, _)) => {
xprv.network = network;
xprv.network = network.into();
Some(xprv)
}
ExtendedKey::Public(_) => None,
@ -355,7 +355,7 @@ impl<Ctx: ScriptContext> ExtendedKey<Ctx> {
ExtendedKey::Public((xpub, _)) => xpub,
};
xpub.network = network;
xpub.network = network.into();
xpub
}
}
@ -402,7 +402,7 @@ impl<Ctx: ScriptContext> From<bip32::Xpriv> for ExtendedKey<Ctx> {
/// impl<Ctx: ScriptContext> DerivableKey<Ctx> for MyCustomKeyType {
/// fn into_extended_key(self) -> Result<ExtendedKey<Ctx>, KeyError> {
/// let xprv = bip32::Xpriv {
/// network: self.network,
/// network: self.network.into(),
/// depth: 0,
/// parent_fingerprint: bip32::Fingerprint::default(),
/// private_key: self.key_data.inner,
@ -434,7 +434,7 @@ impl<Ctx: ScriptContext> From<bip32::Xpriv> for ExtendedKey<Ctx> {
/// impl<Ctx: ScriptContext> DerivableKey<Ctx> for MyCustomKeyType {
/// fn into_extended_key(self) -> Result<ExtendedKey<Ctx>, KeyError> {
/// let xprv = bip32::Xpriv {
/// network: bitcoin::Network::Bitcoin, // pick an arbitrary network here
/// network: bitcoin::Network::Bitcoin.into(), // pick an arbitrary network here
/// depth: 0,
/// parent_fingerprint: bip32::Fingerprint::default(),
/// private_key: self.key_data.inner,
@ -717,7 +717,7 @@ impl<Ctx: ScriptContext> GeneratableKey<Ctx> for PrivateKey {
let inner = secp256k1::SecretKey::from_slice(&entropy)?;
let private_key = PrivateKey {
compressed: options.compressed,
network: Network::Bitcoin,
network: Network::Bitcoin.into(),
inner,
};
@ -847,9 +847,7 @@ impl<Ctx: ScriptContext> IntoDescriptorKey<Ctx> for DescriptorPublicKey {
fn into_descriptor_key(self) -> Result<DescriptorKey<Ctx>, KeyError> {
let networks = match self {
DescriptorPublicKey::Single(_) => any_network(),
DescriptorPublicKey::XPub(DescriptorXKey { xkey, .. })
if xkey.network == Network::Bitcoin =>
{
DescriptorPublicKey::XPub(DescriptorXKey { xkey, .. }) if xkey.network.is_mainnet() => {
mainnet_network()
}
_ => test_networks(),
@ -882,12 +880,8 @@ impl<Ctx: ScriptContext> IntoDescriptorKey<Ctx> for XOnlyPublicKey {
impl<Ctx: ScriptContext> IntoDescriptorKey<Ctx> for DescriptorSecretKey {
fn into_descriptor_key(self) -> Result<DescriptorKey<Ctx>, KeyError> {
let networks = match &self {
DescriptorSecretKey::Single(sk) if sk.key.network == Network::Bitcoin => {
mainnet_network()
}
DescriptorSecretKey::XPrv(DescriptorXKey { xkey, .. })
if xkey.network == Network::Bitcoin =>
{
DescriptorSecretKey::Single(sk) if sk.key.network.is_mainnet() => mainnet_network(),
DescriptorSecretKey::XPrv(DescriptorXKey { xkey, .. }) if xkey.network.is_mainnet() => {
mainnet_network()
}
_ => test_networks(),
@ -1003,6 +997,6 @@ pub mod test {
.unwrap();
let xprv = xkey.into_xprv(Network::Testnet).unwrap();
assert_eq!(xprv.network, Network::Testnet);
assert_eq!(xprv.network, Network::Testnet.into());
}
}

View File

@ -316,7 +316,7 @@ pub fn decide_change(remaining_amount: u64, fee_rate: FeeRate, drain_script: &Sc
let drain_val = remaining_amount.saturating_sub(change_fee);
if drain_val.is_dust(drain_script) {
let dust_threshold = drain_script.dust_value().to_sat();
let dust_threshold = drain_script.minimal_non_dust().to_sat();
Excess::NoChange {
dust_threshold,
change_fee,

View File

@ -164,7 +164,7 @@ impl FullyNodedExport {
fn check_ms<Ctx: ScriptContext>(
terminal: &Terminal<String, Ctx>,
) -> Result<(), &'static str> {
if let Terminal::Multi(_, _) = terminal {
if let Terminal::Multi(_) = terminal {
Ok(())
} else {
Err("The descriptor contains operators not supported by Bitcoin Core")

View File

@ -1177,7 +1177,7 @@ impl Wallet {
};
let mut changeset = ChangeSet::default();
let txid = tx.txid();
let txid = tx.compute_txid();
changeset.append(self.indexed_graph.insert_tx(tx).into());
if let Some(anchor) = anchor {
changeset.append(self.indexed_graph.insert_anchor(txid, anchor).into());
@ -1478,10 +1478,7 @@ impl Wallet {
let recipients = params.recipients.iter().map(|(r, v)| (r, *v));
for (index, (script_pubkey, value)) in recipients.enumerate() {
if !params.allow_dust
&& value.is_dust(script_pubkey)
&& !script_pubkey.is_provably_unspendable()
{
if !params.allow_dust && value.is_dust(script_pubkey) && !script_pubkey.is_op_return() {
return Err(CreateTxError::OutputBelowDustLimit(index));
}
@ -1635,7 +1632,7 @@ impl Wallet {
/// let tx = psbt.clone().extract_tx().expect("tx");
/// // broadcast tx but it's taking too long to confirm so we want to bump the fee
/// let mut psbt = {
/// let mut builder = wallet.build_fee_bump(tx.txid())?;
/// let mut builder = wallet.build_fee_bump(tx.compute_txid())?;
/// builder
/// .fee_rate(FeeRate::from_sat_per_vb(5).expect("valid feerate"));
/// builder.finish()?
@ -1673,7 +1670,9 @@ impl Wallet {
.iter()
.any(|txin| txin.sequence.to_consensus_u32() <= 0xFFFFFFFD)
{
return Err(BuildFeeBumpError::IrreplaceableTransaction(tx.txid()));
return Err(BuildFeeBumpError::IrreplaceableTransaction(
tx.compute_txid(),
));
}
let fee = self
@ -1704,7 +1703,8 @@ impl Wallet {
let satisfaction_weight = self
.get_descriptor_for_keychain(keychain)
.max_weight_to_satisfy()
.unwrap();
.unwrap()
.to_wu() as usize;
WeightedUtxo {
utxo: Utxo::Local(LocalOutput {
outpoint: txin.previous_output,
@ -2037,6 +2037,7 @@ impl Wallet {
self.get_descriptor_for_keychain(keychain)
.max_weight_to_satisfy()
.unwrap()
.to_wu() as usize
})
})
.collect()

View File

@ -91,7 +91,7 @@ use bitcoin::bip32::{ChildNumber, DerivationPath, Fingerprint, Xpriv};
use bitcoin::hashes::hash160;
use bitcoin::secp256k1::Message;
use bitcoin::sighash::{EcdsaSighashType, TapSighash, TapSighashType};
use bitcoin::{ecdsa, psbt, sighash, taproot};
use bitcoin::{ecdsa, psbt, sighash, taproot, transaction};
use bitcoin::{key::TapTweak, key::XOnlyPublicKey, secp256k1};
use bitcoin::{PrivateKey, Psbt, PublicKey};
@ -159,8 +159,12 @@ pub enum SignerError {
NonStandardSighash,
/// Invalid SIGHASH for the signing context in use
InvalidSighash,
/// Error while computing the hash to sign
SighashError(sighash::Error),
/// Error while computing the hash to sign a P2WPKH input.
SighashP2wpkh(sighash::P2wpkhError),
/// Error while computing the hash to sign a Taproot input.
SighashTaproot(sighash::TaprootError),
/// Error while computing the hash, out of bounds access on the transaction inputs.
TxInputsIndexError(transaction::InputsIndexError),
/// Miniscript PSBT error
MiniscriptPsbt(MiniscriptPsbtError),
/// To be used only by external libraries implementing [`InputSigner`] or
@ -169,9 +173,21 @@ pub enum SignerError {
External(String),
}
impl From<sighash::Error> for SignerError {
fn from(e: sighash::Error) -> Self {
SignerError::SighashError(e)
impl From<transaction::InputsIndexError> for SignerError {
fn from(v: transaction::InputsIndexError) -> Self {
Self::TxInputsIndexError(v)
}
}
impl From<sighash::P2wpkhError> for SignerError {
fn from(e: sighash::P2wpkhError) -> Self {
Self::SighashP2wpkh(e)
}
}
impl From<sighash::TaprootError> for SignerError {
fn from(e: sighash::TaprootError) -> Self {
Self::SighashTaproot(e)
}
}
@ -189,7 +205,9 @@ impl fmt::Display for SignerError {
Self::MissingHdKeypath => write!(f, "Missing fingerprint and derivation path"),
Self::NonStandardSighash => write!(f, "The psbt contains a non standard sighash"),
Self::InvalidSighash => write!(f, "Invalid SIGHASH for the signing context in use"),
Self::SighashError(err) => write!(f, "Error while computing the hash to sign: {}", err),
Self::SighashP2wpkh(err) => write!(f, "Error while computing the hash to sign a P2WPKH input: {}", err),
Self::SighashTaproot(err) => write!(f, "Error while computing the hash to sign a Taproot input: {}", err),
Self::TxInputsIndexError(err) => write!(f, "Error while computing the hash, out of bounds access on the transaction inputs: {}", err),
Self::MiniscriptPsbt(err) => write!(f, "Miniscript PSBT error: {}", err),
Self::External(err) => write!(f, "{}", err),
}
@ -549,21 +567,24 @@ fn sign_psbt_ecdsa(
secret_key: &secp256k1::SecretKey,
pubkey: PublicKey,
psbt_input: &mut psbt::Input,
hash: impl bitcoin::hashes::Hash + bitcoin::secp256k1::ThirtyTwoByteHash,
hash_ty: EcdsaSighashType,
hash: impl bitcoin::hashes::Hash<Bytes = [u8; 32]>,
sighash_type: EcdsaSighashType,
secp: &SecpCtx,
allow_grinding: bool,
) {
let msg = &Message::from(hash);
let sig = if allow_grinding {
let msg = &Message::from_digest(hash.to_byte_array());
let signature = if allow_grinding {
secp.sign_ecdsa_low_r(msg, secret_key)
} else {
secp.sign_ecdsa(msg, secret_key)
};
secp.verify_ecdsa(msg, &sig, &pubkey.inner)
secp.verify_ecdsa(msg, &signature, &pubkey.inner)
.expect("invalid or corrupted ecdsa signature");
let final_signature = ecdsa::Signature { sig, hash_ty };
let final_signature = ecdsa::Signature {
signature,
sighash_type,
};
psbt_input.partial_sigs.insert(pubkey, final_signature);
}
@ -574,7 +595,7 @@ fn sign_psbt_schnorr(
leaf_hash: Option<taproot::TapLeafHash>,
psbt_input: &mut psbt::Input,
hash: TapSighash,
hash_ty: TapSighashType,
sighash_type: TapSighashType,
secp: &SecpCtx,
) {
let keypair = secp256k1::Keypair::from_seckey_slice(secp, secret_key.as_ref()).unwrap();
@ -586,11 +607,14 @@ fn sign_psbt_schnorr(
};
let msg = &Message::from(hash);
let sig = secp.sign_schnorr(msg, &keypair);
secp.verify_schnorr(&sig, msg, &XOnlyPublicKey::from_keypair(&keypair).0)
let signature = secp.sign_schnorr(msg, &keypair);
secp.verify_schnorr(&signature, msg, &XOnlyPublicKey::from_keypair(&keypair).0)
.expect("invalid or corrupted schnorr signature");
let final_signature = taproot::Signature { sig, hash_ty };
let final_signature = taproot::Signature {
signature,
sighash_type,
};
if let Some(lh) = leaf_hash {
psbt_input
@ -933,7 +957,7 @@ impl ComputeSighash for Segwitv0 {
// Always try first with the non-witness utxo
let utxo = if let Some(prev_tx) = &psbt_input.non_witness_utxo {
// Check the provided prev-tx
if prev_tx.txid() != tx_input.previous_output.txid {
if prev_tx.compute_txid() != tx_input.previous_output.txid {
return Err(SignerError::InvalidNonWitnessUtxo);
}

View File

@ -295,7 +295,9 @@ impl<'a, Cs> TxBuilder<'a, Cs> {
for utxo in utxos {
let descriptor = wallet.get_descriptor_for_keychain(utxo.keychain);
let satisfaction_weight = descriptor.max_weight_to_satisfy().unwrap();
let satisfaction_weight =
descriptor.max_weight_to_satisfy().unwrap().to_wu() as usize;
self.params.utxos.push(WeightedUtxo {
satisfaction_weight,
utxo: Utxo::Local(utxo),
@ -385,9 +387,9 @@ impl<'a, Cs> TxBuilder<'a, Cs> {
if psbt_input.witness_utxo.is_none() {
match psbt_input.non_witness_utxo.as_ref() {
Some(tx) => {
if tx.txid() != outpoint.txid {
if tx.compute_txid() != outpoint.txid {
return Err(AddForeignUtxoError::InvalidTxid {
input_txid: tx.txid(),
input_txid: tx.compute_txid(),
foreign_utxo: outpoint,
});
}

View File

@ -10,7 +10,7 @@
// licenses.
use bitcoin::secp256k1::{All, Secp256k1};
use bitcoin::{absolute, Script, Sequence};
use bitcoin::{absolute, relative, Script, Sequence};
use miniscript::{MiniscriptKey, Satisfier, ToPublicKey};
@ -26,7 +26,7 @@ pub trait IsDust {
impl IsDust for u64 {
fn is_dust(&self, script: &Script) -> bool {
*self < script.dust_value().to_sat()
*self < script.minimal_non_dust().to_sat()
}
}
@ -95,7 +95,7 @@ impl Older {
}
impl<Pk: MiniscriptKey + ToPublicKey> Satisfier<Pk> for Older {
fn check_older(&self, n: Sequence) -> bool {
fn check_older(&self, n: relative::LockTime) -> bool {
if let Some(current_height) = self.current_height {
// TODO: test >= / >
current_height

View File

@ -46,7 +46,7 @@ pub fn get_funded_wallet_with_change(descriptor: &str, change: &str) -> (Wallet,
lock_time: bitcoin::absolute::LockTime::ZERO,
input: vec![TxIn {
previous_output: OutPoint {
txid: tx0.txid(),
txid: tx0.compute_txid(),
vout: 0,
},
script_sig: Default::default(),
@ -96,7 +96,7 @@ pub fn get_funded_wallet_with_change(descriptor: &str, change: &str) -> (Wallet,
)
.unwrap();
(wallet, tx1.txid())
(wallet, tx1.compute_txid())
}
/// Return a fake wallet that appears to be funded for testing.

View File

@ -45,7 +45,7 @@ fn receive_output(wallet: &mut Wallet, value: u64, height: ConfirmationTime) ->
wallet.insert_tx(tx.clone(), height).unwrap();
OutPoint {
txid: tx.txid(),
txid: tx.compute_txid(),
vout: 0,
}
}
@ -1151,7 +1151,7 @@ fn test_create_tx_add_utxo() {
builder
.add_recipient(addr.script_pubkey(), Amount::from_sat(30_000))
.add_utxo(OutPoint {
txid: small_output_tx.txid(),
txid: small_output_tx.compute_txid(),
vout: 0,
})
.unwrap();
@ -1202,7 +1202,7 @@ fn test_create_tx_manually_selected_insufficient() {
builder
.add_recipient(addr.script_pubkey(), Amount::from_sat(30_000))
.add_utxo(OutPoint {
txid: small_output_tx.txid(),
txid: small_output_tx.compute_txid(),
vout: 0,
})
.unwrap()
@ -1306,8 +1306,6 @@ fn test_create_tx_policy_path_ignored_subtree_with_csv() {
#[test]
fn test_create_tx_global_xpubs_with_origin() {
use bitcoin::bip32;
use bitcoin::hex::FromHex;
let (mut wallet, _) = get_funded_wallet("wpkh([73756c7f/48'/0'/0'/2']tpubDCKxNyM3bLgbEX13Mcd8mYxbVg9ajDkWXMh29hMWBurKfVmBfWAM96QVP3zaUcN51HvkZ3ar4VwP82kC8JZhhux8vFQoJintSpVBwpFvyU3/0/*)");
let addr = wallet.next_unused_address(KeychainKind::External).unwrap();
let mut builder = wallet.build_tx();
@ -1348,7 +1346,11 @@ fn test_add_foreign_utxo() {
builder
.add_recipient(addr.script_pubkey(), Amount::from_sat(60_000))
.only_witness_utxo()
.add_foreign_utxo(utxo.outpoint, psbt_input, foreign_utxo_satisfaction)
.add_foreign_utxo(
utxo.outpoint,
psbt_input,
foreign_utxo_satisfaction.to_wu() as usize,
)
.unwrap();
let mut psbt = builder.finish().unwrap();
wallet1.insert_txout(utxo.outpoint, utxo.txout);
@ -1399,7 +1401,7 @@ fn test_add_foreign_utxo() {
#[test]
#[should_panic(
expected = "MissingTxOut([OutPoint { txid: 0x21d7fb1bceda00ab4069fc52d06baa13470803e9050edd16f5736e5d8c4925fd, vout: 0 }])"
expected = "MissingTxOut([OutPoint { txid: 21d7fb1bceda00ab4069fc52d06baa13470803e9050edd16f5736e5d8c4925fd, vout: 0 }])"
)]
fn test_calculate_fee_with_missing_foreign_utxo() {
let (mut wallet1, _) = get_funded_wallet_wpkh();
@ -1424,7 +1426,11 @@ fn test_calculate_fee_with_missing_foreign_utxo() {
builder
.add_recipient(addr.script_pubkey(), Amount::from_sat(60_000))
.only_witness_utxo()
.add_foreign_utxo(utxo.outpoint, psbt_input, foreign_utxo_satisfaction)
.add_foreign_utxo(
utxo.outpoint,
psbt_input,
foreign_utxo_satisfaction.to_wu() as usize,
)
.unwrap();
let psbt = builder.finish().unwrap();
let tx = psbt.extract_tx().expect("failed to extract tx");
@ -1441,8 +1447,11 @@ fn test_add_foreign_utxo_invalid_psbt_input() {
.unwrap();
let mut builder = wallet.build_tx();
let result =
builder.add_foreign_utxo(outpoint, psbt::Input::default(), foreign_utxo_satisfaction);
let result = builder.add_foreign_utxo(
outpoint,
psbt::Input::default(),
foreign_utxo_satisfaction.to_wu() as usize,
);
assert!(matches!(result, Err(AddForeignUtxoError::MissingUtxo)));
}
@ -1470,7 +1479,7 @@ fn test_add_foreign_utxo_where_outpoint_doesnt_match_psbt_input() {
non_witness_utxo: Some(tx1.as_ref().clone()),
..Default::default()
},
satisfaction_weight
satisfaction_weight.to_wu() as usize
)
.is_err(),
"should fail when outpoint doesn't match psbt_input"
@ -1483,7 +1492,7 @@ fn test_add_foreign_utxo_where_outpoint_doesnt_match_psbt_input() {
non_witness_utxo: Some(tx2.as_ref().clone()),
..Default::default()
},
satisfaction_weight
satisfaction_weight.to_wu() as usize
)
.is_ok(),
"should be ok when outpoint does match psbt_input"
@ -1515,7 +1524,11 @@ fn test_add_foreign_utxo_only_witness_utxo() {
..Default::default()
};
builder
.add_foreign_utxo(utxo2.outpoint, psbt_input, satisfaction_weight)
.add_foreign_utxo(
utxo2.outpoint,
psbt_input,
satisfaction_weight.to_wu() as usize,
)
.unwrap();
assert!(
builder.finish().is_err(),
@ -1531,7 +1544,11 @@ fn test_add_foreign_utxo_only_witness_utxo() {
};
builder
.only_witness_utxo()
.add_foreign_utxo(utxo2.outpoint, psbt_input, satisfaction_weight)
.add_foreign_utxo(
utxo2.outpoint,
psbt_input,
satisfaction_weight.to_wu() as usize,
)
.unwrap();
assert!(
builder.finish().is_ok(),
@ -1547,7 +1564,11 @@ fn test_add_foreign_utxo_only_witness_utxo() {
..Default::default()
};
builder
.add_foreign_utxo(utxo2.outpoint, psbt_input, satisfaction_weight)
.add_foreign_utxo(
utxo2.outpoint,
psbt_input,
satisfaction_weight.to_wu() as usize,
)
.unwrap();
assert!(
builder.finish().is_ok(),
@ -1583,8 +1604,6 @@ fn test_create_tx_global_xpubs_origin_missing() {
#[test]
fn test_create_tx_global_xpubs_master_without_origin() {
use bitcoin::bip32;
use bitcoin::hex::FromHex;
let (mut wallet, _) = get_funded_wallet("wpkh(tpubD6NzVbkrYhZ4Y55A58Gv9RSNF5hy84b5AJqYy7sCcjFrkcLpPre8kmgfit6kY1Zs3BLgeypTDBZJM222guPpdz7Cup5yzaMu62u7mYGbwFL/0/*)");
let addr = wallet.next_unused_address(KeychainKind::External).unwrap();
let mut builder = wallet.build_tx();
@ -1613,7 +1632,7 @@ fn test_bump_fee_irreplaceable_tx() {
let psbt = builder.finish().unwrap();
let tx = psbt.extract_tx().expect("failed to extract tx");
let txid = tx.txid();
let txid = tx.compute_txid();
wallet
.insert_tx(tx, ConfirmationTime::Unconfirmed { last_seen: 0 })
.unwrap();
@ -1630,7 +1649,7 @@ fn test_bump_fee_confirmed_tx() {
let psbt = builder.finish().unwrap();
let tx = psbt.extract_tx().expect("failed to extract tx");
let txid = tx.txid();
let txid = tx.compute_txid();
wallet
.insert_tx(
@ -1657,7 +1676,7 @@ fn test_bump_fee_low_fee_rate() {
let feerate = psbt.fee_rate().unwrap();
let tx = psbt.extract_tx().expect("failed to extract tx");
let txid = tx.txid();
let txid = tx.compute_txid();
wallet
.insert_tx(tx, ConfirmationTime::Unconfirmed { last_seen: 0 })
@ -1690,7 +1709,7 @@ fn test_bump_fee_low_abs() {
let psbt = builder.finish().unwrap();
let tx = psbt.extract_tx().expect("failed to extract tx");
let txid = tx.txid();
let txid = tx.compute_txid();
wallet
.insert_tx(tx, ConfirmationTime::Unconfirmed { last_seen: 0 })
@ -1713,7 +1732,7 @@ fn test_bump_fee_zero_abs() {
let psbt = builder.finish().unwrap();
let tx = psbt.extract_tx().expect("failed to extract tx");
let txid = tx.txid();
let txid = tx.compute_txid();
wallet
.insert_tx(tx, ConfirmationTime::Unconfirmed { last_seen: 0 })
.unwrap();
@ -1739,7 +1758,7 @@ fn test_bump_fee_reduce_change() {
let original_fee = check_fee!(wallet, psbt);
let tx = psbt.extract_tx().expect("failed to extract tx");
let txid = tx.txid();
let txid = tx.compute_txid();
wallet
.insert_tx(tx, ConfirmationTime::Unconfirmed { last_seen: 0 })
.unwrap();
@ -1837,7 +1856,7 @@ fn test_bump_fee_reduce_single_recipient() {
let tx = psbt.clone().extract_tx().expect("failed to extract tx");
let original_sent_received = wallet.sent_and_received(&tx);
let original_fee = check_fee!(wallet, psbt);
let txid = tx.txid();
let txid = tx.compute_txid();
wallet
.insert_tx(tx, ConfirmationTime::Unconfirmed { last_seen: 0 })
.unwrap();
@ -1885,7 +1904,7 @@ fn test_bump_fee_absolute_reduce_single_recipient() {
let original_fee = check_fee!(wallet, psbt);
let tx = psbt.extract_tx().expect("failed to extract tx");
let original_sent_received = wallet.sent_and_received(&tx);
let txid = tx.txid();
let txid = tx.compute_txid();
wallet
.insert_tx(tx, ConfirmationTime::Unconfirmed { last_seen: 0 })
.unwrap();
@ -1949,7 +1968,7 @@ fn test_bump_fee_drain_wallet() {
builder
.drain_to(addr.script_pubkey())
.add_utxo(OutPoint {
txid: tx.txid(),
txid: tx.compute_txid(),
vout: 0,
})
.unwrap()
@ -1959,7 +1978,7 @@ fn test_bump_fee_drain_wallet() {
let tx = psbt.extract_tx().expect("failed to extract tx");
let original_sent_received = wallet.sent_and_received(&tx);
let txid = tx.txid();
let txid = tx.compute_txid();
wallet
.insert_tx(tx, ConfirmationTime::Unconfirmed { last_seen: 0 })
.unwrap();
@ -2011,7 +2030,7 @@ fn test_bump_fee_remove_output_manually_selected_only() {
)
.unwrap();
let outpoint = OutPoint {
txid: init_tx.txid(),
txid: init_tx.compute_txid(),
vout: 0,
};
let addr = Address::from_str("2N1Ffz3WaNzbeLFBb51xyFMHYSEUXcbiSoX")
@ -2027,7 +2046,7 @@ fn test_bump_fee_remove_output_manually_selected_only() {
let psbt = builder.finish().unwrap();
let tx = psbt.extract_tx().expect("failed to extract tx");
let original_sent_received = wallet.sent_and_received(&tx);
let txid = tx.txid();
let txid = tx.compute_txid();
wallet
.insert_tx(tx, ConfirmationTime::Unconfirmed { last_seen: 0 })
.unwrap();
@ -2074,7 +2093,7 @@ fn test_bump_fee_add_input() {
let psbt = builder.finish().unwrap();
let tx = psbt.extract_tx().expect("failed to extract tx");
let original_details = wallet.sent_and_received(&tx);
let txid = tx.txid();
let txid = tx.compute_txid();
wallet
.insert_tx(tx, ConfirmationTime::Unconfirmed { last_seen: 0 })
.unwrap();
@ -2131,7 +2150,7 @@ fn test_bump_fee_absolute_add_input() {
let psbt = builder.finish().unwrap();
let tx = psbt.extract_tx().expect("failed to extract tx");
let original_sent_received = wallet.sent_and_received(&tx);
let txid = tx.txid();
let txid = tx.compute_txid();
wallet
.insert_tx(tx, ConfirmationTime::Unconfirmed { last_seen: 0 })
.unwrap();
@ -2197,7 +2216,7 @@ fn test_bump_fee_no_change_add_input_and_change() {
let original_fee = check_fee!(wallet, psbt);
let tx = psbt.extract_tx().expect("failed to extract tx");
let txid = tx.txid();
let txid = tx.compute_txid();
wallet
.insert_tx(tx, ConfirmationTime::Unconfirmed { last_seen: 0 })
.unwrap();
@ -2267,7 +2286,7 @@ fn test_bump_fee_add_input_change_dust() {
let original_tx_weight = tx.weight();
assert_eq!(tx.input.len(), 1);
assert_eq!(tx.output.len(), 2);
let txid = tx.txid();
let txid = tx.compute_txid();
wallet
.insert_tx(tx, ConfirmationTime::Unconfirmed { last_seen: 0 })
.unwrap();
@ -2335,7 +2354,7 @@ fn test_bump_fee_force_add_input() {
let psbt = builder.finish().unwrap();
let mut tx = psbt.extract_tx().expect("failed to extract tx");
let original_sent_received = wallet.sent_and_received(&tx);
let txid = tx.txid();
let txid = tx.compute_txid();
for txin in &mut tx.input {
txin.witness.push([0x00; P2WPKH_FAKE_WITNESS_SIZE]); // fake signature
}
@ -2401,7 +2420,7 @@ fn test_bump_fee_absolute_force_add_input() {
let psbt = builder.finish().unwrap();
let mut tx = psbt.extract_tx().expect("failed to extract tx");
let original_sent_received = wallet.sent_and_received(&tx);
let txid = tx.txid();
let txid = tx.compute_txid();
// skip saving the new utxos, we know they can't be used anyways
for txin in &mut tx.input {
txin.witness.push([0x00; P2WPKH_FAKE_WITNESS_SIZE]); // fake signature
@ -2481,7 +2500,7 @@ fn test_bump_fee_unconfirmed_inputs_only() {
ConfirmationTime::Unconfirmed { last_seen: 0 },
);
let mut tx = psbt.extract_tx().expect("failed to extract tx");
let txid = tx.txid();
let txid = tx.compute_txid();
for txin in &mut tx.input {
txin.witness.push([0x00; P2WPKH_FAKE_WITNESS_SIZE]); // fake signature
}
@ -2514,7 +2533,7 @@ fn test_bump_fee_unconfirmed_input() {
.enable_rbf();
let psbt = builder.finish().unwrap();
let mut tx = psbt.extract_tx().expect("failed to extract tx");
let txid = tx.txid();
let txid = tx.compute_txid();
for txin in &mut tx.input {
txin.witness.push([0x00; P2WPKH_FAKE_WITNESS_SIZE]); // fake signature
}
@ -3386,7 +3405,11 @@ fn test_taproot_foreign_utxo() {
let mut builder = wallet1.build_tx();
builder
.add_recipient(addr.script_pubkey(), Amount::from_sat(60_000))
.add_foreign_utxo(utxo.outpoint, psbt_input, foreign_utxo_satisfaction)
.add_foreign_utxo(
utxo.outpoint,
psbt_input,
foreign_utxo_satisfaction.to_wu() as usize,
)
.unwrap();
let psbt = builder.finish().unwrap();
let sent_received =
@ -3890,7 +3913,10 @@ fn test_fee_rate_sign_no_grinding_high_r() {
.unwrap();
// We only have one key in the partial_sigs map, this is a trick to retrieve it
let key = psbt.inputs[0].partial_sigs.keys().next().unwrap();
sig_len = psbt.inputs[0].partial_sigs[key].sig.serialize_der().len();
sig_len = psbt.inputs[0].partial_sigs[key]
.signature
.serialize_der()
.len();
}
// Actually finalizing the transaction...
wallet
@ -3936,7 +3962,10 @@ fn test_fee_rate_sign_grinding_low_r() {
.unwrap();
let key = psbt.inputs[0].partial_sigs.keys().next().unwrap();
let sig_len = psbt.inputs[0].partial_sigs[key].sig.serialize_der().len();
let sig_len = psbt.inputs[0].partial_sigs[key]
.signature
.serialize_der()
.len();
assert_eq!(sig_len, 70);
assert_fee_rate!(psbt, fee.unwrap_or(Amount::ZERO), fee_rate);
}

View File

@ -643,7 +643,7 @@ where
match (broadcast)(chain_specific, &transaction) {
Ok(_) => {
println!("Broadcasted Tx : {}", transaction.txid());
println!("Broadcasted Tx : {}", transaction.compute_txid());
let keychain_changeset = graph.lock().unwrap().insert_tx(transaction);

View File

@ -94,7 +94,7 @@ fn main() -> Result<(), anyhow::Error> {
let tx = psbt.extract_tx()?;
client.transaction_broadcast(&tx)?;
println!("Tx broadcasted! Txid: {}", tx.txid());
println!("Tx broadcasted! Txid: {}", tx.compute_txid());
Ok(())
}

View File

@ -103,7 +103,7 @@ async fn main() -> Result<(), anyhow::Error> {
let tx = psbt.extract_tx()?;
client.broadcast(&tx).await?;
println!("Tx broadcasted! Txid: {}", tx.txid());
println!("Tx broadcasted! Txid: {}", tx.compute_txid());
Ok(())
}

View File

@ -80,7 +80,7 @@ fn main() -> Result<(), anyhow::Error> {
let tx = psbt.extract_tx()?;
client.broadcast(&tx)?;
println!("Tx broadcasted! Txid: {}", tx.txid());
println!("Tx broadcasted! Txid: {}", tx.compute_txid());
Ok(())
}

View File

@ -240,7 +240,7 @@ fn plan_steps<Ak: Clone + CanDerive, Ctx: ScriptContext>(
if max_sequence.is_height_locked() == older.is_height_locked() {
if max_sequence.to_consensus_u32() >= older.to_consensus_u32() {
Some(TermPlan {
min_sequence: Some(*older),
min_sequence: Some((*older).into()),
..Default::default()
})
} else {
@ -318,8 +318,8 @@ fn plan_steps<Ak: Clone + CanDerive, Ctx: ScriptContext>(
(lplan, rplan) => lplan.or(rplan),
}
}
Terminal::Thresh(_, _) => todo!(),
Terminal::Multi(_, _) => todo!(),
Terminal::MultiA(_, _) => todo!(),
Terminal::Thresh(_) => todo!(),
Terminal::Multi(_) => todo!(),
Terminal::MultiA(_) => todo!(),
}
}

View File

@ -87,20 +87,28 @@ pub enum RequiredSignatures<Ak> {
#[derive(Clone, Debug)]
pub enum SigningError {
SigHashError(sighash::Error),
SigHashP2wpkh(sighash::P2wpkhError),
SigHashTaproot(sighash::TaprootError),
DerivationError(bip32::Error),
}
impl From<sighash::Error> for SigningError {
fn from(e: sighash::Error) -> Self {
Self::SigHashError(e)
impl From<sighash::TaprootError> for SigningError {
fn from(v: sighash::TaprootError) -> Self {
Self::SigHashTaproot(v)
}
}
impl From<sighash::P2wpkhError> for SigningError {
fn from(v: sighash::P2wpkhError) -> Self {
Self::SigHashP2wpkh(v)
}
}
impl core::fmt::Display for SigningError {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
match self {
SigningError::SigHashError(e) => e.fmt(f),
SigningError::SigHashP2wpkh(e) => e.fmt(f),
SigningError::SigHashTaproot(e) => e.fmt(f),
SigningError::DerivationError(e) => e.fmt(f),
}
}
@ -170,8 +178,8 @@ impl RequiredSignatures<DescriptorPublicKey> {
let sig = secp.sign_schnorr_no_aux_rand(&msg, &keypair);
let bitcoin_sig = taproot::Signature {
sig,
hash_ty: schnorr_sighashty,
signature: sig,
sighash_type: schnorr_sighashty,
};
auth_data
@ -210,10 +218,10 @@ impl RequiredSignatures<DescriptorPublicKey> {
};
let keypair = Keypair::from_secret_key(&secp, &secret_key.clone());
let msg = Message::from_digest(sighash.to_byte_array());
let sig = secp.sign_schnorr_no_aux_rand(&msg, &keypair);
let signature = secp.sign_schnorr_no_aux_rand(&msg, &keypair);
let bitcoin_sig = taproot::Signature {
sig,
hash_ty: sighash_type,
signature,
sighash_type,
};
auth_data