From 3e034d5eded6242e00ba760f00b8933c35d16dea Mon Sep 17 00:00:00 2001 From: yancy Date: Tue, 20 Aug 2024 11:07:07 -0500 Subject: [PATCH] Add Arbitrary dependency Implement Arbitrary for a select subset of types. --- Cargo-minimal.lock | 8 ++++++++ Cargo-recent.lock | 8 ++++++++ bitcoin/Cargo.toml | 2 ++ bitcoin/contrib/test_vars.sh | 4 ++-- bitcoin/src/blockdata/script/owned.rs | 11 +++++++++++ bitcoin/src/blockdata/transaction.rs | 13 +++++++++++++ units/Cargo.toml | 1 + units/contrib/test_vars.sh | 4 ++-- units/src/amount.rs | 11 +++++++++++ units/src/fee_rate.rs | 11 +++++++++++ 10 files changed, 69 insertions(+), 4 deletions(-) diff --git a/Cargo-minimal.lock b/Cargo-minimal.lock index 16c7e5987..8f347e12e 100644 --- a/Cargo-minimal.lock +++ b/Cargo-minimal.lock @@ -8,6 +8,12 @@ version = "1.0.57" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "08f9b8508dccb7687a1d6c4ce66b2b0ecef467c94667de27d8d7fe1f8d2a9cdc" +[[package]] +name = "arbitrary" +version = "1.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7d5a26814d8dcb93b0e5a0ff3c6d80a8843bafb21b39e8e18a6f05471870e110" + [[package]] name = "arrayvec" version = "0.7.4" @@ -49,6 +55,7 @@ dependencies = [ name = "bitcoin" version = "0.32.0-rc1" dependencies = [ + "arbitrary", "base58ck", "base64", "bech32", @@ -115,6 +122,7 @@ dependencies = [ name = "bitcoin-units" version = "0.1.1" dependencies = [ + "arbitrary", "bitcoin-internals", "serde", "serde_json", diff --git a/Cargo-recent.lock b/Cargo-recent.lock index fb2340a80..38d55aabc 100644 --- a/Cargo-recent.lock +++ b/Cargo-recent.lock @@ -8,6 +8,12 @@ version = "1.0.71" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9c7d0618f0e0b7e8ff11427422b64564d5fb0be1940354bfe2e0529b18a9d9b8" +[[package]] +name = "arbitrary" +version = "1.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7d5a26814d8dcb93b0e5a0ff3c6d80a8843bafb21b39e8e18a6f05471870e110" + [[package]] name = "arrayvec" version = "0.7.4" @@ -48,6 +54,7 @@ dependencies = [ name = "bitcoin" version = "0.32.0-rc1" dependencies = [ + "arbitrary", "base58ck", "base64", "bech32", @@ -114,6 +121,7 @@ dependencies = [ name = "bitcoin-units" version = "0.1.1" dependencies = [ + "arbitrary", "bitcoin-internals", "serde", "serde_json", diff --git a/bitcoin/Cargo.toml b/bitcoin/Cargo.toml index 3396486a1..3b9ebd23a 100644 --- a/bitcoin/Cargo.toml +++ b/bitcoin/Cargo.toml @@ -22,6 +22,7 @@ rand = ["secp256k1/rand"] serde = ["dep:serde", "hashes/serde", "internals/serde", "primitives/serde", "secp256k1/serde", "units/serde"] secp-lowmemory = ["secp256k1/lowmemory"] secp-recovery = ["secp256k1/recovery"] +arbitrary = ["dep:arbitrary", "units/arbitrary"] [dependencies] base58 = { package = "base58ck", version = "0.1.0", default-features = false, features = ["alloc"] } @@ -40,6 +41,7 @@ ordered = { version = "0.2.0", optional = true } bitcoinconsensus = { version = "0.106.0", default-features = false, optional = true } serde = { version = "1.0.103", default-features = false, features = [ "derive", "alloc" ], optional = true } +arbitrary = { version = "1", optional = true } [dev-dependencies] internals = { package = "bitcoin-internals", version = "0.3.0", features = ["test-serde"] } diff --git a/bitcoin/contrib/test_vars.sh b/bitcoin/contrib/test_vars.sh index aac69b689..c65af099d 100644 --- a/bitcoin/contrib/test_vars.sh +++ b/bitcoin/contrib/test_vars.sh @@ -5,10 +5,10 @@ # shellcheck disable=SC2034 # Test all these features with "std" enabled. -FEATURES_WITH_STD="rand-std serde secp-recovery bitcoinconsensus base64 ordered" +FEATURES_WITH_STD="rand-std serde secp-recovery bitcoinconsensus base64 ordered arbitrary" # Test all these features without "std" or "alloc" enabled. -FEATURES_WITHOUT_STD="rand serde secp-recovery bitcoinconsensus base64 ordered" +FEATURES_WITHOUT_STD="rand serde secp-recovery bitcoinconsensus base64 ordered arbitrary" # Run these examples. EXAMPLES="ecdsa-psbt:std,bitcoinconsensus sign-tx-segwit-v0:rand-std sign-tx-taproot:rand-std taproot-psbt:bitcoinconsensus,rand-std sighash:std" diff --git a/bitcoin/src/blockdata/script/owned.rs b/bitcoin/src/blockdata/script/owned.rs index 3f001818c..69c67f969 100644 --- a/bitcoin/src/blockdata/script/owned.rs +++ b/bitcoin/src/blockdata/script/owned.rs @@ -11,6 +11,9 @@ use crate::opcodes::all::*; use crate::opcodes::{self, Opcode}; use crate::prelude::{Box, Vec}; +#[cfg(feature = "arbitrary")] +use arbitrary::{Arbitrary, Unstructured}; + /// An owned, growable script. /// /// `ScriptBuf` is the most common script type that has the ownership over the contents of the @@ -155,6 +158,14 @@ crate::internal_macros::define_extension_trait! { } } +#[cfg(feature = "arbitrary")] +impl<'a> Arbitrary<'a> for ScriptBuf { + fn arbitrary(u: &mut Unstructured<'a>) -> arbitrary::Result { + let v = Vec::::arbitrary(u)?; + Ok(ScriptBuf(v)) + } +} + crate::internal_macros::define_extension_trait! { pub(crate) trait ScriptBufExtPriv impl for ScriptBuf { /// Pretends to convert `&mut ScriptBuf` to `&mut Vec` so that it can be modified. diff --git a/bitcoin/src/blockdata/transaction.rs b/bitcoin/src/blockdata/transaction.rs index 49e80be95..a2a8e671a 100644 --- a/bitcoin/src/blockdata/transaction.rs +++ b/bitcoin/src/blockdata/transaction.rs @@ -29,6 +29,9 @@ use crate::sighash::{EcdsaSighashType, TapSighashType}; use crate::witness::Witness; use crate::{Amount, FeeRate, SignedAmount, VarInt}; +#[cfg(feature = "arbitrary")] +use arbitrary::{Arbitrary, Unstructured}; + hashes::hash_newtype! { /// A bitcoin transaction hash/transaction ID. /// @@ -399,6 +402,16 @@ impl TxOut { } } +#[cfg(feature = "arbitrary")] +impl<'a> Arbitrary<'a> for TxOut { + fn arbitrary(u: &mut Unstructured<'a>) -> arbitrary::Result { + Ok(TxOut { + value: Amount::arbitrary(u)?, + script_pubkey: ScriptBuf::arbitrary(u)?, + }) + } +} + /// Returns the total number of bytes that this script pubkey would contribute to a transaction. fn size_from_script_pubkey(script_pubkey: &Script) -> usize { let len = script_pubkey.len(); diff --git a/units/Cargo.toml b/units/Cargo.toml index a289a0756..a393f878f 100644 --- a/units/Cargo.toml +++ b/units/Cargo.toml @@ -21,6 +21,7 @@ alloc = ["internals/alloc"] internals = { package = "bitcoin-internals", version = "0.3.0" } serde = { version = "1.0.103", default-features = false, features = ["derive"], optional = true } +arbitrary = { version = "1", optional =true } [dev-dependencies] internals = { package = "bitcoin-internals", version = "0.3.0", features = ["test-serde"] } diff --git a/units/contrib/test_vars.sh b/units/contrib/test_vars.sh index ad0a3f27e..91030c5de 100644 --- a/units/contrib/test_vars.sh +++ b/units/contrib/test_vars.sh @@ -5,10 +5,10 @@ # shellcheck disable=SC2034 # Test all these features with "std" enabled. -FEATURES_WITH_STD="serde" +FEATURES_WITH_STD="serde arbitrary" # Test all these features without "std" enabled. -FEATURES_WITHOUT_STD="alloc serde" +FEATURES_WITHOUT_STD="alloc serde arbitrary" # Run these examples. EXAMPLES="" diff --git a/units/src/amount.rs b/units/src/amount.rs index 939718467..724e5fd21 100644 --- a/units/src/amount.rs +++ b/units/src/amount.rs @@ -16,6 +16,9 @@ use ::serde::{Deserialize, Serialize}; use internals::error::InputString; use internals::write_err; +#[cfg(feature = "arbitrary")] +use arbitrary::{Arbitrary, Unstructured}; + /// A set of denominations in which amounts can be expressed. /// /// # Accepted Denominations @@ -1071,6 +1074,14 @@ impl Amount { } } +#[cfg(feature = "arbitrary")] +impl<'a> Arbitrary<'a> for Amount { + fn arbitrary(u: &mut Unstructured<'a>) -> arbitrary::Result { + let a = u64::arbitrary(u)?; + Ok(Amount(a)) + } +} + impl default::Default for Amount { fn default() -> Self { Amount::ZERO } } diff --git a/units/src/fee_rate.rs b/units/src/fee_rate.rs index 901f9ce65..8b8c32334 100644 --- a/units/src/fee_rate.rs +++ b/units/src/fee_rate.rs @@ -11,6 +11,9 @@ use serde::{Deserialize, Serialize}; use crate::amount::Amount; use crate::weight::Weight; +#[cfg(feature = "arbitrary")] +use arbitrary::{Arbitrary, Unstructured}; + /// Represents fee rate. /// /// This is an integer newtype representing fee rate in `sat/kwu`. It provides protection against mixing @@ -107,6 +110,14 @@ impl FeeRate { } } +#[cfg(feature = "arbitrary")] +impl<'a> Arbitrary<'a> for FeeRate { + fn arbitrary(u: &mut Unstructured<'a>) -> arbitrary::Result { + let f = u64::arbitrary(u)?; + Ok(FeeRate(f)) + } +} + /// Alternative will display the unit. impl fmt::Display for FeeRate { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {