Repository: rust-bitcoin/rust-bitcoin
Pull request #2326 (2024-01-09 23:56:59)

Improve the `justfile`
Improve the `justfile` by doing:

- Update linter toolchain
- Add `just sane` to run a minimal set of checks/tests that can be used pre-push but is not as slow as using `DO_FEATURE_MATRIX=true contrib/test.sh`.

tcharding: Ah cool, I didn't know that syntax. It does change the order like you mention but that is ok here. 

Although, now I re-look at this it might not be a good idea to mix the lint and `cargo test` commands in a single `just`  command because they use different toolchains so re-running when one gets an error is going to be slow - better to run `just lint` (and fix, re-run) then run `just sane` (and fix, re-run).

Thanks for the review @RCasatta and for the lesson!
tcharding: Changes in force push: Removed the call to `just lint` from the `sane` command. 
tcharding: Needs rebasing once #2332 merges to get past CI.

Patch:
diff --git a/.github/labeler.yml b/.github/labeler.yml
deleted file mode 100644
index 986c15a0..00000000
--- a/.github/labeler.yml
+++ /dev/null
@@ -1,13 +0,0 @@
-ci:
-  - changed-files:
-    - any-glob-to-any-file: .github/**
-test:
-  - changed-files:
-    - any-glob-to-any-file: fuzz/**
-    - any-glob-to-any-file: '*/tests/**'
-    - any-glob-to-any-file: 'dep_test'
-    - any-glob-to-any-file: 'contrib/test.sh'
-    - any-glob-to-any-file: '*/contrib/test.sh'
-doc:
-  - changed-files:
-    - any-glob-to-any-file: '**/*.md'
diff --git a/.github/workflows/coveralls.yml b/.github/workflows/coveralls.yml
deleted file mode 100644
index a3d37cd3..00000000
--- a/.github/workflows/coveralls.yml
+++ /dev/null
@@ -1,24 +0,0 @@
-on:
-  - push
-  - pull_request
-
-name: Code coverage with llvm-cov
-
-jobs:
-  Coveralls:
-    name: Code coverage - stable toolchain
-    runs-on: ubuntu-latest
-    strategy:
-      fail-fast: false
-    steps:
-      - name: Checkout Crate
-        uses: actions/checkout@v4
-      - name: Checkout Toolchain
-        # https://github.com/dtolnay/rust-toolchain
-        uses: dtolnay/rust-toolchain@stable
-      - name: Install cargo-llvm-cov
-        uses: taiki-e/install-action@cargo-llvm-cov
-      - name: Generate code coverage for tests
-        run: cargo llvm-cov --ignore-filename-regex fuzz --all-features --workspace --lcov --output-path lcov.info
-      - name: Upload report to coveralls
-        uses: coverallsapp/github-action@v2        
diff --git a/.github/workflows/fuzz.yml b/.github/workflows/fuzz.yml
index 3a0e4d1a..865f7c92 100644
--- a/.github/workflows/fuzz.yml
+++ b/.github/workflows/fuzz.yml
@@ -39,7 +39,7 @@ jobs:
       - name: Install test dependencies
         run: sudo apt-get update -y && sudo apt-get install -y binutils-dev libunwind8-dev libcurl4-openssl-dev libelf-dev libdw-dev cmake gcc libiberty-dev
       - uses: actions/checkout@v4
-      - uses: actions/cache@v4
+      - uses: actions/cache@v3
         id: cache-fuzz
         with:
           path: |
diff --git a/.github/workflows/kani.yml b/.github/workflows/kani.yml
index dff1e54b..520ad176 100644
--- a/.github/workflows/kani.yml
+++ b/.github/workflows/kani.yml
@@ -11,4 +11,4 @@ jobs:
         uses: actions/checkout@v4
 
       - name: 'Run Kani on your code.'
-        uses: model-checking/kani-github-action@v1.1
+        uses: model-checking/kani-github-action@v1.0
diff --git a/.github/workflows/manage-pr.yml b/.github/workflows/manage-pr.yml
deleted file mode 100644
index 1ae25001..00000000
--- a/.github/workflows/manage-pr.yml
+++ /dev/null
@@ -1,26 +0,0 @@
-name: Manage PR
-on:
-  - pull_request_target
-
-jobs:
-  labeler:
-    permissions:
-      contents: read
-      pull-requests: write
-    runs-on: ubuntu-latest
-    steps:
-      - name: Checkout master
-        uses: actions/checkout@v4
-        with:
-          path: master
-      - name: Checkout merge commit
-        uses: actions/checkout@v4
-        with:
-          path: merge
-          ref: "refs/pull/${{ github.event.number }}/merge"
-      - name: Generate label config
-        run: cd master && SCAN_DIR=../merge ./contrib/gen_label_config.sh
-      - name: Update labels
-        uses: actions/labeler@v5
-        with:
-          configuration-path: master/.github/labeler.yml
diff --git a/.github/workflows/rust.yml b/.github/workflows/rust.yml
index 4e75c7e4..02aedb92 100644
--- a/.github/workflows/rust.yml
+++ b/.github/workflows/rust.yml
@@ -21,6 +21,7 @@ jobs:
         uses: dtolnay/rust-toolchain@stable
       - name: Running test script
         env:
+          DO_COV: true
           AS_DEPENDENCY: false
           DO_DOCS: true
           DO_FEATURE_MATRIX: true
