Repository: rust-bitcoin/rust-bitcoin
Pull request #4127 (2025-02-26 01:22:23)

units: Prevent casting pub enums as ints
A public enum with simple variants gets an automatic integer variant that can be cast by library consumers. This puts a unnecessary maintenance burden upon us because we cannot then add variants in the middle of others.

Add a hidden variant to the single public non-error enum in `units`.

tcharding: I didn't go searching for the name you suggested already @Kixunil, happy to change the one here to it if you post it.
github-actions[bot]: :rotating_light: API BREAKING CHANGE DETECTED

To see the changes click details on "Check semver breaks / PR Semver - stable toolchain" job then expand "Run semver checker script" and scroll to the end of the section.
github-actions[bot]: :rotating_light: API BREAKING CHANGE DETECTED

To see the changes click details on "Check semver breaks / PR Semver - stable toolchain" job then expand "Run semver checker script" and scroll to the end of the section.
jirijakes: The annoying and perhaps confusing part is that LSP (rust-analyzer) still offers it for completions and other assistance.

```rs

fn x(d: Denomination) {
    match d {
      |
    }
}
```

Fill match arms:

```rs
fn x(d: Denomination) {
    match d {
        Denomination::Bitcoin => todo!(),
        Denomination::CentiBitcoin => todo!(),
        Denomination::MilliBitcoin => todo!(),
        Denomination::MicroBitcoin => todo!(),
        Denomination::Bit => todo!(),
        Denomination::Satoshi => todo!(),
        Denomination::PreventCastingVariantAsInt(infallible) => todo!(),
    }
}

```

Completion:

![image](https://github.com/user-attachments/assets/e65dc4ff-b680-4293-a8ba-a1f7b096f151)

tcharding: Damn, yes that is ugly.
Kixunil: @jirijakes if you're experiencing it in a downstream crate that's a bug in RA worth reporting. Anyway, I do think this is a hack and ideally the language would have a first class support for this. But it's also possible that underscore will fix it.

Either way, it's better to have an extra variant which obviously shouldn't be used (Maybe we should have "DoNotUse" in the name) than having a silent breakage like the last time.
jirijakes: > if you're experiencing it in a downstream crate 

No, it it was within rust-bitcoin.

And really, in downstream, the hidden variant is suppressed. No underscore even needed. Interesting. Is it because of doc hidden?
Kixunil: Great!

> Is it because of doc hidden?

Yes, that should be the reason.
github-actions[bot]: :rotating_light: API BREAKING CHANGE DETECTED

To see the changes click details on "Check semver breaks / PR Semver - stable toolchain" job then expand "Run semver checker script" and scroll to the end of the section.
github-actions[bot]: :rotating_light: API BREAKING CHANGE DETECTED

To see the changes click details on "Check semver breaks / PR Semver - stable toolchain" job then expand "Run semver checker script" and scroll to the end of the section.

Patch:
diff --git a/.github/workflows/cron-daily-fuzz.yml b/.github/workflows/cron-daily-fuzz.yml
index b5f83c5c..2686f70f 100644
--- a/.github/workflows/cron-daily-fuzz.yml
+++ b/.github/workflows/cron-daily-fuzz.yml
@@ -59,7 +59,7 @@ jobs:
           echo "Using RUSTFLAGS $RUSTFLAGS"
           cd fuzz && ./fuzz.sh "${{ matrix.fuzz_target }}"
       - run: echo "${{ matrix.fuzz_target }}" >executed_${{ matrix.fuzz_target }}
-      - uses: actions/upload-artifact@v4
+      - uses: actions/upload-artifact@v3
         with:
           name: executed_${{ matrix.fuzz_target }}
           path: executed_${{ matrix.fuzz_target }}
@@ -70,7 +70,7 @@ jobs:
     runs-on: ubuntu-latest
     steps:
       - uses: actions/checkout@v4
-      - uses: actions/download-artifact@v4
+      - uses: actions/download-artifact@v3
       - name: Display structure of downloaded files
         run: ls -R
       - run: find executed_* -type f -exec cat {} + | sort > executed
diff --git a/.github/workflows/cron-daily-kani.yml b/.github/workflows/cron-daily-kani.yml
index 61ef6e39..dff1e54b 100644
--- a/.github/workflows/cron-daily-kani.yml
+++ b/.github/workflows/cron-daily-kani.yml
@@ -5,7 +5,7 @@ on:
     - cron: '59 23 * * *'       # midnight every day.
 jobs:
   run-kani:
-    runs-on: ubuntu-24.04
+    runs-on: ubuntu-20.04
     steps:
       - name: 'Checkout your code.'
         uses: actions/checkout@v4
diff --git a/.github/workflows/rust.yml b/.github/workflows/rust.yml
index d9da41a5..37ad742a 100644
--- a/.github/workflows/rust.yml
+++ b/.github/workflows/rust.yml
@@ -296,7 +296,7 @@ jobs:
 
   Kani:
     name: Kani codegen - stable toolchain
-    runs-on: ubuntu-24.04
+    runs-on: ubuntu-20.04
     steps:
       - name: "Checkout repo"
         uses: actions/checkout@v4
diff --git a/bitcoin/examples/ecdsa-psbt-simple.rs b/bitcoin/examples/ecdsa-psbt-simple.rs
index 024f71c5..45014db0 100644
--- a/bitcoin/examples/ecdsa-psbt-simple.rs
+++ b/bitcoin/examples/ecdsa-psbt-simple.rs
@@ -26,14 +26,13 @@
 
 use bitcoin::address::script_pubkey::ScriptBufExt as _;
 use bitcoin::bip32::{ChildNumber, DerivationPath, Fingerprint, IntoDerivationPath, Xpriv, Xpub};
-use bitcoin::key::WPubkeyHash;
 use bitcoin::locktime::absolute;
 use bitcoin::psbt::Input;
 use bitcoin::secp256k1::{Secp256k1, Signing};
 use bitcoin::witness::WitnessExt as _;
 use bitcoin::{
     consensus, transaction, Address, Amount, EcdsaSighashType, Network, OutPoint, Psbt, ScriptBuf,
-    Sequence, Transaction, TxIn, TxOut, Txid, Witness,
+    Sequence, Transaction, TxIn, TxOut, Txid, WPubkeyHash, Witness,
 };
 
 // The master xpriv, from which we derive the keys we control.
diff --git a/bitcoin/examples/sign-tx-segwit-v0.rs b/bitcoin/examples/sign-tx-segwit-v0.rs
index a30c02d9..f7d35c58 100644
--- a/bitcoin/examples/sign-tx-segwit-v0.rs
+++ b/bitcoin/examples/sign-tx-segwit-v0.rs
@@ -3,14 +3,13 @@
 //! Demonstrate creating a transaction that spends to and from p2wpkh outputs.
 
 use bitcoin::address::script_pubkey::ScriptBufExt as _;
-use bitcoin::key::WPubkeyHash;
 use bitcoin::locktime::absolute;
 use bitcoin::secp256k1::{rand, Message, Secp256k1, SecretKey, Signing};
 use bitcoin::sighash::{EcdsaSighashType, SighashCache};
 use bitcoin::witness::WitnessExt as _;
 use bitcoin::{
     transaction, Address, Amount, Network, OutPoint, ScriptBuf, Sequence, Transaction, TxIn, TxOut,
-    Txid, Witness,
+    Txid, WPubkeyHash, Witness,
 };
 
 const DUMMY_UTXO_AMOUNT: Amount = Amount::from_sat_unchecked(20_000_000);
diff --git a/bitcoin/src/blockdata/mod.rs b/bitcoin/src/blockdata/mod.rs
index cc4b1ecb..02fcb250 100644
--- a/bitcoin/src/blockdata/mod.rs
+++ b/bitcoin/src/blockdata/mod.rs
@@ -7,7 +7,6 @@
 
 pub mod block;
 pub mod constants;
-pub mod opcodes;
 pub mod script;
 pub mod transaction;
 pub mod witness;
@@ -71,6 +70,12 @@ pub mod relative {
     }
 }
 
