From 518f0970c9554242a5625c09bbdb78ff68b4397c Mon Sep 17 00:00:00 2001 From: "Tobin C. Harding" Date: Sat, 2 Dec 2023 08:50:51 +1100 Subject: [PATCH] Implement ArbitaryOrd for absolute::LockTime At times we would like to provide types that do not implement `PartialOrd` and `Ord` because it does not make sense. I.e., we do not want users writing `a < b`. This could range from kind-of-iffy to down-right-buggy (like comparing absolute locktimes). However this decision effects downstream users who may not care about what the ordering means they just need to use it for some other reason e.g., to use as part of a key for a `BTreeMap` (as we do in `miniscript` requiring the `AbsLockTime` type). A solution to this problem is to provide a wrapper data type that adds `PartialOrd` and `Ord` implementations. I wrote the `ordered` crate is for this very purpose. Feature gate a new dependency on `ordered` and implement `ArbitraryOrd` for `absolute::LockTime`. --- Cargo-minimal.lock | 7 +++++++ Cargo-recent.lock | 7 +++++++ bitcoin/Cargo.toml | 1 + bitcoin/src/blockdata/locktime/absolute.rs | 14 ++++++++++++++ bitcoin/src/lib.rs | 4 ++++ 5 files changed, 33 insertions(+) diff --git a/Cargo-minimal.lock b/Cargo-minimal.lock index 1cae13ca..fb048b8c 100644 --- a/Cargo-minimal.lock +++ b/Cargo-minimal.lock @@ -45,6 +45,7 @@ dependencies = [ "hex-conservative", "hex_lit", "mutagen", + "ordered", "secp256k1", "serde", "serde_json", @@ -235,6 +236,12 @@ 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 90a84ae2..ceda6598 100644 --- a/Cargo-recent.lock +++ b/Cargo-recent.lock @@ -44,6 +44,7 @@ dependencies = [ "hex-conservative", "hex_lit", "mutagen", + "ordered", "secp256k1", "serde", "serde_json", @@ -234,6 +235,12 @@ 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 f06cc572..8c899897 100644 --- a/bitcoin/Cargo.toml +++ b/bitcoin/Cargo.toml @@ -38,6 +38,7 @@ 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/src/blockdata/locktime/absolute.rs b/bitcoin/src/blockdata/locktime/absolute.rs index 4099c2b9..6138aa4f 100644 --- a/bitcoin/src/blockdata/locktime/absolute.rs +++ b/bitcoin/src/blockdata/locktime/absolute.rs @@ -389,6 +389,20 @@ impl<'de> serde::Deserialize<'de> for LockTime { } } +#[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))] diff --git a/bitcoin/src/lib.rs b/bitcoin/src/lib.rs index f92e8b93..a108da24 100644 --- a/bitcoin/src/lib.rs +++ b/bitcoin/src/lib.rs @@ -70,6 +70,10 @@ pub extern crate hex; /// 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;