diff --git a/Cargo-minimal.lock b/Cargo-minimal.lock
index fb048b8c..1cae13ca 100644
--- a/Cargo-minimal.lock
+++ b/Cargo-minimal.lock
@@ -45,7 +45,6 @@ dependencies = [
  "hex-conservative",
  "hex_lit",
  "mutagen",
- "ordered",
  "secp256k1",
  "serde",
  "serde_json",
@@ -236,12 +235,6 @@ dependencies = [
  "proc-macro2",
 ]
 
-[[package]]
-name = "ordered"
-version = "0.2.2"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "7f0642533dea0bb58bd5cae31bafc1872429f0f12ac8c61fe2b4ba44f80b959b"
-
 [[package]]
 name = "ppv-lite86"
 version = "0.2.8"
diff --git a/Cargo-recent.lock b/Cargo-recent.lock
index ceda6598..90a84ae2 100644
--- a/Cargo-recent.lock
+++ b/Cargo-recent.lock
@@ -44,7 +44,6 @@ dependencies = [
  "hex-conservative",
  "hex_lit",
  "mutagen",
- "ordered",
  "secp256k1",
  "serde",
  "serde_json",
@@ -235,12 +234,6 @@ dependencies = [
  "proc-macro2",
 ]
 
-[[package]]
-name = "ordered"
-version = "0.2.2"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "7f0642533dea0bb58bd5cae31bafc1872429f0f12ac8c61fe2b4ba44f80b959b"
-
 [[package]]
 name = "ppv-lite86"
 version = "0.2.17"
diff --git a/bitcoin/Cargo.toml b/bitcoin/Cargo.toml
index 8c899897..f06cc572 100644
--- a/bitcoin/Cargo.toml
+++ b/bitcoin/Cargo.toml
@@ -38,7 +38,6 @@ secp256k1 = { version = "0.28.0", default-features = false, features = ["hashes"
 units = { package = "bitcoin-units", version = "0.1.0", default-features = false, features = ["alloc"] }
 
 base64 = { version = "0.21.3", optional = true }
-ordered = { version = "0.2.0", optional = true }
 # Only use this feature for no-std builds, otherwise use bitcoinconsensus-std.
 bitcoinconsensus = { version = "0.20.2-0.5.0", default-features = false, optional = true }
 
diff --git a/bitcoin/examples/bip32.rs b/bitcoin/examples/bip32.rs
index 9d8efbc7..98642870 100644
--- a/bitcoin/examples/bip32.rs
+++ b/bitcoin/examples/bip32.rs
@@ -3,12 +3,12 @@
 use std::str::FromStr;
 use std::{env, process};
 
-use bitcoin::address::{Address, KnownHrp};
+use bitcoin::address::Address;
 use bitcoin::bip32::{ChildNumber, DerivationPath, Xpriv, Xpub};
 use bitcoin::hex::FromHex;
 use bitcoin::secp256k1::ffi::types::AlignedType;
 use bitcoin::secp256k1::Secp256k1;
-use bitcoin::{CompressedPublicKey, NetworkKind};
+use bitcoin::{CompressedPublicKey, Network, NetworkKind};
 
 fn main() {
     // This example derives root xprv from a 32-byte seed,
@@ -50,6 +50,6 @@ fn main() {
     // manually creating indexes this time
     let zero = ChildNumber::from_normal_idx(0).unwrap();
     let public_key = xpub.derive_pub(&secp, &[zero, zero]).unwrap().public_key;
-    let address = Address::p2wpkh(&CompressedPublicKey(public_key), KnownHrp::Mainnet);
+    let address = Address::p2wpkh(&CompressedPublicKey(public_key), Network::Bitcoin);
     println!("First receiving address: {}", address);
 }
diff --git a/bitcoin/examples/handshake.rs b/bitcoin/examples/handshake.rs
index be3043a0..9a3bb462 100644
--- a/bitcoin/examples/handshake.rs
+++ b/bitcoin/examples/handshake.rs
@@ -11,7 +11,7 @@
 use bitcoin::secp256k1::rand::Rng;
 
 fn main() {
-    // This example establishes a connection to a Bitcoin node, sends the initial
+    // This example establishes a connection to a Bitcoin node, sends the intial
     // "version" message, waits for the reply, and finally closes the connection.
     let args: Vec<String> = env::args().collect();
     if args.len() < 2 {
diff --git a/bitcoin/examples/sighash.rs b/bitcoin/examples/sighash.rs
index 08088173..bdddaa7e 100644
--- a/bitcoin/examples/sighash.rs
+++ b/bitcoin/examples/sighash.rs
@@ -12,6 +12,8 @@
 
 //run with: cargo run --example sighash
 
+//TODO add P2TR examples, ideally for both key-path and script-path spending
+
 /// Computes segwit sighash for a transaction input that spends a p2wpkh output with "witness_v0_keyhash" scriptPubKey.type
 ///
 /// # Arguments
@@ -42,7 +44,7 @@ fn compute_sighash_p2wpkh(raw_tx: &[u8], inp_idx: usize, value: u64) {
 
     let mut cache = sighash::SighashCache::new(&tx);
     let sighash = cache
-        .p2wpkh_signature_hash(inp_idx, &spk, Amount::from_sat(value), sig.sighash_type)
+        .p2wpkh_signature_hash(inp_idx, &spk, Amount::from_sat(value), sig.hash_ty)
         .expect("failed to compute sighash");
     println!("Segwit p2wpkh sighash: {:x}", sighash);
     let msg = secp256k1::Message::from_digest(sighash.to_byte_array());
@@ -91,9 +93,9 @@ fn compute_sighash_legacy(raw_tx: &[u8], inp_idx: usize, script_pubkey_bytes_opt
         let sig = ecdsa::Signature::from_slice(instr.unwrap().push_bytes().unwrap().as_bytes())
             .expect("failed to parse sig");
         let sighash = cache
-            .legacy_signature_hash(inp_idx, script_code, sig.sighash_type.to_u32())
+            .legacy_signature_hash(inp_idx, script_code, sig.hash_ty.to_u32())
             .expect("failed to compute sighash");
-        println!("Legacy sighash: {:x} (sighash flag {})", sighash, sig.sighash_type);
+        println!("Legacy sighash: {:x} (sighash flag {})", sighash, sig.hash_ty);
     }
 }
 
@@ -124,14 +126,9 @@ fn compute_sighash_p2wsh(raw_tx: &[u8], inp_idx: usize, value: u64) {
         assert!((70..=72).contains(&sig_len), "signature length {} out of bounds", sig_len);
         //here we assume that all sighash_flags are the same. Can they be different?
         let sighash = cache
-            .p2wsh_signature_hash(
-                inp_idx,
-                witness_script,
-                Amount::from_sat(value),
-                sig.sighash_type,
-            )
+            .p2wsh_signature_hash(inp_idx, witness_script, Amount::from_sat(value), sig.hash_ty)
             .expect("failed to compute sighash");
-        println!("Segwit p2wsh sighash: {:x} ({})", sighash, sig.sighash_type);
+        println!("Segwit p2wsh sighash: {:x} ({})", sighash, sig.hash_ty);
     }
 }
 
diff --git a/bitcoin/examples/sign-tx-segwit-v0.rs b/bitcoin/examples/sign-tx-segwit-v0.rs
index 6a8879d3..ef7f969c 100644
--- a/bitcoin/examples/sign-tx-segwit-v0.rs
+++ b/bitcoin/examples/sign-tx-segwit-v0.rs
@@ -66,10 +66,10 @@ fn main() {
 
     // Sign the sighash using the secp256k1 library (exported by rust-bitcoin).
     let msg = Message::from(sighash);
-    let signature = secp.sign_ecdsa(&msg, &sk);
+    let sig = secp.sign_ecdsa(&msg, &sk);
 
     // Update the witness stack.
-    let signature = bitcoin::ecdsa::Signature { signature, sighash_type };
+    let signature = bitcoin::ecdsa::Signature { sig, hash_ty: EcdsaSighashType::All };
     let pk = sk.public_key(&secp);
     *sighasher.witness_mut(input_index).unwrap() = Witness::p2wpkh(&signature, &pk);
 
diff --git a/bitcoin/examples/sign-tx-taproot.rs b/bitcoin/examples/sign-tx-taproot.rs
index 9076c009..c9025df2 100644
--- a/bitcoin/examples/sign-tx-taproot.rs
+++ b/bitcoin/examples/sign-tx-taproot.rs
@@ -72,11 +72,11 @@ fn main() {
     // Sign the sighash using the secp256k1 library (exported by rust-bitcoin).
     let tweaked: TweakedKeypair = keypair.tap_tweak(&secp, None);
     let msg = Message::from_digest(sighash.to_byte_array());
-    let signature = secp.sign_schnorr(&msg, &tweaked.to_inner());
+    let sig = secp.sign_schnorr(&msg, &tweaked.to_inner());
 
     // Update the witness stack.
-    let signature = bitcoin::taproot::Signature { signature, sighash_type };
-    *sighasher.witness_mut(input_index).unwrap() = Witness::p2tr_key_spend(&signature);
+    let signature = bitcoin::taproot::Signature { sig, hash_ty: sighash_type };
+    sighasher.witness_mut(input_index).unwrap().push(&signature.to_vec());
 
     // Get the signed transaction.
     let tx = sighasher.into_transaction();
diff --git a/bitcoin/examples/taproot-psbt.rs b/bitcoin/examples/taproot-psbt.rs
index 6827e0af..1b4d4a81 100644
--- a/bitcoin/examples/taproot-psbt.rs
+++ b/bitcoin/examples/taproot-psbt.rs
@@ -282,14 +282,14 @@ fn generate_bip86_key_spend_tx(
     let unsigned_tx = psbt.unsigned_tx.clone();
     psbt.inputs.iter_mut().enumerate().try_for_each::<_, Result<(), Box<dyn std::error::Error>>>(
         |(vout, input)| {
-            let sighash_type = input
+            let hash_ty = input
                 .sighash_type
                 .and_then(|psbt_sighash_type| psbt_sighash_type.taproot_hash_ty().ok())
                 .unwrap_or(TapSighashType::All);
             let hash = SighashCache::new(&unsigned_tx).taproot_key_spend_signature_hash(
                 vout,
                 &sighash::Prevouts::All(input_txouts.as_slice()),
-                sighash_type,
+                hash_ty,
             )?;
 
             let (_, (_, derivation_path)) = input
@@ -304,7 +304,7 @@ fn generate_bip86_key_spend_tx(
                 None,
                 input,
                 hash,
-                sighash_type,
+                hash_ty,
                 secp,
             );
 
@@ -425,7 +425,7 @@ fn create_inheritance_funding_tx(
             version: transaction::Version::TWO,
             lock_time,
             input: vec![TxIn {
-                previous_output: OutPoint { txid: tx.compute_txid(), vout: 0 },
+                previous_output: OutPoint { txid: tx.txid(), vout: 0 },
                 script_sig: ScriptBuf::new(),
                 sequence: bitcoin::Sequence(0xFFFFFFFD), // enable locktime and opt-in RBF
                 witness: Witness::default(),
@@ -512,7 +512,7 @@ fn refresh_tx(
             psbt.outputs = vec![Output::default()];
             psbt.unsigned_tx.lock_time = absolute::LockTime::ZERO;
 
-            let sighash_type = input
+            let hash_ty = input
                 .sighash_type
                 .and_then(|psbt_sighash_type| psbt_sighash_type.taproot_hash_ty().ok())
                 .unwrap_or(TapSighashType::All);
@@ -522,7 +522,7 @@ fn refresh_tx(
                     value: input_value,
                     script_pubkey: prevout_script_pubkey,
                 }]),
-                sighash_type,
+                hash_ty,
             )?;
 
             {
@@ -538,7 +538,7 @@ fn refresh_tx(
                     None,
                     input,
                     hash,
-                    sighash_type,
+                    hash_ty,
                     &self.secp,
                 );
             }
@@ -568,7 +568,7 @@ fn refresh_tx(
                 version: transaction::Version::TWO,
                 lock_time,
                 input: vec![TxIn {
-                    previous_output: OutPoint { txid: tx.compute_txid(), vout: 0 },
+                    previous_output: OutPoint { txid: tx.txid(), vout: 0 },
                     script_sig: ScriptBuf::new(),
                     sequence: bitcoin::Sequence(0xFFFFFFFD), // enable locktime and opt-in RBF
                     witness: Witness::default(),
@@ -654,7 +654,7 @@ fn spend_inheritance(
             let secret_key =
                 self.master_xpriv.derive_priv(&self.secp, &derivation_path)?.to_priv().inner;
             for lh in leaf_hashes {
-                let sighash_type = TapSighashType::All;
+                let hash_ty = TapSighashType::All;
                 let hash = SighashCache::new(&unsigned_tx).taproot_script_spend_signature_hash(
                     0,
                     &sighash::Prevouts::All(&[TxOut {
@@ -662,7 +662,7 @@ fn spend_inheritance(
                         script_pubkey: input_script_pubkey.clone(),
                     }]),
                     *lh,
-                    sighash_type,
+                    hash_ty,
                 )?;
                 sign_psbt_taproot(
                     &secret_key,
@@ -670,7 +670,7 @@ fn spend_inheritance(
                     Some(*lh),
                     &mut psbt.inputs[0],
                     hash,
-                    sighash_type,
+                    hash_ty,
                     &self.secp,
                 );
             }
@@ -730,7 +730,7 @@ fn sign_psbt_taproot(
     leaf_hash: Option<TapLeafHash>,
     psbt_input: &mut psbt::Input,
     hash: TapSighash,
-    sighash_type: TapSighashType,
+    hash_ty: TapSighashType,
     secp: &Secp256k1<secp256k1::All>,
 ) {
     let keypair = secp256k1::Keypair::from_seckey_slice(secp, secret_key.as_ref()).unwrap();
@@ -740,9 +740,9 @@ fn sign_psbt_taproot(
     };
 
     let msg = secp256k1::Message::from_digest(hash.to_byte_array());
-    let signature = secp.sign_schnorr(&msg, &keypair);
+    let sig = secp.sign_schnorr(&msg, &keypair);
 
-    let final_signature = taproot::Signature { signature, sighash_type };
+    let final_signature = taproot::Signature { sig, hash_ty };
 
     if let Some(lh) = leaf_hash {
         psbt_input.tap_script_sigs.insert((pubkey, lh), final_signature);
diff --git a/bitcoin/src/address/mod.rs b/bitcoin/src/address/mod.rs
index aeca55ab..d1d8175e 100644
--- a/bitcoin/src/address/mod.rs
+++ b/bitcoin/src/address/mod.rs
@@ -180,12 +180,9 @@ fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
 }
 
 /// Known bech32 human-readable parts.
-///
-/// This is the human-readable part before the separator (`1`) in a bech32 encoded address e.g.,
-/// the "bc" in "bc1p2wsldez5mud2yam29q22wgfh9439spgduvct83k3pm50fcxa5dps59h4z5".
 #[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
 #[non_exhaustive]
-pub enum KnownHrp {
+enum KnownHrp {
     /// The main Bitcoin network.
     Mainnet,
     /// The test networks, testnet and signet.
@@ -390,9 +387,9 @@ fn p2sh_from_hash(hash: ScriptHash, network: impl Into<NetworkKind>) -> Address
     /// Creates a witness pay to public key address from a public key.
     ///
     /// This is the native segwit address type for an output redeemable with a single signature.
-    pub fn p2wpkh(pk: &CompressedPublicKey, hrp: impl Into<KnownHrp>) -> Self {
+    pub fn p2wpkh(pk: &CompressedPublicKey, network: Network) -> Self {
         let program = WitnessProgram::p2wpkh(pk);
-        Address::from_witness_program(program, hrp)
+        Address::from_witness_program(program, network)
     }
 
     /// Creates a pay to script address that embeds a witness pay to public key.
@@ -405,9 +402,9 @@ pub fn p2shwpkh(pk: &CompressedPublicKey, network: impl Into<NetworkKind>) -> Ad
     }
 
     /// Creates a witness pay to script hash address.
-    pub fn p2wsh(script: &Script, hrp: impl Into<KnownHrp>) -> Address {
+    pub fn p2wsh(script: &Script, network: Network) -> Address {
         let program = WitnessProgram::p2wsh(script);
-        Address::from_witness_program(program, hrp)
+        Address::from_witness_program(program, network)
     }
 
     /// Creates a pay to script address that embeds a witness pay to script hash address.
@@ -424,24 +421,26 @@ pub fn p2tr<C: Verification>(
         secp: &Secp256k1<C>,
         internal_key: UntweakedPublicKey,
         merkle_root: Option<TapNodeHash>,
-        hrp: impl Into<KnownHrp>,
+        network: Network,
     ) -> Address {
         let program = WitnessProgram::p2tr(secp, internal_key, merkle_root);
-        Address::from_witness_program(program, hrp)
+        Address::from_witness_program(program, network)
     }
 
     /// Creates a pay to taproot address from a pre-tweaked output key.
-    pub fn p2tr_tweaked(output_key: TweakedPublicKey, hrp: impl Into<KnownHrp>) -> Address {
+    pub fn p2tr_tweaked(output_key: TweakedPublicKey, network: Network) -> Address {
         let program = WitnessProgram::p2tr_tweaked(output_key);
-        Address::from_witness_program(program, hrp)
+        Address::from_witness_program(program, network)
     }
 
     /// Creates an address from an arbitrary witness program.
     ///
     /// This only exists to support future witness versions. If you are doing normal mainnet things
     /// then you likely do not need this constructor.
-    pub fn from_witness_program(program: WitnessProgram, hrp: impl Into<KnownHrp>) -> Address {
-        let inner = AddressInner::Segwit { program, hrp: hrp.into() };
+    // TODO: This is still arguably wrong, could take a KnownHrp/Hrp instead of Network.
+    pub fn from_witness_program(program: WitnessProgram, network: Network) -> Address {
+        let hrp = KnownHrp::from_network(network);
+        let inner = AddressInner::Segwit { program, hrp };
         Address(inner, PhantomData)
     }
 
@@ -875,7 +874,7 @@ fn test_p2wpkh() {
         let key = "033bc8c83c52df5712229a2f72206d90192366c36428cb0c12b6af98324d97bfbc"
             .parse::<CompressedPublicKey>()
             .unwrap();
-        let addr = Address::p2wpkh(&key, KnownHrp::Mainnet);
+        let addr = Address::p2wpkh(&key, Bitcoin);
         assert_eq!(&addr.to_string(), "bc1qvzvkjn4q3nszqxrv3nraga2r822xjty3ykvkuw");
         assert_eq!(addr.address_type(), Some(AddressType::P2wpkh));
         roundtrips(&addr, Bitcoin);
@@ -885,7 +884,7 @@ fn test_p2wpkh() {
     fn test_p2wsh() {
         // stolen from Bitcoin transaction 5df912fda4becb1c29e928bec8d64d93e9ba8efa9b5b405bd683c86fd2c65667
         let script = ScriptBuf::from_hex("52210375e00eb72e29da82b89367947f29ef34afb75e8654f6ea368e0acdfd92976b7c2103a1b26313f430c4b15bb1fdce663207659d8cac749a0e53d70eff01874496feff2103c96d495bfdd5ba4145e3e046fee45e84a8a48ad05bd8dbb395c011a32cf9f88053ae").unwrap();
-        let addr = Address::p2wsh(&script, KnownHrp::Mainnet);
+        let addr = Address::p2wsh(&script, Bitcoin);
         assert_eq!(
             &addr.to_string(),
             "bc1qwqdg6squsna38e46795at95yu9atm8azzmyvckulcc7kytlcckxswvvzej"
@@ -924,7 +923,7 @@ fn test_non_existent_segwit_version() {
         );
         let program = WitnessProgram::new(WitnessVersion::V13, &program).expect("valid program");
 
-        let addr = Address::from_witness_program(program, KnownHrp::Mainnet);
+        let addr = Address::from_witness_program(program, Bitcoin);
         roundtrips(&addr, Bitcoin);
     }
 
@@ -1091,7 +1090,7 @@ fn p2tr_from_untweaked() {
         )
         .unwrap();
         let secp = Secp256k1::verification_only();
-        let address = Address::p2tr(&secp, internal_key, None, KnownHrp::Mainnet);
+        let address = Address::p2tr(&secp, internal_key, None, Network::Bitcoin);
         assert_eq!(
             address.to_string(),
             "bc1p5cyxnuxmeuwuvkwfem96lqzszd02n6xdcjrs20cac6yqjjwudpxqkedrcr"
@@ -1190,7 +1189,7 @@ fn test_is_related_to_pubkey_p2tr() {
         let pubkey = PublicKey::from_str(pubkey_string).expect("pubkey");
         let xonly_pubkey = XOnlyPublicKey::from(pubkey.inner);
         let tweaked_pubkey = TweakedPublicKey::dangerous_assume_tweaked(xonly_pubkey);
-        let address = Address::p2tr_tweaked(tweaked_pubkey, KnownHrp::Mainnet);
+        let address = Address::p2tr_tweaked(tweaked_pubkey, Network::Bitcoin);
 
         assert_eq!(
             address,
@@ -1216,7 +1215,7 @@ fn test_is_related_to_xonly_pubkey() {
         let pubkey = PublicKey::from_str(pubkey_string).expect("pubkey");
         let xonly_pubkey = XOnlyPublicKey::from(pubkey.inner);
         let tweaked_pubkey = TweakedPublicKey::dangerous_assume_tweaked(xonly_pubkey);
-        let address = Address::p2tr_tweaked(tweaked_pubkey, KnownHrp::Mainnet);
+        let address = Address::p2tr_tweaked(tweaked_pubkey, Network::Bitcoin);
 
         assert_eq!(
             address,
diff --git a/bitcoin/src/bip152.rs b/bitcoin/src/bip152.rs
index 5171b859..b9da6710 100644
--- a/bitcoin/src/bip152.rs
+++ b/bitcoin/src/bip152.rs
@@ -12,7 +12,7 @@
 
 use hashes::{sha256, siphash24, Hash};
 use internals::impl_array_newtype;
-use io::{BufRead, Write};
+use io::{Read, Write};
 
 use crate::consensus::encode::{self, Decodable, Encodable, VarInt};
 use crate::internal_macros::{impl_bytes_newtype, impl_consensus_encoding};
@@ -81,7 +81,7 @@ fn consensus_encode<W: Write + ?Sized>(&self, w: &mut W) -> Result<usize, io::Er
 
 impl Decodable for PrefilledTransaction {
     #[inline]
-    fn consensus_decode<R: BufRead + ?Sized>(r: &mut R) -> Result<Self, encode::Error> {
+    fn consensus_decode<R: Read + ?Sized>(r: &mut R) -> Result<Self, encode::Error> {
         let idx = VarInt::consensus_decode(r)?.0;
         let idx = u16::try_from(idx)
             .map_err(|_| encode::Error::ParseFailed("BIP152 prefilled tx index out of bounds"))?;
@@ -137,7 +137,7 @@ fn consensus_encode<W: Write + ?Sized>(&self, w: &mut W) -> Result<usize, io::Er
 
 impl Decodable for ShortId {
     #[inline]
-    fn consensus_decode<R: BufRead + ?Sized>(r: &mut R) -> Result<ShortId, encode::Error> {
+    fn consensus_decode<R: Read + ?Sized>(r: &mut R) -> Result<ShortId, encode::Error> {
         Ok(ShortId(Decodable::consensus_decode(r)?))
     }
 }
@@ -219,8 +219,8 @@ pub fn from_block(
             } else {
                 short_ids.push(ShortId::with_siphash_keys(
                     &match version {
-                        1 => tx.compute_txid().to_raw_hash(),
-                        2 => tx.compute_wtxid().to_raw_hash(),
+                        1 => tx.txid().to_raw_hash(),
+                        2 => tx.wtxid().to_raw_hash(),
                         _ => unreachable!(),
                     },
                     siphash_keys,
@@ -273,7 +273,7 @@ fn consensus_encode<W: Write + ?Sized>(&self, w: &mut W) -> Result<usize, io::Er
 }
 
 impl Decodable for BlockTransactionsRequest {
-    fn consensus_decode<R: BufRead + ?Sized>(r: &mut R) -> Result<Self, encode::Error> {
+    fn consensus_decode<R: Read + ?Sized>(r: &mut R) -> Result<Self, encode::Error> {
         Ok(BlockTransactionsRequest {
             block_hash: BlockHash::consensus_decode(r)?,
             indexes: {
@@ -348,7 +348,7 @@ pub struct BlockTransactions {
 
 impl BlockTransactions {
     /// Construct a [BlockTransactions] from a [BlockTransactionsRequest] and
-    /// the corresponding full [Block] by providing all requested transactions.
+    /// the corresponsing full [Block] by providing all requested transactions.
     pub fn from_request(
         request: &BlockTransactionsRequest,
         block: &Block,
diff --git a/bitcoin/src/bip158.rs b/bitcoin/src/bip158.rs
index 0b0e301d..7ada3c3f 100644
--- a/bitcoin/src/bip158.rs
+++ b/bitcoin/src/bip158.rs
@@ -43,7 +43,7 @@
 
 use hashes::{sha256d, siphash24, Hash};
 use internals::write_err;
-use io::{BufRead, Write};
+use io::{Read, Write};
 
 use crate::blockdata::block::{Block, BlockHash};
 use crate::blockdata::script::Script;
@@ -245,7 +245,7 @@ pub fn match_any<I, R>(&self, reader: &mut R, query: I) -> Result<bool, Error>
     where
         I: Iterator,
         I::Item: Borrow<[u8]>,
-        R: BufRead + ?Sized,
+        R: Read + ?Sized,
     {
         self.reader.match_any(reader, query)
     }
@@ -255,7 +255,7 @@ pub fn match_all<I, R>(&self, reader: &mut R, query: I) -> Result<bool, Error>
     where
         I: Iterator,
         I::Item: Borrow<[u8]>,
-        R: BufRead + ?Sized,
+        R: Read + ?Sized,
     {
         self.reader.match_all(reader, query)
     }
@@ -278,7 +278,7 @@ pub fn match_any<I, R>(&self, reader: &mut R, query: I) -> Result<bool, Error>
     where
         I: Iterator,
         I::Item: Borrow<[u8]>,
-        R: BufRead + ?Sized,
+        R: Read + ?Sized,
     {
         let n_elements: VarInt = Decodable::consensus_decode(reader).unwrap_or(VarInt(0));
         // map hashes to [0, n_elements << grp]
@@ -321,7 +321,7 @@ pub fn match_all<I, R>(&self, reader: &mut R, query: I) -> Result<bool, Error>
     where
         I: Iterator,
         I::Item: Borrow<[u8]>,
-        R: BufRead + ?Sized,
+        R: Read + ?Sized,
     {
         let n_elements: VarInt = Decodable::consensus_decode(reader).unwrap_or(VarInt(0));
         // map hashes to [0, n_elements << grp]
@@ -447,7 +447,7 @@ fn golomb_rice_encode<W>(
     /// Golomb-Rice decodes a number from a bit stream (parameter 2^k).
     fn golomb_rice_decode<R>(&self, reader: &mut BitStreamReader<R>) -> Result<u64, io::Error>
     where
-        R: BufRead + ?Sized,
+        R: Read + ?Sized,
     {
         let mut q = 0u64;
         while reader.read(1)? == 1 {
@@ -470,7 +470,7 @@ pub struct BitStreamReader<'a, R: ?Sized> {
     reader: &'a mut R,
 }
 
-impl<'a, R: BufRead + ?Sized> BitStreamReader<'a, R> {
+impl<'a, R: Read + ?Sized> BitStreamReader<'a, R> {
     /// Creates a new [`BitStreamReader`] that reads bitwise from a given `reader`.
     pub fn new(reader: &'a mut R) -> BitStreamReader<'a, R> {
         BitStreamReader { buffer: [0u8], reader, offset: 8 }
diff --git a/bitcoin/src/blockdata/block.rs b/bitcoin/src/blockdata/block.rs
index 53155904..e66d5f22 100644
--- a/bitcoin/src/blockdata/block.rs
+++ b/bitcoin/src/blockdata/block.rs
@@ -11,7 +11,7 @@
 use core::fmt;
 
 use hashes::{sha256d, Hash, HashEngine};
-use io::{BufRead, Write};
+use io::{Read, Write};
 
 use super::Weight;
 use crate::blockdata::script;
@@ -207,7 +207,7 @@ fn consensus_encode<W: Write + ?Sized>(&self, w: &mut W) -> Result<usize, io::Er
 }
 
 impl Decodable for Version {
-    fn consensus_decode<R: BufRead + ?Sized>(r: &mut R) -> Result<Self, encode::Error> {
+    fn consensus_decode<R: Read + ?Sized>(r: &mut R) -> Result<Self, encode::Error> {
         Decodable::consensus_decode(r).map(Version)
     }
 }
@@ -289,7 +289,7 @@ pub fn check_witness_commitment(&self) -> bool {
 
     /// Computes the transaction merkle root.
     pub fn compute_merkle_root(&self) -> Option<TxMerkleNode> {
-        let hashes = self.txdata.iter().map(|obj| obj.compute_txid().to_raw_hash());
+        let hashes = self.txdata.iter().map(|obj| obj.txid().to_raw_hash());
         merkle_tree::calculate_root(hashes).map(|h| h.into())
     }
 
@@ -311,7 +311,7 @@ pub fn witness_root(&self) -> Option<WitnessMerkleNode> {
                 // Replace the first hash with zeroes.
                 Wtxid::all_zeros().to_raw_hash()
             } else {
-                t.compute_wtxid().to_raw_hash()
+                t.wtxid().to_raw_hash()
             }
         });
         merkle_tree::calculate_root(hashes).map(|h| h.into())
@@ -491,7 +491,7 @@ fn test_coinbase_and_bip34() {
         let block: Block = deserialize(&hex!(BLOCK_HEX)).unwrap();
 
         let cb_txid = "d574f343976d8e70d91cb278d21044dd8a396019e6db70755a0a50e4783dba38";
-        assert_eq!(block.coinbase().unwrap().compute_txid().to_string(), cb_txid);
+        assert_eq!(block.coinbase().unwrap().txid().to_string(), cb_txid);
 
         assert_eq!(block.bip34_block_height(), Ok(100_000));
 
@@ -534,6 +534,7 @@ fn block_test() {
         );
         assert_eq!(real_decode.header.difficulty(network), 1);
         assert_eq!(real_decode.header.difficulty_float(), 1.0);
+        // [test] TODO: check the transaction data
 
         assert_eq!(real_decode.total_size(), some_block.len());
         assert_eq!(real_decode.base_size(), some_block.len());
@@ -576,6 +577,7 @@ fn segwit_block_test() {
         );
         assert_eq!(real_decode.header.difficulty(network), 2456598);
         assert_eq!(real_decode.header.difficulty_float(), 2456598.4399242126);
+        // [test] TODO: check the transaction data
 
         assert_eq!(real_decode.total_size(), segwit_block.len());
         assert_eq!(real_decode.base_size(), 4283);
diff --git a/bitcoin/src/blockdata/constants.rs b/bitcoin/src/blockdata/constants.rs
index 07fcfc85..a74e029a 100644
--- a/bitcoin/src/blockdata/constants.rs
+++ b/bitcoin/src/blockdata/constants.rs
@@ -88,7 +88,7 @@ fn bitcoin_genesis_tx() -> Transaction {
 /// Constructs and returns the genesis block.
 pub fn genesis_block(network: Network) -> Block {
     let txdata = vec![bitcoin_genesis_tx()];
-    let hash: sha256d::Hash = txdata[0].compute_txid().into();
+    let hash: sha256d::Hash = txdata[0].txid().into();
     let merkle_root = hash.into();
     match network {
         Network::Bitcoin => Block {
@@ -213,7 +213,7 @@ fn bitcoin_genesis_first_transaction() {
         assert_eq!(gen.lock_time, absolute::LockTime::ZERO);
 
         assert_eq!(
-            gen.compute_wtxid().to_string(),
+            gen.wtxid().to_string(),
             "4a5e1e4baab89f3a32518a88c31bc87f618f76673e2cc77ab2127b7afdeda33b"
         );
     }
diff --git a/bitcoin/src/blockdata/locktime/absolute.rs b/bitcoin/src/blockdata/locktime/absolute.rs
index e2eae3c7..4099c2b9 100644
--- a/bitcoin/src/blockdata/locktime/absolute.rs
+++ b/bitcoin/src/blockdata/locktime/absolute.rs
@@ -10,7 +10,7 @@
 use core::{fmt, mem};
 
 use internals::write_err;
-use io::{BufRead, Write};
+use io::{Read, Write};
 #[cfg(all(test, mutate))]
 use mutagen::mutate;
 
@@ -345,7 +345,7 @@ fn consensus_encode<W: Write + ?Sized>(&self, w: &mut W) -> Result<usize, io::Er
 
 impl Decodable for LockTime {
     #[inline]
-    fn consensus_decode<R: BufRead + ?Sized>(r: &mut R) -> Result<Self, encode::Error> {
+    fn consensus_decode<R: Read + ?Sized>(r: &mut R) -> Result<Self, encode::Error> {
         u32::consensus_decode(r).map(LockTime::from_consensus)
     }
 }
@@ -389,20 +389,6 @@ fn visit_i64<E: serde::de::Error>(self, v: i64) -> Result<u32, E> {
     }
 }
 
-#[cfg(feature = "ordered")]
-impl ordered::ArbitraryOrd for LockTime {
-    fn arbitrary_cmp(&self, other: &Self) -> Ordering {
-        use LockTime::*;
-
-        match (self, other) {
-            (Blocks(_), Seconds(_)) => Ordering::Less,
-            (Seconds(_), Blocks(_)) => Ordering::Greater,
-            (Blocks(this), Blocks(that)) => this.cmp(that),
-            (Seconds(this), Seconds(that)) => this.cmp(that),
-        }
-    }
-}
-
 /// An absolute block height, guaranteed to always contain a valid height value.
 #[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
 #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
@@ -587,17 +573,17 @@ fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
 
 impl From<ConversionError> for Error {
     #[inline]
-    fn from(e: ConversionError) -> Self { Self::Conversion(e) }
+    fn from(e: ConversionError) -> Self { Error::Conversion(e) }
 }
 
 impl From<OperationError> for Error {
     #[inline]
-    fn from(e: OperationError) -> Self { Self::Operation(e) }
+    fn from(e: OperationError) -> Self { Error::Operation(e) }
 }
 
 impl From<ParseIntError> for Error {
     #[inline]
-    fn from(e: ParseIntError) -> Self { Self::Parse(e) }
+    fn from(e: ParseIntError) -> Self { Error::Parse(e) }
 }
 
 /// An error that occurs when converting a `u32` to a lock time variant.
diff --git a/bitcoin/src/blockdata/opcodes.rs b/bitcoin/src/blockdata/opcodes.rs
index fbf4d592..39c86245 100644
--- a/bitcoin/src/blockdata/opcodes.rs
+++ b/bitcoin/src/blockdata/opcodes.rs
@@ -67,10 +67,10 @@ pub mod all {
         pub static OP_NOP3: Opcode = OP_CSV;
 
         impl fmt::Display for Opcode {
-            fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
+            fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
                  match *self {
                    $(
-                        $op => core::fmt::Display::fmt(stringify!($op), f),
+                        $op => fmt::Display::fmt(stringify!($op), f),
                     )+
                 }
             }
@@ -484,7 +484,7 @@ pub enum Ordinary {
         }
 
         impl fmt::Display for Ordinary {
-            fn fmt(&self, f: &mut fmt::Formatter) -> core::fmt::Result {
+            fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
                 match *self {
                    $(Ordinary::$op => { f.pad(stringify!($op)) }),*
                 }
diff --git a/bitcoin/src/blockdata/script/mod.rs b/bitcoin/src/blockdata/script/mod.rs
index d79a58fd..c48e9a57 100644
--- a/bitcoin/src/blockdata/script/mod.rs
+++ b/bitcoin/src/blockdata/script/mod.rs
@@ -66,7 +66,7 @@
 use core::ops::{Deref, DerefMut};
 
 use hashes::{hash160, sha256};
-use io::{BufRead, Write};
+use io::{Read, Write};
 #[cfg(feature = "serde")]
 use serde;
 
@@ -594,7 +594,7 @@ fn consensus_encode<W: Write + ?Sized>(&self, w: &mut W) -> Result<usize, io::Er
 
 impl Decodable for ScriptBuf {
     #[inline]
-    fn consensus_decode_from_finite_reader<R: BufRead + ?Sized>(
+    fn consensus_decode_from_finite_reader<R: Read + ?Sized>(
         r: &mut R,
     ) -> Result<Self, encode::Error> {
         Ok(ScriptBuf(Decodable::consensus_decode_from_finite_reader(r)?))
diff --git a/bitcoin/src/blockdata/script/witness_version.rs b/bitcoin/src/blockdata/script/witness_version.rs
index 05ee2846..6897631f 100644
--- a/bitcoin/src/blockdata/script/witness_version.rs
+++ b/bitcoin/src/blockdata/script/witness_version.rs
@@ -87,7 +87,7 @@ impl FromStr for WitnessVersion {
     type Err = FromStrError;
 
     fn from_str(s: &str) -> Result<Self, Self::Err> {
-        let version: u8 = crate::parse::int(s)?;
+        let version: u8 = crate::parse::int(s).map_err(FromStrError::Unparsable)?;
         Ok(WitnessVersion::try_from(version)?)
     }
 }
@@ -198,10 +198,6 @@ fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
     }
 }
 
-impl From<ParseIntError> for FromStrError {
-    fn from(e: ParseIntError) -> Self { Self::Unparsable(e) }
-}
-
 impl From<TryFromError> for FromStrError {
     fn from(e: TryFromError) -> Self { Self::Invalid(e) }
 }
diff --git a/bitcoin/src/blockdata/transaction.rs b/bitcoin/src/blockdata/transaction.rs
index d07448ce..caf4274d 100644
--- a/bitcoin/src/blockdata/transaction.rs
+++ b/bitcoin/src/blockdata/transaction.rs
@@ -16,14 +16,14 @@
 
 use hashes::{self, sha256d, Hash};
 use internals::write_err;
-use io::{BufRead, Write};
+use io::{Read, Write};
 
 use super::Weight;
+use crate::blockdata::fee_rate::FeeRate;
 use crate::blockdata::locktime::absolute::{self, Height, Time};
 use crate::blockdata::locktime::relative;
 use crate::blockdata::script::{Script, ScriptBuf};
 use crate::blockdata::witness::Witness;
-use crate::blockdata::FeeRate;
 use crate::consensus::{encode, Decodable, Encodable};
 use crate::internal_macros::{impl_consensus_encoding, impl_hashencode};
 use crate::parse::impl_parse_str_from_int_infallible;
@@ -31,7 +31,7 @@
 #[cfg(doc)]
 use crate::sighash::{EcdsaSighashType, TapSighashType};
 use crate::string::FromHexStr;
-use crate::{Amount, SignedAmount, VarInt};
+use crate::{Amount, VarInt};
 
 #[rustfmt::skip]                // Keep public re-exports separate.
 #[cfg(feature = "bitcoinconsensus")]
@@ -226,12 +226,6 @@ pub struct TxIn {
 }
 
 impl TxIn {
-    /// Returns the input base weight.
-    ///
-    /// Base weight excludes the witness and script.
-    const BASE_WEIGHT: Weight =
-        Weight::from_vb_unwrap(OutPoint::SIZE as u64 + Sequence::SIZE as u64);
-
     /// Returns true if this input enables the [`absolute::LockTime`] (aka `nLockTime`) of its
     /// [`Transaction`].
     ///
@@ -679,21 +673,11 @@ impl Transaction {
     /// Maximum transaction weight for Bitcoin Core 25.0.
     pub const MAX_STANDARD_WEIGHT: Weight = Weight::from_wu(400_000);
 
-    /// Computes a "normalized TXID" which does not include any signatures.
-    ///
-    /// This method is deprecated.  Use `compute_ntxid` instead.
-    #[deprecated(
-        since = "0.31.0",
-        note = "ntxid has been renamed to compute_ntxid to note that it's computationally expensive.  use compute_ntxid() instead."
-    )]
-    pub fn ntxid(&self) -> sha256d::Hash { self.compute_ntxid() }
-
     /// Computes a "normalized TXID" which does not include any signatures.
     ///
     /// This gives a way to identify a transaction that is "the same" as
     /// another in the sense of having same inputs and outputs.
-    #[doc(alias = "ntxid")]
-    pub fn compute_ntxid(&self) -> sha256d::Hash {
+    pub fn ntxid(&self) -> sha256d::Hash {
         let cloned_tx = Transaction {
             version: self.version,
             lock_time: self.lock_time,
@@ -708,25 +692,15 @@ pub fn compute_ntxid(&self) -> sha256d::Hash {
                 .collect(),
             output: self.output.clone(),
         };
-        cloned_tx.compute_txid().into()
+        cloned_tx.txid().into()
     }
 
-    /// Computes the [`Txid`].
-    ///
-    /// This method is deprecated.  Use `compute_txid` instead.
-    #[deprecated(
-        since = "0.31.0",
-        note = "txid has been renamed to compute_txid to note that it's computationally expensive.  use compute_txid() instead."
-    )]
-    pub fn txid(&self) -> Txid { self.compute_txid() }
-
     /// Computes the [`Txid`].
     ///
     /// Hashes the transaction **excluding** the segwit data (i.e. the marker, flag bytes, and the
     /// 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")]
-    pub fn compute_txid(&self) -> Txid {
+    /// this will be equal to [`Transaction::wtxid()`].
+    pub fn txid(&self) -> Txid {
         let mut enc = Txid::engine();
         self.version.consensus_encode(&mut enc).expect("engines don't error");
         self.input.consensus_encode(&mut enc).expect("engines don't error");
@@ -735,22 +709,12 @@ pub fn compute_txid(&self) -> Txid {
         Txid::from_engine(enc)
     }
 
-    /// Computes the segwit version of the transaction id.
-    ///
-    /// This method is deprecated.  Use `compute_wtxid` instead.
-    #[deprecated(
-        since = "0.31.0",
-        note = "wtxid has been renamed to compute_wtxid to note that it's computationally expensive.  use compute_wtxid() instead."
-    )]
-    pub fn wtxid(&self) -> Wtxid { self.compute_wtxid() }
-
     /// Computes the segwit version of the transaction id.
     ///
     /// Hashes the transaction **including** all segwit data (i.e. the marker, flag bytes, and the
     /// witness fields themselves). For non-segwit transactions which do not have any segwit data,
     /// this will be equal to [`Transaction::txid()`].
-    #[doc(alias = "wtxid")]
-    pub fn compute_wtxid(&self) -> Wtxid {
+    pub fn wtxid(&self) -> Wtxid {
         let mut enc = Wtxid::engine();
         self.consensus_encode(&mut enc).expect("engines don't error");
         Wtxid::from_engine(enc)
@@ -791,7 +755,7 @@ pub fn base_size(&self) -> usize {
         size += self.input.iter().map(|input| input.base_size()).sum::<usize>();
 
         size += VarInt::from(self.output.len()).size();
-        size += self.output.iter().map(|output| output.size()).sum::<usize>();
+        size += self.output.iter().map(|input| input.size()).sum::<usize>();
 
         size + absolute::LockTime::SIZE
     }
@@ -803,9 +767,8 @@ pub fn base_size(&self) -> usize {
     #[inline]
     pub fn total_size(&self) -> usize {
         let mut size: usize = 4; // Serialized length of a u32 for the version number.
-	let uses_segwit = self.uses_segwit_serialization();
 
-        if uses_segwit {
+        if self.use_segwit_serialization() {
             size += 2; // 1 byte for the marker and 1 for the flag.
         }
 
@@ -814,7 +777,7 @@ pub fn total_size(&self) -> usize {
             .input
             .iter()
             .map(|input| {
-                if uses_segwit {
+                if self.use_segwit_serialization() {
                     input.total_size()
                 } else {
                     input.base_size()
@@ -1014,91 +977,16 @@ fn count_sigops(prevout: TxOut, input: &TxIn) -> usize {
     }
 
     /// Returns whether or not to serialize transaction as specified in BIP-144.
-    fn uses_segwit_serialization(&self) -> bool {
-        if self.input.iter().any(|input| !input.witness.is_empty()) {
-            return true;
+    fn use_segwit_serialization(&self) -> bool {
+        for input in &self.input {
+            if !input.witness.is_empty() {
+                return true;
+            }
         }
         // To avoid serialization ambiguity, no inputs means we use BIP141 serialization (see
         // `Transaction` docs for full explanation).
         self.input.is_empty()
     }
-
-    /// Returns a reference to the input at `input_index` if it exists.
-    #[inline]
-    pub fn tx_in(&self, input_index: usize) -> Result<&TxIn, InputsIndexError> {
-        self.input
-            .get(input_index)
-            .ok_or(IndexOutOfBoundsError { index: input_index, length: self.input.len() }.into())
-    }
-
-    /// Returns a reference to the output at `output_index` if it exists.
-    #[inline]
-    pub fn tx_out(&self, output_index: usize) -> Result<&TxOut, OutputsIndexError> {
-        self.output
-            .get(output_index)
-            .ok_or(IndexOutOfBoundsError { index: output_index, length: self.output.len() }.into())
-    }
-}
-
-/// Error attempting to do an out of bounds access on the transaction inputs vector.
-#[derive(Debug, Clone, PartialEq, Eq)]
-#[non_exhaustive]
-pub struct InputsIndexError(pub IndexOutOfBoundsError);
-
-impl fmt::Display for InputsIndexError {
-    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
-        write_err!(f, "invalid input index"; self.0)
-    }
-}
-
-#[cfg(feature = "std")]
-impl std::error::Error for InputsIndexError {
-    fn source(&self) -> Option<&(dyn std::error::Error + 'static)> { Some(&self.0) }
-}
-
-impl From<IndexOutOfBoundsError> for InputsIndexError {
-    fn from(e: IndexOutOfBoundsError) -> Self { Self(e) }
-}
-
-/// Error attempting to do an out of bounds access on the transaction outputs vector.
-#[derive(Debug, Clone, PartialEq, Eq)]
-#[non_exhaustive]
-pub struct OutputsIndexError(pub IndexOutOfBoundsError);
-
-impl fmt::Display for OutputsIndexError {
-    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
-        write_err!(f, "invalid output index"; self.0)
-    }
-}
-
-#[cfg(feature = "std")]
-impl std::error::Error for OutputsIndexError {
-    fn source(&self) -> Option<&(dyn std::error::Error + 'static)> { Some(&self.0) }
-}
-
-impl From<IndexOutOfBoundsError> for OutputsIndexError {
-    fn from(e: IndexOutOfBoundsError) -> Self { Self(e) }
-}
-
-/// Error attempting to do an out of bounds access on a vector.
-#[derive(Debug, Clone, PartialEq, Eq)]
-#[non_exhaustive]
-pub struct IndexOutOfBoundsError {
-    /// Attempted index access.
-    pub index: usize,
-    /// Length of the vector where access was attempted.
-    pub length: usize,
-}
-
-impl fmt::Display for IndexOutOfBoundsError {
-    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
-        write!(f, "index {} is out-of-bounds for vector with length {}", self.index, self.length)
-    }
-}
-
-#[cfg(feature = "std")]
-impl std::error::Error for IndexOutOfBoundsError {
-    fn source(&self) -> Option<&(dyn std::error::Error + 'static)> { None }
 }
 
 /// The transaction version.
@@ -1136,7 +1024,7 @@ fn consensus_encode<W: Write + ?Sized>(&self, w: &mut W) -> Result<usize, io::Er
 }
 
 impl Decodable for Version {
-    fn consensus_decode<R: BufRead + ?Sized>(r: &mut R) -> Result<Self, encode::Error> {
+    fn consensus_decode<R: Read + ?Sized>(r: &mut R) -> Result<Self, encode::Error> {
         Decodable::consensus_decode(r).map(Version)
     }
 }
@@ -1154,7 +1042,7 @@ fn consensus_encode<W: Write + ?Sized>(&self, w: &mut W) -> Result<usize, io::Er
     }
 }
 impl Decodable for OutPoint {
-    fn consensus_decode<R: BufRead + ?Sized>(r: &mut R) -> Result<Self, encode::Error> {
+    fn consensus_decode<R: Read + ?Sized>(r: &mut R) -> Result<Self, encode::Error> {
         Ok(OutPoint {
             txid: Decodable::consensus_decode(r)?,
             vout: Decodable::consensus_decode(r)?,
@@ -1173,7 +1061,7 @@ fn consensus_encode<W: Write + ?Sized>(&self, w: &mut W) -> Result<usize, io::Er
 }
 impl Decodable for TxIn {
     #[inline]
-    fn consensus_decode_from_finite_reader<R: BufRead + ?Sized>(
+    fn consensus_decode_from_finite_reader<R: Read + ?Sized>(
         r: &mut R,
     ) -> Result<Self, encode::Error> {
         Ok(TxIn {
@@ -1192,7 +1080,7 @@ fn consensus_encode<W: Write + ?Sized>(&self, w: &mut W) -> Result<usize, io::Er
 }
 
 impl Decodable for Sequence {
-    fn consensus_decode<R: BufRead + ?Sized>(r: &mut R) -> Result<Self, encode::Error> {
+    fn consensus_decode<R: Read + ?Sized>(r: &mut R) -> Result<Self, encode::Error> {
         Decodable::consensus_decode(r).map(Sequence)
     }
 }
@@ -1203,7 +1091,7 @@ fn consensus_encode<W: Write + ?Sized>(&self, w: &mut W) -> Result<usize, io::Er
         len += self.version.consensus_encode(w)?;
 
         // Legacy transaction serialization format only includes inputs and outputs.
-        if !self.uses_segwit_serialization() {
+        if !self.use_segwit_serialization() {
             len += self.input.consensus_encode(w)?;
             len += self.output.consensus_encode(w)?;
         } else {
@@ -1222,7 +1110,7 @@ fn consensus_encode<W: Write + ?Sized>(&self, w: &mut W) -> Result<usize, io::Er
 }
 
 impl Decodable for Transaction {
-    fn consensus_decode_from_finite_reader<R: BufRead + ?Sized>(
+    fn consensus_decode_from_finite_reader<R: Read + ?Sized>(
         r: &mut R,
     ) -> Result<Self, encode::Error> {
         let version = Version::consensus_decode_from_finite_reader(r)?;
@@ -1265,42 +1153,19 @@ fn consensus_decode_from_finite_reader<R: BufRead + ?Sized>(
 }
 
 impl From<Transaction> for Txid {
-    fn from(tx: Transaction) -> Txid { tx.compute_txid() }
+    fn from(tx: Transaction) -> Txid { tx.txid() }
 }
 
 impl From<&Transaction> for Txid {
-    fn from(tx: &Transaction) -> Txid { tx.compute_txid() }
+    fn from(tx: &Transaction) -> Txid { tx.txid() }
 }
 
 impl From<Transaction> for Wtxid {
-    fn from(tx: Transaction) -> Wtxid { tx.compute_wtxid() }
+    fn from(tx: Transaction) -> Wtxid { tx.wtxid() }
 }
 
 impl From<&Transaction> for Wtxid {
-    fn from(tx: &Transaction) -> Wtxid { tx.compute_wtxid() }
-}
-
-/// Computes the value of an output accounting for the cost of spending it.
-///
-/// The effective value is the value of an output value minus the amount to spend it.  That is, the
-/// effective_value can be calculated as: value - (fee_rate * weight).
-///
-/// Note: the effective value of a [`Transaction`] may increase less than the effective value of
-/// a [`TxOut`] when adding another [`TxOut`] to the transaction.  This happens when the new
-/// [`TxOut`] added causes the output length `VarInt` to increase its encoding length.
-///
-/// # Arguments
-///
-/// * `fee_rate` - the fee rate of the transaction being created.
-/// * `satisfaction_weight` - satisfied spending conditions weight.
-pub fn effective_value(
-    fee_rate: FeeRate,
-    satisfaction_weight: Weight,
-    value: Amount,
-) -> Option<SignedAmount> {
-    let weight = satisfaction_weight.checked_add(TxIn::BASE_WEIGHT)?;
-    let signed_input_fee = fee_rate.checked_mul_by_weight(weight)?.to_signed().ok()?;
-    value.to_signed().ok()?.checked_sub(signed_input_fee)
+    fn from(tx: &Transaction) -> Wtxid { tx.wtxid() }
 }
 
 /// Predicts the weight of a to-be-constructed transaction.
@@ -1760,11 +1625,11 @@ fn nonsegwit_transaction() {
         assert_eq!(realtx.lock_time, absolute::LockTime::ZERO);
 
         assert_eq!(
-            format!("{:x}", realtx.compute_txid()),
+            format!("{:x}", realtx.txid()),
             "a6eab3c14ab5272a58a5ba91505ba1a4b6d7a3a9fcbd187b6cd99a7b6d548cb7".to_string()
         );
         assert_eq!(
-            format!("{:x}", realtx.compute_wtxid()),
+            format!("{:x}", realtx.wtxid()),
             "a6eab3c14ab5272a58a5ba91505ba1a4b6d7a3a9fcbd187b6cd99a7b6d548cb7".to_string()
         );
         assert_eq!(realtx.weight().to_wu() as usize, tx_bytes.len() * WITNESS_SCALE_FACTOR);
@@ -1773,17 +1638,6 @@ fn nonsegwit_transaction() {
         assert_eq!(realtx.base_size(), tx_bytes.len());
     }
 
-    #[test]
-    fn segwit_invalid_transaction() {
-        let tx_bytes = hex!("0000fd000001021921212121212121212121f8b372b0239cc1dff600000000004f4f4f4f4f4f4f4f000000000000000000000000000000333732343133380d000000000000000000000000000000ff000000000009000dff000000000000000800000000000000000d");
-        let tx: Result<Transaction, _> = deserialize(&tx_bytes);
-        assert!(tx.is_err());
-        assert!(tx
-            .unwrap_err()
-            .to_string()
-            .contains("witness flag set but no witnesses present"));
-    }
-
     #[test]
     fn segwit_transaction() {
         let tx_bytes = hex!(
@@ -1811,11 +1665,11 @@ fn segwit_transaction() {
         assert_eq!(realtx.lock_time, absolute::LockTime::ZERO);
 
         assert_eq!(
-            format!("{:x}", realtx.compute_txid()),
+            format!("{:x}", realtx.txid()),
             "f5864806e3565c34d1b41e716f72609d00b55ea5eac5b924c9719a842ef42206".to_string()
         );
         assert_eq!(
-            format!("{:x}", realtx.compute_wtxid()),
+            format!("{:x}", realtx.wtxid()),
             "80b7d8a82d5d5bf92905b06f2014dd699e03837ca172e3a59d51426ebbe3e7f5".to_string()
         );
         const EXPECTED_WEIGHT: Weight = Weight::from_wu(442);
@@ -1886,17 +1740,17 @@ fn ntxid() {
         let tx_bytes = hex!("0100000001a15d57094aa7a21a28cb20b59aab8fc7d1149a3bdbcddba9c622e4f5f6a99ece010000006c493046022100f93bb0e7d8db7bd46e40132d1f8242026e045f03a0efe71bbb8e3f475e970d790221009337cd7f1f929f00cc6ff01f03729b069a7c21b59b1736ddfee5db5946c5da8c0121033b9b137ee87d5a812d6f506efdd37f0affa7ffc310711c06c7f3e097c9447c52ffffffff0100e1f505000000001976a9140389035a9225b3839e2bbf32d826a1e222031fd888ac00000000");
         let mut tx: Transaction = deserialize(&tx_bytes).unwrap();
 
-        let old_ntxid = tx.compute_ntxid();
+        let old_ntxid = tx.ntxid();
         assert_eq!(
             format!("{:x}", old_ntxid),
             "c3573dbea28ce24425c59a189391937e00d255150fa973d59d61caf3a06b601d"
         );
         // changing sigs does not affect it
         tx.input[0].script_sig = ScriptBuf::new();
-        assert_eq!(old_ntxid, tx.compute_ntxid());
+        assert_eq!(old_ntxid, tx.ntxid());
         // changing pks does
         tx.output[0].script_pubkey = ScriptBuf::new();
-        assert!(old_ntxid != tx.compute_ntxid());
+        assert!(old_ntxid != tx.ntxid());
     }
 
     #[test]
@@ -1935,11 +1789,11 @@ fn txid() {
         let tx: Transaction = deserialize(&tx_bytes).unwrap();
 
         assert_eq!(
-            format!("{:x}", tx.compute_wtxid()),
+            format!("{:x}", tx.wtxid()),
             "d6ac4a5e61657c4c604dcde855a1db74ec6b3e54f32695d72c5e11c7761ea1b4"
         );
         assert_eq!(
-            format!("{:x}", tx.compute_txid()),
+            format!("{:x}", tx.txid()),
             "9652aa62b0e748caeec40c4cb7bc17c6792435cc3dfe447dd1ca24f912a1c6ec"
         );
         assert_eq!(tx.weight(), Weight::from_wu(2718));
@@ -1956,11 +1810,11 @@ fn txid() {
         let tx: Transaction = deserialize(&tx_bytes).unwrap();
 
         assert_eq!(
-            format!("{:x}", tx.compute_wtxid()),
+            format!("{:x}", tx.wtxid()),
             "971ed48a62c143bbd9c87f4bafa2ef213cfa106c6e140f111931d0be307468dd"
         );
         assert_eq!(
-            format!("{:x}", tx.compute_txid()),
+            format!("{:x}", tx.txid()),
             "971ed48a62c143bbd9c87f4bafa2ef213cfa106c6e140f111931d0be307468dd"
         );
     }
@@ -2045,9 +1899,9 @@ fn transaction_verify() {
             .as_slice()).unwrap();
 
         let mut spent = HashMap::new();
-        spent.insert(spent1.compute_txid(), spent1);
-        spent.insert(spent2.compute_txid(), spent2);
-        spent.insert(spent3.compute_txid(), spent3);
+        spent.insert(spent1.txid(), spent1);
+        spent.insert(spent2.txid(), spent2);
+        spent.insert(spent3.txid(), spent3);
         let mut spent2 = spent.clone();
         let mut spent3 = spent.clone();
 
@@ -2135,37 +1989,6 @@ fn sequence_from_str_hex_invalid_hex_should_err() {
         assert!(result.is_err());
     }
 
-    #[test]
-    fn effective_value_happy_path() {
-        let value = Amount::from_str("1 cBTC").unwrap();
-        let fee_rate = FeeRate::from_sat_per_kwu(10);
-        let satisfaction_weight = Weight::from_wu(204);
-        let effective_value = effective_value(fee_rate, satisfaction_weight, value).unwrap();
-
-        // 10 sat/kwu * (204wu + BASE_WEIGHT) = 4 sats
-        let expected_fee = SignedAmount::from_str("4 sats").unwrap();
-        let expected_effective_value = value.to_signed().unwrap() - expected_fee;
-        assert_eq!(effective_value, expected_effective_value);
-    }
-
-    #[test]
-    fn effective_value_fee_rate_does_not_overflow() {
-        let eff_value = effective_value(FeeRate::MAX, Weight::ZERO, Amount::ZERO);
-        assert!(eff_value.is_none());
-    }
-
-    #[test]
-    fn effective_value_weight_does_not_overflow() {
-        let eff_value = effective_value(FeeRate::ZERO, Weight::MAX, Amount::ZERO);
-        assert!(eff_value.is_none());
-    }
-
-    #[test]
-    fn effective_value_value_does_not_overflow() {
-        let eff_value = effective_value(FeeRate::ZERO, Weight::ZERO, Amount::MAX);
-        assert!(eff_value.is_none());
-    }
-
     #[test]
     fn txin_txout_weight() {
         // [(is_segwit, tx_hex, expected_weight)]
@@ -2195,14 +2018,14 @@ fn txin_txout_weight() {
         for (is_segwit, tx, expected_weight) in &txs {
             let txin_weight = if *is_segwit { TxIn::segwit_weight } else { TxIn::legacy_weight };
             let tx: Transaction = deserialize(Vec::from_hex(tx).unwrap().as_slice()).unwrap();
-            assert_eq!(*is_segwit, tx.uses_segwit_serialization());
+            assert_eq!(*is_segwit, tx.use_segwit_serialization());
 
             let mut calculated_weight = empty_transaction_weight
                 + tx.input.iter().fold(Weight::ZERO, |sum, i| sum + txin_weight(i))
                 + tx.output.iter().fold(Weight::ZERO, |sum, o| sum + o.weight());
 
             // The empty tx uses segwit serialization but a legacy tx does not.
-            if !tx.uses_segwit_serialization() {
+            if !tx.use_segwit_serialization() {
                 calculated_weight -= Weight::from_wu(2);
             }
 
diff --git a/bitcoin/src/blockdata/witness.rs b/bitcoin/src/blockdata/witness.rs
index 69af2924..b7011638 100644
--- a/bitcoin/src/blockdata/witness.rs
+++ b/bitcoin/src/blockdata/witness.rs
@@ -8,13 +8,13 @@
 use core::fmt;
 use core::ops::Index;
 
-use io::{BufRead, Write};
+use io::{Read, Write};
 
 use crate::consensus::encode::{Error, MAX_VEC_SIZE};
 use crate::consensus::{Decodable, Encodable, WriteExt};
 use crate::crypto::ecdsa;
 use crate::prelude::*;
-use crate::taproot::{self, TAPROOT_ANNEX_PREFIX};
+use crate::taproot::TAPROOT_ANNEX_PREFIX;
 use crate::{Script, VarInt};
 
 /// The Witness is the data used to unlock bitcoin since the [segwit upgrade].
@@ -124,7 +124,7 @@ pub struct Iter<'a> {
 }
 
 impl Decodable for Witness {
-    fn consensus_decode<R: BufRead + ?Sized>(r: &mut R) -> Result<Self, Error> {
+    fn consensus_decode<R: Read + ?Sized>(r: &mut R) -> Result<Self, Error> {
         let witness_elements = VarInt::consensus_decode(r)?.0 as usize;
         // Minimum size of witness element is 1 byte, so if the count is
         // greater than MAX_VEC_SIZE we must return an error.
@@ -248,13 +248,6 @@ pub fn p2wpkh(signature: &ecdsa::Signature, pubkey: &secp256k1::PublicKey) -> Wi
         witness
     }
 
-    /// Creates a witness required to do a key path spend of a P2TR output.
-    pub fn p2tr_key_spend(signature: &taproot::Signature) -> Witness {
-        let mut witness = Witness::new();
-        witness.push_slice(&signature.serialize());
-        witness
-    }
-
     /// Creates a [`Witness`] object from a slice of bytes slices where each slice is a witness item.
     pub fn from_slice<T: AsRef<[u8]>>(slice: &[T]) -> Self {
         let witness_elements = slice.len();
@@ -644,9 +637,9 @@ fn test_push_ecdsa_sig() {
         // The very first signature in block 734,958
         let sig_bytes =
             hex!("304402207c800d698f4b0298c5aac830b822f011bb02df41eb114ade9a6702f364d5e39c0220366900d2a60cab903e77ef7dd415d46509b1f78ac78906e3296f495aa1b1b541");
-        let signature = secp256k1::ecdsa::Signature::from_der(&sig_bytes).unwrap();
+        let sig = secp256k1::ecdsa::Signature::from_der(&sig_bytes).unwrap();
         let mut witness = Witness::default();
-        let signature = crate::ecdsa::Signature { signature, sighash_type: EcdsaSighashType::All };
+        let signature = crate::ecdsa::Signature { sig, hash_ty: EcdsaSighashType::All };
         witness.push_ecdsa_signature(&signature);
         let expected_witness = vec![hex!(
             "304402207c800d698f4b0298c5aac830b822f011bb02df41eb114ade9a6702f364d5e39c0220366900d2a60cab903e77ef7dd415d46509b1f78ac78906e3296f495aa1b1b54101")
diff --git a/bitcoin/src/consensus/encode.rs b/bitcoin/src/consensus/encode.rs
index ca8da29a..0e3e43d8 100644
--- a/bitcoin/src/consensus/encode.rs
+++ b/bitcoin/src/consensus/encode.rs
@@ -20,7 +20,7 @@
 
 use hashes::{sha256, sha256d, Hash};
 use internals::write_err;
-use io::{Cursor, BufRead, Read, Write};
+use io::{Cursor, Read, Write};
 
 use crate::bip152::{PrefilledTransaction, ShortId};
 use crate::bip158::{FilterHash, FilterHeader};
@@ -193,7 +193,7 @@ pub trait ReadExt: Read {
 macro_rules! encoder_fn {
     ($name:ident, $val_type:ty) => {
         #[inline]
-        fn $name(&mut self, v: $val_type) -> core::result::Result<(), io::Error> {
+        fn $name(&mut self, v: $val_type) -> Result<(), io::Error> {
             self.write_all(&v.to_le_bytes())
         }
     };
@@ -202,7 +202,7 @@ fn $name(&mut self, v: $val_type) -> core::result::Result<(), io::Error> {
 macro_rules! decoder_fn {
     ($name:ident, $val_type:ty, $byte_len: expr) => {
         #[inline]
-        fn $name(&mut self) -> core::result::Result<$val_type, Error> {
+        fn $name(&mut self) -> Result<$val_type, Error> {
             let mut val = [0; $byte_len];
             self.read_exact(&mut val[..]).map_err(Error::Io)?;
             Ok(<$val_type>::from_le_bytes(val))
@@ -301,7 +301,7 @@ pub trait Decodable: Sized {
     ///   avoid creating redundant `Take` wrappers. Failure to do so might result only in a tiny
     ///   performance hit.
     #[inline]
-    fn consensus_decode_from_finite_reader<R: BufRead + ?Sized>(
+    fn consensus_decode_from_finite_reader<R: Read + ?Sized>(
         reader: &mut R,
     ) -> Result<Self, Error> {
         // This method is always strictly less general than, `consensus_decode`, so it's safe and
@@ -319,7 +319,7 @@ fn consensus_decode_from_finite_reader<R: BufRead + ?Sized>(
     /// for types that override [`Self::consensus_decode_from_finite_reader`]
     /// instead.
     #[inline]
-    fn consensus_decode<R: BufRead + ?Sized>(reader: &mut R) -> Result<Self, Error> {
+    fn consensus_decode<R: Read + ?Sized>(reader: &mut R) -> Result<Self, Error> {
         Self::consensus_decode_from_finite_reader(&mut reader.take(MAX_VEC_SIZE as u64))
     }
 }
@@ -357,13 +357,13 @@ macro_rules! impl_int_encodable {
     ($ty:ident, $meth_dec:ident, $meth_enc:ident) => {
         impl Decodable for $ty {
             #[inline]
-            fn consensus_decode<R: BufRead + ?Sized>(r: &mut R) -> core::result::Result<Self, Error> {
+            fn consensus_decode<R: Read + ?Sized>(r: &mut R) -> Result<Self, Error> {
                 ReadExt::$meth_dec(r)
             }
         }
         impl Encodable for $ty {
             #[inline]
-            fn consensus_encode<W: Write + ?Sized>(&self, w: &mut W) -> core::result::Result<usize, io::Error> {
+            fn consensus_encode<W: Write + ?Sized>(&self, w: &mut W) -> Result<usize, io::Error> {
                 w.$meth_enc(*self)?;
                 Ok(mem::size_of::<$ty>())
             }
@@ -440,7 +440,7 @@ fn consensus_encode<W: Write + ?Sized>(&self, w: &mut W) -> Result<usize, io::Er
 
 impl Decodable for VarInt {
     #[inline]
-    fn consensus_decode<R: BufRead + ?Sized>(r: &mut R) -> Result<Self, Error> {
+    fn consensus_decode<R: Read + ?Sized>(r: &mut R) -> Result<Self, Error> {
         let n = ReadExt::read_u8(r)?;
         match n {
             0xFF => {
@@ -482,7 +482,7 @@ fn consensus_encode<W: Write + ?Sized>(&self, w: &mut W) -> Result<usize, io::Er
 
 impl Decodable for bool {
     #[inline]
-    fn consensus_decode<R: BufRead + ?Sized>(r: &mut R) -> Result<bool, Error> {
+    fn consensus_decode<R: Read + ?Sized>(r: &mut R) -> Result<bool, Error> {
         ReadExt::read_bool(r)
     }
 }
@@ -499,7 +499,7 @@ fn consensus_encode<W: Write + ?Sized>(&self, w: &mut W) -> Result<usize, io::Er
 
 impl Decodable for String {
     #[inline]
-    fn consensus_decode<R: BufRead + ?Sized>(r: &mut R) -> Result<String, Error> {
+    fn consensus_decode<R: Read + ?Sized>(r: &mut R) -> Result<String, Error> {
         String::from_utf8(Decodable::consensus_decode(r)?)
             .map_err(|_| self::Error::ParseFailed("String was not valid UTF8"))
     }
@@ -517,7 +517,7 @@ fn consensus_encode<W: Write + ?Sized>(&self, w: &mut W) -> Result<usize, io::Er
 
 impl Decodable for Cow<'static, str> {
     #[inline]
-    fn consensus_decode<R: BufRead + ?Sized>(r: &mut R) -> Result<Cow<'static, str>, Error> {
+    fn consensus_decode<R: Read + ?Sized>(r: &mut R) -> Result<Cow<'static, str>, Error> {
         String::from_utf8(Decodable::consensus_decode(r)?)
             .map_err(|_| self::Error::ParseFailed("String was not valid UTF8"))
             .map(Cow::Owned)
@@ -531,7 +531,7 @@ macro_rules! impl_array {
             fn consensus_encode<W: WriteExt + ?Sized>(
                 &self,
                 w: &mut W,
-            ) -> core::result::Result<usize, io::Error> {
+            ) -> Result<usize, io::Error> {
                 w.emit_slice(&self[..])?;
                 Ok(self.len())
             }
@@ -539,7 +539,7 @@ fn consensus_encode<W: WriteExt + ?Sized>(
 
         impl Decodable for [u8; $size] {
             #[inline]
-            fn consensus_decode<R: BufRead + ?Sized>(r: &mut R) -> core::result::Result<Self, Error> {
+            fn consensus_decode<R: Read + ?Sized>(r: &mut R) -> Result<Self, Error> {
                 let mut ret = [0; $size];
                 r.read_slice(&mut ret)?;
                 Ok(ret)
@@ -560,7 +560,7 @@ fn consensus_decode<R: BufRead + ?Sized>(r: &mut R) -> core::result::Result<Self
 
 impl Decodable for [u16; 8] {
     #[inline]
-    fn consensus_decode<R: BufRead + ?Sized>(r: &mut R) -> Result<Self, Error> {
+    fn consensus_decode<R: Read + ?Sized>(r: &mut R) -> Result<Self, Error> {
         let mut res = [0; 8];
         for item in &mut res {
             *item = Decodable::consensus_decode(r)?;
@@ -583,7 +583,7 @@ macro_rules! impl_vec {
     ($type: ty) => {
         impl Encodable for Vec<$type> {
             #[inline]
-            fn consensus_encode<W: Write + ?Sized>(&self, w: &mut W) -> core::result::Result<usize, io::Error> {
+            fn consensus_encode<W: Write + ?Sized>(&self, w: &mut W) -> Result<usize, io::Error> {
                 let mut len = 0;
                 len += VarInt(self.len() as u64).consensus_encode(w)?;
                 for c in self.iter() {
@@ -595,9 +595,9 @@ fn consensus_encode<W: Write + ?Sized>(&self, w: &mut W) -> core::result::Result
 
         impl Decodable for Vec<$type> {
             #[inline]
-            fn consensus_decode_from_finite_reader<R: BufRead + ?Sized>(
+            fn consensus_decode_from_finite_reader<R: Read + ?Sized>(
                 r: &mut R,
-            ) -> core::result::Result<Self, Error> {
+            ) -> Result<Self, Error> {
                 let len = VarInt::consensus_decode_from_finite_reader(r)?.0;
                 // Do not allocate upfront more items than if the sequence of type
                 // occupied roughly quarter a block. This should never be the case
@@ -685,7 +685,7 @@ fn consensus_encode<W: Write + ?Sized>(&self, w: &mut W) -> Result<usize, io::Er
 
 impl Decodable for Vec<u8> {
     #[inline]
-    fn consensus_decode_from_finite_reader<R: BufRead + ?Sized>(r: &mut R) -> Result<Self, Error> {
+    fn consensus_decode_from_finite_reader<R: Read + ?Sized>(r: &mut R) -> Result<Self, Error> {
         let len = VarInt::consensus_decode(r)?.0 as usize;
         // most real-world vec of bytes data, wouldn't be larger than 128KiB
         let opts = ReadBytesFromFiniteReaderOpts { len, chunk_size: 128 * 1024 };
@@ -702,7 +702,7 @@ fn consensus_encode<W: Write + ?Sized>(&self, w: &mut W) -> Result<usize, io::Er
 
 impl Decodable for Box<[u8]> {
     #[inline]
-    fn consensus_decode_from_finite_reader<R: BufRead + ?Sized>(r: &mut R) -> Result<Self, Error> {
+    fn consensus_decode_from_finite_reader<R: Read + ?Sized>(r: &mut R) -> Result<Self, Error> {
         <Vec<u8>>::consensus_decode_from_finite_reader(r).map(From::from)
     }
 }
@@ -727,7 +727,7 @@ fn consensus_encode<W: Write + ?Sized>(&self, w: &mut W) -> Result<usize, io::Er
 
 impl Decodable for CheckedData {
     #[inline]
-    fn consensus_decode_from_finite_reader<R: BufRead + ?Sized>(r: &mut R) -> Result<Self, Error> {
+    fn consensus_decode_from_finite_reader<R: Read + ?Sized>(r: &mut R) -> Result<Self, Error> {
         let len = u32::consensus_decode_from_finite_reader(r)? as usize;
 
         let checksum = <[u8; 4]>::consensus_decode_from_finite_reader(r)?;
@@ -776,7 +776,7 @@ impl <$($x: Encodable),*> Encodable for ($($x),*) {
             fn consensus_encode<W: Write + ?Sized>(
                 &self,
                 w: &mut W,
-            ) -> core::result::Result<usize, io::Error> {
+            ) -> Result<usize, io::Error> {
                 let &($(ref $x),*) = self;
                 let mut len = 0;
                 $(len += $x.consensus_encode(w)?;)*
@@ -787,7 +787,7 @@ fn consensus_encode<W: Write + ?Sized>(
         impl<$($x: Decodable),*> Decodable for ($($x),*) {
             #[inline]
             #[allow(non_snake_case)]
-            fn consensus_decode<R: BufRead + ?Sized>(r: &mut R) -> core::result::Result<Self, Error> {
+            fn consensus_decode<R: Read + ?Sized>(r: &mut R) -> Result<Self, Error> {
                 Ok(($({let $x = Decodable::consensus_decode(r)?; $x }),*))
             }
         }
@@ -809,7 +809,7 @@ fn consensus_encode<W: Write + ?Sized>(&self, w: &mut W) -> Result<usize, io::Er
 }
 
 impl Decodable for sha256d::Hash {
-    fn consensus_decode<R: BufRead + ?Sized>(r: &mut R) -> Result<Self, Error> {
+    fn consensus_decode<R: Read + ?Sized>(r: &mut R) -> Result<Self, Error> {
         Ok(Self::from_byte_array(<<Self as Hash>::Bytes>::consensus_decode(r)?))
     }
 }
@@ -821,7 +821,7 @@ fn consensus_encode<W: Write + ?Sized>(&self, w: &mut W) -> Result<usize, io::Er
 }
 
 impl Decodable for sha256::Hash {
-    fn consensus_decode<R: BufRead + ?Sized>(r: &mut R) -> Result<Self, Error> {
+    fn consensus_decode<R: Read + ?Sized>(r: &mut R) -> Result<Self, Error> {
         Ok(Self::from_byte_array(<<Self as Hash>::Bytes>::consensus_decode(r)?))
     }
 }
@@ -833,7 +833,7 @@ fn consensus_encode<W: Write + ?Sized>(&self, w: &mut W) -> Result<usize, io::Er
 }
 
 impl Decodable for TapLeafHash {
-    fn consensus_decode<R: BufRead + ?Sized>(r: &mut R) -> Result<Self, Error> {
+    fn consensus_decode<R: Read + ?Sized>(r: &mut R) -> Result<Self, Error> {
         Ok(Self::from_byte_array(<<Self as Hash>::Bytes>::consensus_decode(r)?))
     }
 }
@@ -1017,6 +1017,7 @@ fn serialize_checkeddata_test() {
     #[test]
     fn serialize_vector_test() {
         assert_eq!(serialize(&vec![1u8, 2, 3]), vec![3u8, 1, 2, 3]);
+        // TODO: test vectors of more interesting objects
     }
 
     #[test]
diff --git a/bitcoin/src/consensus/serde.rs b/bitcoin/src/consensus/serde.rs
index 6c9c9c32..7f94341b 100644
--- a/bitcoin/src/consensus/serde.rs
+++ b/bitcoin/src/consensus/serde.rs
@@ -12,7 +12,7 @@
 use core::fmt;
 use core::marker::PhantomData;
 
-use io::{BufRead, Read, Write};
+use io::{Read, Write};
 use serde::de::{SeqAccess, Unexpected, Visitor};
 use serde::ser::SerializeSeq;
 use serde::{Deserializer, Serializer};
@@ -66,7 +66,7 @@ impl Case for super::Upper {
         }
     }
 
-    // We just guessed at a reasonably sane value.
+    // TODO measure various sizes and determine the best value
     const HEX_BUF_SIZE: usize = 512;
 
     /// Hex byte encoder.
@@ -420,12 +420,11 @@ fn into_de_error<DE: serde::de::Error>(self) -> DE {
 
 struct IterReader<E: fmt::Debug, I: Iterator<Item = Result<u8, E>>> {
     iterator: core::iter::Fuse<I>,
-    buf: Option<u8>,
     error: Option<E>,
 }
 
 impl<E: fmt::Debug, I: Iterator<Item = Result<u8, E>>> IterReader<E, I> {
-    fn new(iterator: I) -> Self { IterReader { iterator: iterator.fuse(), buf: None, error: None } }
+    fn new(iterator: I) -> Self { IterReader { iterator: iterator.fuse(), error: None } }
 
     fn decode<T: Decodable>(mut self) -> Result<T, DecodeError<E>> {
         let result = T::consensus_decode(&mut self);
@@ -444,17 +443,8 @@ fn decode<T: Decodable>(mut self) -> Result<T, DecodeError<E>> {
 }
 
 impl<E: fmt::Debug, I: Iterator<Item = Result<u8, E>>> Read for IterReader<E, I> {
-    fn read(&mut self, mut buf: &mut [u8]) -> io::Result<usize> {
+    fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
         let mut count = 0;
-        if buf.is_empty() {
-            return Ok(0);
-        }
-
-        if let Some(first) = self.buf.take() {
-            buf[0] = first;
-            buf = &mut buf[1..];
-            count += 1;
-        }
         for (dst, src) in buf.iter_mut().zip(&mut self.iterator) {
             match src {
                 Ok(byte) => *dst = byte,
@@ -470,34 +460,6 @@ fn read(&mut self, mut buf: &mut [u8]) -> io::Result<usize> {
     }
 }
 
-impl<E: fmt::Debug, I: Iterator<Item = Result<u8, E>>> BufRead for IterReader<E, I> {
-    fn fill_buf(&mut self) -> Result<&[u8], io::Error> {
-        // matching on reference rather than using `ref` confuses borrow checker
-        if let Some(ref byte) = self.buf {
-            Ok(core::slice::from_ref(byte))
-        } else {
-            match self.iterator.next() {
-                Some(Ok(byte)) => {
-                    self.buf = Some(byte);
-                    Ok(core::slice::from_ref(self.buf.as_ref().expect("we've just filled it")))
-                },
-                Some(Err(error)) => {
-                    self.error = Some(error);
-                    Err(io::ErrorKind::Other.into())
-                },
-                None => Ok(&[]),
-            }
-        }
-    }
-
-    fn consume(&mut self, len: usize) {
-        debug_assert!(len <= 1);
-        if len > 0 {
-            self.buf = None;
-        }
-    }
-}
-
 /// Helper for `#[serde(with = "")]`.
 ///
 /// To (de)serialize a field using consensus encoding you can write e.g.:
diff --git a/bitcoin/src/crypto/ecdsa.rs b/bitcoin/src/crypto/ecdsa.rs
index 24940b02..14251fac 100644
--- a/bitcoin/src/crypto/ecdsa.rs
+++ b/bitcoin/src/crypto/ecdsa.rs
@@ -9,7 +9,6 @@
 
 use hex::FromHex;
 use internals::write_err;
-use io::Write;
 use secp256k1;
 
 use crate::prelude::*;
@@ -23,24 +22,24 @@
 #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
 #[cfg_attr(feature = "serde", serde(crate = "actual_serde"))]
 pub struct Signature {
-    /// The underlying ECDSA Signature.
-    pub signature: secp256k1::ecdsa::Signature,
-    /// The corresponding hash type.
-    pub sighash_type: EcdsaSighashType,
+    /// The underlying ECDSA Signature
+    pub sig: secp256k1::ecdsa::Signature,
+    /// The corresponding hash type
+    pub hash_ty: EcdsaSighashType,
 }
 
 impl Signature {
     /// Constructs an ECDSA Bitcoin signature for [`EcdsaSighashType::All`].
-    pub fn sighash_all(signature: secp256k1::ecdsa::Signature) -> Signature {
-        Signature { signature, sighash_type: EcdsaSighashType::All }
+    pub fn sighash_all(sig: secp256k1::ecdsa::Signature) -> Signature {
+        Signature { sig, hash_ty: EcdsaSighashType::All }
     }
 
     /// Deserializes from slice following the standardness rules for [`EcdsaSighashType`].
     pub fn from_slice(sl: &[u8]) -> Result<Self, Error> {
-        let (sighash_type, sig) = sl.split_last().ok_or(Error::EmptySignature)?;
-        let sighash_type = EcdsaSighashType::from_standard(*sighash_type as u32)?;
-        let signature = secp256k1::ecdsa::Signature::from_der(sig).map_err(Error::Secp256k1)?;
-        Ok(Signature { signature, sighash_type })
+        let (hash_ty, sig) = sl.split_last().ok_or(Error::EmptySignature)?;
+        let hash_ty = EcdsaSighashType::from_standard(*hash_ty as u32)?;
+        let sig = secp256k1::ecdsa::Signature::from_der(sig).map_err(Error::Secp256k1)?;
+        Ok(Signature { sig, hash_ty })
     }
 
     /// Serializes an ECDSA signature (inner secp256k1 signature in DER format).
@@ -48,9 +47,9 @@ pub fn from_slice(sl: &[u8]) -> Result<Self, Error> {
     /// This does **not** perform extra heap allocation.
     pub fn serialize(&self) -> SerializedSignature {
         let mut buf = [0u8; MAX_SIG_LEN];
-        let signature = self.signature.serialize_der();
+        let signature = self.sig.serialize_der();
         buf[..signature.len()].copy_from_slice(&signature);
-        buf[signature.len()] = self.sighash_type as u8;
+        buf[signature.len()] = self.hash_ty as u8;
         SerializedSignature { data: buf, len: signature.len() + 1 }
     }
 
@@ -59,26 +58,15 @@ pub fn serialize(&self) -> SerializedSignature {
     /// Note: this performs an extra heap allocation, you might prefer the
     /// [`serialize`](Self::serialize) method instead.
     pub fn to_vec(self) -> Vec<u8> {
-        self.signature
-            .serialize_der()
-            .iter()
-            .copied()
-            .chain(iter::once(self.sighash_type as u8))
-            .collect()
-    }
-
-    /// Serializes an ECDSA signature (inner secp256k1 signature in DER format) to a `writer`.
-    #[inline]
-    pub fn serialize_to_writer<W: Write + ?Sized>(&self, writer: &mut W) -> Result<(), io::Error> {
-        let sig = self.serialize();
-        sig.write_to(writer)
+        // TODO: add support to serialize to a writer to SerializedSig
+        self.sig.serialize_der().iter().copied().chain(iter::once(self.hash_ty as u8)).collect()
     }
 }
 
 impl fmt::Display for Signature {
     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
-        fmt::LowerHex::fmt(&self.signature.serialize_der().as_hex(), f)?;
-        fmt::LowerHex::fmt(&[self.sighash_type as u8].as_hex(), f)
+        fmt::LowerHex::fmt(&self.sig.serialize_der().as_hex(), f)?;
+        fmt::LowerHex::fmt(&[self.hash_ty as u8].as_hex(), f)
     }
 }
 
@@ -89,8 +77,8 @@ fn from_str(s: &str) -> Result<Self, Self::Err> {
         let bytes = Vec::from_hex(s)?;
         let (sighash_byte, signature) = bytes.split_last().ok_or(Error::EmptySignature)?;
         Ok(Signature {
-            signature: secp256k1::ecdsa::Signature::from_der(signature)?,
-            sighash_type: EcdsaSighashType::from_standard(*sighash_byte as u32)?,
+            sig: secp256k1::ecdsa::Signature::from_der(signature)?,
+            hash_ty: EcdsaSighashType::from_standard(*sighash_byte as u32)?,
         })
     }
 }
@@ -112,12 +100,6 @@ impl SerializedSignature {
     /// Returns an iterator over bytes of the signature.
     #[inline]
     pub fn iter(&self) -> core::slice::Iter<'_, u8> { self.into_iter() }
-
-    /// Writes this serialized signature to a `writer`.
-    #[inline]
-    pub fn write_to<W: Write + ?Sized>(&self, writer: &mut W) -> Result<(), io::Error> {
-        writer.write_all(self)
-    }
 }
 
 impl core::ops::Deref for SerializedSignature {
@@ -252,22 +234,3 @@ fn from(err: NonStandardSighashTypeError) -> Self { Error::SighashType(err) }
 impl From<hex::HexToBytesError> for Error {
     fn from(err: hex::HexToBytesError) -> Self { Error::Hex(err) }
 }
-
-#[cfg(test)]
-mod tests {
-    use super::*;
-
-    #[test]
-    fn write_serialized_signature() {
-        let hex = "3046022100839c1fbc5304de944f697c9f4b1d01d1faeba32d751c0f7acb21ac8a0f436a72022100e89bd46bb3a5a62adc679f659b7ce876d83ee297c7a5587b2011c4fcc72eab45";
-        let sig = Signature {
-            signature: secp256k1::ecdsa::Signature::from_str(hex).unwrap(),
-            sighash_type: EcdsaSighashType::All,
-        };
-
-        let mut buf = vec![];
-        sig.serialize_to_writer(&mut buf).expect("write failed");
-
-        assert_eq!(sig.to_vec(), buf)
-    }
-}
diff --git a/bitcoin/src/crypto/key.rs b/bitcoin/src/crypto/key.rs
index fb20eaf8..9ee810cc 100644
--- a/bitcoin/src/crypto/key.rs
+++ b/bitcoin/src/crypto/key.rs
@@ -202,7 +202,7 @@ pub fn verify<C: secp256k1::Verification>(
         msg: &secp256k1::Message,
         sig: &ecdsa::Signature,
     ) -> Result<(), Error> {
-        Ok(secp.verify_ecdsa(msg, &sig.signature, &self.inner)?)
+        Ok(secp.verify_ecdsa(msg, &sig.sig, &self.inner)?)
     }
 }
 
@@ -220,8 +220,12 @@ fn from(pk: PublicKey) -> XOnlyPublicKey { pk.inner.into() }
 
 impl fmt::Display for PublicKey {
     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+        // TODO: fast hex encoding
         self.with_serialized(|bytes| {
-            fmt::Display::fmt(&bytes.as_hex(), f)
+            for ch in bytes {
+                write!(f, "{:02x}", ch)?;
+            }
+            Ok(())
         })
     }
 }
@@ -317,7 +321,7 @@ pub fn verify<C: secp256k1::Verification>(
         msg: &secp256k1::Message,
         sig: &ecdsa::Signature,
     ) -> Result<(), Error> {
-        Ok(secp.verify_ecdsa(msg, &sig.signature, &self.0)?)
+        Ok(secp.verify_ecdsa(msg, &sig.sig, &self.0)?)
     }
 }
 
@@ -1092,21 +1096,21 @@ fn pubkey_read_write() {
             k.write_into(&mut v).expect("writing into vec");
         }
 
-        let mut reader = v.as_slice();
         let mut dec_keys = vec![];
+        let mut cursor = io::Cursor::new(&v);
         for _ in 0..N_KEYS {
-            dec_keys.push(PublicKey::read_from(&mut reader).expect("reading from vec"));
+            dec_keys.push(PublicKey::read_from(&mut cursor).expect("reading from vec"));
         }
+
         assert_eq!(keys, dec_keys);
-        assert!(PublicKey::read_from(&mut reader).is_err());
 
         // sanity checks
-        let mut empty: &[u8] = &[];
-        assert!(PublicKey::read_from(&mut empty).is_err());
-        assert!(PublicKey::read_from(&mut &[0; 33][..]).is_err());
-        assert!(PublicKey::read_from(&mut &[2; 32][..]).is_err());
-        assert!(PublicKey::read_from(&mut &[0; 65][..]).is_err());
-        assert!(PublicKey::read_from(&mut &[4; 64][..]).is_err());
+        assert!(PublicKey::read_from(&mut cursor).is_err());
+        assert!(PublicKey::read_from(&mut io::Cursor::new(&[])).is_err());
+        assert!(PublicKey::read_from(&mut io::Cursor::new(&[0; 33][..])).is_err());
+        assert!(PublicKey::read_from(&mut io::Cursor::new(&[2; 32][..])).is_err());
+        assert!(PublicKey::read_from(&mut io::Cursor::new(&[0; 65][..])).is_err());
+        assert!(PublicKey::read_from(&mut io::Cursor::new(&[4; 64][..])).is_err());
     }
 
     #[test]
diff --git a/bitcoin/src/crypto/sighash.rs b/bitcoin/src/crypto/sighash.rs
index de6170ff..4b805281 100644
--- a/bitcoin/src/crypto/sighash.rs
+++ b/bitcoin/src/crypto/sighash.rs
@@ -22,7 +22,7 @@
 use crate::consensus::{encode, Encodable};
 use crate::prelude::*;
 use crate::taproot::{LeafVersion, TapLeafHash, TAPROOT_ANNEX_PREFIX};
-use crate::{transaction, Amount, Script, ScriptBuf, Sequence, Transaction, TxIn, TxOut};
+use crate::{Amount, Script, ScriptBuf, Sequence, Transaction, TxIn, TxOut};
 
 /// Used for signature hash for invalid use of SIGHASH_SINGLE.
 #[rustfmt::skip]
@@ -198,6 +198,106 @@ fn from_str(s: &str) -> Result<Self, Self::Err> {
     }
 }
 
+/// Possible errors in computing the signature message.
+#[derive(Debug, Clone, PartialEq, Eq)]
+#[non_exhaustive]
+pub enum Error {
+    /// Could happen only by using `*_encode_signing_*` methods with custom writers, engines writers
+    /// like the ones used in methods `*_signature_hash` do not error.
+    Io(io::ErrorKind),
+
+    /// Requested index is greater or equal than the number of inputs in the transaction.
+    IndexOutOfInputsBounds {
+        /// Requested index.
+        index: usize,
+        /// Number of transaction inputs.
+        inputs_size: usize,
+    },
+
+    /// Using `SIGHASH_SINGLE` without a "corresponding output" (an output with the same index as
+    /// the input being verified) is a validation failure.
+    SingleWithoutCorrespondingOutput {
+        /// Requested index.
+        index: usize,
+        /// Number of transaction outputs.
+        outputs_size: usize,
+    },
+
+    /// There are mismatches in the number of prevouts provided compared to the number of inputs in
+    /// the transaction.
+    PrevoutsSize(PrevoutsSizeError),
+
+    /// Requested a prevout index which is greater than the number of prevouts provided or a
+    /// [`Prevouts::One`] with different index.
+    PrevoutsIndex(PrevoutsIndexError),
+
+    /// A single prevout has been provided but all prevouts are needed unless using
+    /// `SIGHASH_ANYONECANPAY`.
+    PrevoutsKind(PrevoutsKindError),
+
+    /// Annex must be at least one byte long and the first bytes must be `0x50`.
+    WrongAnnex,
+
+    /// Invalid Sighash type.
+    InvalidSighashType(u32),
+
+    /// Script is not a witness program for a p2wpkh output.
+    NotP2wpkhScript,
+}
+
+impl fmt::Display for Error {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        use Error::*;
+
+        match *self {
+            Io(error_kind) => write!(f, "writer errored: {:?}", error_kind),
+            IndexOutOfInputsBounds { index, inputs_size } => write!(f, "requested index ({}) is greater or equal than the number of transaction inputs ({})", index, inputs_size),
+            SingleWithoutCorrespondingOutput { index, outputs_size } => write!(f, "SIGHASH_SINGLE for input ({}) haven't a corresponding output (#outputs:{})", index, outputs_size),
+            PrevoutsSize(ref e) => write_err!(f, "prevouts size"; e),
+            PrevoutsIndex(ref e) => write_err!(f, "prevouts index"; e),
+            PrevoutsKind(ref e) => write_err!(f, "prevouts kind"; e),
+            WrongAnnex => write!(f, "annex must be at least one byte long and the first bytes must be `0x50`"),
+            InvalidSighashType(hash_ty) => write!(f, "Invalid taproot signature hash type : {} ", hash_ty),
+            NotP2wpkhScript => write!(f, "script is not a script pubkey for a p2wpkh output"),
+        }
+    }
+}
+
+#[cfg(feature = "std")]
+impl std::error::Error for Error {
+    fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
+        use Error::*;
+
+        match *self {
+            PrevoutsSize(ref e) => Some(e),
+            PrevoutsIndex(ref e) => Some(e),
+            PrevoutsKind(ref e) => Some(e),
+            Io(_)
+            | IndexOutOfInputsBounds { .. }
+            | SingleWithoutCorrespondingOutput { .. }
+            | WrongAnnex
+            | InvalidSighashType(_)
+            | NotP2wpkhScript => None,
+        }
+    }
+}
+
+impl From<io::Error> for Error {
+    fn from(e: io::Error) -> Self { Error::Io(e.kind()) }
+}
+
+impl From<PrevoutsSizeError> for Error {
+    fn from(e: PrevoutsSizeError) -> Self { Self::PrevoutsSize(e) }
+}
+
+impl From<PrevoutsKindError> for Error {
+    fn from(e: PrevoutsKindError) -> Self { Self::PrevoutsKind(e) }
+}
+
+impl From<PrevoutsIndexError> for Error {
+    fn from(e: PrevoutsIndexError) -> Self { Self::PrevoutsIndex(e) }
+}
+
 impl<'u, T> Prevouts<'u, T>
 where
     T: Borrow<TxOut>,
@@ -486,10 +586,10 @@ pub(crate) fn split_anyonecanpay_flag(self) -> (TapSighashType, bool) {
     }
 
     /// Constructs a [`TapSighashType`] from a raw `u8`.
-    pub fn from_consensus_u8(sighash_type: u8) -> Result<Self, InvalidSighashTypeError> {
+    pub fn from_consensus_u8(hash_ty: u8) -> Result<Self, InvalidSighashTypeError> {
         use TapSighashType::*;
 
-        Ok(match sighash_type {
+        Ok(match hash_ty {
             0x00 => Default,
             0x01 => All,
             0x02 => None,
@@ -582,8 +682,8 @@ pub fn taproot_encode_signing_data_to<W: Write + ?Sized, T: Borrow<TxOut>>(
         annex: Option<Annex>,
         leaf_hash_code_separator: Option<(TapLeafHash, u32)>,
         sighash_type: TapSighashType,
-    ) -> Result<(), SigningDataError<TaprootError>> {
-        prevouts.check_all(self.tx.borrow()).map_err(SigningDataError::sighash)?;
+    ) -> Result<(), Error> {
+        prevouts.check_all(self.tx.borrow())?;
 
         let (sighash, anyone_can_pay) = sighash_type.split_anyonecanpay_flag();
 
@@ -608,8 +708,8 @@ pub fn taproot_encode_signing_data_to<W: Write + ?Sized, T: Borrow<TxOut>>(
         //     sha_sequences (32): the SHA256 of the serialization of all input nSequence.
         if !anyone_can_pay {
             self.common_cache().prevouts.consensus_encode(writer)?;
-            self.taproot_cache(prevouts.get_all().map_err(SigningDataError::sighash)?).amounts.consensus_encode(writer)?;
-            self.taproot_cache(prevouts.get_all().map_err(SigningDataError::sighash)?).script_pubkeys.consensus_encode(writer)?;
+            self.taproot_cache(prevouts.get_all()?).amounts.consensus_encode(writer)?;
+            self.taproot_cache(prevouts.get_all()?).script_pubkeys.consensus_encode(writer)?;
             self.common_cache().sequences.consensus_encode(writer)?;
         }
 
@@ -637,8 +737,12 @@ pub fn taproot_encode_signing_data_to<W: Write + ?Sized, T: Borrow<TxOut>>(
         //      scriptPubKey (35): scriptPubKey of the previous output spent by this input, serialized as script inside CTxOut. Its size is always 35 bytes.
         //      nSequence (4): nSequence of this input.
         if anyone_can_pay {
-            let txin = &self.tx.borrow().tx_in(input_index).map_err(SigningDataError::sighash)?;
-            let previous_output = prevouts.get(input_index).map_err(SigningDataError::sighash)?;
+            let txin =
+                &self.tx.borrow().input.get(input_index).ok_or(Error::IndexOutOfInputsBounds {
+                    index: input_index,
+                    inputs_size: self.tx.borrow().input.len(),
+                })?;
+            let previous_output = prevouts.get(input_index)?;
             txin.previous_output.consensus_encode(writer)?;
             previous_output.value.consensus_encode(writer)?;
             previous_output.script_pubkey.consensus_encode(writer)?;
@@ -666,10 +770,10 @@ pub fn taproot_encode_signing_data_to<W: Write + ?Sized, T: Borrow<TxOut>>(
                 .borrow()
                 .output
                 .get(input_index)
-                .ok_or(TaprootError::SingleMissingOutput(SingleMissingOutputError {
-                    input_index,
-                    outputs_length: self.tx.borrow().output.len(),
-                })).map_err(SigningDataError::Sighash)?
+                .ok_or(Error::SingleWithoutCorrespondingOutput {
+                    index: input_index,
+                    outputs_size: self.tx.borrow().output.len(),
+                })?
                 .consensus_encode(&mut enc)?;
             let hash = sha256::Hash::from_engine(enc);
             hash.consensus_encode(writer)?;
@@ -696,7 +800,7 @@ pub fn taproot_signature_hash<T: Borrow<TxOut>>(
         annex: Option<Annex>,
         leaf_hash_code_separator: Option<(TapLeafHash, u32)>,
         sighash_type: TapSighashType,
-    ) -> Result<TapSighash, TaprootError> {
+    ) -> Result<TapSighash, Error> {
         let mut enc = TapSighash::engine();
         self.taproot_encode_signing_data_to(
             &mut enc,
@@ -705,7 +809,7 @@ pub fn taproot_signature_hash<T: Borrow<TxOut>>(
             annex,
             leaf_hash_code_separator,
             sighash_type,
-        ).map_err(SigningDataError::unwrap_sighash)?;
+        )?;
         Ok(TapSighash::from_engine(enc))
     }
 
@@ -715,7 +819,7 @@ pub fn taproot_key_spend_signature_hash<T: Borrow<TxOut>>(
         input_index: usize,
         prevouts: &Prevouts<T>,
         sighash_type: TapSighashType,
-    ) -> Result<TapSighash, TaprootError> {
+    ) -> Result<TapSighash, Error> {
         let mut enc = TapSighash::engine();
         self.taproot_encode_signing_data_to(
             &mut enc,
@@ -724,7 +828,7 @@ pub fn taproot_key_spend_signature_hash<T: Borrow<TxOut>>(
             None,
             None,
             sighash_type,
-        ).map_err(SigningDataError::unwrap_sighash)?;
+        )?;
         Ok(TapSighash::from_engine(enc))
     }
 
@@ -738,7 +842,7 @@ pub fn taproot_script_spend_signature_hash<S: Into<TapLeafHash>, T: Borrow<TxOut
         prevouts: &Prevouts<T>,
         leaf_hash: S,
         sighash_type: TapSighashType,
-    ) -> Result<TapSighash, TaprootError> {
+    ) -> Result<TapSighash, Error> {
         let mut enc = TapSighash::engine();
         self.taproot_encode_signing_data_to(
             &mut enc,
@@ -747,7 +851,7 @@ pub fn taproot_script_spend_signature_hash<S: Into<TapLeafHash>, T: Borrow<TxOut
             None,
             Some((leaf_hash.into(), 0xFFFFFFFF)),
             sighash_type,
-        ).map_err(SigningDataError::unwrap_sighash)?;
+        )?;
         Ok(TapSighash::from_engine(enc))
     }
 
@@ -764,7 +868,7 @@ pub fn segwit_v0_encode_signing_data_to<W: Write + ?Sized>(
         script_code: &Script,
         value: Amount,
         sighash_type: EcdsaSighashType,
-    ) -> Result<(), SigningDataError<transaction::InputsIndexError>> {
+    ) -> Result<(), Error> {
         let zero_hash = sha256d::Hash::all_zeros();
 
         let (sighash, anyone_can_pay) = sighash_type.split_anyonecanpay_flag();
@@ -787,7 +891,12 @@ pub fn segwit_v0_encode_signing_data_to<W: Write + ?Sized>(
         }
 
         {
-            let txin = &self.tx.borrow().tx_in(input_index).map_err(SigningDataError::sighash)?;
+            let txin =
+                &self.tx.borrow().input.get(input_index).ok_or(Error::IndexOutOfInputsBounds {
+                    index: input_index,
+                    inputs_size: self.tx.borrow().input.len(),
+                })?;
+
             txin.previous_output.consensus_encode(writer)?;
             script_code.consensus_encode(writer)?;
             value.consensus_encode(writer)?;
@@ -821,8 +930,8 @@ pub fn p2wpkh_signature_hash(
         script_pubkey: &Script,
         value: Amount,
         sighash_type: EcdsaSighashType,
-    ) -> Result<SegwitV0Sighash, P2wpkhError> {
-        let script_code = script_pubkey.p2wpkh_script_code().ok_or(P2wpkhError::NotP2wpkhScript)?;
+    ) -> Result<SegwitV0Sighash, Error> {
+        let script_code = script_pubkey.p2wpkh_script_code().ok_or(Error::NotP2wpkhScript)?;
 
         let mut enc = SegwitV0Sighash::engine();
         self.segwit_v0_encode_signing_data_to(
@@ -831,7 +940,7 @@ pub fn p2wpkh_signature_hash(
             &script_code,
             value,
             sighash_type,
-        ).map_err(SigningDataError::unwrap_sighash)?;
+        )?;
         Ok(SegwitV0Sighash::from_engine(enc))
     }
 
@@ -842,7 +951,7 @@ pub fn p2wsh_signature_hash(
         witness_script: &Script,
         value: Amount,
         sighash_type: EcdsaSighashType,
-    ) -> Result<SegwitV0Sighash, transaction::InputsIndexError> {
+    ) -> Result<SegwitV0Sighash, Error> {
         let mut enc = SegwitV0Sighash::engine();
         self.segwit_v0_encode_signing_data_to(
             &mut enc,
@@ -850,7 +959,7 @@ pub fn p2wsh_signature_hash(
             witness_script,
             value,
             sighash_type,
-        ).map_err(SigningDataError::unwrap_sighash)?;
+        )?;
         Ok(SegwitV0Sighash::from_engine(enc))
     }
 
@@ -882,10 +991,12 @@ pub fn legacy_encode_signing_data_to<W: Write + ?Sized, U: Into<u32>>(
         input_index: usize,
         script_pubkey: &Script,
         sighash_type: U,
-    ) -> EncodeSigningDataResult<SigningDataError<transaction::InputsIndexError>> {
-        // Validate input_index.
-        if let Err(e) = self.tx.borrow().tx_in(input_index) {
-            return EncodeSigningDataResult::WriteResult(Err(SigningDataError::Sighash(e)));
+    ) -> EncodeSigningDataResult<Error> {
+        if input_index >= self.tx.borrow().input.len() {
+            return EncodeSigningDataResult::WriteResult(Err(Error::IndexOutOfInputsBounds {
+                index: input_index,
+                inputs_size: self.tx.borrow().input.len(),
+            }));
         }
         let sighash_type: u32 = sighash_type.into();
 
@@ -977,7 +1088,7 @@ fn encode_signing_data_to_inner<W: Write + ?Sized>(
                 script_pubkey,
                 sighash_type,
             )
-            .map_err(Into::into),
+            .map_err(|e| Error::Io(e.kind())),
         )
     }
 
@@ -1005,15 +1116,15 @@ pub fn legacy_signature_hash(
         input_index: usize,
         script_pubkey: &Script,
         sighash_type: u32,
-    ) -> Result<LegacySighash, transaction::InputsIndexError> {
-        let mut engine = LegacySighash::engine();
-        match self
-            .legacy_encode_signing_data_to(&mut engine, input_index, script_pubkey, sighash_type)
-            .is_sighash_single_bug()
+    ) -> Result<LegacySighash, Error> {
+        let mut enc = LegacySighash::engine();
+        if self
+            .legacy_encode_signing_data_to(&mut enc, input_index, script_pubkey, sighash_type)
+            .is_sighash_single_bug()?
         {
-            Ok(true) => Ok(LegacySighash::from_byte_array(UINT256_ONE)),
-            Ok(false) => Ok(LegacySighash::from_engine(engine)),
-            Err(e) => Err(e.unwrap_sighash()),
+            Ok(LegacySighash::from_byte_array(UINT256_ONE))
+        } else {
+            Ok(LegacySighash::from_engine(enc))
         }
     }
 
@@ -1116,13 +1227,11 @@ pub fn witness_mut(&mut self, input_index: usize) -> Option<&mut Witness> {
 
 impl<'a> Annex<'a> {
     /// Creates a new `Annex` struct checking the first byte is `0x50`.
-    pub fn new(annex_bytes: &'a [u8]) -> Result<Self, AnnexError> {
-        use AnnexError::*;
-
-        match annex_bytes.first() {
-            Some(&TAPROOT_ANNEX_PREFIX) => Ok(Annex(annex_bytes)),
-            Some(other) => Err(IncorrectPrefix(*other)),
-            None => Err(Empty),
+    pub fn new(annex_bytes: &'a [u8]) -> Result<Self, Error> {
+        if annex_bytes.first() == Some(&TAPROOT_ANNEX_PREFIX) {
+            Ok(Annex(annex_bytes))
+        } else {
+            Err(Error::WrongAnnex)
         }
     }
 
@@ -1136,172 +1245,9 @@ fn consensus_encode<W: Write + ?Sized>(&self, w: &mut W) -> Result<usize, io::Er
     }
 }
 
-/// Error computing a taproot sighash.
-#[derive(Debug, Clone, PartialEq, Eq)]
-#[non_exhaustive]
-pub enum TaprootError {
-    /// Index out of bounds when accessing transaction input vector.
-    InputsIndex(transaction::InputsIndexError),
-    /// Using `SIGHASH_SINGLE` requires an output at the same index is the input.
-    SingleMissingOutput(SingleMissingOutputError),
-    /// Prevouts size error.
-    PrevoutsSize(PrevoutsSizeError),
-    /// Prevouts index error.
-    PrevoutsIndex(PrevoutsIndexError),
-    /// Prevouts kind error.
-    PrevoutsKind(PrevoutsKindError),
-    /// Invalid Sighash type.
-    InvalidSighashType(u32),
-}
-
-impl fmt::Display for TaprootError {
-    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
-        use TaprootError::*;
-
-        match *self {
-            InputsIndex(ref e) => write_err!(f, "inputs index"; e),
-            SingleMissingOutput(ref e) => write_err!(f, "sighash single"; e),
-            PrevoutsSize(ref e) => write_err!(f, "prevouts size"; e),
-            PrevoutsIndex(ref e) => write_err!(f, "prevouts index"; e),
-            PrevoutsKind(ref e) => write_err!(f, "prevouts kind"; e),
-            InvalidSighashType(hash_ty) => write!(f, "invalid taproot sighash type : {} ", hash_ty),
-        }
-    }
-}
-
-#[cfg(feature = "std")]
-impl std::error::Error for TaprootError {
-    fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
-        use TaprootError::*;
-
-        match *self {
-            InputsIndex(ref e) => Some(e),
-            SingleMissingOutput(ref e) => Some(e),
-            PrevoutsSize(ref e) => Some(e),
-            PrevoutsIndex(ref e) => Some(e),
-            PrevoutsKind(ref e) => Some(e),
-            InvalidSighashType(_) => None,
-        }
-    }
-}
-
-impl From<transaction::InputsIndexError> for TaprootError {
-    fn from(e: transaction::InputsIndexError) -> Self { Self::InputsIndex(e) }
-}
-
-impl From<PrevoutsSizeError> for TaprootError {
-    fn from(e: PrevoutsSizeError) -> Self { Self::PrevoutsSize(e) }
-}
-
-impl From<PrevoutsKindError> for TaprootError {
-    fn from(e: PrevoutsKindError) -> Self { Self::PrevoutsKind(e) }
-}
-
-impl From<PrevoutsIndexError> for TaprootError {
-    fn from(e: PrevoutsIndexError) -> Self { Self::PrevoutsIndex(e) }
-}
-
-/// Error computing a P2WPKH sighash.
-#[derive(Debug, Clone, PartialEq, Eq)]
-#[non_exhaustive]
-pub enum P2wpkhError {
-    /// Error computing the sighash.
-    Sighash(transaction::InputsIndexError),
-    /// Script is not a witness program for a p2wpkh output.
-    NotP2wpkhScript,
-}
-
-impl From<transaction::InputsIndexError> for P2wpkhError {
-    fn from(value: transaction::InputsIndexError) -> Self {
-        P2wpkhError::Sighash(value)
-    }
-}
-
-impl fmt::Display for P2wpkhError {
-    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
-        use P2wpkhError::*;
-
-        match *self {
-            Sighash(ref e) => write_err!(f, "error encoding segwit v0 signing data"; e),
-            NotP2wpkhScript => write!(f, "script is not a script pubkey for a p2wpkh output"),
-        }
-    }
-}
-
-#[cfg(feature = "std")]
-impl std::error::Error for P2wpkhError {
-    fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
-        use P2wpkhError::*;
-
-        match *self {
-            Sighash(ref e) => Some(e),
-            NotP2wpkhScript => None,
-        }
-    }
-}
-
-/// Using `SIGHASH_SINGLE` requires an output at the same index as the input.
-#[derive(Debug, Clone, PartialEq, Eq)]
-#[non_exhaustive]
-pub struct SingleMissingOutputError {
-    /// Input index.
-    pub input_index: usize,
-    /// Length of the output vector.
-    pub outputs_length: usize,
-}
-
-impl fmt::Display for SingleMissingOutputError {
-    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
-        write!(
-            f,
-            "sighash single requires an output at the same index as the input \
-             (input index: {}, outputs length: {})",
-            self.input_index, self.outputs_length
-        )
-    }
-}
-
-#[cfg(feature = "std")]
-impl std::error::Error for SingleMissingOutputError {
-    fn source(&self) -> Option<&(dyn std::error::Error + 'static)> { None }
-}
-
-/// Annex must be at least one byte long and the first bytes must be `0x50`.
-#[derive(Debug, Clone, PartialEq, Eq)]
-#[non_exhaustive]
-pub enum AnnexError {
-    /// The annex is empty.
-    Empty,
-    /// Incorrect prefix byte in the annex.
-    IncorrectPrefix(u8),
-}
-
-impl fmt::Display for AnnexError {
-    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
-        use AnnexError::*;
-
-        match *self {
-            Empty => write!(f, "the annex is empty"),
-            IncorrectPrefix(byte) =>
-                write!(f, "incorrect prefix byte in the annex {:02x}, expecting 0x50", byte),
-        }
-    }
-}
-
-#[cfg(feature = "std")]
-impl std::error::Error for AnnexError {
-    fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
-        use AnnexError::*;
-
-        match *self {
-            Empty | IncorrectPrefix(_) => None,
-        }
-    }
-}
-
-fn is_invalid_use_of_sighash_single(sighash: u32, input_index: usize, outputs_len: usize) -> bool {
+fn is_invalid_use_of_sighash_single(sighash: u32, input_index: usize, output_len: usize) -> bool {
     let ty = EcdsaSighashType::from_consensus(sighash);
-    ty == EcdsaSighashType::Single && input_index >= outputs_len
+    ty == EcdsaSighashType::Single && input_index >= output_len
 }
 
 /// Result of [`SighashCache::legacy_encode_signing_data_to`].
@@ -1372,59 +1318,6 @@ pub fn map_err<E2, F>(self, f: F) -> EncodeSigningDataResult<E2>
     }
 }
 
-/// Error returned when writing signing data fails.
-#[derive(Debug)]
-pub enum SigningDataError<E> {
-    /// Can happen only when using `*_encode_signing_*` methods with custom writers, engines
-    /// like those used in `*_signature_hash` methods do not error.
-    Io(io::Error),
-    /// An argument to the called sighash function was invalid.
-    Sighash(E),
-}
-
-impl<E> SigningDataError<E> {
-    /// Returns the sighash variant, panicking if it's IO.
-    ///
-    /// This is used when encoding to hash engine when we know that IO doesn't fail.
-    fn unwrap_sighash(self) -> E {
-        match self {
-            Self::Sighash(error) => error,
-            Self::Io(error) => panic!("hash engine error {}", error),
-        }
-    }
-
-    fn sighash<E2: Into<E>>(error: E2) -> Self {
-        Self::Sighash(error.into())
-    }
-}
-
-// We cannot simultaneously impl `From<E>`. it was determined that this alternative requires less
-// manual `map_err` calls.
-impl<E> From<io::Error> for SigningDataError<E> {
-    fn from(value: io::Error) -> Self {
-        Self::Io(value)
-    }
-}
-
-impl<E: fmt::Display> fmt::Display for SigningDataError<E> {
-    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
-        match self {
-            Self::Io(error) => write_err!(f, "failed to write sighash data"; error),
-            Self::Sighash(error) => write_err!(f, "failed to compute sighash data"; error),
-        }
-    }
-}
-
-#[cfg(feature = "std")]
-impl<E: std::error::Error + 'static> std::error::Error for SigningDataError<E> {
-    fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
-        match self {
-            SigningDataError::Io(error) => Some(error),
-            SigningDataError::Sighash(error) => Some(error),
-        }
-    }
-}
-
 #[cfg(test)]
 mod tests {
     use std::str::FromStr;
@@ -1633,8 +1526,6 @@ fn test_sighashes_with_annex_and_script() {
     #[test]
     #[rustfmt::skip] // Allow long function call `taproot_signature_hash`.
     fn test_sighash_errors() {
-        use crate::transaction::{IndexOutOfBoundsError, InputsIndexError};
-
         let dumb_tx = Transaction {
             version: transaction::Version::TWO,
             lock_time: absolute::LockTime::ZERO,
@@ -1648,53 +1539,53 @@ fn test_sighash_errors() {
         let empty_prevouts : Prevouts<TxOut> = Prevouts::All(&empty_vec);
         assert_eq!(
             c.taproot_signature_hash(0, &empty_prevouts, None, None, TapSighashType::All),
-            Err(TaprootError::PrevoutsSize(PrevoutsSizeError))
+            Err(Error::PrevoutsSize(PrevoutsSizeError))
         );
         let two = vec![TxOut::NULL, TxOut::NULL];
         let too_many_prevouts = Prevouts::All(&two);
         assert_eq!(
             c.taproot_signature_hash(0, &too_many_prevouts, None, None, TapSighashType::All),
-            Err(TaprootError::PrevoutsSize(PrevoutsSizeError))
+            Err(Error::PrevoutsSize(PrevoutsSizeError))
         );
         let tx_out = TxOut::NULL;
         let prevout = Prevouts::One(1, &tx_out);
         assert_eq!(
             c.taproot_signature_hash(0, &prevout, None, None, TapSighashType::All),
-            Err(TaprootError::PrevoutsKind(PrevoutsKindError))
+            Err(Error::PrevoutsKind(PrevoutsKindError))
         );
         assert_eq!(
             c.taproot_signature_hash(0, &prevout, None, None, TapSighashType::AllPlusAnyoneCanPay),
-            Err(TaprootError::PrevoutsIndex(PrevoutsIndexError::InvalidOneIndex))
+            Err(Error::PrevoutsIndex(PrevoutsIndexError::InvalidOneIndex))
         );
         assert_eq!(
             c.taproot_signature_hash(10, &prevout, None, None, TapSighashType::AllPlusAnyoneCanPay),
-            Err(InputsIndexError(IndexOutOfBoundsError {
+            Err(Error::IndexOutOfInputsBounds {
                 index: 10,
-                length: 1
-            }).into())
+                inputs_size: 1
+            })
         );
         let prevout = Prevouts::One(0, &tx_out);
         assert_eq!(
             c.taproot_signature_hash(0, &prevout, None, None, TapSighashType::SinglePlusAnyoneCanPay),
-            Err(TaprootError::SingleMissingOutput(SingleMissingOutputError {
-                input_index: 0,
-                outputs_length: 0
-            }))
+            Err(Error::SingleWithoutCorrespondingOutput {
+                index: 0,
+                outputs_size: 0
+            })
         );
         assert_eq!(
             c.legacy_signature_hash(10, Script::new(), 0u32),
-            Err(InputsIndexError(IndexOutOfBoundsError {
+            Err(Error::IndexOutOfInputsBounds {
                 index: 10,
-                length: 1
-            }))
+                inputs_size: 1
+            })
         );
     }
 
     #[test]
     fn test_annex_errors() {
-        assert_eq!(Annex::new(&[]), Err(AnnexError::Empty));
-        assert_eq!(Annex::new(&[0x51]), Err(AnnexError::IncorrectPrefix(0x51)));
-        assert_eq!(Annex::new(&[0x51, 0x50]), Err(AnnexError::IncorrectPrefix(0x51)));
+        assert_eq!(Annex::new(&[]), Err(Error::WrongAnnex));
+        assert_eq!(Annex::new(&[0x51]), Err(Error::WrongAnnex));
+        assert_eq!(Annex::new(&[0x51, 0x50]), Err(Error::WrongAnnex));
     }
 
     #[allow(clippy::too_many_arguments)]
diff --git a/bitcoin/src/crypto/taproot.rs b/bitcoin/src/crypto/taproot.rs
index b64a8e4d..ca771c8c 100644
--- a/bitcoin/src/crypto/taproot.rs
+++ b/bitcoin/src/crypto/taproot.rs
@@ -8,7 +8,6 @@
 use core::fmt;
 
 use internals::write_err;
-use io::Write;
 
 use crate::prelude::*;
 use crate::sighash::{InvalidSighashTypeError, TapSighashType};
@@ -19,10 +18,10 @@
 #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
 #[cfg_attr(feature = "serde", serde(crate = "actual_serde"))]
 pub struct Signature {
-    /// The underlying schnorr signature.
-    pub signature: secp256k1::schnorr::Signature,
-    /// The corresponding hash type.
-    pub sighash_type: TapSighashType,
+    /// The underlying schnorr signature
+    pub sig: secp256k1::schnorr::Signature,
+    /// The corresponding hash type
+    pub hash_ty: TapSighashType,
 }
 
 impl Signature {
@@ -31,14 +30,14 @@ pub fn from_slice(sl: &[u8]) -> Result<Self, SigFromSliceError> {
         match sl.len() {
             64 => {
                 // default type
-                let signature = secp256k1::schnorr::Signature::from_slice(sl)?;
-                Ok(Signature { signature, sighash_type: TapSighashType::Default })
+                let sig = secp256k1::schnorr::Signature::from_slice(sl)?;
+                Ok(Signature { sig, hash_ty: TapSighashType::Default })
             }
             65 => {
-                let (sighash_type, signature) = sl.split_last().expect("Slice len checked == 65");
-                let sighash_type = TapSighashType::from_consensus_u8(*sighash_type)?;
-                let signature = secp256k1::schnorr::Signature::from_slice(signature)?;
-                Ok(Signature { signature, sighash_type })
+                let (hash_ty, sig) = sl.split_last().expect("Slice len checked == 65");
+                let hash_ty = TapSighashType::from_consensus_u8(*hash_ty)?;
+                let sig = secp256k1::schnorr::Signature::from_slice(sig)?;
+                Ok(Signature { sig, hash_ty })
             }
             len => Err(SigFromSliceError::InvalidSignatureSize(len)),
         }
@@ -48,35 +47,29 @@ pub fn from_slice(sl: &[u8]) -> Result<Self, SigFromSliceError> {
     ///
     /// Note: this allocates on the heap, prefer [`serialize`](Self::serialize) if vec is not needed.
     pub fn to_vec(self) -> Vec<u8> {
-        let mut ser_sig = self.signature.as_ref().to_vec();
-        if self.sighash_type == TapSighashType::Default {
+        // TODO: add support to serialize to a writer to SerializedSig
+        let mut ser_sig = self.sig.as_ref().to_vec();
+        if self.hash_ty == TapSighashType::Default {
             // default sighash type, don't add extra sighash byte
         } else {
-            ser_sig.push(self.sighash_type as u8);
+            ser_sig.push(self.hash_ty as u8);
         }
         ser_sig
     }
 
-    /// Serializes the signature to `writer`.
-    #[inline]
-    pub fn serialize_to_writer<W: Write + ?Sized>(&self, writer: &mut W) -> Result<(), io::Error> {
-        let sig = self.serialize();
-        sig.write_to(writer)
-    }
-
     /// Serializes the signature (without heap allocation)
     ///
     /// This returns a type with an API very similar to that of `Box<[u8]>`.
     /// You can get a slice from it using deref coercions or turn it into an iterator.
     pub fn serialize(self) -> SerializedSignature {
         let mut buf = [0; serialized_signature::MAX_LEN];
-        let ser_sig = self.signature.serialize();
+        let ser_sig = self.sig.serialize();
         buf[..64].copy_from_slice(&ser_sig);
-        let len = if self.sighash_type == TapSighashType::Default {
+        let len = if self.hash_ty == TapSighashType::Default {
             // default sighash type, don't add extra sighash byte
             64
         } else {
-            buf[64] = self.sighash_type as u8;
+            buf[64] = self.hash_ty as u8;
             65
         };
         SerializedSignature::from_raw_parts(buf, len)
diff --git a/bitcoin/src/internal_macros.rs b/bitcoin/src/internal_macros.rs
index 875a2a6f..669c3ff6 100644
--- a/bitcoin/src/internal_macros.rs
+++ b/bitcoin/src/internal_macros.rs
@@ -12,7 +12,7 @@ impl $crate::consensus::Encodable for $thing {
             fn consensus_encode<R: $crate::io::Write + ?Sized>(
                 &self,
                 r: &mut R,
-            ) -> core::result::Result<usize, $crate::io::Error> {
+            ) -> Result<usize, $crate::io::Error> {
                 let mut len = 0;
                 $(len += self.$field.consensus_encode(r)?;)+
                 Ok(len)
@@ -22,18 +22,18 @@ fn consensus_encode<R: $crate::io::Write + ?Sized>(
         impl $crate::consensus::Decodable for $thing {
 
             #[inline]
-            fn consensus_decode_from_finite_reader<R: $crate::io::BufRead + ?Sized>(
+            fn consensus_decode_from_finite_reader<R: $crate::io::Read + ?Sized>(
                 r: &mut R,
-            ) -> core::result::Result<$thing, $crate::consensus::encode::Error> {
+            ) -> Result<$thing, $crate::consensus::encode::Error> {
                 Ok($thing {
                     $($field: $crate::consensus::Decodable::consensus_decode_from_finite_reader(r)?),+
                 })
             }
 
             #[inline]
-            fn consensus_decode<R: $crate::io::BufRead + ?Sized>(
+            fn consensus_decode<R: $crate::io::Read + ?Sized>(
                 r: &mut R,
-            ) -> core::result::Result<$thing, $crate::consensus::encode::Error> {
+            ) -> Result<$thing, $crate::consensus::encode::Error> {
                 let mut r = r.take($crate::consensus::encode::MAX_VEC_SIZE as u64);
                 Ok($thing {
                     $($field: $crate::consensus::Decodable::consensus_decode(&mut r)?),+
@@ -99,9 +99,9 @@ fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
         impl $crate::hex::FromHex for $t {
             type Err = $crate::hex::HexToArrayError;
 
-            fn from_byte_iter<I>(iter: I) -> core::result::Result<Self, $crate::hex::HexToArrayError>
+            fn from_byte_iter<I>(iter: I) -> Result<Self, $crate::hex::HexToArrayError>
             where
-                I: core::iter::Iterator<Item = core::result::Result<u8, $crate::hex::HexToBytesError>>
+                I: core::iter::Iterator<Item = Result<u8, $crate::hex::HexToBytesError>>
                     + core::iter::ExactSizeIterator
                     + core::iter::DoubleEndedIterator,
             {
@@ -111,12 +111,12 @@ fn from_byte_iter<I>(iter: I) -> core::result::Result<Self, $crate::hex::HexToAr
 
         impl core::str::FromStr for $t {
             type Err = $crate::hex::HexToArrayError;
-            fn from_str(s: &str) -> core::result::Result<Self, Self::Err> { $crate::hex::FromHex::from_hex(s) }
+            fn from_str(s: &str) -> Result<Self, Self::Err> { $crate::hex::FromHex::from_hex(s) }
         }
 
         #[cfg(feature = "serde")]
         impl $crate::serde::Serialize for $t {
-            fn serialize<S: $crate::serde::Serializer>(&self, s: S) -> core::result::Result<S::Ok, S::Error> {
+            fn serialize<S: $crate::serde::Serializer>(&self, s: S) -> Result<S::Ok, S::Error> {
                 if s.is_human_readable() {
                     s.collect_str(self)
                 } else {
@@ -127,7 +127,7 @@ fn serialize<S: $crate::serde::Serializer>(&self, s: S) -> core::result::Result<
 
         #[cfg(feature = "serde")]
         impl<'de> $crate::serde::Deserialize<'de> for $t {
-            fn deserialize<D: $crate::serde::Deserializer<'de>>(d: D) -> core::result::Result<$t, D::Error> {
+            fn deserialize<D: $crate::serde::Deserializer<'de>>(d: D) -> Result<$t, D::Error> {
                 if d.is_human_readable() {
                     struct HexVisitor;
 
@@ -138,7 +138,7 @@ fn expecting(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
                             f.write_str("an ASCII hex string")
                         }
 
-                        fn visit_bytes<E>(self, v: &[u8]) -> core::result::Result<Self::Value, E>
+                        fn visit_bytes<E>(self, v: &[u8]) -> Result<Self::Value, E>
                         where
                             E: $crate::serde::de::Error,
                         {
@@ -151,7 +151,7 @@ fn visit_bytes<E>(self, v: &[u8]) -> core::result::Result<Self::Value, E>
                             }
                         }
 
-                        fn visit_str<E>(self, v: &str) -> core::result::Result<Self::Value, E>
+                        fn visit_str<E>(self, v: &str) -> Result<Self::Value, E>
                         where
                             E: $crate::serde::de::Error,
                         {
@@ -170,7 +170,7 @@ fn expecting(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
                             f.write_str("a bytestring")
                         }
 
-                        fn visit_bytes<E>(self, v: &[u8]) -> core::result::Result<Self::Value, E>
+                        fn visit_bytes<E>(self, v: &[u8]) -> Result<Self::Value, E>
                         where
                             E: $crate::serde::de::Error,
                         {
@@ -196,13 +196,13 @@ fn visit_bytes<E>(self, v: &[u8]) -> core::result::Result<Self::Value, E>
 macro_rules! impl_hashencode {
     ($hashtype:ident) => {
         impl $crate::consensus::Encodable for $hashtype {
-            fn consensus_encode<W: $crate::io::Write + ?Sized>(&self, w: &mut W) -> core::result::Result<usize, $crate::io::Error> {
+            fn consensus_encode<W: $crate::io::Write + ?Sized>(&self, w: &mut W) -> Result<usize, $crate::io::Error> {
                 self.0.consensus_encode(w)
             }
         }
 
         impl $crate::consensus::Decodable for $hashtype {
-            fn consensus_decode<R: $crate::io::BufRead + ?Sized>(r: &mut R) -> core::result::Result<Self, $crate::consensus::encode::Error> {
+            fn consensus_decode<R: $crate::io::Read + ?Sized>(r: &mut R) -> Result<Self, $crate::consensus::encode::Error> {
                 use $crate::hashes::Hash;
                 Ok(Self::from_byte_array(<<$hashtype as $crate::hashes::Hash>::Bytes>::consensus_decode(r)?))
             }
diff --git a/bitcoin/src/lib.rs b/bitcoin/src/lib.rs
index 6ea821b8..f09ff75d 100644
--- a/bitcoin/src/lib.rs
+++ b/bitcoin/src/lib.rs
@@ -59,6 +59,9 @@
 /// Encodes and decodes base64 as bytes or utf8.
 pub extern crate base64;
 
+/// Encodes and decodes the Bech32 forrmat.
+pub extern crate bech32;
+
 /// Rust implementation of cryptographic hash function algorithms.
 pub extern crate hashes;
 
@@ -68,10 +71,6 @@
 /// Re-export the `bitcoin-io` crate.
 pub extern crate io;
 
-/// Re-export the `ordered` crate.
-#[cfg(feature = "ordered")]
-pub extern crate ordered;
-
 /// Rust wrapper library for Pieter Wuille's libsecp256k1.  Implements ECDSA and BIP 340 signatures
 /// for the SECG elliptic curve group secp256k1 and related utilities.
 pub extern crate secp256k1;
@@ -113,7 +112,7 @@
 #[rustfmt::skip]                // Keep public re-exports separate.
 #[doc(inline)]
 pub use crate::{
-    address::{Address, AddressType, KnownHrp},
+    address::{Address, AddressType},
     amount::{Amount, Denomination, SignedAmount},
     bip158::{FilterHash, FilterHeader},
     bip32::XKeyIdentifier,
@@ -169,7 +168,7 @@ pub mod amount {
     //! We refer to the documentation on the types for more information.
 
     use crate::consensus::{encode, Decodable, Encodable};
-    use crate::io::{BufRead, Write};
+    use crate::io;
 
     #[rustfmt::skip]            // Keep public re-exports separate.
     #[doc(inline)]
@@ -181,14 +180,14 @@ pub mod amount {
 
     impl Decodable for Amount {
         #[inline]
-        fn consensus_decode<R: BufRead + ?Sized>(r: &mut R) -> Result<Self, encode::Error> {
+        fn consensus_decode<R: io::Read + ?Sized>(r: &mut R) -> Result<Self, encode::Error> {
             Ok(Amount::from_sat(Decodable::consensus_decode(r)?))
         }
     }
 
     impl Encodable for Amount {
         #[inline]
-        fn consensus_encode<W: Write + ?Sized>(&self, w: &mut W) -> Result<usize, io::Error> {
+        fn consensus_encode<W: io::Write + ?Sized>(&self, w: &mut W) -> Result<usize, io::Error> {
             self.to_sat().consensus_encode(w)
         }
     }
diff --git a/bitcoin/src/merkle_tree/block.rs b/bitcoin/src/merkle_tree/block.rs
index 827d06d5..3194454a 100644
--- a/bitcoin/src/merkle_tree/block.rs
+++ b/bitcoin/src/merkle_tree/block.rs
@@ -41,7 +41,7 @@
 use core::fmt;
 
 use hashes::Hash;
-use io::{BufRead, Write};
+use io::{Read, Write};
 
 use self::MerkleBlockError::*;
 use crate::blockdata::block::{self, Block, TxMerkleNode};
@@ -103,7 +103,7 @@ pub fn from_block_with_predicate<F>(block: &Block, match_txids: F) -> Self
     where
         F: Fn(&Txid) -> bool,
     {
-        let block_txids: Vec<_> = block.txdata.iter().map(Transaction::compute_txid).collect();
+        let block_txids: Vec<_> = block.txdata.iter().map(Transaction::txid).collect();
         Self::from_header_txids_with_predicate(&block.header, &block_txids, match_txids)
     }
 
@@ -151,7 +151,7 @@ fn consensus_encode<W: Write + ?Sized>(&self, w: &mut W) -> Result<usize, io::Er
 }
 
 impl Decodable for MerkleBlock {
-    fn consensus_decode<R: BufRead + ?Sized>(r: &mut R) -> Result<Self, encode::Error> {
+    fn consensus_decode<R: Read + ?Sized>(r: &mut R) -> Result<Self, encode::Error> {
         Ok(MerkleBlock {
             header: Decodable::consensus_decode(r)?,
             txn: Decodable::consensus_decode(r)?,
@@ -452,7 +452,7 @@ fn consensus_encode<W: Write + ?Sized>(&self, w: &mut W) -> Result<usize, io::Er
 }
 
 impl Decodable for PartialMerkleTree {
-    fn consensus_decode_from_finite_reader<R: BufRead + ?Sized>(
+    fn consensus_decode_from_finite_reader<R: Read + ?Sized>(
         r: &mut R,
     ) -> Result<Self, encode::Error> {
         let num_transactions: u32 = Decodable::consensus_decode(r)?;
diff --git a/bitcoin/src/merkle_tree/mod.rs b/bitcoin/src/merkle_tree/mod.rs
index c3929d42..0e79117a 100644
--- a/bitcoin/src/merkle_tree/mod.rs
+++ b/bitcoin/src/merkle_tree/mod.rs
@@ -125,7 +125,7 @@ fn both_merkle_root_functions_return_the_same_result() {
         let block: Block = deserialize(&segwit_block[..]).expect("Failed to deserialize block");
         assert!(block.check_merkle_root()); // Sanity check.
 
-        let hashes_iter = block.txdata.iter().map(|obj| obj.compute_txid().to_raw_hash());
+        let hashes_iter = block.txdata.iter().map(|obj| obj.txid().to_raw_hash());
 
         let mut hashes_array: [sha256d::Hash; 15] = [Hash::all_zeros(); 15];
         for (i, hash) in hashes_iter.clone().enumerate() {
diff --git a/bitcoin/src/p2p/address.rs b/bitcoin/src/p2p/address.rs
index e1a69d61..014cadd4 100644
--- a/bitcoin/src/p2p/address.rs
+++ b/bitcoin/src/p2p/address.rs
@@ -9,7 +9,7 @@
 use core::{fmt, iter};
 use std::net::{Ipv4Addr, Ipv6Addr, SocketAddr, SocketAddrV4, SocketAddrV6, ToSocketAddrs};
 
-use io::{BufRead, Read, Write};
+use io::{Read, Write};
 
 use crate::consensus::encode::{self, Decodable, Encodable, ReadExt, VarInt, WriteExt};
 use crate::p2p::ServiceFlags;
@@ -75,7 +75,7 @@ fn consensus_encode<W: Write + ?Sized>(&self, w: &mut W) -> Result<usize, io::Er
 
 impl Decodable for Address {
     #[inline]
-    fn consensus_decode<R: BufRead + ?Sized>(r: &mut R) -> Result<Self, encode::Error> {
+    fn consensus_decode<R: Read + ?Sized>(r: &mut R) -> Result<Self, encode::Error> {
         Ok(Address {
             services: Decodable::consensus_decode(r)?,
             address: read_be_address(r)?,
@@ -167,7 +167,7 @@ fn encode_addr<W: Write + ?Sized>(
 }
 
 impl Decodable for AddrV2 {
-    fn consensus_decode<R: BufRead + ?Sized>(r: &mut R) -> Result<Self, encode::Error> {
+    fn consensus_decode<R: Read + ?Sized>(r: &mut R) -> Result<Self, encode::Error> {
         let network_id = u8::consensus_decode(r)?;
         let len = VarInt::consensus_decode(r)?.0;
         if len > 512 {
@@ -285,7 +285,7 @@ fn consensus_encode<W: Write + ?Sized>(&self, w: &mut W) -> Result<usize, io::Er
 }
 
 impl Decodable for AddrV2Message {
-    fn consensus_decode<R: BufRead + ?Sized>(r: &mut R) -> Result<Self, encode::Error> {
+    fn consensus_decode<R: Read + ?Sized>(r: &mut R) -> Result<Self, encode::Error> {
         Ok(AddrV2Message {
             time: Decodable::consensus_decode(r)?,
             services: ServiceFlags::from(VarInt::consensus_decode(r)?.0),
diff --git a/bitcoin/src/p2p/message.rs b/bitcoin/src/p2p/message.rs
index d09112c2..2c8dc699 100644
--- a/bitcoin/src/p2p/message.rs
+++ b/bitcoin/src/p2p/message.rs
@@ -9,7 +9,7 @@
 use core::{fmt, iter};
 
 use hashes::{sha256d, Hash};
-use io::{BufRead, Write};
+use io::{Read, Write};
 
 use crate::blockdata::{block, transaction};
 use crate::consensus::encode::{self, CheckedData, Decodable, Encodable, VarInt};
@@ -110,7 +110,7 @@ fn consensus_encode<W: Write + ?Sized>(&self, w: &mut W) -> Result<usize, io::Er
 
 impl Decodable for CommandString {
     #[inline]
-    fn consensus_decode<R: BufRead + ?Sized>(r: &mut R) -> Result<Self, encode::Error> {
+    fn consensus_decode<R: Read + ?Sized>(r: &mut R) -> Result<Self, encode::Error> {
         let rawbytes: [u8; 12] = Decodable::consensus_decode(r)?;
         let rv = iter::FromIterator::from_iter(rawbytes.iter().filter_map(|&u| {
             if u > 0 {
@@ -189,6 +189,9 @@ pub enum NetworkMessage {
     SendHeaders,
     /// `getaddr`
     GetAddr,
+    // TODO: checkorder,
+    // TODO: submitorder,
+    // TODO: reply,
     /// `ping`
     Ping(u64),
     /// `pong`
@@ -404,7 +407,7 @@ fn consensus_encode<W: Write + ?Sized>(&self, w: &mut W) -> Result<usize, io::Er
 
 impl Decodable for HeaderDeserializationWrapper {
     #[inline]
-    fn consensus_decode_from_finite_reader<R: BufRead + ?Sized>(
+    fn consensus_decode_from_finite_reader<R: Read + ?Sized>(
         r: &mut R,
     ) -> Result<Self, encode::Error> {
         let len = VarInt::consensus_decode(r)?.0;
@@ -423,13 +426,13 @@ fn consensus_decode_from_finite_reader<R: BufRead + ?Sized>(
     }
 
     #[inline]
-    fn consensus_decode<R: BufRead + ?Sized>(r: &mut R) -> Result<Self, encode::Error> {
+    fn consensus_decode<R: Read + ?Sized>(r: &mut R) -> Result<Self, encode::Error> {
         Self::consensus_decode_from_finite_reader(&mut r.take(MAX_MSG_SIZE as u64))
     }
 }
 
 impl Decodable for RawNetworkMessage {
-    fn consensus_decode_from_finite_reader<R: BufRead + ?Sized>(
+    fn consensus_decode_from_finite_reader<R: Read + ?Sized>(
         r: &mut R,
     ) -> Result<Self, encode::Error> {
         let magic = Decodable::consensus_decode_from_finite_reader(r)?;
@@ -439,7 +442,7 @@ fn consensus_decode_from_finite_reader<R: BufRead + ?Sized>(
         let raw_payload = checked_data.into_data();
         let payload_len = raw_payload.len() as u32;
 
-        let mut mem_d = raw_payload.as_slice();
+        let mut mem_d = io::Cursor::new(raw_payload);
         let payload = match &cmd.0[..] {
             "version" =>
                 NetworkMessage::Version(Decodable::consensus_decode_from_finite_reader(&mut mem_d)?),
@@ -522,13 +525,13 @@ fn consensus_decode_from_finite_reader<R: BufRead + ?Sized>(
             "addrv2" =>
                 NetworkMessage::AddrV2(Decodable::consensus_decode_from_finite_reader(&mut mem_d)?),
             "sendaddrv2" => NetworkMessage::SendAddrV2,
-            _ => NetworkMessage::Unknown { command: cmd, payload: raw_payload },
+            _ => NetworkMessage::Unknown { command: cmd, payload: mem_d.into_inner() },
         };
         Ok(RawNetworkMessage { magic, payload, payload_len, checksum })
     }
 
     #[inline]
-    fn consensus_decode<R: BufRead + ?Sized>(r: &mut R) -> Result<Self, encode::Error> {
+    fn consensus_decode<R: Read + ?Sized>(r: &mut R) -> Result<Self, encode::Error> {
         Self::consensus_decode_from_finite_reader(&mut r.take(MAX_MSG_SIZE as u64))
     }
 }
@@ -548,6 +551,7 @@ mod test {
     use crate::blockdata::script::ScriptBuf;
     use crate::blockdata::transaction::Transaction;
     use crate::consensus::encode::{deserialize, deserialize_partial, serialize};
+    use crate::network::Network;
     use crate::p2p::address::{AddrV2, AddrV2Message, Address};
     use crate::p2p::message_blockdata::{GetBlocksMessage, GetHeadersMessage, Inventory};
     use crate::p2p::message_bloom::{BloomFlags, FilterAdd, FilterLoad};
@@ -561,6 +565,7 @@ mod test {
 
     #[test]
     fn full_round_ser_der_raw_network_message_test() {
+        // TODO: Impl Rand traits here to easily generate random values.
         let version_msg: VersionMessage = deserialize(&hex!("721101000100000000000000e6e0845300000000010000000000000000000000000000000000ffff0000000000000100000000000000fd87d87eeb4364f22cf54dca59412db7208d47d920cffce83ee8102f5361746f7368693a302e392e39392f2c9f040001")).unwrap();
         let tx: Transaction = deserialize(&hex!("0100000001a15d57094aa7a21a28cb20b59aab8fc7d1149a3bdbcddba9c622e4f5f6a99ece010000006c493046022100f93bb0e7d8db7bd46e40132d1f8242026e045f03a0efe71bbb8e3f475e970d790221009337cd7f1f929f00cc6ff01f03729b069a7c21b59b1736ddfee5db5946c5da8c0121033b9b137ee87d5a812d6f506efdd37f0affa7ffc310711c06c7f3e097c9447c52ffffffff0100e1f505000000001976a9140389035a9225b3839e2bbf32d826a1e222031fd888ac00000000")).unwrap();
         let block: Block = deserialize(&include_bytes!("../../tests/data/testnet_block_000000000000045e0b1660b6445b5e5c5ab63c9a4f956be7e1e69be04fa4497b.raw")[..]).unwrap();
@@ -700,7 +705,7 @@ fn commandstring_test() {
     #[test]
     #[rustfmt::skip]
     fn serialize_verack_test() {
-        assert_eq!(serialize(&RawNetworkMessage::new(Magic::BITCOIN, NetworkMessage::Verack)),
+        assert_eq!(serialize(&RawNetworkMessage::new(Magic::from(Network::Bitcoin), NetworkMessage::Verack)),
                    vec![0xf9, 0xbe, 0xb4, 0xd9, 0x76, 0x65, 0x72, 0x61,
                         0x63, 0x6B, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
                         0x00, 0x00, 0x00, 0x00, 0x5d, 0xf6, 0xe0, 0xe2]);
@@ -709,7 +714,7 @@ fn serialize_verack_test() {
     #[test]
     #[rustfmt::skip]
     fn serialize_ping_test() {
-        assert_eq!(serialize(&RawNetworkMessage::new(Magic::BITCOIN, NetworkMessage::Ping(100))),
+        assert_eq!(serialize(&RawNetworkMessage::new(Magic::from(Network::Bitcoin), NetworkMessage::Ping(100))),
                    vec![0xf9, 0xbe, 0xb4, 0xd9, 0x70, 0x69, 0x6e, 0x67,
                         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
                         0x08, 0x00, 0x00, 0x00, 0x24, 0x67, 0xf1, 0x1d,
@@ -719,7 +724,7 @@ fn serialize_ping_test() {
     #[test]
     #[rustfmt::skip]
     fn serialize_mempool_test() {
-        assert_eq!(serialize(&RawNetworkMessage::new(Magic::BITCOIN, NetworkMessage::MemPool)),
+        assert_eq!(serialize(&RawNetworkMessage::new(Magic::from(Network::Bitcoin), NetworkMessage::MemPool)),
                    vec![0xf9, 0xbe, 0xb4, 0xd9, 0x6d, 0x65, 0x6d, 0x70,
                         0x6f, 0x6f, 0x6c, 0x00, 0x00, 0x00, 0x00, 0x00,
                         0x00, 0x00, 0x00, 0x00, 0x5d, 0xf6, 0xe0, 0xe2]);
@@ -728,7 +733,7 @@ fn serialize_mempool_test() {
     #[test]
     #[rustfmt::skip]
     fn serialize_getaddr_test() {
-        assert_eq!(serialize(&RawNetworkMessage::new(Magic::BITCOIN, NetworkMessage::GetAddr)),
+        assert_eq!(serialize(&RawNetworkMessage::new(Magic::from(Network::Bitcoin), NetworkMessage::GetAddr)),
                    vec![0xf9, 0xbe, 0xb4, 0xd9, 0x67, 0x65, 0x74, 0x61,
                         0x64, 0x64, 0x72, 0x00, 0x00, 0x00, 0x00, 0x00,
                         0x00, 0x00, 0x00, 0x00, 0x5d, 0xf6, 0xe0, 0xe2]);
@@ -743,7 +748,7 @@ fn deserialize_getaddr_test() {
             0x00, 0x00, 0x00, 0x00, 0x5d, 0xf6, 0xe0, 0xe2
         ]);
         let preimage =
-            RawNetworkMessage::new(Magic::BITCOIN, NetworkMessage::GetAddr);
+            RawNetworkMessage::new(Magic::from(Network::Bitcoin), NetworkMessage::GetAddr);
         assert!(msg.is_ok());
         let msg: RawNetworkMessage = msg.unwrap();
         assert_eq!(preimage.magic, msg.magic);
@@ -774,7 +779,7 @@ fn deserialize_version_test() {
 
         assert!(msg.is_ok());
         let msg = msg.unwrap();
-        assert_eq!(msg.magic, Magic::BITCOIN);
+        assert_eq!(msg.magic, Magic::from(Network::Bitcoin));
         if let NetworkMessage::Version(version_msg) = msg.payload {
             assert_eq!(version_msg.version, 70015);
             assert_eq!(
@@ -820,7 +825,7 @@ fn deserialize_partial_message_test() {
 
         let (msg, consumed) = msg.unwrap();
         assert_eq!(consumed, data.to_vec().len() - 2);
-        assert_eq!(msg.magic, Magic::BITCOIN);
+        assert_eq!(msg.magic, Magic::from(Network::Bitcoin));
         if let NetworkMessage::Version(version_msg) = msg.payload {
             assert_eq!(version_msg.version, 70015);
             assert_eq!(
diff --git a/bitcoin/src/p2p/message_blockdata.rs b/bitcoin/src/p2p/message_blockdata.rs
index f1a142d5..550029d1 100644
--- a/bitcoin/src/p2p/message_blockdata.rs
+++ b/bitcoin/src/p2p/message_blockdata.rs
@@ -7,7 +7,7 @@
 //!
 
 use hashes::{sha256d, Hash as _};
-use io::{BufRead, Write};
+use io::{Read, Write};
 
 use crate::blockdata::block::BlockHash;
 use crate::blockdata::transaction::{Txid, Wtxid};
@@ -83,7 +83,7 @@ macro_rules! encode_inv {
 
 impl Decodable for Inventory {
     #[inline]
-    fn consensus_decode<R: BufRead + ?Sized>(r: &mut R) -> Result<Self, encode::Error> {
+    fn consensus_decode<R: Read + ?Sized>(r: &mut R) -> Result<Self, encode::Error> {
         let inv_type: u32 = Decodable::consensus_decode(r)?;
         Ok(match inv_type {
             0 => Inventory::Error,
diff --git a/bitcoin/src/p2p/message_bloom.rs b/bitcoin/src/p2p/message_bloom.rs
index cb04fca7..3e89c933 100644
--- a/bitcoin/src/p2p/message_bloom.rs
+++ b/bitcoin/src/p2p/message_bloom.rs
@@ -5,7 +5,7 @@
 //! This module describes BIP37 Connection Bloom filtering network messages.
 //!
 
-use io::{BufRead, Write};
+use io::{Read, Write};
 
 use crate::consensus::{encode, Decodable, Encodable, ReadExt};
 use crate::internal_macros::impl_consensus_encoding;
@@ -48,7 +48,7 @@ fn consensus_encode<W: Write + ?Sized>(&self, w: &mut W) -> Result<usize, io::Er
 }
 
 impl Decodable for BloomFlags {
-    fn consensus_decode<R: BufRead + ?Sized>(r: &mut R) -> Result<Self, encode::Error> {
+    fn consensus_decode<R: Read + ?Sized>(r: &mut R) -> Result<Self, encode::Error> {
         Ok(match r.read_u8()? {
             0 => BloomFlags::None,
             1 => BloomFlags::All,
diff --git a/bitcoin/src/p2p/message_network.rs b/bitcoin/src/p2p/message_network.rs
index bca60bba..f957a4a3 100644
--- a/bitcoin/src/p2p/message_network.rs
+++ b/bitcoin/src/p2p/message_network.rs
@@ -7,7 +7,7 @@
 //!
 
 use hashes::sha256d;
-use io::{BufRead, Write};
+use io::{Read, Write};
 
 use crate::consensus::{encode, Decodable, Encodable, ReadExt};
 use crate::internal_macros::impl_consensus_encoding;
@@ -32,13 +32,6 @@ pub struct VersionMessage {
     /// The network address of the peer sending the message
     pub sender: Address,
     /// A random nonce used to detect loops in the network
-    ///
-    /// The nonce can be used to detect situations when a node accidentally
-    /// connects to itself. Set it to a random value and, in case of incoming
-    /// connections, compare the value - same values mean self-connection.
-    ///
-    /// If your application uses P2P to only fetch the data and doesn't listen
-    /// you may just set it to 0.
     pub nonce: u64,
     /// A string describing the peer's software
     pub user_agent: String,
@@ -117,7 +110,7 @@ fn consensus_encode<W: Write + ?Sized>(&self, w: &mut W) -> Result<usize, io::Er
 }
 
 impl Decodable for RejectReason {
-    fn consensus_decode<R: BufRead + ?Sized>(r: &mut R) -> Result<Self, encode::Error> {
+    fn consensus_decode<R: Read + ?Sized>(r: &mut R) -> Result<Self, encode::Error> {
         Ok(match r.read_u8()? {
             0x01 => RejectReason::Malformed,
             0x10 => RejectReason::Invalid,
diff --git a/bitcoin/src/p2p/mod.rs b/bitcoin/src/p2p/mod.rs
index 1a450375..0c0381fe 100644
--- a/bitcoin/src/p2p/mod.rs
+++ b/bitcoin/src/p2p/mod.rs
@@ -25,7 +25,7 @@
 
 use hex::FromHex;
 use internals::{debug_from_display, write_err};
-use io::{BufRead, Write};
+use io::{Read, Write};
 
 use crate::consensus::encode::{self, Decodable, Encodable};
 use crate::prelude::{Borrow, BorrowMut, String, ToOwned};
@@ -198,7 +198,7 @@ fn consensus_encode<W: Write + ?Sized>(&self, w: &mut W) -> Result<usize, io::Er
 
 impl Decodable for ServiceFlags {
     #[inline]
-    fn consensus_decode<R: BufRead + ?Sized>(r: &mut R) -> Result<Self, encode::Error> {
+    fn consensus_decode<R: Read + ?Sized>(r: &mut R) -> Result<Self, encode::Error> {
         Ok(ServiceFlags(Decodable::consensus_decode(r)?))
     }
 }
@@ -290,7 +290,7 @@ fn consensus_encode<W: Write + ?Sized>(&self, writer: &mut W) -> Result<usize, i
 }
 
 impl Decodable for Magic {
-    fn consensus_decode<R: BufRead + ?Sized>(reader: &mut R) -> Result<Self, encode::Error> {
+    fn consensus_decode<R: Read + ?Sized>(reader: &mut R) -> Result<Self, encode::Error> {
         Ok(Magic(Decodable::consensus_decode(reader)?))
     }
 }
diff --git a/bitcoin/src/parse.rs b/bitcoin/src/parse.rs
index 779abad4..67b66048 100644
--- a/bitcoin/src/parse.rs
+++ b/bitcoin/src/parse.rs
@@ -107,7 +107,7 @@ macro_rules! impl_tryfrom_str_from_int_infallible {
         impl core::convert::TryFrom<$from> for $to {
             type Error = $crate::error::ParseIntError;
 
-            fn try_from(s: $from) -> core::result::Result<Self, Self::Error> {
+            fn try_from(s: $from) -> Result<Self, Self::Error> {
                 $crate::parse::int::<$inner, $from>(s).map($to::$fn)
             }
         }
@@ -127,7 +127,7 @@ macro_rules! impl_parse_str_from_int_infallible {
         impl core::str::FromStr for $to {
             type Err = $crate::error::ParseIntError;
 
-            fn from_str(s: &str) -> core::result::Result<Self, Self::Err> {
+            fn from_str(s: &str) -> Result<Self, Self::Err> {
                 $crate::parse::int::<$inner, &str>(s).map($to::$fn)
             }
         }
@@ -144,7 +144,7 @@ macro_rules! impl_tryfrom_str_from_int_fallible {
         impl core::convert::TryFrom<$from> for $to {
             type Error = $err;
 
-            fn try_from(s: $from) -> core::result::Result<Self, Self::Error> {
+            fn try_from(s: $from) -> Result<Self, Self::Error> {
                 let u = $crate::parse::int::<$inner, $from>(s)?;
                 $to::$fn(u)
             }
@@ -165,7 +165,7 @@ macro_rules! impl_parse_str_from_int_fallible {
         impl core::str::FromStr for $to {
             type Err = $err;
 
-            fn from_str(s: &str) -> core::result::Result<Self, Self::Err> {
+            fn from_str(s: &str) -> Result<Self, Self::Err> {
                 let u = $crate::parse::int::<$inner, &str>(s)?;
                 $to::$fn(u)
             }
diff --git a/bitcoin/src/pow.rs b/bitcoin/src/pow.rs
index d0990b05..68afaab4 100644
--- a/bitcoin/src/pow.rs
+++ b/bitcoin/src/pow.rs
@@ -9,7 +9,7 @@
 use core::fmt::{self, LowerHex, UpperHex};
 use core::ops::{Add, Div, Mul, Not, Rem, Shl, Shr, Sub};
 
-use io::{BufRead, Write};
+use io::{Read, Write};
 #[cfg(all(test, mutate))]
 use mutagen::mutate;
 
@@ -44,17 +44,17 @@ impl $ty {
 
         impl fmt::Display for $ty {
             #[inline]
-            fn fmt(&self, f: &mut fmt::Formatter) -> core::fmt::Result { fmt::Display::fmt(&self.0, f) }
+            fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { fmt::Display::fmt(&self.0, f) }
         }
 
         impl fmt::LowerHex for $ty {
             #[inline]
-            fn fmt(&self, f: &mut fmt::Formatter) -> core::fmt::Result { fmt::LowerHex::fmt(&self.0, f) }
+            fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { fmt::LowerHex::fmt(&self.0, f) }
         }
 
         impl fmt::UpperHex for $ty {
             #[inline]
-            fn fmt(&self, f: &mut fmt::Formatter) -> core::fmt::Result { fmt::UpperHex::fmt(&self.0, f) }
+            fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { fmt::UpperHex::fmt(&self.0, f) }
         }
     };
 }
@@ -301,7 +301,7 @@ fn consensus_encode<W: Write + ?Sized>(&self, w: &mut W) -> Result<usize, io::Er
 
 impl Decodable for CompactTarget {
     #[inline]
-    fn consensus_decode<R: BufRead + ?Sized>(r: &mut R) -> Result<Self, encode::Error> {
+    fn consensus_decode<R: Read + ?Sized>(r: &mut R) -> Result<Self, encode::Error> {
         u32::consensus_decode(r).map(CompactTarget)
     }
 }
@@ -810,7 +810,7 @@ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { write!(f, "{:#x}", self)
 macro_rules! impl_hex {
     ($hex:ident, $case:expr) => {
         impl $hex for U256 {
-            fn fmt(&self, f: &mut fmt::Formatter) -> core::fmt::Result {
+            fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
                 hex::fmt_hex_exact!(f, 32, &self.to_be_bytes(), $case)
             }
         }
@@ -832,6 +832,7 @@ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { write!(f, "{:x}", self.0)
         }
 
         if serializer.is_human_readable() {
+            // TODO: fast hex encoding.
             serializer.collect_str(&DisplayHex(*self))
         } else {
             let bytes = self.to_be_bytes();
@@ -1734,6 +1735,7 @@ fn u256_to_f64() {
 mod verification {
     use super::*;
 
+    // TODO: After we verify div_rem assert x * y / y == x
     #[kani::unwind(5)] // mul_u64 loops over 4 64 bit ints so use one more than 4
     #[kani::proof]
     fn check_mul_u64() {
@@ -1742,13 +1744,4 @@ fn check_mul_u64() {
 
         let _ = x.mul_u64(y);
     }
-
-    #[kani::unwind(5)]   // I can't remember exactly why we need this.
-    #[kani::proof]
-    fn check_div_rem() {
-        let x: U256 = kani::any();
-        let y: U256 = kani::any();
-
-        assert_eq!(x * y / y, x);
-    }
 }
diff --git a/bitcoin/src/psbt/error.rs b/bitcoin/src/psbt/error.rs
index 0243cf96..2ded0e26 100644
--- a/bitcoin/src/psbt/error.rs
+++ b/bitcoin/src/psbt/error.rs
@@ -58,7 +58,7 @@ pub enum Error {
     NonStandardSighashType(u32),
     /// Invalid hash when parsing slice.
     InvalidHash(hashes::FromSliceError),
-    /// The pre-image must hash to the corresponding psbt hash
+    /// The pre-image must hash to the correponding psbt hash
     InvalidPreimageHashPair {
         /// Hash-type
         hash_type: PsbtHash,
@@ -127,8 +127,8 @@ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
             UnexpectedUnsignedTx { expected: ref e, actual: ref a } => write!(
                 f,
                 "different unsigned transaction: expected {}, actual {}",
-                e.compute_txid(),
-                a.compute_txid()
+                e.txid(),
+                a.txid()
             ),
             NonStandardSighashType(ref sht) => write!(f, "non-standard sighash type: {}", sht),
             InvalidHash(ref e) => write_err!(f, "invalid hash when parsing slice"; e),
diff --git a/bitcoin/src/psbt/macros.rs b/bitcoin/src/psbt/macros.rs
index 556c83a7..f07e5bbc 100644
--- a/bitcoin/src/psbt/macros.rs
+++ b/bitcoin/src/psbt/macros.rs
@@ -19,7 +19,7 @@ macro_rules! impl_psbt_de_serialize {
 macro_rules! impl_psbt_deserialize {
     ($thing:ty) => {
         impl $crate::psbt::serialize::Deserialize for $thing {
-            fn deserialize(bytes: &[u8]) -> core::result::Result<Self, $crate::psbt::Error> {
+            fn deserialize(bytes: &[u8]) -> Result<Self, $crate::psbt::Error> {
                 $crate::consensus::deserialize(&bytes[..]).map_err(|e| $crate::psbt::Error::from(e))
             }
         }
@@ -45,7 +45,7 @@ fn serialize(&self) -> Vec<u8> { self.serialize_map() }
 macro_rules! impl_psbtmap_deserialize {
     ($thing:ty) => {
         impl $crate::psbt::serialize::Deserialize for $thing {
-            fn deserialize(bytes: &[u8]) -> core::result::Result<Self, $crate::psbt::Error> {
+            fn deserialize(bytes: &[u8]) -> Result<Self, $crate::psbt::Error> {
                 let mut decoder = bytes;
                 Self::decode(&mut decoder)
             }
@@ -56,9 +56,9 @@ fn deserialize(bytes: &[u8]) -> core::result::Result<Self, $crate::psbt::Error>
 macro_rules! impl_psbtmap_decoding {
     ($thing:ty) => {
         impl $thing {
-            pub(crate) fn decode<R: $crate::io::BufRead + ?Sized>(
+            pub(crate) fn decode<R: $crate::io::Read + ?Sized>(
                 r: &mut R,
-            ) -> core::result::Result<Self, $crate::psbt::Error> {
+            ) -> Result<Self, $crate::psbt::Error> {
                 let mut rv: Self = core::default::Default::default();
 
                 loop {
@@ -148,7 +148,7 @@ macro_rules! impl_psbt_hash_de_serialize {
 macro_rules! impl_psbt_hash_deserialize {
     ($hash_type:ty) => {
         impl $crate::psbt::serialize::Deserialize for $hash_type {
-            fn deserialize(bytes: &[u8]) -> core::result::Result<Self, $crate::psbt::Error> {
+            fn deserialize(bytes: &[u8]) -> Result<Self, $crate::psbt::Error> {
                 <$hash_type>::from_slice(&bytes[..]).map_err(|e| $crate::psbt::Error::from(e))
             }
         }
diff --git a/bitcoin/src/psbt/map/global.rs b/bitcoin/src/psbt/map/global.rs
index 8de2ea4b..7803df2b 100644
--- a/bitcoin/src/psbt/map/global.rs
+++ b/bitcoin/src/psbt/map/global.rs
@@ -1,6 +1,6 @@
 // SPDX-License-Identifier: CC0-1.0
 
-use io::{Cursor, BufRead, Read};
+use io::{Cursor, Read};
 
 use crate::bip32::{ChildNumber, DerivationPath, Fingerprint, Xpub};
 use crate::blockdata::transaction::Transaction;
@@ -70,7 +70,7 @@ fn get_pairs(&self) -> Vec<raw::Pair> {
 }
 
 impl Psbt {
-    pub(crate) fn decode_global<R: BufRead + ?Sized>(r: &mut R) -> Result<Self, Error> {
+    pub(crate) fn decode_global<R: Read + ?Sized>(r: &mut R) -> Result<Self, Error> {
         let mut r = r.take(MAX_VEC_SIZE as u64);
         let mut tx: Option<Transaction> = None;
         let mut version: Option<u32> = None;
diff --git a/bitcoin/src/psbt/map/input.rs b/bitcoin/src/psbt/map/input.rs
index 01bc954f..5deb923d 100644
--- a/bitcoin/src/psbt/map/input.rs
+++ b/bitcoin/src/psbt/map/input.rs
@@ -97,6 +97,7 @@ pub struct Input {
     /// The finalized, fully-constructed scriptWitness with signatures and any
     /// other scripts necessary for this input to pass validation.
     pub final_script_witness: Option<Witness>,
+    /// TODO: Proof of reserves commitment
     /// RIPEMD160 hash to preimage map.
     #[cfg_attr(feature = "serde", serde(with = "crate::serde_utils::btreemap_byte_values"))]
     pub ripemd160_preimages: BTreeMap<ripemd160::Hash, Vec<u8>>,
diff --git a/bitcoin/src/psbt/mod.rs b/bitcoin/src/psbt/mod.rs
index 22c8f49a..b59d55f6 100644
--- a/bitcoin/src/psbt/mod.rs
+++ b/bitcoin/src/psbt/mod.rs
@@ -23,7 +23,7 @@
 use secp256k1::{Message, Secp256k1, Signing};
 
 use crate::bip32::{self, KeySource, Xpriv, Xpub};
-use crate::blockdata::transaction::{self, Transaction, TxOut};
+use crate::blockdata::transaction::{Transaction, TxOut};
 use crate::crypto::ecdsa;
 use crate::crypto::key::{PrivateKey, PublicKey};
 use crate::prelude::*;
@@ -371,10 +371,8 @@ fn bip32_sign_ecdsa<C, K, T>(
                 Ok((msg, sighash_ty)) => (msg, sighash_ty),
             };
 
-            let sig = ecdsa::Signature {
-                signature: secp.sign_ecdsa(&msg, &sk.inner),
-                sighash_type: sighash_ty,
-            };
+            let sig =
+                ecdsa::Signature { sig: secp.sign_ecdsa(&msg, &sk.inner), hash_ty: sighash_ty };
 
             let pk = sk.public_key(secp);
 
@@ -409,17 +407,14 @@ pub fn sighash_ecdsa<T: Borrow<Transaction>>(
 
         match self.output_type(input_index)? {
             Bare => {
-                let sighash = cache
-                    .legacy_signature_hash(input_index, spk, hash_ty.to_u32())
-                    .expect("input checked above");
+                let sighash = cache.legacy_signature_hash(input_index, spk, hash_ty.to_u32())?;
                 Ok((Message::from_digest(sighash.to_byte_array()), hash_ty))
             }
             Sh => {
                 let script_code =
                     input.redeem_script.as_ref().ok_or(SignError::MissingRedeemScript)?;
-                let sighash = cache
-                    .legacy_signature_hash(input_index, script_code, hash_ty.to_u32())
-                    .expect("input checked above");
+                let sighash =
+                    cache.legacy_signature_hash(input_index, script_code, hash_ty.to_u32())?;
                 Ok((Message::from_digest(sighash.to_byte_array()), hash_ty))
             }
             Wpkh => {
@@ -436,7 +431,7 @@ pub fn sighash_ecdsa<T: Borrow<Transaction>>(
                 let witness_script =
                     input.witness_script.as_ref().ok_or(SignError::MissingWitnessScript)?;
                 let sighash =
-                    cache.p2wsh_signature_hash(input_index, witness_script, utxo.value, hash_ty).map_err(SignError::SegwitV0Sighash)?;
+                    cache.p2wsh_signature_hash(input_index, witness_script, utxo.value, hash_ty)?;
                 Ok((Message::from_digest(sighash.to_byte_array()), hash_ty))
             }
             Tr => {
@@ -770,10 +765,8 @@ pub enum SignError {
     NotEcdsa,
     /// The `scriptPubkey` is not a P2WPKH script.
     NotWpkh,
-    /// Sighash computation error (segwit v0 input).
-    SegwitV0Sighash(transaction::InputsIndexError),
-    /// Sighash computation error (p2wpkh input).
-    P2wpkhSighash(sighash::P2wpkhError),
+    /// Sighash computation error.
+    SighashComputation(sighash::Error),
     /// Unable to determine the output type.
     UnknownOutputType,
     /// Unable to find key.
@@ -798,8 +791,7 @@ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
             MismatchedAlgoKey => write!(f, "signing algorithm and key type does not match"),
             NotEcdsa => write!(f, "attempted to ECDSA sign an non-ECDSA input"),
             NotWpkh => write!(f, "the scriptPubkey is not a P2WPKH script"),
-            SegwitV0Sighash(ref e) => write_err!(f, "segwit v0 sighash"; e),
-            P2wpkhSighash(ref e) => write_err!(f, "p2wpkh sighash"; e),
+            SighashComputation(ref e) => write!(f, "sighash: {}", e),
             UnknownOutputType => write!(f, "unable to determine the output type"),
             KeyNotFound => write!(f, "unable to find key"),
             WrongSigningAlgorithm =>
@@ -815,8 +807,7 @@ fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
         use SignError::*;
 
         match *self {
-            SegwitV0Sighash(ref e) => Some(e),
-            P2wpkhSighash(ref e) => Some(e),
+            SighashComputation(ref e) => Some(e),
             IndexOutOfBounds(ref e) => Some(e),
             InvalidSighashType
             | MissingInputUtxo
@@ -834,8 +825,8 @@ fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
     }
 }
 
-impl From<sighash::P2wpkhError> for SignError {
-    fn from(e: sighash::P2wpkhError) -> Self { Self::P2wpkhSighash(e) }
+impl From<sighash::Error> for SignError {
+    fn from(e: sighash::Error) -> Self { SignError::SighashComputation(e) }
 }
 
 impl From<IndexOutOfBoundsError> for SignError {
@@ -1593,7 +1584,7 @@ fn valid_vector_3() {
             let tx_input = &psbt.unsigned_tx.input[0];
             let psbt_non_witness_utxo = psbt.inputs[0].non_witness_utxo.as_ref().unwrap();
 
-            assert_eq!(tx_input.previous_output.txid, psbt_non_witness_utxo.compute_txid());
+            assert_eq!(tx_input.previous_output.txid, psbt_non_witness_utxo.txid());
             assert!(psbt_non_witness_utxo.output[tx_input.previous_output.vout as usize]
                 .script_pubkey
                 .is_p2pkh());
@@ -1660,7 +1651,7 @@ fn valid_vector_6() {
 
             let tx = &psbt.unsigned_tx;
             assert_eq!(
-                tx.compute_txid(),
+                tx.txid(),
                 "75c5c9665a570569ad77dd1279e6fd4628a093c4dcbf8d41532614044c14c115".parse().unwrap(),
             );
 
diff --git a/bitcoin/src/psbt/raw.rs b/bitcoin/src/psbt/raw.rs
index 9f9c64fd..db4af227 100644
--- a/bitcoin/src/psbt/raw.rs
+++ b/bitcoin/src/psbt/raw.rs
@@ -8,7 +8,7 @@
 
 use core::fmt;
 
-use io::{BufRead, Write};
+use io::{Read, Write};
 
 use super::serialize::{Deserialize, Serialize};
 use crate::consensus::encode::{
@@ -74,7 +74,7 @@ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
 }
 
 impl Key {
-    pub(crate) fn decode<R: BufRead + ?Sized>(r: &mut R) -> Result<Self, Error> {
+    pub(crate) fn decode<R: Read + ?Sized>(r: &mut R) -> Result<Self, Error> {
         let VarInt(byte_size): VarInt = Decodable::consensus_decode(r)?;
 
         if byte_size == 0 {
@@ -137,7 +137,7 @@ fn deserialize(bytes: &[u8]) -> Result<Self, Error> {
 }
 
 impl Pair {
-    pub(crate) fn decode<R: BufRead + ?Sized>(r: &mut R) -> Result<Self, Error> {
+    pub(crate) fn decode<R: Read + ?Sized>(r: &mut R) -> Result<Self, Error> {
         Ok(Pair { key: Key::decode(r)?, value: Decodable::consensus_decode(r)? })
     }
 }
@@ -159,14 +159,10 @@ impl<Subtype> Decodable for ProprietaryKey<Subtype>
 where
     Subtype: Copy + From<u8> + Into<u8>,
 {
-    fn consensus_decode<R: BufRead + ?Sized>(r: &mut R) -> Result<Self, encode::Error> {
+    fn consensus_decode<R: Read + ?Sized>(r: &mut R) -> Result<Self, encode::Error> {
         let prefix = Vec::<u8>::consensus_decode(r)?;
         let subtype = Subtype::from(r.read_u8()?);
-
-        // The limit is a DOS protection mechanism the exact value is not
-        // important, 1024 bytes is bigger than any key should be.
-        let mut key = vec![];
-        let _ = r.read_to_limit(&mut key, 1024)?;
+        let key = read_to_end(r)?;
 
         Ok(ProprietaryKey { prefix, subtype, key })
     }
@@ -198,3 +194,18 @@ fn try_from(key: Key) -> Result<Self, Self::Error> {
         Ok(deserialize(&key.key)?)
     }
 }
+
+// core2 doesn't have read_to_end
+pub(crate) fn read_to_end<D: Read + ?Sized>(d: &mut D) -> Result<Vec<u8>, io::Error> {
+    let mut result = vec![];
+    let mut buf = [0u8; 64];
+    loop {
+        match d.read(&mut buf) {
+            Ok(0) => break,
+            Ok(n) => result.extend_from_slice(&buf[0..n]),
+            Err(ref e) if e.kind() == io::ErrorKind::Interrupted => {}
+            Err(e) => return Err(e),
+        };
+    }
+    Ok(result)
+}
diff --git a/bitcoin/src/psbt/serialize.rs b/bitcoin/src/psbt/serialize.rs
index 188d5758..92bef807 100644
--- a/bitcoin/src/psbt/serialize.rs
+++ b/bitcoin/src/psbt/serialize.rs
@@ -321,6 +321,7 @@ impl Serialize for (Vec<TapLeafHash>, KeySource) {
     fn serialize(&self) -> Vec<u8> {
         let mut buf = Vec::with_capacity(32 * self.0.len() + key_source_len(&self.1));
         self.0.consensus_encode(&mut buf).expect("Vecs don't error allocation");
+        // TODO: Add support for writing into a writer for key-source
         buf.extend(self.1.serialize());
         buf
     }
diff --git a/bitcoin/src/serde_utils.rs b/bitcoin/src/serde_utils.rs
index 7b1c5b7d..c0789e0c 100644
--- a/bitcoin/src/serde_utils.rs
+++ b/bitcoin/src/serde_utils.rs
@@ -309,7 +309,7 @@ fn visit_str<E>(self, v: &str) -> Result<Self::Value, E>
 macro_rules! serde_string_serialize_impl {
     ($name:ty, $expecting:literal) => {
         impl $crate::serde::Serialize for $name {
-            fn serialize<S>(&self, serializer: S) -> core::result::Result<S::Ok, S::Error>
+            fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
             where
                 S: $crate::serde::Serializer,
             {
@@ -322,21 +322,21 @@ fn serialize<S>(&self, serializer: S) -> core::result::Result<S::Ok, S::Error>
 macro_rules! serde_string_deserialize_impl {
     ($name:ty, $expecting:literal) => {
         impl<'de> $crate::serde::Deserialize<'de> for $name {
-            fn deserialize<D>(deserializer: D) -> core::result::Result<$name, D::Error>
+            fn deserialize<D>(deserializer: D) -> Result<$name, D::Error>
             where
                 D: $crate::serde::de::Deserializer<'de>,
             {
-                use core::fmt::Formatter;
+                use core::fmt::{self, Formatter};
 
                 struct Visitor;
                 impl<'de> $crate::serde::de::Visitor<'de> for Visitor {
                     type Value = $name;
 
-                    fn expecting(&self, f: &mut Formatter) -> core::fmt::Result {
+                    fn expecting(&self, f: &mut Formatter) -> fmt::Result {
                         f.write_str($expecting)
                     }
 
-                    fn visit_str<E>(self, v: &str) -> core::result::Result<Self::Value, E>
+                    fn visit_str<E>(self, v: &str) -> Result<Self::Value, E>
                     where
                         E: $crate::serde::de::Error,
                     {
@@ -363,23 +363,23 @@ macro_rules! serde_string_impl {
 macro_rules! serde_struct_human_string_impl {
     ($name:ident, $expecting:literal, $($fe:ident),*) => (
         impl<'de> $crate::serde::Deserialize<'de> for $name {
-            fn deserialize<D>(deserializer: D) -> core::result::Result<$name, D::Error>
+            fn deserialize<D>(deserializer: D) -> Result<$name, D::Error>
             where
                 D: $crate::serde::de::Deserializer<'de>,
             {
                 if deserializer.is_human_readable() {
-                    use core::fmt::Formatter;
+                    use core::fmt::{self, Formatter};
                     use core::str::FromStr;
 
                     struct Visitor;
                     impl<'de> $crate::serde::de::Visitor<'de> for Visitor {
                         type Value = $name;
 
-                        fn expecting(&self, f: &mut Formatter) -> core::fmt::Result {
+                        fn expecting(&self, f: &mut Formatter) -> fmt::Result {
                             f.write_str($expecting)
                         }
 
-                        fn visit_str<E>(self, v: &str) -> core::result::Result<Self::Value, E>
+                        fn visit_str<E>(self, v: &str) -> Result<Self::Value, E>
                         where
                             E: $crate::serde::de::Error,
                         {
@@ -390,7 +390,7 @@ fn visit_str<E>(self, v: &str) -> core::result::Result<Self::Value, E>
 
                     deserializer.deserialize_str(Visitor)
                 } else {
-                    use core::fmt::Formatter;
+                    use core::fmt::{self, Formatter};
                     use $crate::serde::de::IgnoredAny;
 
                     #[allow(non_camel_case_types)]
@@ -400,11 +400,11 @@ enum Enum { Unknown__Field, $($fe),* }
                     impl<'de> $crate::serde::de::Visitor<'de> for EnumVisitor {
                         type Value = Enum;
 
-                        fn expecting(&self, f: &mut Formatter) -> core::fmt::Result {
+                        fn expecting(&self, f: &mut Formatter) -> fmt::Result {
                             f.write_str("a field name")
                         }
 
-                        fn visit_str<E>(self, v: &str) -> core::result::Result<Self::Value, E>
+                        fn visit_str<E>(self, v: &str) -> Result<Self::Value, E>
                         where
                             E: $crate::serde::de::Error,
                         {
@@ -418,7 +418,7 @@ fn visit_str<E>(self, v: &str) -> core::result::Result<Self::Value, E>
                     }
 
                     impl<'de> $crate::serde::Deserialize<'de> for Enum {
-                        fn deserialize<D>(deserializer: D) -> core::result::Result<Self, D::Error>
+                        fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
                         where
                             D: $crate::serde::de::Deserializer<'de>,
                         {
@@ -431,11 +431,11 @@ fn deserialize<D>(deserializer: D) -> core::result::Result<Self, D::Error>
                     impl<'de> $crate::serde::de::Visitor<'de> for Visitor {
                         type Value = $name;
 
-                        fn expecting(&self, f: &mut Formatter) -> core::fmt::Result {
+                        fn expecting(&self, f: &mut Formatter) -> fmt::Result {
                             f.write_str("a struct")
                         }
 
-                        fn visit_seq<V>(self, mut seq: V) -> core::result::Result<Self::Value, V::Error>
+                        fn visit_seq<V>(self, mut seq: V) -> Result<Self::Value, V::Error>
                         where
                             V: $crate::serde::de::SeqAccess<'de>,
                         {
@@ -457,7 +457,7 @@ fn visit_seq<V>(self, mut seq: V) -> core::result::Result<Self::Value, V::Error>
                             Ok(ret)
                         }
 
-                        fn visit_map<A>(self, mut map: A) -> core::result::Result<Self::Value, A::Error>
+                        fn visit_map<A>(self, mut map: A) -> Result<Self::Value, A::Error>
                         where
                             A: $crate::serde::de::MapAccess<'de>,
                         {
@@ -503,7 +503,7 @@ fn visit_map<A>(self, mut map: A) -> core::result::Result<Self::Value, A::Error>
         }
 
         impl $crate::serde::Serialize for $name {
-            fn serialize<S>(&self, serializer: S) -> core::result::Result<S::Ok, S::Error>
+            fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
             where
                 S: $crate::serde::Serializer,
             {
diff --git a/bitcoin/src/taproot/mod.rs b/bitcoin/src/taproot/mod.rs
index 203ac314..32271bf2 100644
--- a/bitcoin/src/taproot/mod.rs
+++ b/bitcoin/src/taproot/mod.rs
@@ -1436,7 +1436,7 @@ mod test {
 
     use super::*;
     use crate::sighash::{TapSighash, TapSighashTag};
-    use crate::{Address, KnownHrp};
+    use crate::{Address, Network};
     extern crate serde_json;
 
     #[cfg(feature = "serde")]
@@ -1828,7 +1828,7 @@ fn process_script_trees(
 
             let tweak = TapTweakHash::from_key_and_tweak(internal_key, merkle_root);
             let (output_key, _parity) = internal_key.tap_tweak(secp, merkle_root);
-            let addr = Address::p2tr(secp, internal_key, merkle_root, KnownHrp::Mainnet);
+            let addr = Address::p2tr(secp, internal_key, merkle_root, Network::Bitcoin);
             let spk = addr.script_pubkey();
 
             assert_eq!(expected_output_key, output_key.to_inner());
diff --git a/bitcoin/src/taproot/serialized_signature.rs b/bitcoin/src/taproot/serialized_signature.rs
index 581c139b..845847e8 100644
--- a/bitcoin/src/taproot/serialized_signature.rs
+++ b/bitcoin/src/taproot/serialized_signature.rs
@@ -10,7 +10,6 @@
 use core::{fmt, ops};
 
 pub use into_iter::IntoIter;
-use io::Write;
 
 use super::{SigFromSliceError, Signature};
 
@@ -167,12 +166,6 @@ pub fn to_signature(&self) -> Result<Signature, SigFromSliceError> {
     /// (this serializes it)
     #[inline]
     pub fn from_signature(sig: &Signature) -> SerializedSignature { sig.serialize() }
-
-    /// Writes this serialized signature to a `writer`.
-    #[inline]
-    pub fn write_to<W: Write + ?Sized>(&self, writer: &mut W) -> Result<(), io::Error> {
-        writer.write_all(self)
-    }
 }
 
 /// Separate mod to prevent outside code from accidentally breaking invariants.
@@ -230,7 +223,7 @@ fn size_hint(&self) -> (usize, Option<usize>) {
         #[inline]
         fn nth(&mut self, n: usize) -> Option<Self::Item> {
             if n >= self.len() {
-                // upholds invariant because the values will be equal
+                // upholds invariant becasue the values will be equal
                 self.pos = self.signature.len();
                 None
             } else {
diff --git a/contrib/gen_label_config.sh b/contrib/gen_label_config.sh
deleted file mode 100755
index 1f88145a..00000000
--- a/contrib/gen_label_config.sh
+++ /dev/null
@@ -1,39 +0,0 @@
-#!/bin/bash
-
-set -e
-
-# Generates the label configuration using crates in the repository.
-# The label configuration is appended to the labeler config file.
-
-config=.github/labeler.yml
-
-if [ -n "$SCAN_DIR" ];
-then
-	scan_dir="$SCAN_DIR"
-else
-	scan_dir=.
-fi
-
-if [ "$1" '!=' "--force" ] && ! git diff --exit-code "$config";
-then
-	echo "Error: $config is not committed."
-	echo "Refusing to overwrite it to prevent disaster."
-	echo "Run the script with --force to override this."
-	exit 1
-fi
-
-excluded_crates="fuzz|dep_test"
-
-CRATES="`cd "$scan_dir" && cargo metadata --no-deps --format-version 1 | jq -j -r '.packages | map(.manifest_path | rtrimstr("/Cargo.toml") | ltrimstr("'$PWD'/")) | join(" ")'`"
-
-for crate in $CRATES;
-do
-	if echo "$crate" | grep -qE "$excluded_crates";
-	then
-		continue
-	fi
-
-	echo "C-$crate:" >> "$config"
-	echo "  - changed-files:" >> "$config"
-	echo "    - any-glob-to-any-file: $crate/**" >> "$config"
-done
diff --git a/hashes/Cargo.toml b/hashes/Cargo.toml
index bbe6b292..a68a0a70 100644
--- a/hashes/Cargo.toml
+++ b/hashes/Cargo.toml
@@ -17,6 +17,7 @@ exclude = ["tests", "contrib"]
 default = ["std"]
 std = ["alloc", "hex/std", "bitcoin-io/std"]
 alloc = ["hex/alloc"]
+serde-std = ["serde/std"]
 # If you want I/O you must enable either "std" or "io".
 io = ["bitcoin-io"]
 # Smaller (but slower) implementation of sha256, sha512 and ripemd160
@@ -31,6 +32,7 @@ hex = { package = "hex-conservative", version = "0.1.1", default-features = fals
 
 bitcoin-io = { version = "0.1", default-features = false, optional = true }
 schemars = { version = "0.8.3", default-features = false, optional = true }
+# Only enable this if you explicitly do not want to use "std", otherwise enable "serde-std".
 serde = { version = "1.0", default-features = false, optional = true }
 
 [dev-dependencies]
diff --git a/hashes/src/hmac.rs b/hashes/src/hmac.rs
index 32b967a5..b196f297 100644
--- a/hashes/src/hmac.rs
+++ b/hashes/src/hmac.rs
@@ -44,7 +44,7 @@ pub struct HmacMidState<T: Hash> {
     pub outer: <T::Engine as HashEngine>::MidState,
 }
 
-/// Pair of underlying hash engines, used for the inner and outer hash of HMAC.
+/// Pair of underyling hash engines, used for the inner and outer hash of HMAC.
 #[derive(Clone)]
 pub struct HmacEngine<T: Hash> {
     iengine: T::Engine,
diff --git a/hashes/src/internal_macros.rs b/hashes/src/internal_macros.rs
index 9352cde5..bb99febc 100644
--- a/hashes/src/internal_macros.rs
+++ b/hashes/src/internal_macros.rs
@@ -104,7 +104,7 @@ pub fn backward_hex(&self) -> impl '_ + core::fmt::LowerHex + core::fmt::UpperHe
 
         impl<$($gen: $gent),*> str::FromStr for Hash<$($gen),*> {
             type Err = $crate::hex::HexToArrayError;
-            fn from_str(s: &str) -> $crate::_export::_core::result::Result<Self, Self::Err> {
+            fn from_str(s: &str) -> Result<Self, Self::Err> {
                 use $crate::hex::{FromHex, HexToBytesIter};
                 use $crate::Hash;
 
@@ -151,7 +151,7 @@ fn from_engine(e: HashEngine) -> Hash<$($gen),*> {
                 from_engine(e)
             }
 
-            fn from_slice(sl: &[u8]) -> $crate::_export::_core::result::Result<Hash<$($gen),*>, FromSliceError> {
+            fn from_slice(sl: &[u8]) -> Result<Hash<$($gen),*>, FromSliceError> {
                 if sl.len() != $bits / 8 {
                     Err(FromSliceError{expected: Self::LEN, got: sl.len()})
                 } else {
diff --git a/hashes/src/serde_macros.rs b/hashes/src/serde_macros.rs
index 3646af39..ded28b2f 100644
--- a/hashes/src/serde_macros.rs
+++ b/hashes/src/serde_macros.rs
@@ -25,7 +25,7 @@ fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
             formatter.write_str("an ASCII hex string")
         }
 
-        fn visit_bytes<E>(self, v: &[u8]) -> core::result::Result<Self::Value, E>
+        fn visit_bytes<E>(self, v: &[u8]) -> Result<Self::Value, E>
         where
             E: de::Error,
         {
@@ -36,7 +36,7 @@ fn visit_bytes<E>(self, v: &[u8]) -> core::result::Result<Self::Value, E>
             }
         }
 
-        fn visit_str<E>(self, v: &str) -> core::result::Result<Self::Value, E>
+        fn visit_str<E>(self, v: &str) -> Result<Self::Value, E>
         where
             E: de::Error,
         {
@@ -57,7 +57,7 @@ fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
             formatter.write_str("a bytestring")
         }
 
-        fn visit_bytes<E>(self, v: &[u8]) -> core::result::Result<Self::Value, E>
+        fn visit_bytes<E>(self, v: &[u8]) -> Result<Self::Value, E>
         where
             E: de::Error,
         {
@@ -82,10 +82,10 @@ pub trait SerdeHash
         const N: usize;
 
         /// Helper function to turn a deserialized slice into the correct hash type.
-        fn from_slice_delegated(sl: &[u8]) -> core::result::Result<Self, FromSliceError>;
+        fn from_slice_delegated(sl: &[u8]) -> Result<Self, FromSliceError>;
 
         /// Do serde serialization.
-        fn serialize<S: Serializer>(&self, s: S) -> core::result::Result<S::Ok, S::Error> {
+        fn serialize<S: Serializer>(&self, s: S) -> Result<S::Ok, S::Error> {
             if s.is_human_readable() {
                 s.collect_str(self)
             } else {
@@ -94,7 +94,7 @@ fn serialize<S: Serializer>(&self, s: S) -> core::result::Result<S::Ok, S::Error
         }
 
         /// Do serde deserialization.
-        fn deserialize<'de, D: Deserializer<'de>>(d: D) -> core::result::Result<Self, D::Error> {
+        fn deserialize<'de, D: Deserializer<'de>>(d: D) -> Result<Self, D::Error> {
             if d.is_human_readable() {
                 d.deserialize_str(HexVisitor::<Self>(PhantomData))
             } else {
@@ -112,7 +112,7 @@ macro_rules! serde_impl(
     ($t:ident, $len:expr $(, $gen:ident: $gent:ident)*) => (
         impl<$($gen: $gent),*> $crate::serde_macros::serde_details::SerdeHash for $t<$($gen),*> {
             const N : usize = $len;
-            fn from_slice_delegated(sl: &[u8]) -> core::result::Result<Self, $crate::FromSliceError> {
+            fn from_slice_delegated(sl: &[u8]) -> Result<Self, $crate::FromSliceError> {
                 #[allow(unused_imports)]
                 use $crate::Hash as _;
                 $t::from_slice(sl)
@@ -120,13 +120,13 @@ fn from_slice_delegated(sl: &[u8]) -> core::result::Result<Self, $crate::FromSli
         }
 
         impl<$($gen: $gent),*> $crate::serde::Serialize for $t<$($gen),*> {
-            fn serialize<S: $crate::serde::Serializer>(&self, s: S) -> core::result::Result<S::Ok, S::Error> {
+            fn serialize<S: $crate::serde::Serializer>(&self, s: S) -> Result<S::Ok, S::Error> {
                 $crate::serde_macros::serde_details::SerdeHash::serialize(self, s)
             }
         }
 
         impl<'de $(, $gen: $gent)*> $crate::serde::Deserialize<'de> for $t<$($gen),*> {
-            fn deserialize<D: $crate::serde::Deserializer<'de>>(d: D) -> core::result::Result<$t<$($gen),*>, D::Error> {
+            fn deserialize<D: $crate::serde::Deserializer<'de>>(d: D) -> Result<$t<$($gen),*>, D::Error> {
                 $crate::serde_macros::serde_details::SerdeHash::deserialize(d)
             }
         }
diff --git a/hashes/src/util.rs b/hashes/src/util.rs
index 92fd4855..393718c9 100644
--- a/hashes/src/util.rs
+++ b/hashes/src/util.rs
@@ -241,7 +241,7 @@ fn from_engine(e: Self::Engine) -> Self {
             }
 
             #[inline]
-            fn from_slice(sl: &[u8]) -> $crate::_export::_core::result::Result<$newtype, $crate::FromSliceError> {
+            fn from_slice(sl: &[u8]) -> Result<$newtype, $crate::FromSliceError> {
                 Ok($newtype(<$hash as $crate::Hash>::from_slice(sl)?))
             }
 
diff --git a/internals/src/macros.rs b/internals/src/macros.rs
index 91e60a1c..799730f0 100644
--- a/internals/src/macros.rs
+++ b/internals/src/macros.rs
@@ -42,7 +42,7 @@ pub fn is_empty(&self) -> bool { false }
         impl<'a> core::convert::TryFrom<&'a [$ty]> for $thing {
             type Error = core::array::TryFromSliceError;
 
-            fn try_from(data: &'a [$ty]) -> core::result::Result<Self, Self::Error> {
+            fn try_from(data: &'a [$ty]) -> Result<Self, Self::Error> {
                 use core::convert::TryInto;
 
                 Ok($thing(data.try_into()?))
@@ -99,7 +99,7 @@ fn index(&self, index: I) -> &Self::Output { &self.0[index] }
 macro_rules! debug_from_display {
     ($thing:ident) => {
         impl core::fmt::Debug for $thing {
-            fn fmt(&self, f: &mut core::fmt::Formatter) -> core::result::Result<(), core::fmt::Error> {
+            fn fmt(&self, f: &mut core::fmt::Formatter) -> Result<(), core::fmt::Error> {
                 core::fmt::Display::fmt(self, f)
             }
         }
diff --git a/internals/src/parse.rs b/internals/src/parse.rs
index ddf54169..1aed7605 100644
--- a/internals/src/parse.rs
+++ b/internals/src/parse.rs
@@ -9,7 +9,7 @@ macro_rules! impl_try_from_stringly {
         impl core::convert::TryFrom<$from> for $to {
             type Error = $error;
 
-            fn try_from(s: $from) -> core::result::Result<Self, Self::Error> {
+            fn try_from(s: $from) -> Result<Self, Self::Error> {
                 $func(AsRef::<str>::as_ref(s)).map_err(|source| <$error>::new(s, source))
             }
         }
@@ -36,7 +36,7 @@ macro_rules! impl_parse {
         impl core::str::FromStr for $type {
             type Err = $error;
 
-            fn from_str(s: &str) -> core::result::Result<Self, Self::Err> {
+            fn from_str(s: &str) -> Result<Self, Self::Err> {
                 $func(s).map_err(|source| <$error>::new(s, source))
             }
         }
@@ -64,7 +64,7 @@ macro_rules! impl_parse_and_serde {
         // We don't use `serde_string_impl` because we want to avoid allocating input.
         #[cfg(feature = "serde")]
         impl<'de> $crate::serde::Deserialize<'de> for $type {
-            fn deserialize<D>(deserializer: D) -> core::result::Result<$name, D::Error>
+            fn deserialize<D>(deserializer: D) -> Result<$name, D::Error>
             where
                 D: $crate::serde::de::Deserializer<'de>,
             {
@@ -75,11 +75,11 @@ fn deserialize<D>(deserializer: D) -> core::result::Result<$name, D::Error>
                 impl<'de> $crate::serde::de::Visitor<'de> for Visitor {
                     type Value = $name;
 
-                    fn expecting(&self, f: &mut Formatter) -> core::fmt::Result {
+                    fn expecting(&self, f: &mut Formatter) -> fmt::Result {
                         f.write_str($descr)
                     }
 
-                    fn visit_str<E>(self, s: &str) -> core::result::Result<Self::Value, E>
+                    fn visit_str<E>(self, s: &str) -> Result<Self::Value, E>
                     where
                         E: $crate::serde::de::Error,
                     {
@@ -96,7 +96,7 @@ fn visit_str<E>(self, s: &str) -> core::result::Result<Self::Value, E>
 
         #[cfg(feature = "serde")]
         impl $crate::serde::Serialize for $name {
-            fn serialize<S>(&self, serializer: S) -> core::result::Result<S::Ok, S::Error>
+            fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
             where
                 S: $crate::serde::Serializer,
             {
diff --git a/io/README.md b/io/README.md
deleted file mode 100644
index e38e2d06..00000000
--- a/io/README.md
+++ /dev/null
@@ -1,10 +0,0 @@
-Rust-Bitcoin IO Library
-=======================
-
-The `std::io` module is not exposed in `no-std` Rust so building `no-std` applications which require
-reading and writing objects via standard traits is not generally possible. Thus, this library exists
-to export a minmal version of `std::io`'s traits which we use in `rust-bitcoin` so that we can
-support `no-std` applications.
-
-These traits are not one-for-one drop-ins, but are as close as possible while still implementing
-`std::io`'s traits without unnecessary complexity.
diff --git a/io/src/lib.rs b/io/src/lib.rs
index a338b52e..8d234c19 100644
--- a/io/src/lib.rs
+++ b/io/src/lib.rs
@@ -1,11 +1,16 @@
 //! Rust-Bitcoin IO Library
 //!
-//! The `std::io` module is not exposed in `no-std` Rust so building `no-std` applications which
-//! require reading and writing objects via standard traits is not generally possible. Thus, this
-//! library exists to export a minmal version of `std::io`'s traits which we use in `rust-bitcoin`
-//! so that we can support `no-std` applications.
+//! Because the core `std::io` module is not yet exposed in `no-std` Rust, building `no-std`
+//! applications which require reading and writing objects via standard traits is not generally
+//! possible. While there is ongoing work to improve this situation, this module is not likely to
+//! be available for applications with broad rustc version support for some time.
 //!
-//! These traits are not one-for-one drop-ins, but are as close as possible while still implementing
+//! Thus, this library exists to export a minmal version of `std::io`'s traits which `no-std`
+//! applications may need. With the `std` feature, these traits are also implemented for the
+//! `std::io` traits, allowing standard objects to be used wherever the traits from this crate are
+//! required.
+//!
+//! This traits are not one-for-one drop-ins, but are as close as possible while still implementing
 //! `std::io`'s traits without unnecessary complexity.
 
 #![cfg_attr(not(feature = "std"), no_std)]
@@ -18,8 +23,6 @@
 mod error;
 mod macros;
 
-#[cfg(feature = "alloc")]
-use alloc::vec::Vec;
 use core::cmp;
 use core::convert::TryInto;
 
@@ -47,32 +50,6 @@ fn read_exact(&mut self, mut buf: &mut [u8]) -> Result<()> {
 
     #[inline]
     fn take(&mut self, limit: u64) -> Take<Self> { Take { reader: self, remaining: limit } }
-
-    /// Attempts to read up to limit bytes from the reader, allocating space in `buf` as needed.
-    ///
-    /// `limit` is used to prevent a denial of service attack vector since an unbounded reader will
-    /// exhaust all memory.
-    ///
-    /// Similar to `std::io::Read::read_to_end` but with the DOS protection.
-    #[doc(alias = "read_to_end")]
-    #[cfg(any(feature = "alloc", feature = "std"))]
-    #[inline]
-    fn read_to_limit(&mut self, buf: &mut Vec<u8>, limit: u64) -> Result<usize> {
-        self.take(limit).read_to_end(buf)
-    }
-}
-
-/// A trait describing an input stream that uses an internal buffer when reading.
-pub trait BufRead: Read {
-    /// Returns data read from this reader, filling the internal buffer if needed.
-    fn fill_buf(&mut self) -> Result<&[u8]>;
-
-    /// Marks the buffered data up to amount as consumed.
-    ///
-    /// # Panics
-    ///
-    /// May panic if `amount` is greater than amount of data read by `fill_buf`.
-    fn consume(&mut self, amount: usize);
 }
 
 pub struct Take<'a, R: Read + ?Sized> {
@@ -80,27 +57,6 @@ pub struct Take<'a, R: Read + ?Sized> {
     remaining: u64,
 }
 
-impl<'a, R: Read + ?Sized> Take<'a, R> {
-    #[cfg(any(feature = "alloc", feature = "std"))]
-    #[inline]
-    fn read_to_end(&mut self, buf: &mut Vec<u8>) -> Result<usize> {
-        let mut read: usize = 0;
-        let mut chunk = [0u8; 64];
-        loop {
-            match self.read(&mut chunk) {
-                Ok(0) => break,
-                Ok(n) => {
-                    buf.extend_from_slice(&chunk[0..n]);
-                    read += n;
-                }
-                Err(ref e) if e.kind() == ErrorKind::Interrupted => {}
-                Err(e) => return Err(e),
-            };
-        }
-        Ok(read)
-    }
-}
-
 impl<'a, R: Read + ?Sized> Read for Take<'a, R> {
     #[inline]
     fn read(&mut self, buf: &mut [u8]) -> Result<usize> {
@@ -111,30 +67,6 @@ fn read(&mut self, buf: &mut [u8]) -> Result<usize> {
     }
 }
 
-// Impl copied from Rust stdlib.
-impl<'a, R: BufRead + ?Sized> BufRead for Take<'a, R> {
-    #[inline]
-    fn fill_buf(&mut self) -> Result<&[u8]> {
-        // Don't call into inner reader at all at EOF because it may still block
-        if self.remaining == 0 {
-            return Ok(&[]);
-        }
-
-        let buf = self.reader.fill_buf()?;
-        // Cast length to a u64 instead of casting `remaining` to a `usize`
-        // (in case `remaining > u32::MAX` and we are on a 32 bit machine).
-        let cap = cmp::min(buf.len() as u64, self.remaining) as usize;
-        Ok(&buf[..cap])
-    }
-
-    #[inline]
-    fn consume(&mut self, amount: usize) {
-        assert!(amount as u64 <= self.remaining);
-        self.remaining -= amount as u64;
-        self.reader.consume(amount);
-    }
-}
-
 #[cfg(feature = "std")]
 impl<R: std::io::Read> Read for R {
     #[inline]
@@ -143,15 +75,6 @@ fn read(&mut self, buf: &mut [u8]) -> Result<usize> {
     }
 }
 
-#[cfg(feature = "std")]
-impl<R: std::io::BufRead + Read + ?Sized> BufRead for R {
-    #[inline]
-    fn fill_buf(&mut self) -> Result<&[u8]> { Ok(std::io::BufRead::fill_buf(self)?) }
-
-    #[inline]
-    fn consume(&mut self, amount: usize) { std::io::BufRead::consume(self, amount) }
-}
-
 #[cfg(not(feature = "std"))]
 impl Read for &[u8] {
     #[inline]
@@ -163,16 +86,6 @@ fn read(&mut self, buf: &mut [u8]) -> Result<usize> {
     }
 }
 
-#[cfg(not(feature = "std"))]
-impl BufRead for &[u8] {
-    #[inline]
-    fn fill_buf(&mut self) -> Result<&[u8]> { Ok(self) }
-
-    // This panics if amount is out of bounds, same as the std version.
-    #[inline]
-    fn consume(&mut self, amount: usize) { *self = &self[amount..] }
-}
-
 pub struct Cursor<T> {
     inner: T,
     pos: u64,
@@ -202,20 +115,6 @@ fn read(&mut self, buf: &mut [u8]) -> Result<usize> {
     }
 }
 
-impl<T: AsRef<[u8]>> BufRead for Cursor<T> {
-    #[inline]
-    fn fill_buf(&mut self) -> Result<&[u8]> {
-        let inner: &[u8] = self.inner.as_ref();
-        Ok(&inner[self.pos as usize..])
-    }
-
-    #[inline]
-    fn consume(&mut self, amount: usize) {
-        assert!(amount <= self.inner.as_ref().len());
-        self.pos += amount as u64;
-    }
-}
-
 /// A generic trait describing an output stream. See [`std::io::Write`] for more info.
 pub trait Write {
     fn write(&mut self, buf: &[u8]) -> Result<usize>;
@@ -303,55 +202,3 @@ fn flush(&mut self) -> std::io::Result<()> { Ok(()) }
 /// Returns a sink to which all writes succeed. See [`std::io::sink`] for more info.
 #[inline]
 pub fn sink() -> Sink { Sink }
-
-#[cfg(test)]
-mod tests {
-    use super::*;
-
-    #[test]
-    fn buf_read_fill_and_consume_slice() {
-        let data = [0_u8, 1, 2];
-
-        let mut slice = &data[..];
-
-        let fill = BufRead::fill_buf(&mut slice).unwrap();
-        assert_eq!(fill.len(), 3);
-        assert_eq!(fill, &[0_u8, 1, 2]);
-        slice.consume(2);
-
-        let fill = BufRead::fill_buf(&mut slice).unwrap();
-        assert_eq!(fill.len(), 1);
-        assert_eq!(fill, &[2_u8]);
-        slice.consume(1);
-
-        // checks we can attempt to read from a now-empty reader.
-        let fill = BufRead::fill_buf(&mut slice).unwrap();
-        assert_eq!(fill.len(), 0);
-        assert_eq!(fill, &[]);
-    }
-
-    #[test]
-    #[cfg(any(feature = "alloc", feature = "std"))]
-    fn read_to_limit_greater_than_total_length() {
-        let s = "16-byte-string!!".to_string();
-        let mut reader = Cursor::new(&s);
-        let mut buf = vec![];
-
-        // 32 is greater than the reader length.
-        let read = reader.read_to_limit(&mut buf, 32).expect("failed to read to limit");
-        assert_eq!(read, s.len());
-        assert_eq!(&buf, s.as_bytes())
-    }
-
-    #[test]
-    #[cfg(any(feature = "alloc", feature = "std"))]
-    fn read_to_limit_less_than_total_length() {
-        let s = "16-byte-string!!".to_string();
-        let mut reader = Cursor::new(&s);
-        let mut buf = vec![];
-
-        let read = reader.read_to_limit(&mut buf, 2).expect("failed to read to limit");
-        assert_eq!(read, 2);
-        assert_eq!(&buf, "16".as_bytes())
-    }
-}
diff --git a/justfile b/justfile
index b52728ca..b9c33a2b 100644
--- a/justfile
+++ b/justfile
@@ -11,12 +11,27 @@ check:
 
 # Lint everything.
 lint:
-  cargo clippy --workspace --all-targets --all-features -- --deny warnings
+  cargo +nightly clippy --workspace --all-targets --all-features -- --deny warnings
 
 # Check the formatting
 format:
   cargo +nightly fmt --all --check
 
+# Quick and dirty CI useful for pre-push checks.
+sane: lint
+  cargo test --quiet --workspace --all-targets --no-default-features > /dev/null || exit 1
+  cargo test --quiet --workspace --all-targets > /dev/null || exit 1
+  cargo test --quiet --workspace --all-targets --all-features > /dev/null || exit 1
+
+  # Docs tests (these don't run when testing from workspace root)
+  cargo test --quiet --manifest-path bitcoin/Cargo.toml --doc > /dev/null  || exit 1
+  cargo test --quiet --manifest-path hashes/Cargo.toml --doc > /dev/null  || exit 1
+  cargo test --quiet --manifest-path io/Cargo.toml --doc > /dev/null  || exit 1
+  cargo test --quiet --manifest-path units/Cargo.toml --doc > /dev/null  || exit 1
+
+  # Make an attempt to catch feature gate problems in doctests
+  cargo test --manifest-path bitcoin/Cargo.toml --doc --no-default-features > /dev/null || exit 1
+
 # Update the recent and minimal lock files.
 update-lock-files:
   contrib/update-lock-files.sh
diff --git a/units/src/amount.rs b/units/src/amount.rs
index 0716cd34..9feba679 100644
--- a/units/src/amount.rs
+++ b/units/src/amount.rs
@@ -59,12 +59,6 @@ pub enum Denomination {
 }
 
 impl Denomination {
-    /// Convenience alias for `Denomination::Bitcoin`.
-    pub const BTC: Self = Denomination::Bitcoin;
-
-    /// Convenience alias for `Denomination::Satoshi`.
-    pub const SAT: Self = Denomination::Satoshi;
-
     /// The number of decimal places more than a satoshi.
     fn precision(self) -> i8 {
         match self {
@@ -145,54 +139,14 @@ fn from_str(s: &str) -> Result<Self, Self::Err> {
     }
 }
 
-/// An error during amount parsing amount with denomination.
-#[derive(Debug, Clone, PartialEq, Eq)]
-#[non_exhaustive]
-pub enum ParseError {
-    /// Invalid amount.
-    Amount(ParseAmountError),
-
-    /// Invalid denomination.
-    Denomination(ParseDenominationError),
-}
-
-impl From<ParseAmountError> for ParseError {
-    fn from(e: ParseAmountError) -> Self { Self::Amount(e) }
-}
-
-impl From<ParseDenominationError> for ParseError {
-    fn from(e: ParseDenominationError) -> Self { Self::Denomination(e) }
-}
-
-impl From<OutOfRangeError> for ParseError {
-    fn from(e: OutOfRangeError) -> Self { Self::Amount(e.into()) }
-}
-
-impl fmt::Display for ParseError {
-    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
-        match self {
-            ParseError::Amount(error) => write_err!(f, "invalid amount"; error),
-            ParseError::Denomination(error) => write_err!(f, "invalid denomination"; error),
-        }
-    }
-}
-
-#[cfg(feature = "std")]
-impl std::error::Error for ParseError {
-    fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
-        match self {
-            ParseError::Amount(error) => Some(error),
-            ParseError::Denomination(error) => Some(error),
-        }
-    }
-}
-
 /// An error during amount parsing.
 #[derive(Debug, Clone, PartialEq, Eq)]
 #[non_exhaustive]
 pub enum ParseAmountError {
-    /// The amount is too big or too small.
-    OutOfRange(OutOfRangeError),
+    /// Amount is negative.
+    Negative,
+    /// Amount is too big to fit inside the type.
+    TooBig,
     /// Amount has higher precision than supported by the type.
     TooPrecise,
     /// Invalid number format.
@@ -201,6 +155,8 @@ pub enum ParseAmountError {
     InputTooLarge,
     /// Invalid character in input.
     InvalidCharacter(char),
+    /// Invalid denomination.
+    InvalidDenomination(ParseDenominationError),
 }
 
 impl fmt::Display for ParseAmountError {
@@ -208,11 +164,13 @@ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
         use ParseAmountError::*;
 
         match *self {
-            OutOfRange(error) => write_err!(f, "amount out of range"; error),
+            Negative => f.write_str("amount is negative"),
+            TooBig => f.write_str("amount is too big"),
             TooPrecise => f.write_str("amount has a too high precision"),
             InvalidFormat => f.write_str("invalid number format"),
             InputTooLarge => f.write_str("input string was too large"),
             InvalidCharacter(c) => write!(f, "invalid character in input: {}", c),
+            InvalidDenomination(ref e) => write_err!(f, "invalid denomination"; e),
         }
     }
 }
@@ -223,85 +181,17 @@ fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
         use ParseAmountError::*;
 
         match *self {
-            TooPrecise | InvalidFormat | InputTooLarge
+            Negative | TooBig | TooPrecise | InvalidFormat | InputTooLarge
             | InvalidCharacter(_) => None,
-            OutOfRange(ref error) => Some(error),
-        }
-    }
-}
-
-/// Returned when a parsed amount is too big or too small.
-#[derive(Debug, Copy, Clone, Eq, PartialEq)]
-pub struct OutOfRangeError {
-    is_signed: bool,
-    is_greater_than_max: bool,
-}
-
-impl OutOfRangeError {
-    /// Returns the minimum and maximum allowed values for the type that was parsed.
-    ///
-    /// This can be used to give a hint to the user which values are allowed.
-    pub fn valid_range(&self) -> (i64, u64) {
-        match self.is_signed {
-            true => (i64::MIN, i64::MAX as u64),
-            false => (0, u64::MAX),
-        }
-    }
-
-    /// Returns true if the input value was large than the maximum allowed value.
-    pub fn is_above_max(&self) -> bool {
-        self.is_greater_than_max
-    }
-
-    /// Returns true if the input value was smaller than the minimum allowed value.
-    pub fn is_below_min(&self) -> bool {
-        !self.is_greater_than_max
-    }
-
-    pub(crate) fn too_big(is_signed: bool) -> Self {
-        Self {
-            is_signed,
-            is_greater_than_max: true,
-        }
-    }
-
-    pub(crate) fn too_small() -> Self {
-        Self {
-            // implied - negative() is used for the other
-            is_signed: true,
-            is_greater_than_max: false,
-        }
-    }
-
-    pub(crate) fn negative() -> Self {
-        Self {
-            // implied - too_small() is used for the other
-            is_signed: false,
-            is_greater_than_max: false,
-        }
-    }
-}
-
-impl fmt::Display for OutOfRangeError {
-    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
-        if self.is_greater_than_max {
-            write!(f, "the amount is greater than {}", self.valid_range().1)
-        } else {
-            write!(f, "the amount is less than {}", self.valid_range().0)
+            InvalidDenomination(ref e) => Some(e),
         }
     }
 }
 
-#[cfg(feature = "std")]
-impl std::error::Error for OutOfRangeError {}
-
-impl From<OutOfRangeError> for ParseAmountError {
-    fn from(value: OutOfRangeError) -> Self {
-        ParseAmountError::OutOfRange(value)
-    }
+impl From<ParseDenominationError> for ParseAmountError {
+    fn from(e: ParseDenominationError) -> Self { Self::InvalidDenomination(e) }
 }
 
-
 /// An error during amount parsing.
 #[derive(Debug, Clone, PartialEq, Eq)]
 #[non_exhaustive]
@@ -381,18 +271,18 @@ fn is_too_precise(s: &str, precision: usize) -> bool {
 fn parse_signed_to_satoshi(
     mut s: &str,
     denom: Denomination,
-) -> Result<(bool, u64), InnerParseError> {
+) -> Result<(bool, u64), ParseAmountError> {
     if s.is_empty() {
-        return Err(InnerParseError::InvalidFormat);
+        return Err(ParseAmountError::InvalidFormat);
     }
     if s.len() > 50 {
-        return Err(InnerParseError::InputTooLarge);
+        return Err(ParseAmountError::InputTooLarge);
     }
 
     let is_negative = s.starts_with('-');
     if is_negative {
         if s.len() == 1 {
-            return Err(InnerParseError::InvalidFormat);
+            return Err(ParseAmountError::InvalidFormat);
         }
         s = &s[1..];
     }
@@ -406,11 +296,11 @@ fn parse_signed_to_satoshi(
             // into a less precise amount. That is not allowed unless
             // there are no decimals and the last digits are zeroes as
             // many as the difference in precision.
-            let last_n = precision_diff.unsigned_abs().into();
+            let last_n = unsigned_abs(precision_diff).into();
             if is_too_precise(s, last_n) {
                 match s.parse::<i64>() {
                     Ok(0) => return Ok((is_negative, 0)),
-                    _ => return Err(InnerParseError::TooPrecise),
+                    _ => return Err(ParseAmountError::TooPrecise),
                 }
             }
             s = &s[0..s.find('.').unwrap_or(s.len()) - last_n];
@@ -427,9 +317,9 @@ fn parse_signed_to_satoshi(
             '0'..='9' => {
                 // Do `value = 10 * value + digit`, catching overflows.
                 match 10_u64.checked_mul(value) {
-                    None => return Err(InnerParseError::Overflow { is_negative }),
+                    None => return Err(ParseAmountError::TooBig),
                     Some(val) => match val.checked_add((c as u8 - b'0') as u64) {
-                        None => return Err(InnerParseError::Overflow { is_negative }),
+                        None => return Err(ParseAmountError::TooBig),
                         Some(val) => value = val,
                     },
                 }
@@ -437,16 +327,16 @@ fn parse_signed_to_satoshi(
                 decimals = match decimals {
                     None => None,
                     Some(d) if d < max_decimals => Some(d + 1),
-                    _ => return Err(InnerParseError::TooPrecise),
+                    _ => return Err(ParseAmountError::TooPrecise),
                 };
             }
             '.' => match decimals {
                 None if max_decimals <= 0 => break,
                 None => decimals = Some(0),
                 // Double decimal dot.
-                _ => return Err(InnerParseError::InvalidFormat),
+                _ => return Err(ParseAmountError::InvalidFormat),
             },
-            c => return Err(InnerParseError::InvalidCharacter(c)),
+            c => return Err(ParseAmountError::InvalidCharacter(c)),
         }
     }
 
@@ -455,34 +345,14 @@ fn parse_signed_to_satoshi(
     for _ in 0..scale_factor {
         value = match 10_u64.checked_mul(value) {
             Some(v) => v,
-            None => return Err(InnerParseError::Overflow { is_negative }),
+            None => return Err(ParseAmountError::TooBig),
         };
     }
 
     Ok((is_negative, value))
 }
 
-enum InnerParseError {
-    Overflow { is_negative: bool },
-    TooPrecise,
-    InvalidFormat,
-    InputTooLarge,
-    InvalidCharacter(char),
-}
-
-impl InnerParseError {
-    fn convert(self, is_signed: bool) -> ParseAmountError {
-        match self {
-            Self::Overflow { is_negative } => OutOfRangeError { is_signed, is_greater_than_max: !is_negative }.into(),
-            Self::TooPrecise => ParseAmountError::TooPrecise,
-            Self::InvalidFormat => ParseAmountError::InvalidFormat,
-            Self::InputTooLarge => ParseAmountError::InputTooLarge,
-            Self::InvalidCharacter(c) => ParseAmountError::InvalidCharacter(c),
-        }
-    }
-}
-
-fn split_amount_and_denomination(s: &str) -> Result<(&str, Denomination), ParseError> {
+fn split_amount_and_denomination(s: &str) -> Result<(&str, Denomination), ParseAmountError> {
     let (i, j) = if let Some(i) = s.find(' ') {
         (i, i + 1)
     } else {
@@ -540,6 +410,9 @@ fn dec_width(mut num: u64) -> usize {
     width
 }
 
+// NIH due to MSRV, impl copied from `core::i8::unsigned_abs` (introduced in Rust 1.51.1).
+fn unsigned_abs(x: i8) -> u8 { x.wrapping_abs() as u8 }
+
 fn repeat_char(f: &mut dyn fmt::Write, c: char, count: usize) -> fmt::Result {
     for _ in 0..count {
         f.write_char(c)?;
@@ -573,7 +446,7 @@ fn fmt_satoshi_in(
             trailing_decimal_zeros = options.precision.unwrap_or(0);
         }
         Ordering::Less => {
-            let precision = precision.unsigned_abs();
+            let precision = unsigned_abs(precision);
             let divisor = 10u64.pow(precision.into());
             num_before_decimal_point = satoshi / divisor;
             num_after_decimal_point = satoshi % divisor;
@@ -734,10 +607,12 @@ pub const fn from_int_btc(btc: u64) -> Amount {
     /// Note: This only parses the value string.  If you want to parse a value
     /// with denomination, use [FromStr].
     pub fn from_str_in(s: &str, denom: Denomination) -> Result<Amount, ParseAmountError> {
-        let (negative, satoshi) = parse_signed_to_satoshi(s, denom)
-            .map_err(|error| error.convert(false))?;
+        let (negative, satoshi) = parse_signed_to_satoshi(s, denom)?;
         if negative {
-            return Err(ParseAmountError::OutOfRange(OutOfRangeError::negative()));
+            return Err(ParseAmountError::Negative);
+        }
+        if satoshi > i64::MAX as u64 {
+            return Err(ParseAmountError::TooBig);
         }
         Ok(Amount::from_sat(satoshi))
     }
@@ -746,9 +621,9 @@ pub fn from_str_in(s: &str, denom: Denomination) -> Result<Amount, ParseAmountEr
     /// [Self::to_string_with_denomination] or with [fmt::Display].
     /// If you want to parse only the amount without the denomination,
     /// use [Self::from_str_in].
-    pub fn from_str_with_denomination(s: &str) -> Result<Amount, ParseError> {
+    pub fn from_str_with_denomination(s: &str) -> Result<Amount, ParseAmountError> {
         let (amt, denom) = split_amount_and_denomination(s)?;
-        Amount::from_str_in(amt, denom).map_err(Into::into)
+        Amount::from_str_in(amt, denom)
     }
 
     /// Express this [Amount] as a floating-point value in the given denomination.
@@ -777,7 +652,7 @@ pub fn to_btc(self) -> f64 { self.to_float_in(Denomination::Bitcoin) }
     /// Please be aware of the risk of using floating-point numbers.
     pub fn from_float_in(value: f64, denom: Denomination) -> Result<Amount, ParseAmountError> {
         if value < 0.0 {
-            return Err(OutOfRangeError::negative().into());
+            return Err(ParseAmountError::Negative);
         }
         // This is inefficient, but the safest way to deal with this. The parsing logic is safe.
         // Any performance-critical application should not be dealing with floats.
@@ -862,7 +737,7 @@ pub fn checked_rem(self, rhs: u64) -> Option<Amount> { self.0.checked_rem(rhs).m
     /// Convert to a signed amount.
     pub fn to_signed(self) -> Result<SignedAmount, ParseAmountError> {
         if self.to_sat() > SignedAmount::MAX.to_sat() as u64 {
-            Err(ParseAmountError::OutOfRange(OutOfRangeError::too_big(true)))
+            Err(ParseAmountError::TooBig)
         } else {
             Ok(SignedAmount::from_sat(self.to_sat() as i64))
         }
@@ -947,7 +822,7 @@ fn div_assign(&mut self, rhs: u64) { *self = *self / rhs }
 }
 
 impl FromStr for Amount {
-    type Err = ParseError;
+    type Err = ParseAmountError;
 
     fn from_str(s: &str) -> Result<Self, Self::Err> { Amount::from_str_with_denomination(s) }
 }
@@ -1065,12 +940,12 @@ pub fn from_btc(btc: f64) -> Result<SignedAmount, ParseAmountError> {
     /// Note: This only parses the value string.  If you want to parse a value
     /// with denomination, use [FromStr].
     pub fn from_str_in(s: &str, denom: Denomination) -> Result<SignedAmount, ParseAmountError> {
-        match parse_signed_to_satoshi(s, denom).map_err(|error| error.convert(true))? {
+        match parse_signed_to_satoshi(s, denom)? {
             // (negative, amount)
-            (false, sat) if sat > i64::MAX as u64 => Err(ParseAmountError::OutOfRange(OutOfRangeError::too_big(true))),
+            (false, sat) if sat > i64::MAX as u64 => Err(ParseAmountError::TooBig),
             (false, sat) => Ok(SignedAmount(sat as i64)),
-            (true, sat) if sat == i64::MIN.unsigned_abs() => Ok(SignedAmount(i64::MIN)),
-            (true, sat) if sat > i64::MIN.unsigned_abs() => Err(ParseAmountError::OutOfRange(OutOfRangeError::too_small())),
+            (true, sat) if sat == i64::MAX as u64 + 1 => Ok(SignedAmount(i64::MIN)),
+            (true, sat) if sat > i64::MAX as u64 + 1 => Err(ParseAmountError::TooBig),
             (true, sat) => Ok(SignedAmount(-(sat as i64))),
         }
     }
@@ -1079,9 +954,9 @@ pub fn from_str_in(s: &str, denom: Denomination) -> Result<SignedAmount, ParseAm
     /// [Self::to_string_with_denomination] or with [fmt::Display].
     /// If you want to parse only the amount without the denomination,
     /// use [Self::from_str_in].
-    pub fn from_str_with_denomination(s: &str) -> Result<SignedAmount, ParseError> {
+    pub fn from_str_with_denomination(s: &str) -> Result<SignedAmount, ParseAmountError> {
         let (amt, denom) = split_amount_and_denomination(s)?;
-        SignedAmount::from_str_in(amt, denom).map_err(Into::into)
+        SignedAmount::from_str_in(amt, denom)
     }
 
     /// Express this [SignedAmount] as a floating-point value in the given denomination.
@@ -1112,10 +987,15 @@ pub fn from_float_in(
         SignedAmount::from_str_in(&value.to_string(), denom)
     }
 
+    /// Returns the absolute value as satoshis.
+    ///
+    /// This is the implementation of `unsigned_abs()` copied from `core` to support older MSRV.
+    fn to_sat_abs(self) -> u64 { self.to_sat().wrapping_abs() as u64 }
+
     /// Create an object that implements [`fmt::Display`] using specified denomination.
     pub fn display_in(self, denomination: Denomination) -> Display {
         Display {
-            sats_abs: self.unsigned_abs().to_sat(),
+            sats_abs: self.to_sat_abs(),
             is_negative: self.is_negative(),
             style: DisplayStyle::FixedDenomination { denomination, show_denomination: false },
         }
@@ -1127,7 +1007,7 @@ pub fn display_in(self, denomination: Denomination) -> Display {
     /// avoid confusion the denomination is always shown.
     pub fn display_dynamic(self) -> Display {
         Display {
-            sats_abs: self.unsigned_abs().to_sat(),
+            sats_abs: self.to_sat_abs(),
             is_negative: self.is_negative(),
             style: DisplayStyle::DynamicDenomination,
         }
@@ -1138,7 +1018,7 @@ pub fn display_dynamic(self) -> Display {
     /// Does not include the denomination.
     #[rustfmt::skip]
     pub fn fmt_value_in(self, f: &mut dyn fmt::Write, denom: Denomination) -> fmt::Result {
-        fmt_satoshi_in(self.unsigned_abs().to_sat(), self.is_negative(), f, denom, false, FormatOptions::default())
+        fmt_satoshi_in(self.to_sat_abs(), self.is_negative(), f, denom, false, FormatOptions::default())
     }
 
     /// Get a string number of this [SignedAmount] in the given denomination.
@@ -1164,9 +1044,6 @@ pub fn to_string_with_denomination(self, denom: Denomination) -> String {
     /// Get the absolute value of this [SignedAmount].
     pub fn abs(self) -> SignedAmount { SignedAmount(self.0.abs()) }
 
-    /// Get the absolute value of this [SignedAmount] returning `Amount`.
-    pub fn unsigned_abs(self) -> Amount { Amount(self.0.unsigned_abs()) }
-
     /// Returns a number representing sign of this [SignedAmount].
     ///
     /// - `0` if the amount is zero
@@ -1229,9 +1106,9 @@ pub fn positive_sub(self, rhs: SignedAmount) -> Option<SignedAmount> {
     }
 
     /// Convert to an unsigned amount.
-    pub fn to_unsigned(self) -> Result<Amount, OutOfRangeError> {
+    pub fn to_unsigned(self) -> Result<Amount, ParseAmountError> {
         if self.is_negative() {
-            Err(OutOfRangeError::negative())
+            Err(ParseAmountError::Negative)
         } else {
             Ok(Amount::from_sat(self.to_sat() as u64))
         }
@@ -1318,7 +1195,7 @@ fn div_assign(&mut self, rhs: i64) { *self = *self / rhs }
 }
 
 impl FromStr for SignedAmount {
-    type Err = ParseError;
+    type Err = ParseAmountError;
 
     fn from_str(s: &str) -> Result<Self, Self::Err> { SignedAmount::from_str_with_denomination(s) }
 }
@@ -1390,10 +1267,9 @@ pub mod serde {
     //! }
     //! ```
 
-    use core::fmt;
     use serde::{Deserialize, Deserializer, Serialize, Serializer};
 
-    use crate::amount::{Amount, Denomination, SignedAmount, ParseAmountError};
+    use crate::amount::{Amount, Denomination, SignedAmount};
 
     /// This trait is used only to avoid code duplication and naming collisions
     /// of the different serde serialization crates.
@@ -1419,30 +1295,6 @@ pub trait SerdeAmountForOpt: Copy + Sized + SerdeAmount + private::Sealed {
         fn ser_btc_opt<S: Serializer>(self, s: S) -> Result<S::Ok, S::Error>;
     }
 
-    struct DisplayFullError(ParseAmountError);
-
-    #[cfg(feature = "std")]
-    impl fmt::Display for DisplayFullError {
-        fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
-            use std::error::Error;
-
-            fmt::Display::fmt(&self.0, f)?;
-            let mut source_opt = self.0.source();
-            while let Some(source) = source_opt {
-                write!(f, ": {}", source)?;
-                source_opt = source.source();
-            }
-            Ok(())
-        }
-    }
-
-    #[cfg(not(feature = "std"))]
-    impl fmt::Display for DisplayFullError {
-        fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
-            fmt::Display::fmt(&self.0, f)
-        }
-    }
-
     impl SerdeAmount for Amount {
         fn ser_sat<S: Serializer>(self, s: S) -> Result<S::Ok, S::Error> {
             u64::serialize(&self.to_sat(), s)
@@ -1455,9 +1307,7 @@ fn ser_btc<S: Serializer>(self, s: S) -> Result<S::Ok, S::Error> {
         }
         fn des_btc<'d, D: Deserializer<'d>>(d: D) -> Result<Self, D::Error> {
             use serde::de::Error;
-            Amount::from_btc(f64::deserialize(d)?)
-                .map_err(DisplayFullError)
-                .map_err(D::Error::custom)
+            Amount::from_btc(f64::deserialize(d)?).map_err(D::Error::custom)
         }
     }
 
@@ -1483,9 +1333,7 @@ fn ser_btc<S: Serializer>(self, s: S) -> Result<S::Ok, S::Error> {
         }
         fn des_btc<'d, D: Deserializer<'d>>(d: D) -> Result<Self, D::Error> {
             use serde::de::Error;
-            SignedAmount::from_btc(f64::deserialize(d)?)
-                .map_err(DisplayFullError)
-                .map_err(D::Error::custom)
+            SignedAmount::from_btc(f64::deserialize(d)?).map_err(D::Error::custom)
         }
     }
 
@@ -1678,7 +1526,7 @@ fn u_amount_add_homomorphic() {
             if n1 <= i64::MAX as u64 {
                 Ok(SignedAmount::from_sat(n1.try_into().unwrap()))
             } else {
-                Err(ParseAmountError::OutOfRange(OutOfRangeError::too_big(false)))
+                Err(ParseAmountError::TooBig)
             },
         );
     }
@@ -1781,7 +1629,7 @@ fn from_str_zero() {
 
             let s = format!("-0 {}", denom);
             match Amount::from_str(&s) {
-                Err(e) => assert_eq!(e, ParseError::Amount(ParseAmountError::OutOfRange(OutOfRangeError::negative()))),
+                Err(e) => assert_eq!(e, ParseAmountError::Negative),
                 Ok(_) => panic!("Unsigned amount from {}", s),
             }
             match SignedAmount::from_str(&s) {
@@ -1859,24 +1707,20 @@ fn floating_point() {
         assert_eq!(f(0.0001234, D::Bitcoin), Ok(sat(12340)));
         assert_eq!(sf(-0.00012345, D::Bitcoin), Ok(ssat(-12345)));
 
-        assert_eq!(f(-100.0, D::MilliSatoshi), Err(OutOfRangeError::negative().into()));
+        assert_eq!(f(-100.0, D::MilliSatoshi), Err(ParseAmountError::Negative));
         assert_eq!(f(11.22, D::Satoshi), Err(ParseAmountError::TooPrecise));
         assert_eq!(sf(-100.0, D::MilliSatoshi), Err(ParseAmountError::TooPrecise));
+        assert_eq!(sf(-100.0, D::MilliSatoshi), Err(ParseAmountError::TooPrecise));
         assert_eq!(f(42.123456781, D::Bitcoin), Err(ParseAmountError::TooPrecise));
-        assert_eq!(sf(-184467440738.0, D::Bitcoin), Err(OutOfRangeError::too_small().into()));
-        assert_eq!(f(18446744073709551617.0, D::Satoshi), Err(OutOfRangeError::too_big(false).into()));
-
-        // Amount can be grater than the max SignedAmount.
-        assert!(f(SignedAmount::MAX.to_float_in(D::Satoshi) + 1.0, D::Satoshi).is_ok());
-
+        assert_eq!(sf(-184467440738.0, D::Bitcoin), Err(ParseAmountError::TooBig));
+        assert_eq!(f(18446744073709551617.0, D::Satoshi), Err(ParseAmountError::TooBig));
         assert_eq!(
-            f(Amount::MAX.to_float_in(D::Satoshi) + 1.0, D::Satoshi),
-            Err(OutOfRangeError::too_big(false).into())
+            f(SignedAmount::MAX.to_float_in(D::Satoshi) + 1.0, D::Satoshi),
+            Err(ParseAmountError::TooBig)
         );
-
         assert_eq!(
-            sf(SignedAmount::MAX.to_float_in(D::Satoshi) + 1.0, D::Satoshi),
-            Err(OutOfRangeError::too_big(true).into())
+            f(Amount::MAX.to_float_in(D::Satoshi) + 1.0, D::Satoshi),
+            Err(ParseAmountError::TooBig)
         );
 
         let btc = move |f| SignedAmount::from_btc(f).unwrap();
@@ -1906,7 +1750,7 @@ fn parsing() {
         assert_eq!(p("0.0 ", btc), Err(ParseAmountError::InvalidCharacter(' ')));
         assert_eq!(p("0.000.000", btc), Err(E::InvalidFormat));
         let more_than_max = format!("1{}", Amount::MAX);
-        assert_eq!(p(&more_than_max, btc), Err(OutOfRangeError::too_big(false).into()));
+        assert_eq!(p(&more_than_max, btc), Err(E::TooBig));
         assert_eq!(p("0.000000042", btc), Err(E::TooPrecise));
         assert_eq!(p("999.0000000", msat), Err(E::TooPrecise));
         assert_eq!(p("1.0000000", msat), Err(E::TooPrecise));
@@ -1937,14 +1781,16 @@ fn parsing() {
         // make sure satoshi > i64::MAX is checked.
         let amount = Amount::from_sat(i64::MAX as u64);
         assert_eq!(Amount::from_str_in(&amount.to_string_in(sat), sat), Ok(amount));
-        assert!(SignedAmount::from_str_in(&(amount + Amount(1)).to_string_in(sat), sat).is_err());
-        assert!(Amount::from_str_in(&(amount + Amount(1)).to_string_in(sat), sat).is_ok());
+        assert_eq!(
+            Amount::from_str_in(&(amount + Amount(1)).to_string_in(sat), sat),
+            Err(E::TooBig)
+        );
 
         assert_eq!(p("12.000", Denomination::MilliSatoshi), Err(E::TooPrecise));
         // exactly 50 chars.
         assert_eq!(
             p("100000000000000.0000000000000000000000000000000000", Denomination::Bitcoin),
-            Err(OutOfRangeError::too_big(false).into())
+            Err(E::TooBig)
         );
         // more than 50 chars.
         assert_eq!(
@@ -2160,12 +2006,13 @@ fn $test_name() {
 
     #[test]
     fn test_unsigned_signed_conversion() {
+        use super::ParseAmountError as E;
         let sa = SignedAmount::from_sat;
         let ua = Amount::from_sat;
 
-        assert_eq!(Amount::MAX.to_signed(), Err(OutOfRangeError::too_big(true).into()));
+        assert_eq!(Amount::MAX.to_signed(), Err(E::TooBig));
         assert_eq!(ua(i64::MAX as u64).to_signed(), Ok(sa(i64::MAX)));
-        assert_eq!(ua(i64::MAX as u64 + 1).to_signed(), Err(OutOfRangeError::too_big(true).into()));
+        assert_eq!(ua(i64::MAX as u64 + 1).to_signed(), Err(E::TooBig));
 
         assert_eq!(sa(i64::MAX).to_unsigned(), Ok(ua(i64::MAX as u64)));
 
@@ -2179,7 +2026,7 @@ fn from_str() {
 
         use super::ParseAmountError as E;
 
-        assert_eq!(Amount::from_str("x BTC"), Err(E::InvalidCharacter('x').into()));
+        assert_eq!(Amount::from_str("x BTC"), Err(E::InvalidCharacter('x')));
         assert_eq!(
             Amount::from_str("xBTC"),
             Err(Unknown(UnknownDenominationError("xBTC".into())).into()),
@@ -2188,56 +2035,42 @@ fn from_str() {
             Amount::from_str("5 BTC BTC"),
             Err(Unknown(UnknownDenominationError("BTC BTC".into())).into()),
         );
-        assert_eq!(Amount::from_str("5BTC BTC"), Err(E::InvalidCharacter('B').into()));
+        assert_eq!(Amount::from_str("5BTC BTC"), Err(E::InvalidCharacter('B')));
         assert_eq!(
             Amount::from_str("5 5 BTC"),
             Err(Unknown(UnknownDenominationError("5 BTC".into())).into()),
         );
 
         #[track_caller]
-        fn ok_case(s: &str, expected: Amount) {
-            assert_eq!(Amount::from_str(s).unwrap(), expected);
-            assert_eq!(Amount::from_str(&s.replace(' ', "")).unwrap(), expected);
-        }
-
-        #[track_caller]
-        fn case(s: &str, expected: Result<Amount, impl Into<ParseError>>) {
-            let expected = expected.map_err(Into::into);
+        fn case(s: &str, expected: Result<Amount, ParseAmountError>) {
             assert_eq!(Amount::from_str(s), expected);
             assert_eq!(Amount::from_str(&s.replace(' ', "")), expected);
         }
 
         #[track_caller]
-        fn ok_scase(s: &str, expected: SignedAmount) {
-            assert_eq!(SignedAmount::from_str(s).unwrap(), expected);
-            assert_eq!(SignedAmount::from_str(&s.replace(' ', "")).unwrap(), expected);
-        }
-
-        #[track_caller]
-        fn scase(s: &str, expected: Result<SignedAmount, impl Into<ParseError>>) {
-            let expected = expected.map_err(Into::into);
+        fn scase(s: &str, expected: Result<SignedAmount, ParseAmountError>) {
             assert_eq!(SignedAmount::from_str(s), expected);
             assert_eq!(SignedAmount::from_str(&s.replace(' ', "")), expected);
         }
 
-        case("5 BCH", Err(Unknown(UnknownDenominationError("BCH".into()))));
+        case("5 BCH", Err(Unknown(UnknownDenominationError("BCH".into())).into()));
 
-        case("-1 BTC", Err(OutOfRangeError::negative()));
-        case("-0.0 BTC", Err(OutOfRangeError::negative()));
+        case("-1 BTC", Err(E::Negative));
+        case("-0.0 BTC", Err(E::Negative));
         case("0.123456789 BTC", Err(E::TooPrecise));
         scase("-0.1 satoshi", Err(E::TooPrecise));
         case("0.123456 mBTC", Err(E::TooPrecise));
         scase("-1.001 bits", Err(E::TooPrecise));
-        scase("-200000000000 BTC", Err(OutOfRangeError::too_small()));
-        case("18446744073709551616 sat", Err(OutOfRangeError::too_big(false)));
+        scase("-200000000000 BTC", Err(E::TooBig));
+        case("18446744073709551616 sat", Err(E::TooBig));
 
-        ok_case(".5 bits", Amount::from_sat(50));
-        ok_scase("-.5 bits", SignedAmount::from_sat(-50));
-        ok_case("0.00253583 BTC", Amount::from_sat(253583));
-        ok_scase("-5 satoshi", SignedAmount::from_sat(-5));
-        ok_case("0.10000000 BTC", Amount::from_sat(100_000_00));
-        ok_scase("-100 bits", SignedAmount::from_sat(-10_000));
-        ok_scase(&format!("{} SAT", i64::MIN), SignedAmount::from_sat(i64::MIN));
+        case(".5 bits", Ok(Amount::from_sat(50)));
+        scase("-.5 bits", Ok(SignedAmount::from_sat(-50)));
+        case("0.00253583 BTC", Ok(Amount::from_sat(253583)));
+        scase("-5 satoshi", Ok(SignedAmount::from_sat(-5)));
+        case("0.10000000 BTC", Ok(Amount::from_sat(100_000_00)));
+        scase("-100 bits", Ok(SignedAmount::from_sat(-10_000)));
+        scase(&format!("{} SAT", i64::MIN), Ok(SignedAmount::from_sat(i64::MIN)));
     }
 
     #[test]
@@ -2282,7 +2115,10 @@ fn to_from_string_in() {
             ua_str(&ua_sat(1_000_000_000_000).to_string_in(D::MilliBitcoin), D::MilliBitcoin),
             Ok(ua_sat(1_000_000_000_000))
         );
-        assert!(ua_str(&ua_sat(u64::MAX).to_string_in(D::MilliBitcoin), D::MilliBitcoin).is_ok());
+        assert_eq!(
+            ua_str(&ua_sat(u64::MAX).to_string_in(D::MilliBitcoin), D::MilliBitcoin),
+            Err(ParseAmountError::TooBig)
+        );
 
         assert_eq!(
             sa_str(&sa_sat(-1).to_string_in(D::MicroBitcoin), D::MicroBitcoin),
@@ -2291,12 +2127,12 @@ fn to_from_string_in() {
 
         assert_eq!(
             sa_str(&sa_sat(i64::MAX).to_string_in(D::Satoshi), D::MicroBitcoin),
-            Err(OutOfRangeError::too_big(true).into())
+            Err(ParseAmountError::TooBig)
         );
         // Test an overflow bug in `abs()`
         assert_eq!(
             sa_str(&sa_sat(i64::MIN).to_string_in(D::Satoshi), D::MicroBitcoin),
-            Err(OutOfRangeError::too_small().into())
+            Err(ParseAmountError::TooBig)
         );
 
         assert_eq!(
@@ -2409,7 +2245,7 @@ struct T {
             serde_json::from_str("{\"amt\": 1000000.000000001, \"samt\": 1}");
         assert!(t.unwrap_err().to_string().contains(&ParseAmountError::TooPrecise.to_string()));
         let t: Result<T, serde_json::Error> = serde_json::from_str("{\"amt\": -1, \"samt\": 1}");
-        assert!(dbg!(t.unwrap_err().to_string()).contains(&OutOfRangeError::negative().to_string()));
+        assert!(t.unwrap_err().to_string().contains(&ParseAmountError::Negative.to_string()));
     }
 
     #[cfg(feature = "serde")]
@@ -2582,7 +2418,7 @@ fn disallow_unknown_denomination() {
         for denom in unknown.iter() {
             match Denomination::from_str(denom) {
                 Ok(_) => panic!("from_str should error for {}", denom),
-                Err(ParseDenominationError::Unknown(_)) => (),
+                Err(ParseDenominationError::Unknown(_)) => {}
                 Err(e) => panic!("unexpected error: {}", e),
             }
         }
diff --git a/units/src/lib.rs b/units/src/lib.rs
index 8ba67671..ed5d2609 100644
--- a/units/src/lib.rs
+++ b/units/src/lib.rs
@@ -29,6 +29,7 @@
 #[cfg(feature = "serde")]
 pub extern crate serde;
 
+// TODO: Make amount module less dependent on an allocator.
 #[cfg(feature = "alloc")]
 pub mod amount;
 


Test patch:
diff --git a/bitcoin/contrib/test.sh b/bitcoin/contrib/test.sh
index 6124872a..45b5b79f 100755
--- a/bitcoin/contrib/test.sh
+++ b/bitcoin/contrib/test.sh
@@ -4,6 +4,11 @@ set -ex
 
 FEATURES="std rand-std rand serde secp-recovery bitcoinconsensus-std base64 bitcoinconsensus"
 
+if [ "$DO_COV" = true ]
+then
+    export RUSTFLAGS="-C link-dead-code"
+fi
+
 cargo --version
 rustc --version
 
diff --git a/bitcoin/tests/serde.rs b/bitcoin/tests/serde.rs
index 6112ce6d..04686a7c 100644
--- a/bitcoin/tests/serde.rs
+++ b/bitcoin/tests/serde.rs
@@ -174,8 +174,8 @@ fn serde_regression_extended_pub_key() {
 fn serde_regression_ecdsa_sig() {
     let s = include_str!("data/serde/ecdsa_sig_hex");
     let sig = ecdsa::Signature {
-        signature: secp256k1::ecdsa::Signature::from_str(s.trim()).unwrap(),
-        sighash_type: EcdsaSighashType::All,
+        sig: secp256k1::ecdsa::Signature::from_str(s.trim()).unwrap(),
+        hash_ty: EcdsaSighashType::All,
     };
 
     let got = serialize(&sig).unwrap();
@@ -348,8 +348,8 @@ fn serde_regression_proprietary_key() {
 fn serde_regression_taproot_sig() {
     let s = include_str!("data/serde/taproot_sig_hex");
     let sig = taproot::Signature {
-        signature: secp256k1::schnorr::Signature::from_str(s.trim()).unwrap(),
-        sighash_type: TapSighashType::All,
+        sig: secp256k1::schnorr::Signature::from_str(s.trim()).unwrap(),
+        hash_ty: TapSighashType::All,
     };
 
     let got = serialize(&sig).unwrap();
diff --git a/hashes/contrib/test.sh b/hashes/contrib/test.sh
index 72ee47ce..a0dc5e34 100755
--- a/hashes/contrib/test.sh
+++ b/hashes/contrib/test.sh
@@ -2,7 +2,7 @@
 
 set -ex
 
-FEATURES="serde std io alloc"
+FEATURES="serde serde-std std io alloc"
 
 cargo --version
 rustc --version