Skip to content

Commit

Permalink
Upgrade to latest bitcoin
Browse files Browse the repository at this point in the history
Includes upgrade to:

- bitcoin v0.32.2
- miniscript v12.2.0
- secp256k1 v0.29.0
- bitcoin-internals v0.3.0

To upgrade we need to make the v0 module mirror the code in
rust-bitcoin::psbt, by diffing the files that is reasonably easy to do
and only slightly error prone - would be great if someone else would
diff and view as well.

It gets wild in the v2 module because we copied code from the v0
module then modified it for PSBT v2. All changes to the v2 module need
going over very carefully.
  • Loading branch information
tcharding committed Aug 22, 2024
1 parent d3d1f86 commit 001000d
Show file tree
Hide file tree
Showing 25 changed files with 502 additions and 268 deletions.
23 changes: 12 additions & 11 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -18,31 +18,29 @@ rustdoc-args = ["--cfg", "docsrs"]

[features]
default = ["std"]
std = ["bitcoin/std"]
no-std = ["bitcoin/no-std", "core2"]
serde = ["actual-serde", "bitcoin/serde"]
std = ["bitcoin/std", "bitcoin-internals/std"]
rand-std = ["bitcoin/rand-std", "std"]
rand = ["bitcoin/rand"]
serde = ["actual-serde", "bitcoin/serde", "bitcoin-internals/serde"]
base64 = ["bitcoin/base64"]

miniscript-std = ["std", "miniscript/std"]
miniscript-no-std = ["no-std", "miniscript/no-std"]

[dependencies]
bitcoin = { version = "0.31.0", default-features = false }
bitcoin = { version = "0.32.2", default-features = false }
bitcoin-internals = { version = "0.3.0", features = ["alloc"] }

# Do not use this feature, use "miniscript-std" or "miniscript-no-std" instead.
miniscript = { version = "11.0.0", default-features = false, optional = true }
# Only use this feature if you are doing a no-std build, othewise use "miniscript-std".
miniscript = { version = "12.2.0", default-features = false, optional = true }
# Do NOT use this as a feature! Use the `serde` feature instead.
actual-serde = { package = "serde", version = "1.0.103", default-features = false, features = [ "derive", "alloc" ], optional = true }
# There is no reason to use this dependency directly, it is activated by the "no-std" feature.
core2 = { version = "0.3.2", default-features = false, features = ["alloc"], optional = true }

[dev-dependencies]
anyhow = "1"
serde_json = "1.0.0"
serde_test = "1.0.19"
serde_derive = "1.0.103"
bincode = "1.3.1"
secp256k1 = { version = "0.28", features = ["rand-std", "global-context"] }
secp256k1 = { version = "0.29", features = ["rand-std", "global-context"] }

[[example]]
name = "v0"
Expand All @@ -55,3 +53,6 @@ required-features = ["std"]
[[example]]
name = "v2-separate-creator-constructor"
required-features = ["std"]

[lints.rust]
unexpected_cfgs = { level = "deny", check-cfg = ['cfg(rust_v_1_60)'] }
9 changes: 5 additions & 4 deletions examples/v0.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,8 @@ use psbt_v2::bitcoin::locktime::absolute;
use psbt_v2::bitcoin::opcodes::all::OP_CHECKMULTISIG;
use psbt_v2::bitcoin::secp256k1::{self, rand, SECP256K1};
use psbt_v2::bitcoin::{
script, transaction, Address, Amount, Network, OutPoint, PublicKey, ScriptBuf, Sequence,
Transaction, TxIn, TxOut, Txid, Witness,
script, transaction, Address, Amount, CompressedPublicKey, Network, OutPoint, PublicKey,
ScriptBuf, Sequence, Transaction, TxIn, TxOut, Txid, Witness,
};
use psbt_v2::v0::{self, Psbt};