+/// Bitcoin script opcodes.
+pub mod opcodes {
+    /// Re-export everything from the [`primitives::opcodes`] module.
+    pub use primitives::opcodes::*;
+}
+
 /// Implements `Weight` and associated features.
 pub mod weight {
     /// Re-export everything from the [`units::weight`] module.
diff --git a/bitcoin/src/blockdata/opcodes.rs b/bitcoin/src/blockdata/opcodes.rs
deleted file mode 100644
index 5da0295d..00000000
--- a/bitcoin/src/blockdata/opcodes.rs
+++ /dev/null
@@ -1,901 +0,0 @@
-// SPDX-License-Identifier: CC0-1.0
-
-//! Bitcoin script opcodes.
-//!
-//! Bitcoin's script uses a stack-based assembly language. This module defines
-//! all of the opcodes for that language.
-
-#![allow(non_camel_case_types)]
-
-use core::fmt;
-
-#[cfg(feature = "serde")]
-use crate::prelude::ToString;
-
-/// A script Opcode.
-///
-/// We do not implement Ord on this type because there is no natural ordering on opcodes, but there
-/// may appear to be one (e.g. because all the push opcodes appear in a consecutive block) and we
-/// don't want to encourage subtly buggy code. Please use [`Opcode::classify`] to distinguish different
-/// types of opcodes.
-///
-/// <details>
-///   <summary>Example of Core bug caused by assuming ordering</summary>
-///
-///   Bitcoin Core's `IsPushOnly` considers `OP_RESERVED` to be a "push code", allowing this opcode
-///   in contexts where only pushes are supposed to be allowed.
-/// </details>
-#[derive(Copy, Clone, PartialEq, Eq)]
-pub struct Opcode {
-    code: u8,
-}
-
-use self::all::*;
-
-macro_rules! all_opcodes {
-    ($($op:ident => $val:expr, $doc:expr);*) => {
-        /// Enables wildcard imports to bring into scope all opcodes and nothing else.
-        ///
-        /// The `all` module is provided so one can use a wildcard import `use bitcoin::opcodes::all::*` to
-        /// get all the `OP_FOO` opcodes without getting other types defined in `opcodes` (e.g. `Opcode`, `Class`).
-        ///
-        /// This module is guaranteed to never contain anything except opcode constants and all opcode
-        /// constants are guaranteed to begin with OP_.
-        pub mod all {
-            use super::Opcode;
-            $(
-                #[doc = $doc]
-                pub const $op: Opcode = Opcode { code: $val};
-            )*
-        }
-
-        /// Push an empty array onto the stack.
-        pub static OP_0: Opcode = OP_PUSHBYTES_0;
-        /// Empty stack is also FALSE.
-        pub static OP_FALSE: Opcode = OP_PUSHBYTES_0;
-        /// Number 1 is also TRUE.
-        pub static OP_TRUE: Opcode = OP_PUSHNUM_1;
-        /// Previously called OP_NOP2.
-        pub static OP_NOP2: Opcode = OP_CLTV;
-        /// Previously called OP_NOP3.
-        pub static OP_NOP3: Opcode = OP_CSV;
-
-        impl fmt::Display for Opcode {
-            fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
-                 match *self {
-                   $(
-                        $op => core::fmt::Display::fmt(stringify!($op), f),
-                    )+
-                }
-            }
-        }
-    }
-}
-
-all_opcodes! {
-    OP_PUSHBYTES_0 => 0x00, "Push an empty array onto the stack.";
-    OP_PUSHBYTES_1 => 0x01, "Push the next byte as an array onto the stack.";
-    OP_PUSHBYTES_2 => 0x02, "Push the next 2 bytes as an array onto the stack.";
-    OP_PUSHBYTES_3 => 0x03, "Push the next 3 bytes as an array onto the stack.";
-    OP_PUSHBYTES_4 => 0x04, "Push the next 4 bytes as an array onto the stack.";
-    OP_PUSHBYTES_5 => 0x05, "Push the next 5 bytes as an array onto the stack.";
-    OP_PUSHBYTES_6 => 0x06, "Push the next 6 bytes as an array onto the stack.";
-    OP_PUSHBYTES_7 => 0x07, "Push the next 7 bytes as an array onto the stack.";
-    OP_PUSHBYTES_8 => 0x08, "Push the next 8 bytes as an array onto the stack.";
-    OP_PUSHBYTES_9 => 0x09, "Push the next 9 bytes as an array onto the stack.";
-    OP_PUSHBYTES_10 => 0x0a, "Push the next 10 bytes as an array onto the stack.";
-    OP_PUSHBYTES_11 => 0x0b, "Push the next 11 bytes as an array onto the stack.";
-    OP_PUSHBYTES_12 => 0x0c, "Push the next 12 bytes as an array onto the stack.";
-    OP_PUSHBYTES_13 => 0x0d, "Push the next 13 bytes as an array onto the stack.";
-    OP_PUSHBYTES_14 => 0x0e, "Push the next 14 bytes as an array onto the stack.";
-    OP_PUSHBYTES_15 => 0x0f, "Push the next 15 bytes as an array onto the stack.";
-    OP_PUSHBYTES_16 => 0x10, "Push the next 16 bytes as an array onto the stack.";
-    OP_PUSHBYTES_17 => 0x11, "Push the next 17 bytes as an array onto the stack.";
-    OP_PUSHBYTES_18 => 0x12, "Push the next 18 bytes as an array onto the stack.";
-    OP_PUSHBYTES_19 => 0x13, "Push the next 19 bytes as an array onto the stack.";
-    OP_PUSHBYTES_20 => 0x14, "Push the next 20 bytes as an array onto the stack.";
-    OP_PUSHBYTES_21 => 0x15, "Push the next 21 bytes as an array onto the stack.";
-    OP_PUSHBYTES_22 => 0x16, "Push the next 22 bytes as an array onto the stack.";
-    OP_PUSHBYTES_23 => 0x17, "Push the next 23 bytes as an array onto the stack.";
-    OP_PUSHBYTES_24 => 0x18, "Push the next 24 bytes as an array onto the stack.";
-    OP_PUSHBYTES_25 => 0x19, "Push the next 25 bytes as an array onto the stack.";
-    OP_PUSHBYTES_26 => 0x1a, "Push the next 26 bytes as an array onto the stack.";
-    OP_PUSHBYTES_27 => 0x1b, "Push the next 27 bytes as an array onto the stack.";
-    OP_PUSHBYTES_28 => 0x1c, "Push the next 28 bytes as an array onto the stack.";
-    OP_PUSHBYTES_29 => 0x1d, "Push the next 29 bytes as an array onto the stack.";
-    OP_PUSHBYTES_30 => 0x1e, "Push the next 30 bytes as an array onto the stack.";
-    OP_PUSHBYTES_31 => 0x1f, "Push the next 31 bytes as an array onto the stack.";
-    OP_PUSHBYTES_32 => 0x20, "Push the next 32 bytes as an array onto the stack.";
-    OP_PUSHBYTES_33 => 0x21, "Push the next 33 bytes as an array onto the stack.";
-    OP_PUSHBYTES_34 => 0x22, "Push the next 34 bytes as an array onto the stack.";
-    OP_PUSHBYTES_35 => 0x23, "Push the next 35 bytes as an array onto the stack.";
-    OP_PUSHBYTES_36 => 0x24, "Push the next 36 bytes as an array onto the stack.";
-    OP_PUSHBYTES_37 => 0x25, "Push the next 37 bytes as an array onto the stack.";
-    OP_PUSHBYTES_38 => 0x26, "Push the next 38 bytes as an array onto the stack.";
-    OP_PUSHBYTES_39 => 0x27, "Push the next 39 bytes as an array onto the stack.";
-    OP_PUSHBYTES_40 => 0x28, "Push the next 40 bytes as an array onto the stack.";
-    OP_PUSHBYTES_41 => 0x29, "Push the next 41 bytes as an array onto the stack.";
-    OP_PUSHBYTES_42 => 0x2a, "Push the next 42 bytes as an array onto the stack.";
-    OP_PUSHBYTES_43 => 0x2b, "Push the next 43 bytes as an array onto the stack.";
-    OP_PUSHBYTES_44 => 0x2c, "Push the next 44 bytes as an array onto the stack.";
-    OP_PUSHBYTES_45 => 0x2d, "Push the next 45 bytes as an array onto the stack.";
-    OP_PUSHBYTES_46 => 0x2e, "Push the next 46 bytes as an array onto the stack.";
-    OP_PUSHBYTES_47 => 0x2f, "Push the next 47 bytes as an array onto the stack.";
-    OP_PUSHBYTES_48 => 0x30, "Push the next 48 bytes as an array onto the stack.";
-    OP_PUSHBYTES_49 => 0x31, "Push the next 49 bytes as an array onto the stack.";
-    OP_PUSHBYTES_50 => 0x32, "Push the next 50 bytes as an array onto the stack.";
-    OP_PUSHBYTES_51 => 0x33, "Push the next 51 bytes as an array onto the stack.";
-    OP_PUSHBYTES_52 => 0x34, "Push the next 52 bytes as an array onto the stack.";
-    OP_PUSHBYTES_53 => 0x35, "Push the next 53 bytes as an array onto the stack.";
-    OP_PUSHBYTES_54 => 0x36, "Push the next 54 bytes as an array onto the stack.";
-    OP_PUSHBYTES_55 => 0x37, "Push the next 55 bytes as an array onto the stack.";
-    OP_PUSHBYTES_56 => 0x38, "Push the next 56 bytes as an array onto the stack.";
-    OP_PUSHBYTES_57 => 0x39, "Push the next 57 bytes as an array onto the stack.";
-    OP_PUSHBYTES_58 => 0x3a, "Push the next 58 bytes as an array onto the stack.";
-    OP_PUSHBYTES_59 => 0x3b, "Push the next 59 bytes as an array onto the stack.";
-    OP_PUSHBYTES_60 => 0x3c, "Push the next 60 bytes as an array onto the stack.";
-    OP_PUSHBYTES_61 => 0x3d, "Push the next 61 bytes as an array onto the stack.";
-    OP_PUSHBYTES_62 => 0x3e, "Push the next 62 bytes as an array onto the stack.";
-    OP_PUSHBYTES_63 => 0x3f, "Push the next 63 bytes as an array onto the stack.";
-    OP_PUSHBYTES_64 => 0x40, "Push the next 64 bytes as an array onto the stack.";
-    OP_PUSHBYTES_65 => 0x41, "Push the next 65 bytes as an array onto the stack.";
-    OP_PUSHBYTES_66 => 0x42, "Push the next 66 bytes as an array onto the stack.";
-    OP_PUSHBYTES_67 => 0x43, "Push the next 67 bytes as an array onto the stack.";
-    OP_PUSHBYTES_68 => 0x44, "Push the next 68 bytes as an array onto the stack.";
-    OP_PUSHBYTES_69 => 0x45, "Push the next 69 bytes as an array onto the stack.";
-    OP_PUSHBYTES_70 => 0x46, "Push the next 70 bytes as an array onto the stack.";
-    OP_PUSHBYTES_71 => 0x47, "Push the next 71 bytes as an array onto the stack.";
-    OP_PUSHBYTES_72 => 0x48, "Push the next 72 bytes as an array onto the stack.";
-    OP_PUSHBYTES_73 => 0x49, "Push the next 73 bytes as an array onto the stack.";
-    OP_PUSHBYTES_74 => 0x4a, "Push the next 74 bytes as an array onto the stack.";
-    OP_PUSHBYTES_75 => 0x4b, "Push the next 75 bytes as an array onto the stack.";
-    OP_PUSHDATA1 => 0x4c, "Read the next byte as N; push the next N bytes as an array onto the stack.";
-    OP_PUSHDATA2 => 0x4d, "Read the next 2 bytes as N; push the next N bytes as an array onto the stack.";
-    OP_PUSHDATA4 => 0x4e, "Read the next 4 bytes as N; push the next N bytes as an array onto the stack.";
-    OP_PUSHNUM_NEG1 => 0x4f, "Push the array `0x81` onto the stack.";
-    OP_RESERVED => 0x50, "Synonym for OP_RETURN.";
-    OP_PUSHNUM_1 => 0x51, "Push the array `0x01` onto the stack.";
-    OP_PUSHNUM_2 => 0x52, "Push the array `0x02` onto the stack.";
-    OP_PUSHNUM_3 => 0x53, "Push the array `0x03` onto the stack.";
-    OP_PUSHNUM_4 => 0x54, "Push the array `0x04` onto the stack.";
-    OP_PUSHNUM_5 => 0x55, "Push the array `0x05` onto the stack.";
-    OP_PUSHNUM_6 => 0x56, "Push the array `0x06` onto the stack.";
-    OP_PUSHNUM_7 => 0x57, "Push the array `0x07` onto the stack.";
-    OP_PUSHNUM_8 => 0x58, "Push the array `0x08` onto the stack.";
-    OP_PUSHNUM_9 => 0x59, "Push the array `0x09` onto the stack.";
-    OP_PUSHNUM_10 => 0x5a, "Push the array `0x0a` onto the stack.";
-    OP_PUSHNUM_11 => 0x5b, "Push the array `0x0b` onto the stack.";
-    OP_PUSHNUM_12 => 0x5c, "Push the array `0x0c` onto the stack.";
-    OP_PUSHNUM_13 => 0x5d, "Push the array `0x0d` onto the stack.";
-    OP_PUSHNUM_14 => 0x5e, "Push the array `0x0e` onto the stack.";
-    OP_PUSHNUM_15 => 0x5f, "Push the array `0x0f` onto the stack.";
-    OP_PUSHNUM_16 => 0x60, "Push the array `0x10` onto the stack.";
-    OP_NOP => 0x61, "Does nothing.";
-    OP_VER => 0x62, "Synonym for OP_RETURN.";
-    OP_IF => 0x63, "Pop and execute the next statements if a nonzero element was popped.";
-    OP_NOTIF => 0x64, "Pop and execute the next statements if a zero element was popped.";
-    OP_VERIF => 0x65, "Fail the script unconditionally, does not even need to be executed.";
-    OP_VERNOTIF => 0x66, "Fail the script unconditionally, does not even need to be executed.";
-    OP_ELSE => 0x67, "Execute statements if those after the previous OP_IF were not, and vice-versa. \
-             If there is no previous OP_IF, this acts as a RETURN.";
-    OP_ENDIF => 0x68, "Pop and execute the next statements if a zero element was popped.";
-    OP_VERIFY => 0x69, "If the top value is zero or the stack is empty, fail; otherwise, pop the stack.";
-    OP_RETURN => 0x6a, "Fail the script immediately. (Must be executed.).";
-    OP_TOALTSTACK => 0x6b, "Pop one element from the main stack onto the alt stack.";
-    OP_FROMALTSTACK => 0x6c, "Pop one element from the alt stack onto the main stack.";
-    OP_2DROP => 0x6d, "Drops the top two stack items.";
-    OP_2DUP => 0x6e, "Duplicates the top two stack items as AB -> ABAB.";
-    OP_3DUP => 0x6f, "Duplicates the two three stack items as ABC -> ABCABC.";
-    OP_2OVER => 0x70, "Copies the two stack items of items two spaces back to the front, as xxAB -> ABxxAB.";
-    OP_2ROT => 0x71, "Moves the two stack items four spaces back to the front, as xxxxAB -> ABxxxx.";
-    OP_2SWAP => 0x72, "Swaps the top two pairs, as ABCD -> CDAB.";
-    OP_IFDUP => 0x73, "Duplicate the top stack element unless it is zero.";
-    OP_DEPTH => 0x74, "Push the current number of stack items onto the stack.";
-    OP_DROP => 0x75, "Drops the top stack item.";
-    OP_DUP => 0x76, "Duplicates the top stack item.";
-    OP_NIP => 0x77, "Drops the second-to-top stack item.";
-    OP_OVER => 0x78, "Copies the second-to-top stack item, as xA -> AxA.";
-    OP_PICK => 0x79, "Pop the top stack element as N. Copy the Nth stack element to the top.";
-    OP_ROLL => 0x7a, "Pop the top stack element as N. Move the Nth stack element to the top.";
-    OP_ROT => 0x7b, "Rotate the top three stack items, as [top next1 next2] -> [next2 top next1].";
-    OP_SWAP => 0x7c, "Swap the top two stack items.";
-    OP_TUCK => 0x7d, "Copy the top stack item to before the second item, as [top next] -> [top next top].";
-    OP_CAT => 0x7e, "Fail the script unconditionally, does not even need to be executed.";
-    OP_SUBSTR => 0x7f, "Fail the script unconditionally, does not even need to be executed.";
-    OP_LEFT => 0x80, "Fail the script unconditionally, does not even need to be executed.";
-    OP_RIGHT => 0x81, "Fail the script unconditionally, does not even need to be executed.";
-    OP_SIZE => 0x82, "Pushes the length of the top stack item onto the stack.";
-    OP_INVERT => 0x83, "Fail the script unconditionally, does not even need to be executed.";
-    OP_AND => 0x84, "Fail the script unconditionally, does not even need to be executed.";
-    OP_OR => 0x85, "Fail the script unconditionally, does not even need to be executed.";
-    OP_XOR => 0x86, "Fail the script unconditionally, does not even need to be executed.";
-    OP_EQUAL => 0x87, "Pushes 1 if the inputs are exactly equal, 0 otherwise.";
-    OP_EQUALVERIFY => 0x88, "Returns success if the inputs are exactly equal, failure otherwise.";
-    OP_RESERVED1 => 0x89, "Synonym for OP_RETURN.";
-    OP_RESERVED2 => 0x8a, "Synonym for OP_RETURN.";
-    OP_1ADD => 0x8b, "Increment the top stack element in place.";
-    OP_1SUB => 0x8c, "Decrement the top stack element in place.";
-    OP_2MUL => 0x8d, "Fail the script unconditionally, does not even need to be executed.";
-    OP_2DIV => 0x8e, "Fail the script unconditionally, does not even need to be executed.";
-    OP_NEGATE => 0x8f, "Multiply the top stack item by -1 in place.";
-    OP_ABS => 0x90, "Absolute value the top stack item in place.";
-    OP_NOT => 0x91, "Map 0 to 1 and everything else to 0, in place.";
-    OP_0NOTEQUAL => 0x92, "Map 0 to 0 and everything else to 1, in place.";
-    OP_ADD => 0x93, "Pop two stack items and push their sum.";
-    OP_SUB => 0x94, "Pop two stack items and push the second minus the top.";
-    OP_MUL => 0x95, "Fail the script unconditionally, does not even need to be executed.";
-    OP_DIV => 0x96, "Fail the script unconditionally, does not even need to be executed.";
-    OP_MOD => 0x97, "Fail the script unconditionally, does not even need to be executed.";
-    OP_LSHIFT => 0x98, "Fail the script unconditionally, does not even need to be executed.";
-    OP_RSHIFT => 0x99, "Fail the script unconditionally, does not even need to be executed.";
-    OP_BOOLAND => 0x9a, "Pop the top two stack items and push 1 if both are nonzero, else push 0.";
-    OP_BOOLOR => 0x9b, "Pop the top two stack items and push 1 if either is nonzero, else push 0.";
-    OP_NUMEQUAL => 0x9c, "Pop the top two stack items and push 1 if both are numerically equal, else push 0.";
-    OP_NUMEQUALVERIFY => 0x9d, "Pop the top two stack items and return success if both are numerically equal, else return failure.";
-    OP_NUMNOTEQUAL => 0x9e, "Pop the top two stack items and push 0 if both are numerically equal, else push 1.";
-    OP_LESSTHAN  => 0x9f, "Pop the top two items; push 1 if the second is less than the top, 0 otherwise.";
-    OP_GREATERTHAN  => 0xa0, "Pop the top two items; push 1 if the second is greater than the top, 0 otherwise.";
-    OP_LESSTHANOREQUAL  => 0xa1, "Pop the top two items; push 1 if the second is <= the top, 0 otherwise.";
-    OP_GREATERTHANOREQUAL  => 0xa2, "Pop the top two items; push 1 if the second is >= the top, 0 otherwise.";
-    OP_MIN => 0xa3, "Pop the top two items; push the smaller.";
-    OP_MAX => 0xa4, "Pop the top two items; push the larger.";
-    OP_WITHIN => 0xa5, "Pop the top three items; if the top is >= the second and < the third, push 1, otherwise push 0.";
-    OP_RIPEMD160 => 0xa6, "Pop the top stack item and push its RIPEMD160 hash.";
-    OP_SHA1 => 0xa7, "Pop the top stack item and push its SHA1 hash.";
-    OP_SHA256 => 0xa8, "Pop the top stack item and push its SHA256 hash.";
-    OP_HASH160 => 0xa9, "Pop the top stack item and push its RIPEMD(SHA256) hash.";
-    OP_HASH256 => 0xaa, "Pop the top stack item and push its SHA256(SHA256) hash.";
-    OP_CODESEPARATOR => 0xab, "Ignore this and everything preceding when deciding what to sign when signature-checking.";
-    OP_CHECKSIG => 0xac, "<https://en.bitcoin.it/wiki/OP_CHECKSIG> pushing 1/0 for success/failure.";
-    OP_CHECKSIGVERIFY => 0xad, "<https://en.bitcoin.it/wiki/OP_CHECKSIG> returning success/failure.";
-    OP_CHECKMULTISIG => 0xae, "Pop N, N pubkeys, M, M signatures, a dummy (due to bug in reference code), \
-                      and verify that all M signatures are valid. Push 1 for 'all valid', 0 otherwise.";
-    OP_CHECKMULTISIGVERIFY => 0xaf, "Like the above but return success/failure.";
-    OP_NOP1 => 0xb0, "Does nothing.";
-    OP_CLTV => 0xb1, "<https://github.com/bitcoin/bips/blob/master/bip-0065.mediawiki>";
-    OP_CSV => 0xb2, "<https://github.com/bitcoin/bips/blob/master/bip-0112.mediawiki>";
-    OP_NOP4 => 0xb3, "Does nothing.";
-    OP_NOP5 => 0xb4, "Does nothing.";
-    OP_NOP6 => 0xb5, "Does nothing.";
-    OP_NOP7 => 0xb6, "Does nothing.";
-    OP_NOP8 => 0xb7, "Does nothing.";
-    OP_NOP9 => 0xb8, "Does nothing.";
-    OP_NOP10 => 0xb9, "Does nothing.";
-    // Every other opcode acts as OP_RETURN
-    OP_CHECKSIGADD => 0xba, "OP_CHECKSIGADD post tapscript.";
-    OP_RETURN_187 => 0xbb, "Synonym for OP_RETURN.";
-    OP_RETURN_188 => 0xbc, "Synonym for OP_RETURN.";
-    OP_RETURN_189 => 0xbd, "Synonym for OP_RETURN.";
-    OP_RETURN_190 => 0xbe, "Synonym for OP_RETURN.";
-    OP_RETURN_191 => 0xbf, "Synonym for OP_RETURN.";
-    OP_RETURN_192 => 0xc0, "Synonym for OP_RETURN.";
-    OP_RETURN_193 => 0xc1, "Synonym for OP_RETURN.";
-    OP_RETURN_194 => 0xc2, "Synonym for OP_RETURN.";
-    OP_RETURN_195 => 0xc3, "Synonym for OP_RETURN.";
-    OP_RETURN_196 => 0xc4, "Synonym for OP_RETURN.";
-    OP_RETURN_197 => 0xc5, "Synonym for OP_RETURN.";
-    OP_RETURN_198 => 0xc6, "Synonym for OP_RETURN.";
-    OP_RETURN_199 => 0xc7, "Synonym for OP_RETURN.";
-    OP_RETURN_200 => 0xc8, "Synonym for OP_RETURN.";
-    OP_RETURN_201 => 0xc9, "Synonym for OP_RETURN.";
-    OP_RETURN_202 => 0xca, "Synonym for OP_RETURN.";
-    OP_RETURN_203 => 0xcb, "Synonym for OP_RETURN.";
-    OP_RETURN_204 => 0xcc, "Synonym for OP_RETURN.";
-    OP_RETURN_205 => 0xcd, "Synonym for OP_RETURN.";
-    OP_RETURN_206 => 0xce, "Synonym for OP_RETURN.";
-    OP_RETURN_207 => 0xcf, "Synonym for OP_RETURN.";
-    OP_RETURN_208 => 0xd0, "Synonym for OP_RETURN.";
-    OP_RETURN_209 => 0xd1, "Synonym for OP_RETURN.";
-    OP_RETURN_210 => 0xd2, "Synonym for OP_RETURN.";
-    OP_RETURN_211 => 0xd3, "Synonym for OP_RETURN.";
-    OP_RETURN_212 => 0xd4, "Synonym for OP_RETURN.";
-    OP_RETURN_213 => 0xd5, "Synonym for OP_RETURN.";
-    OP_RETURN_214 => 0xd6, "Synonym for OP_RETURN.";
-    OP_RETURN_215 => 0xd7, "Synonym for OP_RETURN.";
-    OP_RETURN_216 => 0xd8, "Synonym for OP_RETURN.";
-    OP_RETURN_217 => 0xd9, "Synonym for OP_RETURN.";
-    OP_RETURN_218 => 0xda, "Synonym for OP_RETURN.";
-    OP_RETURN_219 => 0xdb, "Synonym for OP_RETURN.";
-    OP_RETURN_220 => 0xdc, "Synonym for OP_RETURN.";
-    OP_RETURN_221 => 0xdd, "Synonym for OP_RETURN.";
-    OP_RETURN_222 => 0xde, "Synonym for OP_RETURN.";
-    OP_RETURN_223 => 0xdf, "Synonym for OP_RETURN.";
-    OP_RETURN_224 => 0xe0, "Synonym for OP_RETURN.";
-    OP_RETURN_225 => 0xe1, "Synonym for OP_RETURN.";
-    OP_RETURN_226 => 0xe2, "Synonym for OP_RETURN.";
-    OP_RETURN_227 => 0xe3, "Synonym for OP_RETURN.";
-    OP_RETURN_228 => 0xe4, "Synonym for OP_RETURN.";
-    OP_RETURN_229 => 0xe5, "Synonym for OP_RETURN.";
-    OP_RETURN_230 => 0xe6, "Synonym for OP_RETURN.";
-    OP_RETURN_231 => 0xe7, "Synonym for OP_RETURN.";
-    OP_RETURN_232 => 0xe8, "Synonym for OP_RETURN.";
-    OP_RETURN_233 => 0xe9, "Synonym for OP_RETURN.";
-    OP_RETURN_234 => 0xea, "Synonym for OP_RETURN.";
-    OP_RETURN_235 => 0xeb, "Synonym for OP_RETURN.";
-    OP_RETURN_236 => 0xec, "Synonym for OP_RETURN.";
-    OP_RETURN_237 => 0xed, "Synonym for OP_RETURN.";
-    OP_RETURN_238 => 0xee, "Synonym for OP_RETURN.";
-    OP_RETURN_239 => 0xef, "Synonym for OP_RETURN.";
-    OP_RETURN_240 => 0xf0, "Synonym for OP_RETURN.";
-    OP_RETURN_241 => 0xf1, "Synonym for OP_RETURN.";
-    OP_RETURN_242 => 0xf2, "Synonym for OP_RETURN.";
-    OP_RETURN_243 => 0xf3, "Synonym for OP_RETURN.";
-    OP_RETURN_244 => 0xf4, "Synonym for OP_RETURN.";
-    OP_RETURN_245 => 0xf5, "Synonym for OP_RETURN.";
-    OP_RETURN_246 => 0xf6, "Synonym for OP_RETURN.";
-    OP_RETURN_247 => 0xf7, "Synonym for OP_RETURN.";
-    OP_RETURN_248 => 0xf8, "Synonym for OP_RETURN.";
-    OP_RETURN_249 => 0xf9, "Synonym for OP_RETURN.";
-    OP_RETURN_250 => 0xfa, "Synonym for OP_RETURN.";
-    OP_RETURN_251 => 0xfb, "Synonym for OP_RETURN.";
-    OP_RETURN_252 => 0xfc, "Synonym for OP_RETURN.";
-    OP_RETURN_253 => 0xfd, "Synonym for OP_RETURN.";
-    OP_RETURN_254 => 0xfe, "Synonym for OP_RETURN.";
-    OP_INVALIDOPCODE => 0xff, "Synonym for OP_RETURN."
-}
-
-/// Classification context for the opcode.
-///
-/// Some opcodes like [`OP_RESERVED`] abort the script in `ClassifyContext::Legacy` context,
-/// but will act as `OP_SUCCESSx` in `ClassifyContext::TapScript` (see BIP342 for full list).
-#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
-pub enum ClassifyContext {
-    /// Opcode used in tapscript context.
-    TapScript,
-    /// Opcode used in legacy context.
-    Legacy,
-}
-
-impl Opcode {
-    /// Classifies an Opcode into a broad class.
-    #[inline]
-    #[must_use]
-    pub fn classify(self, ctx: ClassifyContext) -> Class {
-        match (self, ctx) {
-            // 3 opcodes illegal in all contexts
-            (OP_VERIF, _) | (OP_VERNOTIF, _) | (OP_INVALIDOPCODE, _) => Class::IllegalOp,
-
-            // 15 opcodes illegal in Legacy context
-            #[rustfmt::skip]
-            (OP_CAT, ctx) | (OP_SUBSTR, ctx)
-            | (OP_LEFT, ctx) | (OP_RIGHT, ctx)
-            | (OP_INVERT, ctx)
-            | (OP_AND, ctx) | (OP_OR, ctx) | (OP_XOR, ctx)
-            | (OP_2MUL, ctx) | (OP_2DIV, ctx)
-            | (OP_MUL, ctx) | (OP_DIV, ctx) | (OP_MOD, ctx)
-            | (OP_LSHIFT, ctx) | (OP_RSHIFT, ctx) if ctx == ClassifyContext::Legacy => Class::IllegalOp,
-
-            // 87 opcodes of SuccessOp class only in TapScript context
-            (op, ClassifyContext::TapScript)
-                if op.code == 80
-                    || op.code == 98
-                    || (op.code >= 126 && op.code <= 129)
-                    || (op.code >= 131 && op.code <= 134)
-                    || (op.code >= 137 && op.code <= 138)
-                    || (op.code >= 141 && op.code <= 142)
-                    || (op.code >= 149 && op.code <= 153)
-                    || (op.code >= 187 && op.code <= 254) =>
-                Class::SuccessOp,
-
-            // 11 opcodes of NoOp class
-            (OP_NOP, _) => Class::NoOp,
-            (op, _) if op.code >= OP_NOP1.code && op.code <= OP_NOP10.code => Class::NoOp,
-
-            // 1 opcode for `OP_RETURN`
-            (OP_RETURN, _) => Class::ReturnOp,
-
-            // 4 opcodes operating equally to `OP_RETURN` only in Legacy context
-            (OP_RESERVED, ctx) | (OP_RESERVED1, ctx) | (OP_RESERVED2, ctx) | (OP_VER, ctx)
-                if ctx == ClassifyContext::Legacy =>
-                Class::ReturnOp,
-
-            // 71 opcodes operating equally to `OP_RETURN` only in Legacy context
-            (op, ClassifyContext::Legacy) if op.code >= OP_CHECKSIGADD.code => Class::ReturnOp,
-
-            // 2 opcodes operating equally to `OP_RETURN` only in TapScript context
-            (OP_CHECKMULTISIG, ClassifyContext::TapScript)
-            | (OP_CHECKMULTISIGVERIFY, ClassifyContext::TapScript) => Class::ReturnOp,
-
-            // 1 opcode of PushNum class
-            (OP_PUSHNUM_NEG1, _) => Class::PushNum(-1),
-
-            // 16 opcodes of PushNum class
-            (op, _) if op.code >= OP_PUSHNUM_1.code && op.code <= OP_PUSHNUM_16.code =>
-                Class::PushNum(1 + self.code as i32 - OP_PUSHNUM_1.code as i32),
-
-            // 76 opcodes of PushBytes class
-            (op, _) if op.code <= OP_PUSHBYTES_75.code => Class::PushBytes(self.code as u32),
-
-            // opcodes of Ordinary class: 61 for Legacy and 60 for TapScript context
-            (_, _) => Class::Ordinary(Ordinary::with(self)),
-        }
-    }
-
-    /// Encodes [`Opcode`] as a byte.
-    #[inline]
-    pub const fn to_u8(self) -> u8 { self.code }
-
-    /// Encodes PUSHNUM [`Opcode`] as a `u8` representing its number (1-16).
-    ///
-    /// Does not convert `OP_FALSE` to 0. Only `1` to `OP_PUSHNUM_16` are covered.
-    ///
-    /// # Returns
-    ///
-    /// Returns `None` if `self` is not a PUSHNUM.
-    #[inline]
-    #[must_use]
-    pub const fn decode_pushnum(self) -> Option<u8> {
-        const START: u8 = OP_PUSHNUM_1.code;
-        const END: u8 = OP_PUSHNUM_16.code;
-        match self.code {
-            START..=END => Some(self.code - START + 1),
-            _ => None,
-        }
-    }
-}
-
-impl From<u8> for Opcode {
-    #[inline]
-    fn from(b: u8) -> Opcode { Opcode { code: b } }
-}
-
-impl fmt::Debug for Opcode {
-    fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> { fmt::Display::fmt(self, f) }
-}
-
-#[cfg(feature = "serde")]
-impl serde::Serialize for Opcode {
-    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
-    where
-        S: serde::Serializer,
-    {
-        serializer.serialize_str(&self.to_string())
-    }
-}
-
-/// Broad categories of opcodes with similar behavior.
-#[derive(Copy, Clone, PartialEq, Eq, Debug)]
-pub enum Class {
-    /// Pushes the given number onto the stack.
-    PushNum(i32),
-    /// Pushes the given number of bytes onto the stack.
-    PushBytes(u32),
-    /// Fails the script if executed.
-    ReturnOp,
-    /// Succeeds the script even if not executed.
-    SuccessOp,
-    /// Fails the script even if not executed.
-    IllegalOp,
-    /// Does nothing.
-    NoOp,
-    /// Any opcode not covered above.
-    Ordinary(Ordinary),
-}
-
-macro_rules! ordinary_opcode {
-    ($($op:ident),*) => (
-        #[repr(u8)]
-        #[doc(hidden)]
-        #[derive(Copy, Clone, PartialEq, Eq, Debug)]
-        pub enum Ordinary {
-            $( $op = $op.code ),*
-        }
-
-        impl fmt::Display for Ordinary {
-            fn fmt(&self, f: &mut fmt::Formatter) -> core::fmt::Result {
-                match *self {
-                   $(Ordinary::$op => { f.pad(stringify!($op)) }),*
-                }
-            }
-        }
-
-        impl Ordinary {
-            fn with(b: Opcode) -> Self {
-                match b {
-                    $( $op => { Ordinary::$op } ),*
-                    _ => unreachable!("construction of `Ordinary` type from non-ordinary opcode {}", b),
-                }
-            }
-
-            /// Constructs a new [`Ordinary`] from an [`Opcode`].
-            pub fn from_opcode(b: Opcode) -> Option<Self> {
-                match b {
-                    $( $op => { Some(Ordinary::$op) } ),*
-                    _ => None,
-                }
-            }
-        }
-    );
-}
-
-// "Ordinary" opcodes -- should be 61 of these
-ordinary_opcode! {
-    // pushdata
-    OP_PUSHDATA1, OP_PUSHDATA2, OP_PUSHDATA4,
-    // control flow
-    OP_IF, OP_NOTIF, OP_ELSE, OP_ENDIF, OP_VERIFY,
-    // stack
-    OP_TOALTSTACK, OP_FROMALTSTACK,
-    OP_2DROP, OP_2DUP, OP_3DUP, OP_2OVER, OP_2ROT, OP_2SWAP,
-    OP_DROP, OP_DUP, OP_NIP, OP_OVER, OP_PICK, OP_ROLL, OP_ROT, OP_SWAP, OP_TUCK,
-    OP_IFDUP, OP_DEPTH, OP_SIZE,
-    // equality
-    OP_EQUAL, OP_EQUALVERIFY,
-    // arithmetic
-    OP_1ADD, OP_1SUB, OP_NEGATE, OP_ABS, OP_NOT, OP_0NOTEQUAL,
-    OP_ADD, OP_SUB, OP_BOOLAND, OP_BOOLOR,
-    OP_NUMEQUAL, OP_NUMEQUALVERIFY, OP_NUMNOTEQUAL, OP_LESSTHAN,
-    OP_GREATERTHAN, OP_LESSTHANOREQUAL, OP_GREATERTHANOREQUAL,
-    OP_MIN, OP_MAX, OP_WITHIN,
-    // crypto
-    OP_RIPEMD160, OP_SHA1, OP_SHA256, OP_HASH160, OP_HASH256,
-    OP_CODESEPARATOR, OP_CHECKSIG, OP_CHECKSIGVERIFY,
-    OP_CHECKMULTISIG, OP_CHECKMULTISIGVERIFY,
-    OP_CHECKSIGADD
-}
-
-impl Ordinary {
-    /// Encodes [`Opcode`] as a byte.
-    #[inline]
-    pub fn to_u8(self) -> u8 { self as u8 }
-}
-
-#[cfg(test)]
-mod tests {
-    use std::collections::HashSet;
-
-    use super::*;
-
-    macro_rules! roundtrip {
-        ($unique:expr, $op:ident) => {
-            assert_eq!($op, Opcode::from($op.to_u8()));
-
-            let s1 = format!("{}", $op);
-            let s2 = format!("{:?}", $op);
-            assert_eq!(s1, s2);
-            assert_eq!(s1, stringify!($op));
-            assert!($unique.insert(s1));
-        };
-    }
-
-    #[test]
-    fn formatting_works() {
-        let op = all::OP_NOP;
-        let s = format!("{:>10}", op);
-        assert_eq!(s, "    OP_NOP");
-    }
-
-    #[test]
-    fn ordinary_op_code() {
-        let ordinary_op = Ordinary::from_opcode(OP_PUSHDATA1).expect("0x4C");
-        assert_eq!(ordinary_op.to_u8(), 0x4C_u8);
-    }
-
-    #[test]
-    fn decode_pushnum() {
-        // Test all possible opcodes
-        // - Sanity check
-        assert_eq!(OP_PUSHNUM_1.code, 0x51_u8);
-        assert_eq!(OP_PUSHNUM_16.code, 0x60_u8);
-        for i in 0x00..=0xff_u8 {
-            let expected = match i {
-                // OP_PUSHNUM_1 ..= OP_PUSHNUM_16
-                0x51..=0x60 => Some(i - 0x50),
-                _ => None,
-            };
-            assert_eq!(Opcode::from(i).decode_pushnum(), expected);
-        }
-
-        // Test the named opcode constants
-        // - This is the OP right before PUSHNUMs start
-        assert!(OP_RESERVED.decode_pushnum().is_none());
-        assert_eq!(OP_PUSHNUM_1.decode_pushnum().expect("pushnum"), 1);
-        assert_eq!(OP_PUSHNUM_2.decode_pushnum().expect("pushnum"), 2);
-        assert_eq!(OP_PUSHNUM_3.decode_pushnum().expect("pushnum"), 3);
-        assert_eq!(OP_PUSHNUM_4.decode_pushnum().expect("pushnum"), 4);
-        assert_eq!(OP_PUSHNUM_5.decode_pushnum().expect("pushnum"), 5);
-        assert_eq!(OP_PUSHNUM_6.decode_pushnum().expect("pushnum"), 6);
-        assert_eq!(OP_PUSHNUM_7.decode_pushnum().expect("pushnum"), 7);
-        assert_eq!(OP_PUSHNUM_8.decode_pushnum().expect("pushnum"), 8);
-        assert_eq!(OP_PUSHNUM_9.decode_pushnum().expect("pushnum"), 9);
-        assert_eq!(OP_PUSHNUM_10.decode_pushnum().expect("pushnum"), 10);
-        assert_eq!(OP_PUSHNUM_11.decode_pushnum().expect("pushnum"), 11);
-        assert_eq!(OP_PUSHNUM_12.decode_pushnum().expect("pushnum"), 12);
-        assert_eq!(OP_PUSHNUM_13.decode_pushnum().expect("pushnum"), 13);
-        assert_eq!(OP_PUSHNUM_14.decode_pushnum().expect("pushnum"), 14);
-        assert_eq!(OP_PUSHNUM_15.decode_pushnum().expect("pushnum"), 15);
-        assert_eq!(OP_PUSHNUM_16.decode_pushnum().expect("pushnum"), 16);
-        // - This is the OP right after PUSHNUMs end
-        assert!(OP_NOP.decode_pushnum().is_none());
-    }
-
-    #[test]
-    fn classify_test() {
-        let op174 = OP_CHECKMULTISIG;
-        assert_eq!(
-            op174.classify(ClassifyContext::Legacy),
-            Class::Ordinary(Ordinary::OP_CHECKMULTISIG)
-        );
-        assert_eq!(op174.classify(ClassifyContext::TapScript), Class::ReturnOp);
-
-        let op175 = OP_CHECKMULTISIGVERIFY;
-        assert_eq!(
-            op175.classify(ClassifyContext::Legacy),
-            Class::Ordinary(Ordinary::OP_CHECKMULTISIGVERIFY)
-        );
-        assert_eq!(op175.classify(ClassifyContext::TapScript), Class::ReturnOp);
-
-        let op186 = OP_CHECKSIGADD;
-        assert_eq!(op186.classify(ClassifyContext::Legacy), Class::ReturnOp);
-        assert_eq!(
-            op186.classify(ClassifyContext::TapScript),
-            Class::Ordinary(Ordinary::OP_CHECKSIGADD)
-        );
-
-        let op187 = OP_RETURN_187;
-        assert_eq!(op187.classify(ClassifyContext::Legacy), Class::ReturnOp);
-        assert_eq!(op187.classify(ClassifyContext::TapScript), Class::SuccessOp);
-    }
-
-    #[test]
-    fn str_roundtrip() {
-        let mut unique = HashSet::new();
-        roundtrip!(unique, OP_PUSHBYTES_0);
-        roundtrip!(unique, OP_PUSHBYTES_1);
-        roundtrip!(unique, OP_PUSHBYTES_2);
-        roundtrip!(unique, OP_PUSHBYTES_3);
-        roundtrip!(unique, OP_PUSHBYTES_4);
-        roundtrip!(unique, OP_PUSHBYTES_5);
-        roundtrip!(unique, OP_PUSHBYTES_6);
-        roundtrip!(unique, OP_PUSHBYTES_7);
-        roundtrip!(unique, OP_PUSHBYTES_8);
-        roundtrip!(unique, OP_PUSHBYTES_9);
-        roundtrip!(unique, OP_PUSHBYTES_10);
-        roundtrip!(unique, OP_PUSHBYTES_11);
-        roundtrip!(unique, OP_PUSHBYTES_12);
-        roundtrip!(unique, OP_PUSHBYTES_13);
-        roundtrip!(unique, OP_PUSHBYTES_14);
-        roundtrip!(unique, OP_PUSHBYTES_15);
-        roundtrip!(unique, OP_PUSHBYTES_16);
-        roundtrip!(unique, OP_PUSHBYTES_17);
-        roundtrip!(unique, OP_PUSHBYTES_18);
-        roundtrip!(unique, OP_PUSHBYTES_19);
-        roundtrip!(unique, OP_PUSHBYTES_20);
-        roundtrip!(unique, OP_PUSHBYTES_21);
-        roundtrip!(unique, OP_PUSHBYTES_22);
-        roundtrip!(unique, OP_PUSHBYTES_23);
-        roundtrip!(unique, OP_PUSHBYTES_24);
-        roundtrip!(unique, OP_PUSHBYTES_25);
-        roundtrip!(unique, OP_PUSHBYTES_26);
-        roundtrip!(unique, OP_PUSHBYTES_27);
-        roundtrip!(unique, OP_PUSHBYTES_28);
-        roundtrip!(unique, OP_PUSHBYTES_29);
-        roundtrip!(unique, OP_PUSHBYTES_30);
-        roundtrip!(unique, OP_PUSHBYTES_31);
-        roundtrip!(unique, OP_PUSHBYTES_32);
-        roundtrip!(unique, OP_PUSHBYTES_33);
-        roundtrip!(unique, OP_PUSHBYTES_34);
-        roundtrip!(unique, OP_PUSHBYTES_35);
-        roundtrip!(unique, OP_PUSHBYTES_36);
-        roundtrip!(unique, OP_PUSHBYTES_37);
-        roundtrip!(unique, OP_PUSHBYTES_38);
-        roundtrip!(unique, OP_PUSHBYTES_39);
-        roundtrip!(unique, OP_PUSHBYTES_40);
-        roundtrip!(unique, OP_PUSHBYTES_41);
-        roundtrip!(unique, OP_PUSHBYTES_42);
-        roundtrip!(unique, OP_PUSHBYTES_43);
-        roundtrip!(unique, OP_PUSHBYTES_44);
-        roundtrip!(unique, OP_PUSHBYTES_45);
-        roundtrip!(unique, OP_PUSHBYTES_46);
-        roundtrip!(unique, OP_PUSHBYTES_47);
-        roundtrip!(unique, OP_PUSHBYTES_48);
-        roundtrip!(unique, OP_PUSHBYTES_49);
-        roundtrip!(unique, OP_PUSHBYTES_50);
-        roundtrip!(unique, OP_PUSHBYTES_51);
-        roundtrip!(unique, OP_PUSHBYTES_52);
-        roundtrip!(unique, OP_PUSHBYTES_53);
-        roundtrip!(unique, OP_PUSHBYTES_54);
-        roundtrip!(unique, OP_PUSHBYTES_55);
-        roundtrip!(unique, OP_PUSHBYTES_56);
-        roundtrip!(unique, OP_PUSHBYTES_57);
-        roundtrip!(unique, OP_PUSHBYTES_58);
-        roundtrip!(unique, OP_PUSHBYTES_59);
-        roundtrip!(unique, OP_PUSHBYTES_60);
-        roundtrip!(unique, OP_PUSHBYTES_61);
-        roundtrip!(unique, OP_PUSHBYTES_62);
-        roundtrip!(unique, OP_PUSHBYTES_63);
-        roundtrip!(unique, OP_PUSHBYTES_64);
-        roundtrip!(unique, OP_PUSHBYTES_65);
-        roundtrip!(unique, OP_PUSHBYTES_66);
-        roundtrip!(unique, OP_PUSHBYTES_67);
-        roundtrip!(unique, OP_PUSHBYTES_68);
-        roundtrip!(unique, OP_PUSHBYTES_69);
-        roundtrip!(unique, OP_PUSHBYTES_70);
-        roundtrip!(unique, OP_PUSHBYTES_71);
-        roundtrip!(unique, OP_PUSHBYTES_72);
-        roundtrip!(unique, OP_PUSHBYTES_73);
-        roundtrip!(unique, OP_PUSHBYTES_74);
-        roundtrip!(unique, OP_PUSHBYTES_75);
-        roundtrip!(unique, OP_PUSHDATA1);
-        roundtrip!(unique, OP_PUSHDATA2);
-        roundtrip!(unique, OP_PUSHDATA4);
-        roundtrip!(unique, OP_PUSHNUM_NEG1);
-        roundtrip!(unique, OP_RESERVED);
-        roundtrip!(unique, OP_PUSHNUM_1);
-        roundtrip!(unique, OP_PUSHNUM_2);
-        roundtrip!(unique, OP_PUSHNUM_3);
-        roundtrip!(unique, OP_PUSHNUM_4);
-        roundtrip!(unique, OP_PUSHNUM_5);
-        roundtrip!(unique, OP_PUSHNUM_6);
-        roundtrip!(unique, OP_PUSHNUM_7);
-        roundtrip!(unique, OP_PUSHNUM_8);
-        roundtrip!(unique, OP_PUSHNUM_9);
-        roundtrip!(unique, OP_PUSHNUM_10);
-        roundtrip!(unique, OP_PUSHNUM_11);
-        roundtrip!(unique, OP_PUSHNUM_12);
-        roundtrip!(unique, OP_PUSHNUM_13);
-        roundtrip!(unique, OP_PUSHNUM_14);
-        roundtrip!(unique, OP_PUSHNUM_15);
-        roundtrip!(unique, OP_PUSHNUM_16);
-        roundtrip!(unique, OP_NOP);
-        roundtrip!(unique, OP_VER);
-        roundtrip!(unique, OP_IF);
-        roundtrip!(unique, OP_NOTIF);
-        roundtrip!(unique, OP_VERIF);
-        roundtrip!(unique, OP_VERNOTIF);
-        roundtrip!(unique, OP_ELSE);
-        roundtrip!(unique, OP_ENDIF);
-        roundtrip!(unique, OP_VERIFY);
-        roundtrip!(unique, OP_RETURN);
-        roundtrip!(unique, OP_TOALTSTACK);
-        roundtrip!(unique, OP_FROMALTSTACK);
-        roundtrip!(unique, OP_2DROP);
-        roundtrip!(unique, OP_2DUP);
-        roundtrip!(unique, OP_3DUP);
-        roundtrip!(unique, OP_2OVER);
-        roundtrip!(unique, OP_2ROT);
-        roundtrip!(unique, OP_2SWAP);
-        roundtrip!(unique, OP_IFDUP);
-        roundtrip!(unique, OP_DEPTH);
-        roundtrip!(unique, OP_DROP);
-        roundtrip!(unique, OP_DUP);
-        roundtrip!(unique, OP_NIP);
-        roundtrip!(unique, OP_OVER);
-        roundtrip!(unique, OP_PICK);
-        roundtrip!(unique, OP_ROLL);
-        roundtrip!(unique, OP_ROT);
-        roundtrip!(unique, OP_SWAP);
-        roundtrip!(unique, OP_TUCK);
-        roundtrip!(unique, OP_CAT);
-        roundtrip!(unique, OP_SUBSTR);
-        roundtrip!(unique, OP_LEFT);
-        roundtrip!(unique, OP_RIGHT);
-        roundtrip!(unique, OP_SIZE);
-        roundtrip!(unique, OP_INVERT);
-        roundtrip!(unique, OP_AND);
-        roundtrip!(unique, OP_OR);
-        roundtrip!(unique, OP_XOR);
-        roundtrip!(unique, OP_EQUAL);
-        roundtrip!(unique, OP_EQUALVERIFY);
-        roundtrip!(unique, OP_RESERVED1);
-        roundtrip!(unique, OP_RESERVED2);
-        roundtrip!(unique, OP_1ADD);
-        roundtrip!(unique, OP_1SUB);
-        roundtrip!(unique, OP_2MUL);
-        roundtrip!(unique, OP_2DIV);
-        roundtrip!(unique, OP_NEGATE);
-        roundtrip!(unique, OP_ABS);
-        roundtrip!(unique, OP_NOT);
-        roundtrip!(unique, OP_0NOTEQUAL);
-        roundtrip!(unique, OP_ADD);
-        roundtrip!(unique, OP_SUB);
-        roundtrip!(unique, OP_MUL);
-        roundtrip!(unique, OP_DIV);
-        roundtrip!(unique, OP_MOD);
-        roundtrip!(unique, OP_LSHIFT);
-        roundtrip!(unique, OP_RSHIFT);
-        roundtrip!(unique, OP_BOOLAND);
-        roundtrip!(unique, OP_BOOLOR);
-        roundtrip!(unique, OP_NUMEQUAL);
-        roundtrip!(unique, OP_NUMEQUALVERIFY);
-        roundtrip!(unique, OP_NUMNOTEQUAL);
-        roundtrip!(unique, OP_LESSTHAN);
-        roundtrip!(unique, OP_GREATERTHAN);
-        roundtrip!(unique, OP_LESSTHANOREQUAL);
-        roundtrip!(unique, OP_GREATERTHANOREQUAL);
-        roundtrip!(unique, OP_MIN);
-        roundtrip!(unique, OP_MAX);
-        roundtrip!(unique, OP_WITHIN);
-        roundtrip!(unique, OP_RIPEMD160);
-        roundtrip!(unique, OP_SHA1);
-        roundtrip!(unique, OP_SHA256);
-        roundtrip!(unique, OP_HASH160);
-        roundtrip!(unique, OP_HASH256);
-        roundtrip!(unique, OP_CODESEPARATOR);
-        roundtrip!(unique, OP_CHECKSIG);
-        roundtrip!(unique, OP_CHECKSIGVERIFY);
-        roundtrip!(unique, OP_CHECKMULTISIG);
-        roundtrip!(unique, OP_CHECKMULTISIGVERIFY);
-        roundtrip!(unique, OP_NOP1);
-        roundtrip!(unique, OP_CLTV);
-        roundtrip!(unique, OP_CSV);
-        roundtrip!(unique, OP_NOP4);
-        roundtrip!(unique, OP_NOP5);
-        roundtrip!(unique, OP_NOP6);
-        roundtrip!(unique, OP_NOP7);
-        roundtrip!(unique, OP_NOP8);
-        roundtrip!(unique, OP_NOP9);
-        roundtrip!(unique, OP_NOP10);
-        roundtrip!(unique, OP_CHECKSIGADD);
-        roundtrip!(unique, OP_RETURN_187);
-        roundtrip!(unique, OP_RETURN_188);
-        roundtrip!(unique, OP_RETURN_189);
-        roundtrip!(unique, OP_RETURN_190);
-        roundtrip!(unique, OP_RETURN_191);
-        roundtrip!(unique, OP_RETURN_192);
-        roundtrip!(unique, OP_RETURN_193);
-        roundtrip!(unique, OP_RETURN_194);
-        roundtrip!(unique, OP_RETURN_195);
-        roundtrip!(unique, OP_RETURN_196);
-        roundtrip!(unique, OP_RETURN_197);
-        roundtrip!(unique, OP_RETURN_198);
-        roundtrip!(unique, OP_RETURN_199);
-        roundtrip!(unique, OP_RETURN_200);
-        roundtrip!(unique, OP_RETURN_201);
-        roundtrip!(unique, OP_RETURN_202);
-        roundtrip!(unique, OP_RETURN_203);
-        roundtrip!(unique, OP_RETURN_204);
-        roundtrip!(unique, OP_RETURN_205);
-        roundtrip!(unique, OP_RETURN_206);
-        roundtrip!(unique, OP_RETURN_207);
-        roundtrip!(unique, OP_RETURN_208);
-        roundtrip!(unique, OP_RETURN_209);
-        roundtrip!(unique, OP_RETURN_210);
-        roundtrip!(unique, OP_RETURN_211);
-        roundtrip!(unique, OP_RETURN_212);
-        roundtrip!(unique, OP_RETURN_213);
-        roundtrip!(unique, OP_RETURN_214);
-        roundtrip!(unique, OP_RETURN_215);
-        roundtrip!(unique, OP_RETURN_216);
-        roundtrip!(unique, OP_RETURN_217);
-        roundtrip!(unique, OP_RETURN_218);
-        roundtrip!(unique, OP_RETURN_219);
-        roundtrip!(unique, OP_RETURN_220);
-        roundtrip!(unique, OP_RETURN_221);
-        roundtrip!(unique, OP_RETURN_222);
-        roundtrip!(unique, OP_RETURN_223);
-        roundtrip!(unique, OP_RETURN_224);
-        roundtrip!(unique, OP_RETURN_225);
-        roundtrip!(unique, OP_RETURN_226);
-        roundtrip!(unique, OP_RETURN_227);
-        roundtrip!(unique, OP_RETURN_228);
-        roundtrip!(unique, OP_RETURN_229);
-        roundtrip!(unique, OP_RETURN_230);
-        roundtrip!(unique, OP_RETURN_231);
-        roundtrip!(unique, OP_RETURN_232);
-        roundtrip!(unique, OP_RETURN_233);
-        roundtrip!(unique, OP_RETURN_234);
-        roundtrip!(unique, OP_RETURN_235);
-        roundtrip!(unique, OP_RETURN_236);
-        roundtrip!(unique, OP_RETURN_237);
-        roundtrip!(unique, OP_RETURN_238);
-        roundtrip!(unique, OP_RETURN_239);
-        roundtrip!(unique, OP_RETURN_240);
-        roundtrip!(unique, OP_RETURN_241);
-        roundtrip!(unique, OP_RETURN_242);
-        roundtrip!(unique, OP_RETURN_243);
-        roundtrip!(unique, OP_RETURN_244);
-        roundtrip!(unique, OP_RETURN_245);
-        roundtrip!(unique, OP_RETURN_246);
-        roundtrip!(unique, OP_RETURN_247);
-        roundtrip!(unique, OP_RETURN_248);
-        roundtrip!(unique, OP_RETURN_249);
-        roundtrip!(unique, OP_RETURN_250);
-        roundtrip!(unique, OP_RETURN_251);
-        roundtrip!(unique, OP_RETURN_252);
-        roundtrip!(unique, OP_RETURN_253);
-        roundtrip!(unique, OP_RETURN_254);
-        roundtrip!(unique, OP_INVALIDOPCODE);
-        assert_eq!(unique.len(), 256);
-    }
-}
diff --git a/bitcoin/src/blockdata/script/mod.rs b/bitcoin/src/blockdata/script/mod.rs
index 1bd2bddf..b77acb2c 100644
--- a/bitcoin/src/blockdata/script/mod.rs
+++ b/bitcoin/src/blockdata/script/mod.rs
@@ -61,12 +61,12 @@
 use core::fmt;
 
 use io::{BufRead, Write};
