- 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
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
# 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]
.graph
.txs
.iter()
- .map(|tx| tx.txid())
+ .map(|tx| tx.compute_txid())
.collect::<BTreeSet<Txid>>(),
exp_txids,
"changeset should have the 3 mempool transactions",
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,
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",
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",
let emitted_txids = emitter
.mempool()?
.into_iter()
- .map(|(tx, _)| tx.txid())
+ .map(|(tx, _)| tx.compute_txid())
.collect::<BTreeSet<_>>();
assert_eq!(
emitted_txids, exp_txids,
emitter
.mempool()?
.into_iter()
- .map(|(tx, _)| tx.txid())
+ .map(|(tx, _)| tx.compute_txid())
.collect::<BTreeSet<_>>(),
env.rpc_client()
.get_raw_mempool()?
let mempool = emitter
.mempool()?
.into_iter()
- .map(|(tx, _)| tx.txid())
+ .map(|(tx, _)| tx.compute_txid())
.collect::<BTreeSet<_>>();
let exp_mempool = tx_introductions
.iter()
let mempool = emitter
.mempool()?
.into_iter()
- .map(|(tx, _)| tx.txid())
+ .map(|(tx, _)| tx.compute_txid())
.collect::<BTreeSet<_>>();
let exp_mempool = tx_introductions
.iter()
# 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"
self.at_derivation_index(0)
.expect("descriptor can't have hardened derivation")
.script_pubkey()
- .dust_value()
+ .minimal_non_dust()
.to_sat()
}
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));
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
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);
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
}
/// 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) {
/// 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()),
/// 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,
/// 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,
&'g self,
tx: &'g Transaction,
) -> impl Iterator<Item = (usize, Txid)> + '_ {
- let txid = tx.txid();
+ let txid = tx.compute_txid();
tx.input
.iter()
.enumerate()
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)
}
) -> 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
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()
}
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"
);
// 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 {
// 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
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);
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)))
}
.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)
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)
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)
// 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 {
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!(
) = 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!(
// 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,
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!(
lock_time: absolute::LockTime::ZERO,
input: vec![TxIn {
previous_output: OutPoint {
- txid: tx1.txid(),
+ txid: tx1.compute_txid(),
vout: 0,
},
..Default::default()
// 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()
}
);
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()
}
);
);
assert_eq!(
- graph.tx_outputs(update_txs.txid()).expect("should exists"),
+ graph
+ .tx_outputs(update_txs.compute_txid())
+ .expect("should exists"),
[(
0u32,
&TxOut {
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()
}
);
};
let op = OutPoint {
- txid: tx1.txid(),
+ txid: tx1.compute_txid(),
vout: 0,
};
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));
}
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)
);
}
let changeset = tx_graph.insert_txout(
OutPoint {
- txid: tx.txid(),
+ txid: tx.compute_txid(),
vout: 0,
},
TxOut {
let _ = tx_graph.insert_txout(
OutPoint {
- txid: tx.txid(),
+ txid: tx.compute_txid(),
vout: 0,
},
TxOut {
assert_eq!(
tx_graph
.get_txout(OutPoint {
- txid: tx.txid(),
+ txid: tx.compute_txid(),
vout: 0
})
.unwrap()
);
assert_eq!(
tx_graph.get_txout(OutPoint {
- txid: tx.txid(),
+ txid: tx.compute_txid(),
vout: 1
}),
None
let _ = tx_graph.insert_txout(
OutPoint {
- txid: tx.txid(),
+ txid: tx.compute_txid(),
vout: 0,
},
TxOut {
let _ = tx_graph.insert_txout(
OutPoint {
- txid: tx.txid(),
+ txid: tx.compute_txid(),
vout: 0,
},
TxOut {
assert_eq!(
tx_graph
.get_txout(OutPoint {
- txid: tx.txid(),
+ txid: tx.compute_txid(),
vout: 0
})
.unwrap()
);
assert_eq!(
tx_graph.get_txout(OutPoint {
- txid: tx.txid(),
+ txid: tx.compute_txid(),
vout: 1
}),
None
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()
// 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],
// 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],
// 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],
// 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],
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()
},
],
// 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],
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()
},
],
// 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],
]);
[&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());
});
// 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,
// 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);
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],
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],
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()
},
],
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],
.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);
// 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![
// 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![
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,
// 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(),
// 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)
// 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)
// 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)
);
// 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());
}
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
[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 }
\ No newline at end of file
+bdk_testenv = { path = "../testenv", default-features = false }
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`:
[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 }
[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"]
[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"] }
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 })
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);
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(),
};
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>> =
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(),
};
[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"]
[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 }
$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)
(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 )* ) ) => ({
( 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 ),* )
( 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 ),* )
/// 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
}
}
-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)
}
}
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)
}
.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();
}
_ => {}
}
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;
.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 {
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;
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,
};
/// Relative timelock locktime
RelativeTimelock {
/// The timelock value
- value: Sequence,
+ value: relative::LockTime,
},
/// Multi-signature public keys with threshold count
Multisig {
Ok(Some(policy))
}
- fn make_multisig<Ctx: ScriptContext + 'static>(
- keys: &[DescriptorPublicKey],
+ fn make_multi<Ctx: ScriptContext + 'static>(
+ threshold: &Threshold<DescriptorPublicKey, MAX_PUBKEYS_PER_MULTISIG>,
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 {
let mut policy: Policy = SatisfiableItem::Multisig {
keys: parsed_keys,
- threshold,
+ threshold: threshold.k(),
}
.into();
policy.contribution = contribution;
Ok(Some(policy))
}
+ fn make_multi_a<Ctx: ScriptContext + 'static>(
+ threshold: &Threshold<DescriptorPublicKey, MAX_PUBKEYS_IN_CHECKSIGADD>,
+ signers: &SignersContainer,
+ build_sat: BuildSatisfaction,
+ sorted: bool,
+ secp: &SecpCtx,
+ ) -> Result<Option<Policy>, PolicyError> {
+ let parsed_keys = threshold.iter().map(|k| PkOrF::from_key(k, secp)).collect();
+
+ let mut contribution = Satisfaction::Partial {
+ n: threshold.n(),
+ m: threshold.k(),
+ items: vec![],
+ conditions: Default::default(),
+ sorted: Some(sorted),
+ };
+ let mut satisfaction = contribution.clone();
+
+ for (index, key) in threshold.iter().enumerate() {
+ if signers.find(signer_id(key, secp)).is_some() {
+ contribution.add(
+ &Satisfaction::Complete {
+ condition: Default::default(),
+ },
+ index,
+ )?;
+ }
+ if let Some(psbt) = build_sat.psbt() {
+ if Ctx::find_signature(psbt, key, secp) {
+ satisfaction.add(
+ &Satisfaction::Complete {
+ condition: Default::default(),
+ },
+ index,
+ )?;
+ }
+ }
+ }
+ satisfaction.finalize();
+ contribution.finalize();
+
+ let mut policy: Policy = SatisfiableItem::Multisig {
+ keys: parsed_keys,
+ threshold: threshold.k(),
+ }
+ .into();
+ policy.contribution = contribution;
+ policy.satisfaction = satisfaction;
+ Ok(Some(policy))
+ }
+
/// Return whether or not a specific path in the policy tree is required to unambiguously
/// create a transaction
///
timelock: Some(*value),
}),
SatisfiableItem::RelativeTimelock { value } => Ok(Condition {
- csv: Some(*value),
+ csv: Some((*value).into()),
timelock: None,
}),
_ => Ok(Condition::default()),
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 {
} = 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();
}
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>(threshold, signers, build_sat, false, secp)?
+ }
+ Terminal::MultiA(threshold) => {
+ Policy::make_multi_a::<Ctx>(threshold, signers, build_sat, false, secp)?
}
// Identities
Terminal::Alt(inner)
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))
.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
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>(
+ &threshold, signers, build_sat, true, secp,
)?)
}
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();
}
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();
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,
ExtendedKey::Public((xpub, _)) => xpub,
};
- xpub.network = network;
+ xpub.network = network.into();
xpub
}
}
/// 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,
/// 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,
let inner = secp256k1::SecretKey::from_slice(&entropy)?;
let private_key = PrivateKey {
compressed: options.compressed,
- network: Network::Bitcoin,
+ network: Network::Bitcoin.into(),
inner,
};
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(),
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(),
.unwrap();
let xprv = xkey.into_xprv(Network::Testnet).unwrap();
- assert_eq!(xprv.network, Network::Testnet);
+ assert_eq!(xprv.network, Network::Testnet.into());
}
}
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,
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")
};
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());
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));
}
/// 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()?
.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
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,
self.get_descriptor_for_keychain(keychain)
.max_weight_to_satisfy()
.unwrap()
+ .to_wu() as usize
})
})
.collect()
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};
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
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)
}
}
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),
}
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);
}
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();
};
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
// 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);
}
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),
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,
});
}
// licenses.
use bitcoin::secp256k1::{All, Secp256k1};
-use bitcoin::{absolute, Script, Sequence};
+use bitcoin::{absolute, relative, Script, Sequence};
use miniscript::{MiniscriptKey, Satisfier, ToPublicKey};
impl IsDust for u64 {
fn is_dust(&self, script: &Script) -> bool {
- *self < script.dust_value().to_sat()
+ *self < script.minimal_non_dust().to_sat()
}
}
}
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
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(),
)
.unwrap();
- (wallet, tx1.txid())
+ (wallet, tx1.compute_txid())
}
/// Return a fake wallet that appears to be funded for testing.
wallet.insert_tx(tx.clone(), height).unwrap();
OutPoint {
- txid: tx.txid(),
+ txid: tx.compute_txid(),
vout: 0,
}
}
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();
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()
#[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();
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);
#[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();
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");
.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)));
}
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"
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"
..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(),
};
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(),
..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(),
#[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();
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();
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(
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 })
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 })
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();
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();
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();
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();
builder
.drain_to(addr.script_pubkey())
.add_utxo(OutPoint {
- txid: tx.txid(),
+ txid: tx.compute_txid(),
vout: 0,
})
.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();
)
.unwrap();
let outpoint = OutPoint {
- txid: init_tx.txid(),
+ txid: init_tx.compute_txid(),
vout: 0,
};
let addr = Address::from_str("2N1Ffz3WaNzbeLFBb51xyFMHYSEUXcbiSoX")
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();
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();
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();
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();
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();
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
}
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
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
}
.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
}
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 =
.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
.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);
}
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);
let tx = psbt.extract_tx()?;
client.transaction_broadcast(&tx)?;
- println!("Tx broadcasted! Txid: {}", tx.txid());
+ println!("Tx broadcasted! Txid: {}", tx.compute_txid());
Ok(())
}
let tx = psbt.extract_tx()?;
client.broadcast(&tx).await?;
- println!("Tx broadcasted! Txid: {}", tx.txid());
+ println!("Tx broadcasted! Txid: {}", tx.compute_txid());
Ok(())
}
let tx = psbt.extract_tx()?;
client.broadcast(&tx)?;
- println!("Tx broadcasted! Txid: {}", tx.txid());
+ println!("Tx broadcasted! Txid: {}", tx.compute_txid());
Ok(())
}
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 {
(lplan, rplan) => lplan.or(rplan),
}
}
- Terminal::Thresh(_, _) => todo!(),
- Terminal::Multi(_, _) => todo!(),
- Terminal::MultiA(_, _) => todo!(),
+ Terminal::Thresh(_) => todo!(),
+ Terminal::Multi(_) => todo!(),
+ Terminal::MultiA(_) => todo!(),
}
}
#[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),
}
}
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
};
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