Skip to content

Commit

Permalink
bitcoin: Depend on tip of master
Browse files Browse the repository at this point in the history
  • Loading branch information
tcharding committed Mar 21, 2024
1 parent d18e8ff commit fde0d27
Show file tree
Hide file tree
Showing 10 changed files with 128 additions and 45 deletions.
35 changes: 31 additions & 4 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ edition = "2018"
[features]
default = ["std"]
std = ["bitcoin/std", "bitcoin/secp-recovery", "bech32/std"]
no-std = ["bitcoin/no-std", "bech32/alloc"]
no-std = ["bech32/alloc"]
compiler = []
trace = []

Expand All @@ -23,15 +23,15 @@ base64 = ["bitcoin/base64"]

[dependencies]
bech32 = { version = "0.11.0", default-features = false }
bitcoin = { version = "0.31.0", default-features = false }
bitcoin = { version = "0.32.0", default-features = false }

# Do NOT use this as a feature! Use the `serde` feature instead.
actual-serde = { package = "serde", version = "1.0.103", optional = true }

[dev-dependencies]
serde_test = "1.0.147"
bitcoin = { version = "0.31.0", features = ["base64"] }
secp256k1 = {version = "0.28.0", features = ["rand-std"]}
bitcoin = { version = "0.32.0", features = ["base64"] }
secp256k1 = {version = "0.29.0", features = ["rand-std"]}

[[example]]
name = "htlc"
Expand Down Expand Up @@ -64,3 +64,30 @@ required-features = ["std", "base64"]
[workspace]
members = ["bitcoind-tests", "fuzz"]
exclude = ["embedded"]

[patch.crates-io.secp256k1]
path = "/home/tobin/build/github.com/tcharding/rust-secp256k1/test-bitcoin"

[patch.crates-io.bitcoind]
path = "/home/tobin/build/github.com/tcharding/bitcoind/test-bitcoin"

[patch.crates-io.bitcoincore-rpc]
path = "/home/tobin/build/github.com/tcharding/rust-bitcoincore-rpc/test-bitcoin/client"

[patch.crates-io.base58ck]
path = "/home/tobin/build/github.com/tcharding/rust-bitcoin/release/base58"

[patch.crates-io.bitcoin]
path = "/home/tobin/build/github.com/tcharding/rust-bitcoin/release/bitcoin"

[patch.crates-io.bitcoin_hashes]
path = "/home/tobin/build/github.com/tcharding/rust-bitcoin/release/hashes"

[patch.crates-io.bitcoin-internals]
path = "/home/tobin/build/github.com/tcharding/rust-bitcoin/release/internals"

[patch.crates-io.bitcoin-io]
path = "/home/tobin/build/github.com/tcharding/rust-bitcoin/release/io"

[patch.crates-io.bitcoin-units]
path = "/home/tobin/build/github.com/tcharding/rust-bitcoin/release/units"
31 changes: 29 additions & 2 deletions bitcoind-tests/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,33 @@ publish = false

[dependencies]
miniscript = {path = "../"}
bitcoind = { version = "0.34.0" }
bitcoind = { version = "0.35.0" }
actual-rand = { package = "rand", version = "0.8.4"}
secp256k1 = {version = "0.28.0", features = ["rand-std"]}
secp256k1 = {version = "0.29.0", features = ["rand-std"]}

[patch.crates-io.secp256k1]
path = "/home/tobin/build/github.com/tcharding/rust-secp256k1/test-bitcoin"

[patch.crates-io.bitcoind]
path = "/home/tobin/build/github.com/tcharding/bitcoind/test-bitcoin"

[patch.crates-io.bitcoincore-rpc]
path = "/home/tobin/build/github.com/tcharding/rust-bitcoincore-rpc/test-bitcoin/client"

[patch.crates-io.base58ck]
path = "/home/tobin/build/github.com/tcharding/rust-bitcoin/release/base58"

[patch.crates-io.bitcoin]
path = "/home/tobin/build/github.com/tcharding/rust-bitcoin/release/bitcoin"

[patch.crates-io.bitcoin_hashes]
path = "/home/tobin/build/github.com/tcharding/rust-bitcoin/release/hashes"