+use primitives::opcodes::all::*;
+use primitives::opcodes::Opcode;
 
 use crate::consensus::{encode, Decodable, Encodable};
 use crate::internal_macros::impl_asref_push_bytes;
 use crate::key::WPubkeyHash;
-use crate::opcodes::all::*;
-use crate::opcodes::Opcode;
 use crate::prelude::Vec;
 use crate::OutPoint;
 
diff --git a/bitcoin/src/crypto/key.rs b/bitcoin/src/crypto/key.rs
index c1d67bb6..7a045cfb 100644
--- a/bitcoin/src/crypto/key.rs
+++ b/bitcoin/src/crypto/key.rs
@@ -459,22 +459,17 @@ pub fn to_bytes(self) -> Vec<u8> { self.to_vec() }
     /// Serializes the private key to bytes.
     pub fn to_vec(self) -> Vec<u8> { self.inner[..].to_vec() }
 
-    /// Deserializes a private key from a byte array.
-    pub fn from_byte_array(
-        data: [u8; 32],
-        network: impl Into<NetworkKind>
-    ) -> Result<PrivateKey, secp256k1::Error> {
-        Ok(PrivateKey::new(secp256k1::SecretKey::from_byte_array(&data)?, network))
-    }
-
     /// Deserializes a private key from a slice.