Expand Down Expand Up @@ -126,8 +126,9 @@ impl Alice {
let out = OutPoint { txid: Txid::all_zeros(), vout: 0 };

// The usual caveat about reusing addresses applies here, this is just an example.
let address =
Address::p2wpkh(&self.public_key(), Network::Bitcoin).expect("uncompressed key");
let compressed =
CompressedPublicKey::try_from(self.public_key()).expect("uncompressed key");
let address = Address::p2wpkh(&compressed, Network::Bitcoin);

// This is a made up value, it is supposed to represent the outpoints value minus the value
// contributed to the multisig.
Expand Down
10 changes: 6 additions & 4 deletions examples/v2.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,8 @@ use psbt_v2::bitcoin::locktime::absolute;
use psbt_v2::bitcoin::opcodes::all::OP_CHECKMULTISIG;
use psbt_v2::bitcoin::secp256k1::{self, SECP256K1};
use psbt_v2::bitcoin::{
script, Address, Amount, Network, OutPoint, PublicKey, ScriptBuf, Sequence, TxOut, Txid,
script, Address, Amount, CompressedPublicKey, Network, OutPoint, PublicKey, ScriptBuf,
Sequence, TxOut, Txid,
};
use psbt_v2::v2::{
self, Constructor, InputBuilder, Modifiable, Output, OutputBuilder, Psbt, Signer, Updater,
Expand Down Expand Up @@ -147,8 +148,9 @@ impl Alice {
let out = OutPoint { txid: Txid::all_zeros(), vout: 0 };

// The usual caveat about reusing addresses applies here, this is just an example.
let address = Address::p2wpkh(&self.multisig_public_key()?, Network::Bitcoin)
.expect("uncompressed key");
let compressed =
CompressedPublicKey::try_from(self.multisig_public_key()?).expect("uncompressed key");
let address = Address::p2wpkh(&compressed, Network::Bitcoin);

// This is a made up value, it is supposed to represent the outpoints value minus the value
// contributed to the multisig.
Expand Down Expand Up @@ -250,7 +252,7 @@ impl Entity {
let path = DerivationPath::from_str(derivation_path)?;
let xpriv = self.master.derive_priv(SECP256K1, &path)?;
let pk = Xpub::from_priv(SECP256K1, &xpriv);
Ok(pk.to_pub())
Ok(pk.to_pub().into())
}

/// Returns a dummy utxo that we can spend.
Expand Down
4 changes: 4 additions & 0 deletions justfile
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,10 @@ test:
lint:
cargo clippy --all --all-targets --all-features -- --deny warnings

# Run the formatter
fmt:
cargo +nightly fmt --all

# Check the formatting
format:
cargo +nightly fmt --all --check
2 changes: 1 addition & 1 deletion rustfmt.toml
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,7 @@ color = "Auto"
unstable_features = false
disable_all_formatting = false
skip_children = false
hide_parse_errors = false
show_parse_errors = true
error_on_line_overflow = false
error_on_unformatted = false
emit_mode = "Files"
Expand Down
9 changes: 1 addition & 8 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,9 +14,6 @@
// Coding conventions
#![warn(missing_docs)]

#[cfg(not(any(feature = "std", feature = "no-std")))]
compile_error!("at least one of the `std` or `no-std` features must be enabled");

#[macro_use]
extern crate alloc;

Expand Down Expand Up @@ -48,11 +45,7 @@ pub mod v0;
pub mod v2;
mod version;

#[cfg(feature = "std")]
use std::io;

#[cfg(not(feature = "std"))]
use core2::io;
use bitcoin::io;

#[rustfmt::skip] // Keep pubic re-exports separate
#[doc(inline)]
Expand Down
33 changes: 11 additions & 22 deletions src/raw.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,9 +18,10 @@ use bitcoin::consensus::encode::{
};
use bitcoin::hex::DisplayHex;

use crate::io::{self, BufRead, Write};
use crate::prelude::*;
use crate::serialize;
use crate::serialize::{Deserialize, Serialize};
use crate::{io, serialize};

/// A PSBT key-value pair in its raw byte form.
///
Expand All @@ -39,7 +40,7 @@ pub struct Pair {
}

impl Pair {
pub(crate) fn decode<R: io::Read + ?Sized>(r: &mut R) -> Result<Self, serialize::Error> {
pub(crate) fn decode<R: BufRead + ?Sized>(r: &mut R) -> Result<Self, serialize::Error> {
Ok(Pair { key: Key::decode(r)?, value: Decodable::consensus_decode(r)? })
}
}
Expand Down Expand Up @@ -80,13 +81,12 @@ pub struct Key {
/// The `keytype` of this PSBT map key (`keytype`).
pub type_value: u8,
/// The `keydata` itself in raw byte form.
// TODO: Consider renaming to `data`.
#[cfg_attr(feature = "serde", serde(with = "crate::serde_utils::hex_bytes"))]
pub key: Vec<u8>,
}

impl Key {
pub(crate) fn decode<R: io::Read + ?Sized>(r: &mut R) -> Result<Self, serialize::Error> {
pub(crate) fn decode<R: BufRead + ?Sized>(r: &mut R) -> Result<Self, serialize::Error> {
let VarInt(byte_size): VarInt = Decodable::consensus_decode(r)?;

if byte_size == 0 {
Expand Down Expand Up @@ -186,7 +186,7 @@ impl<Subtype> Encodable for ProprietaryKey<Subtype>
where
Subtype: Copy + From<u8> + Into<u8>,
{
fn consensus_encode<W: io::Write + ?Sized>(&self, w: &mut W) -> Result<usize, io::Error> {
fn consensus_encode<W: Write + ?Sized>(&self, w: &mut W) -> Result<usize, io::Error> {
let mut len = self.prefix.consensus_encode(w)? + 1;
w.emit_u8(self.subtype.into())?;
w.write_all(&self.key)?;
Expand All @@ -199,26 +199,15 @@ impl<Subtype> Decodable for ProprietaryKey<Subtype>
where
Subtype: Copy + From<u8> + Into<u8>,
{
fn consensus_decode<R: io::Read + ?Sized>(r: &mut R) -> Result<Self, consensus::Error> {
fn consensus_decode<R: BufRead + ?Sized>(r: &mut R) -> Result<Self, consensus::Error> {
let prefix = Vec::<u8>::consensus_decode(r)?;
let subtype = Subtype::from(r.read_u8()?);
let key = read_to_end(r)?;

Ok(ProprietaryKey { prefix, subtype, key })
}
}
// The limit is a DOS protection mechanism the exact value is not
// important, 1024 bytes is bigger than any key should be.
let mut key = vec![];
let _ = r.read_to_limit(&mut key, 1024)?;

// core2 doesn't have read_to_end
pub(crate) fn read_to_end<D: io::Read>(mut d: D) -> Result<Vec<u8>, io::Error> {
let mut result = vec![];
let mut buf = [0u8; 64];
loop {
match d.read(&mut buf) {
Ok(0) => break,
Ok(n) => result.extend_from_slice(&buf[0..n]),
Err(ref e) if e.kind() == io::ErrorKind::Interrupted => {}
Err(e) => return Err(e),
};
Ok(ProprietaryKey { prefix, subtype, key })
}
Ok(result)
}
8 changes: 4 additions & 4 deletions src/serialize.rs
Original file line number Diff line number Diff line change
Expand Up @@ -389,7 +389,7 @@ pub enum Error {
/// Serialization error in bitcoin consensus-encoded structures
ConsensusEncoding(consensus::encode::Error),
/// Parsing error indicating invalid public keys
InvalidPublicKey(bitcoin::key::Error),
InvalidPublicKey(bitcoin::key::FromSliceError),
/// Parsing error indicating invalid secp256k1 public keys
InvalidSecp256k1PublicKey(secp256k1::Error),
/// Parsing error indicating invalid xonly public keys
Expand All @@ -410,7 +410,7 @@ pub enum Error {
/// PSBT data is not consumed entirely
PartialDataConsumption,
/// Couldn't converting parsed u32 to a lock time.
LockTime(absolute::Error),
LockTime(absolute::ConversionError),
/// Unsupported PSBT version.
UnsupportedVersion(version::UnsupportedVersionError),
}
Expand Down Expand Up @@ -480,8 +480,8 @@ impl From<consensus::encode::Error> for Error {
fn from(e: consensus::encode::Error) -> Self { Self::ConsensusEncoding(e) }
}

impl From<absolute::Error> for Error {
fn from(e: absolute::Error) -> Self { Self::LockTime(e) }
impl From<absolute::ConversionError> for Error {
fn from(e: absolute::ConversionError) -> Self { Self::LockTime(e) }
}

impl From<version::UnsupportedVersionError> for Error {
Expand Down
6 changes: 3 additions & 3 deletions src/v0/bitcoin/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,7 @@ pub enum Error {
/// Integer overflow in fee calculation
FeeOverflow,
/// Parsing error indicating invalid public keys
InvalidPublicKey(bitcoin::key::Error),
InvalidPublicKey(bitcoin::key::FromSliceError),
/// Parsing error indicating invalid secp256k1 public keys
InvalidSecp256k1PublicKey(secp256k1::Error),
/// Parsing error indicating invalid xonly public keys
Expand Down Expand Up @@ -133,8 +133,8 @@ impl fmt::Display for Error {
UnexpectedUnsignedTx { expected: ref e, actual: ref a } => write!(
f,
"different unsigned transaction: expected {}, actual {}",
e.txid(),
a.txid()
e.compute_txid(),
a.compute_txid()
),
NonStandardSighashType(ref sht) => write!(f, "non-standard sighash type: {}", sht),
InvalidHash(ref e) => write_err!(f, "invalid hash when parsing slice"; e),
Expand Down
10 changes: 5 additions & 5 deletions src/v0/bitcoin/macros.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ macro_rules! impl_psbt_de_serialize {
macro_rules! impl_psbt_deserialize {
($thing:ty) => {
impl $crate::v0::bitcoin::serialize::Deserialize for $thing {
fn deserialize(bytes: &[u8]) -> Result<Self, $crate::v0::bitcoin::Error> {
fn deserialize(bytes: &[u8]) -> core::result::Result<Self, $crate::v0::bitcoin::Error> {
$crate::bitcoin::consensus::deserialize(&bytes[..])
.map_err(|e| $crate::v0::bitcoin::Error::from(e))
}
Expand Down Expand Up @@ -48,7 +48,7 @@ macro_rules! impl_psbtmap_serialize {
macro_rules! impl_psbtmap_deserialize {
($thing:ty) => {
impl $crate::v0::bitcoin::serialize::Deserialize for $thing {
fn deserialize(bytes: &[u8]) -> Result<Self, $crate::v0::bitcoin::Error> {
fn deserialize(bytes: &[u8]) -> core::result::Result<Self, $crate::v0::bitcoin::Error> {
let mut decoder = bytes;
Self::decode(&mut decoder)
}
Expand All @@ -59,9 +59,9 @@ macro_rules! impl_psbtmap_deserialize {
macro_rules! impl_psbtmap_decoding {
($thing:ty) => {
impl $thing {
pub(crate) fn decode<R: $crate::io::Read + ?Sized>(
pub(crate) fn decode<R: $crate::io::BufRead + ?Sized>(
r: &mut R,
) -> Result<Self, $crate::v0::bitcoin::Error> {
) -> core::result::Result<Self, $crate::v0::bitcoin::Error> {
let mut rv: Self = core::default::Default::default();

loop {
Expand Down Expand Up @@ -151,7 +151,7 @@ macro_rules! impl_psbt_hash_de_serialize {
macro_rules! impl_psbt_hash_deserialize {
($hash_type:ty) => {
impl $crate::v0::bitcoin::serialize::Deserialize for $hash_type {
fn deserialize(bytes: &[u8]) -> Result<Self, $crate::v0::bitcoin::Error> {
fn deserialize(bytes: &[u8]) -> core::result::Result<Self, $crate::v0::bitcoin::Error> {
<$hash_type>::from_slice(&bytes[..])
.map_err(|e| $crate::v0::bitcoin::Error::from(e))
}
Expand Down
4 changes: 2 additions & 2 deletions src/v0/bitcoin/map/global.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ use bitcoin::blockdata::transaction::Transaction;
use bitcoin::consensus::encode::MAX_VEC_SIZE;
use bitcoin::consensus::{encode, Decodable};

use crate::io::{self, Cursor, Read};
use crate::io::{BufRead, Cursor, Read};
use crate::prelude::*;
use crate::v0::bitcoin::map::Map;
use crate::v0::bitcoin::{raw, Error, Psbt};
Expand Down Expand Up @@ -83,7 +83,7 @@ impl Map for Psbt {
}

impl Psbt {
pub(crate) fn decode_global<R: io::Read + ?Sized>(r: &mut R) -> Result<Self, Error> {
pub(crate) fn decode_global<R: BufRead + ?Sized>(r: &mut R) -> Result<Self, Error> {
let mut r = r.take(MAX_VEC_SIZE as u64);
let mut tx: Option<Transaction> = None;
let mut version: Option<u32> = None;
Expand Down
5 changes: 1 addition & 4 deletions src/v0/bitcoin/map/input.rs
Original file line number Diff line number Diff line change
Expand Up @@ -104,7 +104,6 @@ pub struct Input {
/// The finalized, fully-constructed scriptWitness with signatures and any
/// other scripts necessary for this input to pass validation.
pub final_script_witness: Option<Witness>,
/// TODO: Proof of reserves commitment
/// RIPEMD160 hash to preimage map.
#[cfg_attr(feature = "serde", serde(with = "crate::serde_utils::btreemap_byte_values"))]
pub ripemd160_preimages: BTreeMap<ripemd160::Hash, Vec<u8>>,
Expand Down Expand Up @@ -159,9 +158,7 @@ impl Input {
/// # Errors
///
/// If the `sighash_type` field is set to a invalid Taproot sighash value.
pub fn taproot_hash_ty(
&self,
) -> Result<TapSighashType, crate::sighash_type::InvalidSighashTypeError> {
pub fn taproot_hash_ty(&self) -> Result<TapSighashType, InvalidSighashTypeError> {
self.sighash_type
.map(|sighash_type| sighash_type.taproot_hash_ty())
.unwrap_or(Ok(TapSighashType::Default))
Expand Down
Loading

0 comments on commit 001000d

Please sign in to comment.