deps(bdk): bump bitcoin to 0.32.0, miniscript to 12.0.0

deps(chain): bump `bitcoin` to `0.32.0`, miniscript to `12.0.0`

fix(chain): use `minimal_non_dust()` instead of `dust_value()`

fix(chain): use `compute_txid()` instead of `txid`

deps(testenv): bump `electrsd` to `0.28.0`

deps(electrum): bump `electrum-client` to `0.20.0`

fix(electrum): use `compute_txid()` instead of `txid`

deps(esplora): bump `esplora-client` to `0.8.0`

deps(bitcoind_rpc): bump `bitcoin` to `0.32.0`, `bitcoincore-rpc` to
`0.19.0`

fix(bitcoind_rpc): use `compute_txid()` instead of `txid`

fix(nursery/tmp_plan): use proper `sighash` errors, and fix the expected
`Signature` fields

fix(sqlite): use `compute_txid()` instead of `txid`

deps(hwi): bump `hwi` to `0.9.0`

deps(wallet): bump `bitcoin` to `0.32.0`, miniscript to `12.0.0`

fix(wallet): use `compute_txid()` and `minimal_non_dust()`

- update to use `compute_txid()` instead of deprecated `txid()`
- update to use `minimal_non_dust()` instead of `dust_value()`
- remove unused `bitcoin::hex::FromHex`.

fix(wallet): uses `.into` conversion on `Network` for `NetworkKind`

- uses `.into()` when appropriate, otherwise use the explicit
  `NetworkKind`, and it's `.is_mainnet()` method.

fix(wallet): add P2wpkh, Taproot, InputsIndex errors to `SignerError`

fix(wallet): fields on taproot, and ecdsa `Signature` structure

fix(wallet/wallet): convert `Weight` to `usize` for now

- converts the `bitcoin-units::Weight` type to `usize` with help of
  `to_wu()` method.
- it should be updated/refactored in the future to handle the `Weight`
  type throughout the code instead of current `usize`, only converting
  it for now.
- allows the usage of deprecated `is_provably_unspendable()`, needs
  further discussion if suggested `is_op_return` is suitable.
- update the expect field to `signature`, as it was renamed from `sig`.

fix(wallet/wallet): use `is_op_return` instead of
`is_provably_unspendable`

fix(wallet/wallet): use `relative::Locktime` instead of `Sequence`

fix(wallet/descriptor): use `ParsePublicKeyError`

fix(wallet/descriptor): use `.into()` to convert from `AbsLockTime` and
`RelLockTime` to `absolute::LockTime` and `relative::LockTime`

fix(wallet/wallet): use `Message::from_digest()` instead of relying on
deprecated `ThirtyTwoByteHash` trait.

fix(wallet/descriptor+wallet): expect `Threshold` type, and handle it
internally

fix(wallet/wallet): remove `0x` prefix from expected `TxId` display

fix(examples): use `compute_txid()` instead of `txid`

fix(ci): remove usage of `bitcoin/no-std` feature

- remove comment: `# The `no-std` feature it's implied when the `std` feature is disabled.`
This commit is contained in:
Leonardo Lima
2024-05-22 18:34:30 -03:00
parent 473ef9714f
commit 2a4564097b
41 changed files with 480 additions and 302 deletions

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>(
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 {
@@ -635,7 +631,7 @@ impl Policy {
let mut policy: Policy = SatisfiableItem::Multisig {
keys: parsed_keys,
threshold,
threshold: threshold.k(),
}
.into();
policy.contribution = contribution;
@@ -644,6 +640,57 @@ impl Policy {
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
///
@@ -725,7 +772,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 +999,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 +1016,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,8 +1038,11 @@ 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>(threshold, signers, build_sat, false, secp)?
}
Terminal::MultiA(threshold) => {
Policy::make_multi_a::<Ctx>(threshold, signers, build_sat, false, secp)?
}
// Identities
Terminal::Alt(inner)
@@ -1016,8 +1071,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 +1083,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 +1143,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>(
&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