-    #[deprecated(since = "TBD", note = "use from_byte_array instead")]
     pub fn from_slice(
         data: &[u8],
         network: impl Into<NetworkKind>,
     ) -> Result<PrivateKey, secp256k1::Error> {
-        let array = data.try_into().map_err(|_| secp256k1::Error::InvalidSecretKey)?;
-        Self::from_byte_array(array, network)
+        Ok(PrivateKey::new(
+            secp256k1::SecretKey::from_byte_array(
+                data[..32].try_into().expect("Slice should be exactly 32 bytes"),
+            )?,
+            network,
+        ))
     }
 
     /// Formats the private key to WIF format.
@@ -1605,13 +1600,4 @@ fn public_key_from_str_invalid_str() {
             panic!("Expected Invalid char error");
         }
     }
-
-    #[test]
-    #[allow(deprecated)] // tests the deprecated function
-    #[allow(deprecated_in_future)]
-    fn invalid_private_key_len() {
-        use crate::Network;
-        assert!(PrivateKey::from_slice(&[1u8; 31], Network::Regtest).is_err());
-        assert!(PrivateKey::from_slice(&[1u8; 33], Network::Regtest).is_err());
-    }
 }
diff --git a/bitcoin/src/hash_types.rs b/bitcoin/src/hash_types.rs
index e564999c..10a995de 100644
--- a/bitcoin/src/hash_types.rs
+++ b/bitcoin/src/hash_types.rs
@@ -13,9 +13,10 @@
 #[cfg(test)]
 mod tests {
     use super::*;
-    use crate::key::{PubkeyHash, WPubkeyHash};
-    use crate::script::{ScriptHash, WScriptHash};
-    use crate::{LegacySighash, SegwitV0Sighash, TapSighash, XKeyIdentifier};
+    use crate::{
+        LegacySighash, PubkeyHash, ScriptHash, SegwitV0Sighash, TapSighash, WPubkeyHash,
+        WScriptHash, XKeyIdentifier,
+    };
 
     #[rustfmt::skip]
     /// sha256d of the empty string
diff --git a/bitcoin/src/lib.rs b/bitcoin/src/lib.rs
index e097ed4f..af6386a4 100644
--- a/bitcoin/src/lib.rs
+++ b/bitcoin/src/lib.rs
@@ -123,6 +123,7 @@
         Unchecked as BlockUnchecked, Validation as BlockValidation, WitnessCommitment,
     },
     merkle_tree::{TxMerkleNode, WitnessMerkleNode},