[patch.crates-io.bitcoin-internals]
path = "/home/tobin/build/github.com/tcharding/rust-bitcoin/release/internals"

[patch.crates-io.bitcoin-io]
path = "/home/tobin/build/github.com/tcharding/rust-bitcoin/release/io"

[patch.crates-io.bitcoin-units]
path = "/home/tobin/build/github.com/tcharding/rust-bitcoin/release/units"
1 change: 0 additions & 1 deletion src/descriptor/key.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@ use core::str::FromStr;
use std::error;

use bitcoin::bip32::{self, XKeyIdentifier};
use bitcoin::hashes::hex::FromHex;
use bitcoin::hashes::{hash160, ripemd160, sha256, Hash, HashEngine};
use bitcoin::key::XOnlyPublicKey;
use bitcoin::secp256k1::{Secp256k1, Signing, Verification};
Expand Down
6 changes: 2 additions & 4 deletions src/descriptor/segwitv0.rs
Original file line number Diff line number Diff line change
Expand Up @@ -366,15 +366,13 @@ impl<Pk: MiniscriptKey> Wpkh<Pk> {
impl<Pk: MiniscriptKey + ToPublicKey> Wpkh<Pk> {
/// Obtains the corresponding script pubkey for this descriptor.
pub fn script_pubkey(&self) -> ScriptBuf {
let addr = Address::p2wpkh(&self.pk.to_public_key(), Network::Bitcoin)
.expect("wpkh descriptors have compressed keys");
let addr = Address::p2wpkh(&self.pk.to_compressed_public_key(), Network::Bitcoin);
addr.script_pubkey()
}

/// Obtains the corresponding script pubkey for this descriptor.
pub fn address(&self, network: Network) -> Address {
Address::p2wpkh(&self.pk.to_public_key(), network)
.expect("Rust Miniscript types don't allow uncompressed pks in segwit descriptors")
Address::p2wpkh(&self.pk.to_compressed_public_key(), network)
}

/// Obtains the underlying miniscript for this descriptor.
Expand Down
6 changes: 3 additions & 3 deletions src/interpreter/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -91,7 +91,7 @@ pub enum Error {
/// Schnorr Signature error
SchnorrSig(bitcoin::taproot::SigFromSliceError),
/// Errors in signature hash calculations
SighashError(bitcoin::sighash::Error),
SighashError(bitcoin::sighash::InvalidSighashTypeError),
/// Taproot Annex Unsupported
TapAnnexUnsupported,
/// An uncompressed public key was encountered in a context where it is
Expand Down Expand Up @@ -234,8 +234,8 @@ impl From<secp256k1::Error> for Error {
}

#[doc(hidden)]
impl From<bitcoin::sighash::Error> for Error {
fn from(e: bitcoin::sighash::Error) -> Error { Error::SighashError(e) }
impl From<bitcoin::sighash::InvalidSighashTypeError> for Error {
fn from(e: bitcoin::sighash::InvalidSighashTypeError) -> Error { Error::SighashError(e) }
}

#[doc(hidden)]
Expand Down
15 changes: 8 additions & 7 deletions src/interpreter/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -211,7 +211,7 @@ impl<'txin> Interpreter<'txin> {
KeySigPair::Ecdsa(key, ecdsa_sig) => {
let script_pubkey = self.script_code.as_ref().expect("Legacy have script code");
let msg = if self.is_legacy() {
let sighash_u32 = ecdsa_sig.hash_ty.to_u32();
let sighash_u32 = ecdsa_sig.sighash_type.to_u32();
let sighash =
cache.legacy_signature_hash(input_idx, script_pubkey, sighash_u32);
sighash.map(|hash| secp256k1::Message::from_digest(hash.to_byte_array()))
Expand All @@ -220,11 +220,12 @@ impl<'txin> Interpreter<'txin> {
Some(txout) => txout.borrow().value,
None => return false,
};
let sighash = cache.segwit_signature_hash(
// TODO: Don't manually handle the script code.
let sighash = cache.p2wsh_signature_hash(
input_idx,
script_pubkey,
amt,
ecdsa_sig.hash_ty,
ecdsa_sig.sighash_type,
);
sighash.map(|hash| secp256k1::Message::from_digest(hash.to_byte_array()))
} else {
Expand All @@ -233,12 +234,12 @@ impl<'txin> Interpreter<'txin> {
};

let success =
msg.map(|msg| secp.verify_ecdsa(&msg, &ecdsa_sig.sig, &key.inner).is_ok());
msg.map(|msg| secp.verify_ecdsa(&msg, &ecdsa_sig.signature, &key.inner).is_ok());
success.unwrap_or(false) // unwrap_or checks for errors, while success would have checksig results
}
KeySigPair::Schnorr(xpk, schnorr_sig) => {
let sighash_msg = if self.is_taproot_v1_key_spend() {
cache.taproot_key_spend_signature_hash(input_idx, prevouts, schnorr_sig.hash_ty)
cache.taproot_key_spend_signature_hash(input_idx, prevouts, schnorr_sig.sighash_type)
} else if self.is_taproot_v1_script_spend() {
let tap_script = self.script_code.as_ref().expect(
"Internal Hack: Saving leaf script instead\
Expand All @@ -252,7 +253,7 @@ impl<'txin> Interpreter<'txin> {
input_idx,
prevouts,
leaf_hash,
schnorr_sig.hash_ty,
schnorr_sig.sighash_type,
)
} else {
// schnorr sigs in ecdsa descriptors
Expand All @@ -261,7 +262,7 @@ impl<'txin> Interpreter<'txin> {
let msg =
sighash_msg.map(|hash| secp256k1::Message::from_digest(hash.to_byte_array()));
let success =
msg.map(|msg| secp.verify_schnorr(&schnorr_sig.sig, &msg, xpk).is_ok());
msg.map(|msg| secp.verify_schnorr(&schnorr_sig.signature, &msg, xpk).is_ok());
success.unwrap_or(false) // unwrap_or_default checks for errors, while success would have checksig results
}
}
Expand Down
24 changes: 20 additions & 4 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -217,6 +217,13 @@ pub trait ToPublicKey: MiniscriptKey {
/// Converts an object to a public key
fn to_public_key(&self) -> bitcoin::PublicKey;

/// Converts an object to a compressed public key.
fn to_compressed_public_key(&self) -> bitcoin::CompressedPublicKey {
use core::convert::TryFrom;
// TODO: Can we remove to_public_key altogether?
bitcoin::key::CompressedPublicKey::try_from(self.to_public_key()).expect("for now just panic for uncompressed keys")
}

/// Convert an object to x-only pubkey
fn to_x_only_pubkey(&self) -> bitcoin::secp256k1::XOnlyPublicKey {
let pk = self.to_public_key();
Expand Down Expand Up @@ -423,7 +430,9 @@ pub enum Error {
/// rust-bitcoin script error
Script(script::Error),
/// rust-bitcoin address error
AddrError(bitcoin::address::Error),
AddrError(bitcoin::address::ParseError),
/// rust-bitcoin p2sh address error
AddrP2shError(bitcoin::address::P2shError),
/// A `CHECKMULTISIG` opcode was preceded by a number > 20
CmsTooManyKeys(u32),
/// A tapscript multi_a cannot support more than Weight::MAX_BLOCK/32 keys
Expand Down Expand Up @@ -451,7 +460,7 @@ pub enum Error {
/// Parsed a miniscript but there were more script opcodes after it
Trailing(String),
/// Failed to parse a push as a public key
BadPubkey(bitcoin::key::Error),
BadPubkey(bitcoin::key::ParsePublicKeyError),
/// Could not satisfy a script (fragment) because of a missing hash preimage
MissingHash(sha256::Hash),
/// Could not satisfy a script (fragment) because of a missing signature
Expand Down Expand Up @@ -518,6 +527,7 @@ impl fmt::Display for Error {
},
Error::Script(ref e) => fmt::Display::fmt(e, f),
Error::AddrError(ref e) => fmt::Display::fmt(e, f),
Error::AddrP2shError(ref e) => fmt::Display::fmt(e, f),
Error::CmsTooManyKeys(n) => write!(f, "checkmultisig with {} keys", n),
Error::Unprintable(x) => write!(f, "unprintable character 0x{:02x}", x),
Error::ExpectedChar(c) => write!(f, "expected {}", c),
Expand Down Expand Up @@ -621,6 +631,7 @@ impl error::Error for Error {
| MultipathDescLenMismatch => None,
Script(e) => Some(e),
AddrError(e) => Some(e),
AddrP2shError(e) => Some(e),
BadPubkey(e) => Some(e),
Secp(e) => Some(e),
#[cfg(feature = "compiler")]
Expand Down Expand Up @@ -664,8 +675,13 @@ impl From<bitcoin::secp256k1::Error> for Error {
}

#[doc(hidden)]
impl From<bitcoin::address::Error> for Error {
fn from(e: bitcoin::address::Error) -> Error { Error::AddrError(e) }
impl From<bitcoin::address::ParseError> for Error {
fn from(e: bitcoin::address::ParseError) -> Error { Error::AddrError(e) }
}

#[doc(hidden)]
impl From<bitcoin::address::P2shError> for Error {
fn from(e: bitcoin::address::P2shError) -> Error { Error::AddrP2shError(e) }
}

#[doc(hidden)]
Expand Down
2 changes: 1 addition & 1 deletion src/miniscript/decode.rs
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ impl ParseableKey for bitcoin::secp256k1::XOnlyPublicKey {
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum KeyParseError {
/// Bitcoin PublicKey parse error
FullKeyParseError(bitcoin::key::Error),
FullKeyParseError(bitcoin::key::FromSliceError),
/// Xonly key parse Error
XonlyKeyParseError(bitcoin::secp256k1::Error),
}
Expand Down
10 changes: 6 additions & 4 deletions src/psbt/finalizer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -182,10 +182,11 @@ fn get_descriptor(psbt: &Psbt, index: usize) -> Result<Descriptor<PublicKey>, In
} else if script_pubkey.is_p2wpkh() {
// 3. `Wpkh`: creates a `wpkh` descriptor if the partial sig has corresponding pk.
let partial_sig_contains_pk = inp.partial_sigs.iter().find(|&(&pk, _sig)| {
use core::convert::TryFrom;
let compressed = bitcoin::key::CompressedPublicKey::try_from(pk).expect("TODO: Handle compressed key");
// Indirect way to check the equivalence of pubkey-hashes.
// Create a pubkey hash and check if they are the same.
let addr = bitcoin::Address::p2wpkh(&pk, bitcoin::Network::Bitcoin)
.expect("Address corresponding to valid pubkey");
let addr = bitcoin::Address::p2wpkh(&compressed, bitcoin::Network::Bitcoin);
*script_pubkey == addr.script_pubkey()
});
match partial_sig_contains_pk {
Expand Down Expand Up @@ -242,8 +243,9 @@ fn get_descriptor(psbt: &Psbt, index: usize) -> Result<Descriptor<PublicKey>, In
} else if redeem_script.is_p2wpkh() {
// 6. `ShWpkh` case
let partial_sig_contains_pk = inp.partial_sigs.iter().find(|&(&pk, _sig)| {
let addr = bitcoin::Address::p2wpkh(&pk, bitcoin::Network::Bitcoin)
.expect("Address corresponding to valid pubkey");
use core::convert::TryFrom;
let compressed = bitcoin::key::CompressedPublicKey::try_from(pk).expect("TODO: Handle compressed key");
let addr = bitcoin::Address::p2wpkh(&compressed, bitcoin::Network::Bitcoin);
*redeem_script == addr.script_pubkey()
});
match partial_sig_contains_pk {
Expand Down
43 changes: 28 additions & 15 deletions src/psbt/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -86,7 +86,7 @@ pub enum InputError {
/// Get the secp Errors directly
SecpErr(bitcoin::secp256k1::Error),
/// Key errors
KeyErr(bitcoin::key::Error),
KeyErr(bitcoin::key::FromSliceError),
/// Could not satisfy taproot descriptor
/// This error is returned when both script path and key paths could not be
/// satisfied. We cannot return a detailed error because we try all miniscripts
Expand Down Expand Up @@ -229,8 +229,8 @@ impl From<bitcoin::secp256k1::Error> for InputError {
}

#[doc(hidden)]
impl From<bitcoin::key::Error> for InputError {
fn from(e: bitcoin::key::Error) -> InputError { InputError::KeyErr(e) }
impl From<bitcoin::key::FromSliceError> for InputError {
fn from(e: bitcoin::key::FromSliceError) -> InputError { InputError::KeyErr(e) }
}

/// Psbt satisfier for at inputs at a particular index
Expand Down Expand Up @@ -399,7 +399,7 @@ fn sanity_check(psbt: &Psbt) -> Result<(), Error> {
None => sighash::EcdsaSighashType::All,
};
for (key, ecdsa_sig) in &input.partial_sigs {
let flag = sighash::EcdsaSighashType::from_standard(ecdsa_sig.hash_ty as u32).map_err(
let flag = sighash::EcdsaSighashType::from_standard(ecdsa_sig.sighash_type as u32).map_err(
|_| {
Error::InputError(
InputError::Interpreter(interpreter::Error::NonStandardSighash(
Expand Down Expand Up @@ -740,7 +740,7 @@ impl PsbtExt for Psbt {
let desc_type = desc.desc_type();

if let Some(non_witness_utxo) = &input.non_witness_utxo {
if txin.previous_output.txid != non_witness_utxo.txid() {
if txin.previous_output.txid != non_witness_utxo.compute_txid() {
return Err(UtxoUpdateError::UtxoCheck);
}
}
Expand Down Expand Up @@ -1313,10 +1313,12 @@ pub enum SighashError {
MissingSpendUtxos,
/// Invalid Sighash type
InvalidSighashType,
/// Sighash computation error
/// Only happens when single does not have corresponding output as psbts
/// already have information to compute the sighash
SighashComputationError(sighash::Error),
/// Computation error for taproot sighash.
SighashTaproot(sighash::TaprootError),
/// Computation error for P2WPKH sighash.
SighashP2wpkh(sighash::P2wpkhError),
/// Computation error for P2WSH sighash.
TransactionInputsIndex(transaction::InputsIndexError),
/// Missing Witness script
MissingWitnessScript,
/// Missing Redeem script,
Expand All @@ -1332,11 +1334,11 @@ impl fmt::Display for SighashError {
SighashError::MissingInputUtxo => write!(f, "Missing input utxo in pbst"),
SighashError::MissingSpendUtxos => write!(f, "Missing Psbt spend utxos"),
SighashError::InvalidSighashType => write!(f, "Invalid Sighash type"),
SighashError::SighashComputationError(e) => {
write!(f, "Sighash computation error : {}", e)
}
SighashError::MissingWitnessScript => write!(f, "Missing Witness Script"),
SighashError::MissingRedeemScript => write!(f, "Missing Redeem Script"),
SighashError::SighashTaproot(ref e) => write!(f, "sighash taproot: {}", e),
SighashError::SighashP2wpkh(ref e) => write!(f, "sighash p2wpkh: {}", e),
SighashError::TransactionInputsIndex(ref e) => write!(f, "tx inputs index: {}", e),
}
}
}
Expand All @@ -1353,13 +1355,24 @@ impl error::Error for SighashError {
| InvalidSighashType
| MissingWitnessScript
| MissingRedeemScript => None,
SighashComputationError(e) => Some(e),
SighashTaproot(ref e) => Some(e),
SighashP2wpkh(ref e) => Some(e),
TransactionInputsIndex(ref e) => Some(e),

}
}
}

impl From<sighash::Error> for SighashError {
fn from(e: sighash::Error) -> Self { SighashError::SighashComputationError(e) }
impl From<sighash::TaprootError> for SighashError {
fn from(e: sighash::TaprootError) -> Self { SighashError::SighashTaproot(e) }
}

impl From<sighash::P2wpkhError> for SighashError {
fn from(e: sighash::P2wpkhError) -> Self { SighashError::SighashP2wpkh(e) }
}

impl From<transaction::InputsIndexError> for SighashError {
fn from(e: transaction::InputsIndexError) -> Self { SighashError::TransactionInputsIndex(e) }
}

/// Sighash message(signing data) for a given psbt transaction input.
Expand Down

0 comments on commit fde0d27

Please sign in to comment.