+    opcodes::Opcode,
     pow::CompactTarget, // No `pow` module outside of `primitives`.
     script::{Script, ScriptBuf},
     sequence::{self, Sequence}, // No `sequence` module outside of `primitives`.
@@ -143,7 +144,9 @@
     bip158::{FilterHash, FilterHeader},
     bip32::XKeyIdentifier,
     crypto::ecdsa,
-    crypto::key::{self, CompressedPublicKey, PrivateKey, PublicKey, XOnlyPublicKey},
+    crypto::key::{
+        self, CompressedPublicKey, PrivateKey, PubkeyHash, PublicKey, WPubkeyHash, XOnlyPublicKey,
+    },
     crypto::sighash::{self, LegacySighash, SegwitV0Sighash, TapSighash, TapSighashTag},
     merkle_tree::MerkleBlock,
     network::params::{self, Params},
@@ -158,12 +161,12 @@
 pub use crate::{
     // Also, re-export types and modules from `blockdata` that don't come from `primitives`.
     blockdata::locktime::{absolute, relative},
-    blockdata::opcodes::{self, Opcode},
     blockdata::script::witness_program::{self, WitnessProgram},
     blockdata::script::witness_version::{self, WitnessVersion},
+    blockdata::script::{ScriptHash, WScriptHash}, // TODO: Move these down below after they are in primitives.
     // These modules also re-export all the respective `primitives` types.
     blockdata::{
-        block, constants, fee_rate, locktime, script, transaction, weight, witness,
+        block, constants, fee_rate, locktime, opcodes, script, transaction, weight, witness,
     },
 };
 
diff --git a/bitcoin/src/psbt/mod.rs b/bitcoin/src/psbt/mod.rs
index f10cbbb3..d7d6c799 100644
--- a/bitcoin/src/psbt/mod.rs
+++ b/bitcoin/src/psbt/mod.rs
@@ -135,7 +135,6 @@ pub fn from_unsigned_tx(tx: Transaction) -> Result<Self, Error> {
     /// An alias for [`extract_tx_fee_rate_limit`].
     ///
     /// [`extract_tx_fee_rate_limit`]: Psbt::extract_tx_fee_rate_limit
-    #[allow(clippy::result_large_err)]  // The PSBT returned in `SendingToomuch` is large.
     pub fn extract_tx(self) -> Result<Transaction, ExtractTxError> {
         self.internal_extract_tx_with_fee_rate_limit(Self::DEFAULT_MAX_FEE_RATE)
     }
@@ -147,7 +146,6 @@ pub fn extract_tx(self) -> Result<Transaction, ExtractTxError> {
     /// [`ExtractTxError`] variants will contain either the [`Psbt`] itself or the [`Transaction`]
     /// that was extracted. These can be extracted from the Errors in order to recover.
     /// See the error documentation for info on the variants. In general, it covers large fees.
-    #[allow(clippy::result_large_err)]  // The PSBT returned in `SendingToomuch` is large.
     pub fn extract_tx_fee_rate_limit(self) -> Result<Transaction, ExtractTxError> {
         self.internal_extract_tx_with_fee_rate_limit(Self::DEFAULT_MAX_FEE_RATE)
     }
@@ -159,7 +157,6 @@ pub fn extract_tx_fee_rate_limit(self) -> Result<Transaction, ExtractTxError> {
     /// See [`extract_tx`].
     ///
     /// [`extract_tx`]: Psbt::extract_tx
-    #[allow(clippy::result_large_err)]  // The PSBT returned in `SendingToomuch` is large.
     pub fn extract_tx_with_fee_rate_limit(
         self,
         max_fee_rate: FeeRate,
@@ -187,7 +184,6 @@ fn internal_extract_tx(self) -> Transaction {
     }
 
     #[inline]
-    #[allow(clippy::result_large_err)]  // The PSBT returned in `SendingToomuch` is large.
     fn internal_extract_tx_with_fee_rate_limit(
         self,
         max_fee_rate: FeeRate,
diff --git a/bitcoin/src/psbt/serialize.rs b/bitcoin/src/psbt/serialize.rs
index 89de08dc..26bfc9b3 100644
--- a/bitcoin/src/psbt/serialize.rs
+++ b/bitcoin/src/psbt/serialize.rs
@@ -261,7 +261,7 @@ fn serialize(&self) -> Vec<u8> { XOnlyPublicKey::serialize(self).to_vec() }
 impl Deserialize for XOnlyPublicKey {
     fn deserialize(bytes: &[u8]) -> Result<Self, Error> {
         XOnlyPublicKey::from_byte_array(
-            bytes.try_into().map_err(|_| Error::InvalidXOnlyPublicKey)?,
+            bytes[..32].try_into().expect("statistically impossible to hit"),
         )
         .map_err(|_| Error::InvalidXOnlyPublicKey)
     }
@@ -461,12 +461,6 @@ fn can_deserialize_non_standard_psbt_sighash_type() {
         assert!(sighash.is_ok())
     }
 
-    #[test]
-    fn deserialize_xonly_public_key_len() {
-        assert!(XOnlyPublicKey::deserialize(&[1; 31]).is_err());
-        assert!(XOnlyPublicKey::deserialize(&[1; 33]).is_err());
-    }
-
     #[test]
     #[should_panic(expected = "InvalidMagic")]
     fn invalid_vector_1() {
diff --git a/contrib/release.sh b/contrib/release.sh
index c0265794..b30f2fb8 100755
--- a/contrib/release.sh
+++ b/contrib/release.sh
@@ -6,7 +6,7 @@
 set -euox pipefail
 
 main () {
-    for crate in "bitcoin" "hashes" "internals" "units"; do
+    for crate in "internals" "hashes" "bitcoin"; do
         if release_changes $crate; then
             echo "$crate has changes implying this is a release PR, checking if we can publish ..."
 
@@ -35,14 +35,12 @@ release_changes() {
 # We use `set -e` so this will fail the script if the dry-run fails.
 publish_dry_run() {
     local crate=$1
-    if [ "$crate" == "bitcoin" ]; then
-        cargo publish -p "bitcoin" --dry-run
-    elif [ "$crate" == "hashes" ]; then
+    if [ "$crate" == "hashes" ]; then
         cargo publish -p "bitcoin_hashes" --dry-run
     elif [ "$crate" == "internals" ]; then
         cargo publish -p "bitcoin-internals" --dry-run
-    elif [ "$crate" == "units" ]; then
-        cargo publish -p "bitcoin-units" --dry-run
+    elif [ "$crate" == "bitcoin" ]; then
+        cargo publish -p "bitcoin" --dry-run
     fi
 }
 
diff --git a/fuzz/fuzz_targets/bitcoin/deserialize_psbt.rs b/fuzz/fuzz_targets/bitcoin/deserialize_psbt.rs
index b3fe54bb..59d28142 100644
--- a/fuzz/fuzz_targets/bitcoin/deserialize_psbt.rs
+++ b/fuzz/fuzz_targets/bitcoin/deserialize_psbt.rs
@@ -1,7 +1,16 @@
 use honggfuzz::fuzz;
 
-mod fuzz_utils;
-use fuzz_utils::consume_random_bytes;
+fn consume_random_bytes<'a>(data: &mut &'a [u8]) -> &'a [u8] {
+    if data.is_empty() {
+        return &[];
+    }
+
+    let length = (data[0] as usize) % (data.len() + 1);
+    let (bytes, rest) = data.split_at(length);
+    *data = rest;
+
+    bytes
+}
 
 fn do_test(data: &[u8]) {
     let mut new_data = data;
diff --git a/fuzz/fuzz_targets/bitcoin/deserialize_script.rs b/fuzz/fuzz_targets/bitcoin/deserialize_script.rs
index e7c1191b..6943bc64 100644
--- a/fuzz/fuzz_targets/bitcoin/deserialize_script.rs
+++ b/fuzz/fuzz_targets/bitcoin/deserialize_script.rs
@@ -1,27 +1,15 @@
 use bitcoin::address::Address;
 use bitcoin::consensus::encode;
 use bitcoin::script::{self, ScriptExt as _};
-use bitcoin::{FeeRate, Network};
+use bitcoin::Network;
 use honggfuzz::fuzz;
 
-mod fuzz_utils;
-use fuzz_utils::{consume_random_bytes, consume_u64};
-
 fn do_test(data: &[u8]) {
-    let mut new_data = data;
-    let bytes = consume_random_bytes(&mut new_data);
-    let s: Result<script::ScriptBuf, _> = encode::deserialize(bytes);
+    let s: Result<script::ScriptBuf, _> = encode::deserialize(data);
     if let Ok(script) = s {
         let _: Result<Vec<script::Instruction>, script::Error> = script.instructions().collect();
 
         let _ = script.to_string();
-        let _ = script.count_sigops();
-        let _ = script.count_sigops_legacy();
-        let _ = script.minimal_non_dust();
-
-        let fee_rate = FeeRate::from_sat_per_kwu(consume_u64(&mut new_data));
-        let _ = script.minimal_non_dust_custom(fee_rate);
-
         let mut b = script::Builder::new();
         for ins in script.instructions_minimal() {
             if ins.is_err() {
diff --git a/fuzz/fuzz_targets/bitcoin/fuzz_utils.rs b/fuzz/fuzz_targets/bitcoin/fuzz_utils.rs
deleted file mode 100644
index aeaa11ae..00000000
--- a/fuzz/fuzz_targets/bitcoin/fuzz_utils.rs
+++ /dev/null
@@ -1,33 +0,0 @@
-pub fn consume_random_bytes<'a>(data: &mut &'a [u8]) -> &'a [u8] {
-    if data.is_empty() {
-        return &[];
-    }
-
-    let length = (data[0] as usize) % (data.len() + 1);
-    let (bytes, rest) = data.split_at(length);
-    *data = rest;
-
-    bytes
-}
-
-#[allow(dead_code)]
-pub fn consume_u64(data: &mut &[u8]) -> u64 {
-    // We need at least 8 bytes to read a u64
-    if data.len() < 8 {
-        return 0;
-    }
-
-    let (u64_bytes, rest) = data.split_at(8);
-    *data = rest;
-
-    u64::from_le_bytes([
-        u64_bytes[0],
-        u64_bytes[1],
-        u64_bytes[2],
-        u64_bytes[3],
-        u64_bytes[4],
-        u64_bytes[5],
-        u64_bytes[6],
-        u64_bytes[7],
-    ])
-}
diff --git a/fuzz/generate-files.sh b/fuzz/generate-files.sh
index bc742f26..e1c8a9d4 100755
--- a/fuzz/generate-files.sh
+++ b/fuzz/generate-files.sh
@@ -89,7 +89,7 @@ $(for name in $(listTargetNames); do echo "          $name,"; done)
           echo "Using RUSTFLAGS \$RUSTFLAGS"
           cd fuzz && ./fuzz.sh "\${{ matrix.fuzz_target }}"
       - run: echo "\${{ matrix.fuzz_target }}" >executed_\${{ matrix.fuzz_target }}
-      - uses: actions/upload-artifact@v4
+      - uses: actions/upload-artifact@v3
         with:
           name: executed_\${{ matrix.fuzz_target }}
           path: executed_\${{ matrix.fuzz_target }}
@@ -100,7 +100,7 @@ $(for name in $(listTargetNames); do echo "          $name,"; done)
     runs-on: ubuntu-latest
     steps:
       - uses: actions/checkout@v4
-      - uses: actions/download-artifact@v4
+      - uses: actions/download-artifact@v3
       - name: Display structure of downloaded files
         run: ls -R
       - run: find executed_* -type f -exec cat {} + | sort > executed
diff --git a/nightly-version b/nightly-version
index 44b3e69d..bd3641e4 100644
--- a/nightly-version
+++ b/nightly-version
@@ -1,1 +1,1 @@
-nightly-2025-03-03
+nightly-2025-02-28
diff --git a/primitives/src/block.rs b/primitives/src/block.rs
index b819734e..b30a2c6c 100644
--- a/primitives/src/block.rs
+++ b/primitives/src/block.rs
@@ -70,7 +70,6 @@ pub struct Block<V = Unchecked>
 #[cfg(feature = "alloc")]
 impl Block<Unchecked> {
     /// Constructs a new `Block` without doing any validation.
-    #[inline]
     pub fn new_unchecked(header: Header, transactions: Vec<Transaction>) -> Block<Unchecked> {
         Block { header, transactions, witness_root: None, marker: PhantomData::<Unchecked> }
     }
@@ -79,7 +78,6 @@ pub fn new_unchecked(header: Header, transactions: Vec<Transaction>) -> Block<Un
     ///
     /// You should only use this function if you trust the block i.e., it comes from a trusted node.
     #[must_use]
-    #[inline]
     pub fn assume_checked(self, witness_root: Option<WitnessMerkleNode>) -> Block<Checked> {
         Block {
             header: self.header,
@@ -90,44 +88,37 @@ pub fn assume_checked(self, witness_root: Option<WitnessMerkleNode>) -> Block<Ch
     }
 
     /// Decomposes block into its constituent parts.
-    #[inline]
     pub fn into_parts(self) -> (Header, Vec<Transaction>) { (self.header, self.transactions) }
 }
 
 #[cfg(feature = "alloc")]
 impl Block<Checked> {
     /// Gets a reference to the block header.
-    #[inline]
     pub fn header(&self) -> &Header { &self.header }
 
     /// Gets a reference to the block's list of transactions.
-    #[inline]
     pub fn transactions(&self) -> &[Transaction] { &self.transactions }
 
     /// Returns the cached witness root if one is present.
     ///
     /// It is assumed that a block will have the witness root calculated and cached as part of the
     /// validation process.
-    #[inline]
     pub fn cached_witness_root(&self) -> Option<WitnessMerkleNode> { self.witness_root }
 }
 
 #[cfg(feature = "alloc")]
 impl<V: Validation> Block<V> {
     /// Returns the block hash.
-    #[inline]
     pub fn block_hash(&self) -> BlockHash { self.header.block_hash() }
 }
 
 #[cfg(feature = "alloc")]
 impl From<Block> for BlockHash {
-    #[inline]
     fn from(block: Block) -> BlockHash { block.block_hash() }
 }
 
 #[cfg(feature = "alloc")]
 impl From<&Block> for BlockHash {
-    #[inline]
     fn from(block: &Block) -> BlockHash { block.block_hash() }
 }
 
@@ -221,12 +212,10 @@ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
 }
 
 impl From<Header> for BlockHash {
-    #[inline]
     fn from(header: Header) -> BlockHash { header.block_hash() }
 }
 
 impl From<&Header> for BlockHash {
-    #[inline]
     fn from(header: &Header) -> BlockHash { header.block_hash() }
 }
 
@@ -274,7 +263,6 @@ pub const fn from_consensus(v: i32) -> Self { Version(v) }
     /// Returns the inner `i32` value.
     ///
     /// This is the data type used in consensus code in Bitcoin Core.
-    #[inline]
     pub fn to_consensus(self) -> i32 { self.0 }
 
     /// Checks whether the version number is signalling a soft fork at the given bit.
@@ -298,7 +286,6 @@ pub fn is_signalling_soft_fork(&self, bit: u8) -> bool {
 }
 
 impl Default for Version {
-    #[inline]
     fn default() -> Version { Self::NO_SOFT_FORK_SIGNALLING }
 }
 
diff --git a/primitives/src/lib.rs b/primitives/src/lib.rs
index 77b74b88..f73a7ce1 100644
--- a/primitives/src/lib.rs
+++ b/primitives/src/lib.rs
@@ -44,7 +44,7 @@ pub mod _core {
 pub mod block;
 pub mod locktime;
 pub mod merkle_tree;
-mod opcodes;
+pub mod opcodes;
 pub mod pow;
 #[cfg(feature = "alloc")]
 pub mod script;
@@ -76,6 +76,7 @@ pub mod _core {
     block::{BlockHash, Header as BlockHeader, WitnessCommitment},
     locktime::{absolute, relative},
     merkle_tree::{TxMerkleNode, WitnessMerkleNode},
+    opcodes::Opcode,
     pow::CompactTarget,
     sequence::Sequence,
     transaction::{OutPoint, Txid, Wtxid},
diff --git a/primitives/src/locktime/absolute.rs b/primitives/src/locktime/absolute.rs
index 639963aa..b6321f77 100644
--- a/primitives/src/locktime/absolute.rs
+++ b/primitives/src/locktime/absolute.rs
@@ -102,7 +102,6 @@ impl LockTime {
     ///
     /// # Ok::<_, units::parse::PrefixedHexError>(())
     /// ```
-    #[inline]
     pub fn from_hex(s: &str) -> Result<Self, PrefixedHexError> {
         let lock_time = parse::hex_u32_prefixed(s)?;
         Ok(Self::from_consensus(lock_time))
@@ -120,7 +119,6 @@ pub fn from_hex(s: &str) -> Result<Self, PrefixedHexError> {
     ///
     /// # Ok::<_, units::parse::UnprefixedHexError>(())
     /// ```
-    #[inline]
     pub fn from_unprefixed_hex(s: &str) -> Result<Self, UnprefixedHexError> {
         let lock_time = parse::hex_u32_unprefixed(s)?;
         Ok(Self::from_consensus(lock_time))
@@ -322,7 +320,6 @@ fn from(t: Time) -> Self { LockTime::Seconds(t) }
 }
 
 impl fmt::Debug for LockTime {
-    #[inline]
     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
         use LockTime::*;
 
diff --git a/primitives/src/locktime/relative.rs b/primitives/src/locktime/relative.rs
index 81518aa4..5acd7816 100644
--- a/primitives/src/locktime/relative.rs
+++ b/primitives/src/locktime/relative.rs
@@ -89,7 +89,6 @@ impl LockTime {
     ///
     /// # Ok::<_, bitcoin_primitives::relative::DisabledLockTimeError>(())
     /// ```
-    #[inline]
     pub fn from_consensus(n: u32) -> Result<Self, DisabledLockTimeError> {
         let sequence = crate::Sequence::from_consensus(n);
         sequence.to_relative_lock_time().ok_or(DisabledLockTimeError(n))
@@ -371,14 +370,12 @@ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
 
 impl convert::TryFrom<Sequence> for LockTime {
     type Error = DisabledLockTimeError;
-    #[inline]
     fn try_from(seq: Sequence) -> Result<LockTime, DisabledLockTimeError> {
         LockTime::from_sequence(seq)
     }
 }
 
 impl From<LockTime> for Sequence {
-    #[inline]
     fn from(lt: LockTime) -> Sequence { lt.to_sequence() }
 }
 
@@ -390,12 +387,10 @@ fn from(lt: LockTime) -> Sequence { lt.to_sequence() }
 impl DisabledLockTimeError {
     /// Accessor for the `u32` whose "disable" flag was set, preventing
     /// it from being parsed as a relative locktime.
-    #[inline]
     pub fn disabled_locktime_value(&self) -> u32 { self.0 }
 }
 
 impl fmt::Display for DisabledLockTimeError {
-    #[inline]
     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
         write!(f, "lock time 0x{:08x} has disable flag set", self.0)
     }
@@ -422,7 +417,6 @@ pub fn expected(&self) -> Time { self.time }
 }
 
 impl fmt::Display for IncompatibleHeightError {
-    #[inline]
     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
         write!(
             f,
@@ -453,7 +447,6 @@ pub fn expected(&self) -> Height { self.height }
 }
 
 impl fmt::Display for IncompatibleTimeError {
-    #[inline]
     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
         write!(
             f,
diff --git a/primitives/src/opcodes.rs b/primitives/src/opcodes.rs
index 42835662..5da0295d 100644
--- a/primitives/src/opcodes.rs
+++ b/primitives/src/opcodes.rs
@@ -6,7 +6,6 @@
 //! all of the opcodes for that language.
 
 #![allow(non_camel_case_types)]
-#![allow(dead_code)]            // This module is private and is duplicated in `bitcoin`.
 
 use core::fmt;
 
@@ -441,7 +440,6 @@ fn from(b: u8) -> Opcode { Opcode { code: b } }
 }
 
 impl fmt::Debug for Opcode {
-    #[inline]
     fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> { fmt::Display::fmt(self, f) }
 }
 
diff --git a/primitives/src/pow.rs b/primitives/src/pow.rs
index df452ded..95743c7a 100644
--- a/primitives/src/pow.rs
+++ b/primitives/src/pow.rs
@@ -24,11 +24,9 @@
 
 impl CompactTarget {
     /// Constructs a new [`CompactTarget`] from a consensus encoded `u32`.
-    #[inline]
     pub fn from_consensus(bits: u32) -> Self { Self(bits) }
 
     /// Returns the consensus encoded `u32` representation of this [`CompactTarget`].
-    #[inline]
     pub fn to_consensus(self) -> u32 { self.0 }
 }
 
diff --git a/primitives/src/sequence.rs b/primitives/src/sequence.rs
index a4e7dbff..e225739f 100644
--- a/primitives/src/sequence.rs
+++ b/primitives/src/sequence.rs
@@ -124,14 +124,12 @@ pub fn is_time_locked(&self) -> bool {
     }
 
     /// Constructs a new `Sequence` from a prefixed hex string.
-    #[inline]
     pub fn from_hex(s: &str) -> Result<Self, PrefixedHexError> {
         let lock_time = parse::hex_u32_prefixed(s)?;
         Ok(Self::from_consensus(lock_time))
     }
 
     /// Constructs a new `Sequence` from an unprefixed hex string.
-    #[inline]
     pub fn from_unprefixed_hex(s: &str) -> Result<Self, UnprefixedHexError> {
         let lock_time = parse::hex_u32_unprefixed(s)?;
         Ok(Self::from_consensus(lock_time))
@@ -205,28 +203,23 @@ pub fn to_relative_lock_time(self) -> Option<relative::LockTime> {
     /// Returns the low 16 bits from sequence number.
     ///
     /// BIP-68 only uses the low 16 bits for relative lock value.
-    #[inline]
     fn low_u16(&self) -> u16 { self.0 as u16 }
 }
 
 impl Default for Sequence {
     /// The default value of sequence is 0xffffffff.
-    #[inline]
     fn default() -> Self { Sequence::MAX }
 }
 
 impl From<Sequence> for u32 {
-    #[inline]
     fn from(sequence: Sequence) -> u32 { sequence.0 }
 }
 
 impl fmt::Display for Sequence {
-    #[inline]
     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { fmt::Display::fmt(&self.0, f) }
 }
 
 impl fmt::LowerHex for Sequence {
-    #[inline]
     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { fmt::LowerHex::fmt(&self.0, f) }
 }
 #[cfg(feature = "alloc")]
@@ -235,12 +228,10 @@ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { fmt::LowerHex::fmt(&self.
 });
 
 impl fmt::UpperHex for Sequence {
-    #[inline]
     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { fmt::UpperHex::fmt(&self.0, f) }
 }
 
 impl fmt::Debug for Sequence {
-    #[inline]
     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
         // 10 because its 8 digits + 2 for the '0x'
         write!(f, "Sequence({:#010x})", self.0)
diff --git a/primitives/src/transaction.rs b/primitives/src/transaction.rs
index 7e708e25..d1ec78b0 100644
--- a/primitives/src/transaction.rs
+++ b/primitives/src/transaction.rs
@@ -115,19 +115,15 @@ impl Transaction {
     pub const MAX_STANDARD_WEIGHT: Weight = Weight::from_wu(400_000);
 
     /// Returns a reference to the transaction inputs.
-    #[inline]
     pub fn inputs(&self) -> &[TxIn] { &self.input }
 
     /// Returns a mutable reference to the transaction inputs.
-    #[inline]
     pub fn inputs_mut(&mut self) -> &mut [TxIn] { &mut self.input }
 
     /// Returns a reference to the transaction outputs.
-    #[inline]
     pub fn outputs(&self) -> &[TxOut] { &self.output }
 
     /// Returns a mutable reference to the transaction outputs.
-    #[inline]
     pub fn outputs_mut(&mut self) -> &mut [TxOut] { &mut self.output }
 
     /// Computes a "normalized TXID" which does not include any signatures.
@@ -159,7 +155,6 @@ pub fn compute_ntxid(&self) -> sha256d::Hash {
     /// witness fields themselves). For non-SegWit transactions which do not have any SegWit data,
     /// this will be equal to [`Transaction::compute_wtxid()`].
     #[doc(alias = "txid")]
-    #[inline]
     pub fn compute_txid(&self) -> Txid {
         let hash = hash_transaction(self, false);
         Txid::from_byte_array(hash.to_byte_array())
@@ -171,7 +166,6 @@ pub fn compute_txid(&self) -> Txid {
     /// witness fields themselves). For non-SegWit transactions which do not have any SegWit data,
     /// this will be equal to [`Transaction::compute_txid()`].
     #[doc(alias = "wtxid")]
-    #[inline]
     pub fn compute_wtxid(&self) -> Wtxid {
         let hash = hash_transaction(self, self.uses_segwit_serialization());
         Wtxid::from_byte_array(hash.to_byte_array())
@@ -179,7 +173,6 @@ pub fn compute_wtxid(&self) -> Wtxid {
 
     /// Returns whether or not to serialize transaction as specified in BIP-144.
     // This is duplicated in `bitcoin`, if you change it please do so in both places.
-    #[inline]
     fn uses_segwit_serialization(&self) -> bool {
         if self.input.iter().any(|input| !input.witness.is_empty()) {
             return true;
@@ -192,7 +185,6 @@ fn uses_segwit_serialization(&self) -> bool {
 
 #[cfg(feature = "alloc")]
 impl cmp::PartialOrd for Transaction {
-    #[inline]
     fn partial_cmp(&self, other: &Self) -> Option<cmp::Ordering> { Some(self.cmp(other)) }
 }
 
@@ -209,25 +201,21 @@ fn cmp(&self, other: &Self) -> cmp::Ordering {
 
 #[cfg(feature = "alloc")]
 impl From<Transaction> for Txid {
-    #[inline]
     fn from(tx: Transaction) -> Txid { tx.compute_txid() }
 }
 
 #[cfg(feature = "alloc")]
 impl From<&Transaction> for Txid {
-    #[inline]
     fn from(tx: &Transaction) -> Txid { tx.compute_txid() }
 }
 
 #[cfg(feature = "alloc")]
 impl From<Transaction> for Wtxid {
-    #[inline]
     fn from(tx: Transaction) -> Wtxid { tx.compute_wtxid() }
 }
 
 #[cfg(feature = "alloc")]
 impl From<&Transaction> for Wtxid {
-    #[inline]
     fn from(tx: &Transaction) -> Wtxid { tx.compute_wtxid() }
 }
 
@@ -389,7 +377,6 @@ impl OutPoint {
 }
 
 impl fmt::Display for OutPoint {
-    #[inline]
     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
         write!(f, "{}:{}", self.txid, self.vout)
     }
@@ -452,7 +439,6 @@ pub enum ParseOutPointError {
 
 #[cfg(feature = "alloc")]
 impl From<Infallible> for ParseOutPointError {
-    #[inline]
     fn from(never: Infallible) -> Self { match never {} }
 }
 
@@ -567,12 +553,10 @@ pub fn is_standard(&self) -> bool {
 }
 
 impl fmt::Display for Version {
-    #[inline]
     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { fmt::Display::fmt(&self.0, f) }
 }
 
 impl From<Version> for u32 {
-    #[inline]
     fn from(version: Version) -> Self { version.0 }
 }
 
diff --git a/primitives/src/witness.rs b/primitives/src/witness.rs
index f8328b82..e892334f 100644
--- a/primitives/src/witness.rs
+++ b/primitives/src/witness.rs
@@ -99,22 +99,18 @@ pub fn from_slice<T: AsRef<[u8]>>(slice: &[T]) -> Self {
     }
 
     /// Convenience method to create an array of byte-arrays from this witness.
-    #[inline]
     pub fn to_vec(&self) -> Vec<Vec<u8>> { self.iter().map(|s| s.to_vec()).collect() }
 
     /// Returns `true` if the witness contains no element.
-    #[inline]
     pub fn is_empty(&self) -> bool { self.witness_elements == 0 }
 
     /// Returns a struct implementing [`Iterator`].
     #[must_use = "iterators are lazy and do nothing unless consumed"]
-    #[inline]
     pub fn iter(&self) -> Iter {
         Iter { inner: self.content.as_slice(), indices_start: self.indices_start, current_index: 0 }
     }
 
     /// Returns the number of elements this witness holds.
-    #[inline]
     pub fn len(&self) -> usize { self.witness_elements }
 
     /// Returns the number of bytes this witness contributes to a transactions total size.
@@ -134,7 +130,6 @@ pub fn size(&self) -> usize {
     }
 
     /// Clear the witness.
-    #[inline]
     pub fn clear(&mut self) {
         self.content.clear();
         self.witness_elements = 0;
@@ -142,7 +137,6 @@ pub fn clear(&mut self) {
     }
 
     /// Push a new element on the witness, requires an allocation.
-    #[inline]
     pub fn push<T: AsRef<[u8]>>(&mut self, new_element: T) {
         self.push_slice(new_element.as_ref());
     }
@@ -184,7 +178,6 @@ fn element_at(&self, index: usize) -> Option<&[u8]> {
     }
 
     /// Returns the last element in the witness, if any.
-    #[inline]
     pub fn last(&self) -> Option<&[u8]> {
         if self.witness_elements == 0 {
             None
@@ -194,7 +187,6 @@ pub fn last(&self) -> Option<&[u8]> {
     }
 
     /// Returns the second-to-last element in the witness, if any.
-    #[inline]
     pub fn second_to_last(&self) -> Option<&[u8]> {
         if self.witness_elements <= 1 {
             None
@@ -204,7 +196,6 @@ pub fn second_to_last(&self) -> Option<&[u8]> {
     }
 
     /// Returns the third-to-last element in the witness, if any.
-    #[inline]
     pub fn third_to_last(&self) -> Option<&[u8]> {
         if self.witness_elements <= 2 {
             None
@@ -214,7 +205,6 @@ pub fn third_to_last(&self) -> Option<&[u8]> {
     }
 
     /// Return the nth element in the witness, if any
-    #[inline]
     pub fn nth(&self, index: usize) -> Option<&[u8]> {
         let pos = decode_cursor(&self.content, self.indices_start, index)?;
         self.element_at(pos)
@@ -274,7 +264,6 @@ pub struct Iter<'a> {
 impl Index<usize> for Witness {
     type Output = [u8];
 
-    #[inline]
     fn index(&self, index: usize) -> &Self::Output { self.nth(index).expect("out of bounds") }
 }
 
@@ -292,7 +281,6 @@ fn next(&mut self) -> Option<Self::Item> {
         Some(&slice[..end])
     }
 
-    #[inline]
     fn size_hint(&self) -> (usize, Option<usize>) {
         let total_count = (self.inner.len() - self.indices_start) / 4;
         let remaining = total_count - self.current_index;
@@ -306,7 +294,6 @@ impl<'a> IntoIterator for &'a Witness {
     type IntoIter = Iter<'a>;
     type Item = &'a [u8];
 
-    #[inline]
     fn into_iter(self) -> Self::IntoIter { self.iter() }
 }
 
@@ -394,27 +381,22 @@ fn visit_seq<A: serde::de::SeqAccess<'de>>(
 }
 
 impl From<Vec<Vec<u8>>> for Witness {
-    #[inline]
     fn from(vec: Vec<Vec<u8>>) -> Self { Witness::from_slice(&vec) }
 }
 
 impl From<&[&[u8]]> for Witness {
-    #[inline]
     fn from(slice: &[&[u8]]) -> Self { Witness::from_slice(slice) }
 }
 
 impl From<&[Vec<u8>]> for Witness {
-    #[inline]
     fn from(slice: &[Vec<u8>]) -> Self { Witness::from_slice(slice) }
 }
 
 impl From<Vec<&[u8]>> for Witness {
-    #[inline]
     fn from(vec: Vec<&[u8]>) -> Self { Witness::from_slice(&vec) }
 }
 
 impl Default for Witness {
-    #[inline]
     fn default() -> Self { Self::new() }
 }
 
diff --git a/units/src/amount/mod.rs b/units/src/amount/mod.rs
index 345c3bad..8af21f0a 100644
--- a/units/src/amount/mod.rs
+++ b/units/src/amount/mod.rs
@@ -91,6 +91,10 @@ pub enum Denomination {
     Bit,
     /// satoshi (1 BTC = 100,000,000 satoshi).
     Satoshi,
+    /// Stops users from casting this enum to an integer.
+    // May get removed if one day Rust supports disabling casts natively.
+    #[doc(hidden)]
+    _DoNotUse(Infallible),
 }
 
 impl Denomination {
@@ -109,6 +113,7 @@ fn precision(self) -> i8 {
             Denomination::MicroBitcoin => -2,
             Denomination::Bit => -2,
             Denomination::Satoshi => 0,
+            Denomination::_DoNotUse(infallible) => match infallible {}
         }
     }
 
@@ -121,6 +126,7 @@ fn as_str(self) -> &'static str {
             Denomination::MicroBitcoin => "uBTC",
             Denomination::Bit => "bits",
             Denomination::Satoshi => "satoshi",
+            Denomination::_DoNotUse(infallible) => match infallible {}
         }
     }
 
diff --git a/units/src/weight.rs b/units/src/weight.rs
index 3cdd9f22..720dfd38 100644
--- a/units/src/weight.rs
+++ b/units/src/weight.rs
@@ -198,16 +198,6 @@ impl ops::Div<Weight> for Weight {
 
         fn div(self, rhs: Weight) -> Self::Output { self.to_wu() / rhs.to_wu() }
     }
-    impl ops::Rem<u64> for Weight {
-        type Output = Weight;
-
-        fn rem(self, rhs: u64) -> Self::Output { Weight(self.0 % rhs) }
-    }
-    impl ops::Rem<Weight> for Weight {
-        type Output = u64;
-
-        fn rem(self, rhs: Weight) -> Self::Output { self.0 % rhs.0 }
-    }
 }
 crate::internal_macros::impl_add_assign!(Weight);
 crate::internal_macros::impl_sub_assign!(Weight);
@@ -220,10 +210,6 @@ impl ops::DivAssign<u64> for Weight {
     fn div_assign(&mut self, rhs: u64) { self.0 /= rhs }
 }
 
-impl ops::RemAssign<u64> for Weight {
-    fn rem_assign(&mut self, rhs: u64) { self.0 %= rhs }
-}
-
 impl core::iter::Sum for Weight {
     fn sum<I>(iter: I) -> Self
     where
@@ -453,23 +439,4 @@ fn div_assign() {
         w /= Weight(4).into();
         assert_eq!(w, Weight(2));
     }
-
-    #[test]
-    fn remainder() {
-        let weight10 = Weight(10);
-        let weight3 = Weight(3);
-
-        let remainder = weight10 % weight3;
-        assert_eq!(remainder, 1);
-
-        let remainder = weight10 % 3;
-        assert_eq!(remainder, Weight(1));
-    }
-
-    #[test]
-    fn remainder_assign() {
-        let mut weight = Weight(10);
-        weight %= 3;
-        assert_eq!(weight, Weight(1));
-    }
 }


Test patch:
diff --git a/bitcoin/src/blockdata/script/tests.rs b/bitcoin/src/blockdata/script/tests.rs
index 9b47ef65..4085085d 100644
--- a/bitcoin/src/blockdata/script/tests.rs
+++ b/bitcoin/src/blockdata/script/tests.rs
@@ -1,6 +1,7 @@
 // SPDX-License-Identifier: CC0-1.0
 
 use hex_lit::hex;
+use primitives::opcodes;
 
 use super::*;
 use crate::address::script_pubkey::{
@@ -8,7 +9,7 @@
 };
 use crate::consensus::encode::{deserialize, serialize};
 use crate::crypto::key::{PublicKey, XOnlyPublicKey};
-use crate::{Amount, FeeRate, opcodes};
+use crate::{Amount, FeeRate};
 
 #[test]
 #[rustfmt::skip]