primitives: Enable pedantic lints

Enable all the pedantic lints and fix warnings.

Notable items:

- `enum_glob_used` import types with a single character alias
- `doc_markdown`: add a whitelist that includes SegWit and OpenSSL
This commit is contained in:
Tobin C. Harding 2025-03-03 15:06:44 +11:00
parent d96d0f72b5
commit df500e9b71
No known key found for this signature in database
GPG Key ID: 40BF9E4C269D6607
12 changed files with 301 additions and 177 deletions

View File

@ -1,3 +1,4 @@
msrv = "1.63.0"
too-many-arguments-threshold = 13
avoid-breaking-exported-api = false
doc-valid-idents = ["SegWit", "OpenSSL"]

View File

@ -40,3 +40,131 @@ rustdoc-args = ["--cfg", "docsrs"]
[lints.rust]
unexpected_cfgs = { level = "deny", check-cfg = ['cfg(mutate)'] }
[lints.clippy]
# Exclude lints we don't think are valuable.
needless_question_mark = "allow" # https://github.com/rust-bitcoin/rust-bitcoin/pull/2134
manual_range_contains = "allow" # More readable than clippy's format.
# Exhaustive list of pedantic clippy lints
assigning_clones = "warn"
bool_to_int_with_if = "warn"
borrow_as_ptr = "warn"
case_sensitive_file_extension_comparisons = "warn"
cast_lossless = "warn"
cast_possible_truncation = "allow" # All casts should include a code comment (except test code).
cast_possible_wrap = "allow" # Same as above re code comment.
cast_precision_loss = "warn"
cast_ptr_alignment = "warn"
cast_sign_loss = "allow" # All casts should include a code comment (except in test code).
checked_conversions = "warn"
cloned_instead_of_copied = "warn"
copy_iterator = "warn"
default_trait_access = "warn"
doc_link_with_quotes = "warn"
doc_markdown = "warn"
empty_enum = "warn"
enum_glob_use = "warn"
expl_impl_clone_on_copy = "warn"
explicit_deref_methods = "warn"
explicit_into_iter_loop = "warn"
explicit_iter_loop = "warn"
filter_map_next = "warn"
flat_map_option = "warn"
float_cmp = "allow" # Bitcoin floats are typically limited to 8 decimal places and we want them exact.
fn_params_excessive_bools = "warn"
from_iter_instead_of_collect = "warn"
if_not_else = "warn"
ignored_unit_patterns = "warn"
implicit_clone = "warn"
implicit_hasher = "warn"
inconsistent_struct_constructor = "warn"
index_refutable_slice = "warn"
inefficient_to_string = "warn"
inline_always = "warn"
into_iter_without_iter = "warn"
invalid_upcast_comparisons = "warn"
items_after_statements = "warn"
iter_filter_is_ok = "warn"
iter_filter_is_some = "warn"
iter_not_returning_iterator = "warn"
iter_without_into_iter = "warn"
large_digit_groups = "warn"
large_futures = "warn"
large_stack_arrays = "warn"
large_types_passed_by_value = "warn"
linkedlist = "warn"
macro_use_imports = "warn"
manual_assert = "warn"
manual_instant_elapsed = "warn"
manual_is_power_of_two = "warn"
manual_is_variant_and = "warn"
manual_let_else = "warn"
manual_ok_or = "warn"
manual_string_new = "warn"
many_single_char_names = "warn"
map_unwrap_or = "warn"
match_bool = "allow" # Adds extra indentation and LOC.
match_on_vec_items = "warn"
match_same_arms = "allow" # Collapses things that are conceptually unrelated to each other.
match_wild_err_arm = "warn"
match_wildcard_for_single_variants = "warn"
maybe_infinite_iter = "warn"
mismatching_type_param_order = "warn"
missing_errors_doc = "allow" # TODO: Write errors section in docs.
missing_fields_in_debug = "warn"
missing_panics_doc = "warn"
must_use_candidate = "allow" # Useful for audit but many false positives.
mut_mut = "warn"
naive_bytecount = "warn"
needless_bitwise_bool = "warn"
needless_continue = "warn"
needless_for_each = "warn"
needless_pass_by_value = "warn"
needless_raw_string_hashes = "warn"
no_effect_underscore_binding = "warn"
no_mangle_with_rust_abi = "warn"
option_as_ref_cloned = "warn"
option_option = "warn"
ptr_as_ptr = "warn"
ptr_cast_constness = "warn"
pub_underscore_fields = "warn"
range_minus_one = "warn"
range_plus_one = "warn"
redundant_closure_for_method_calls = "warn"
redundant_else = "warn"
ref_as_ptr = "warn"
ref_binding_to_reference = "warn"
ref_option = "warn"
ref_option_ref = "warn"
return_self_not_must_use = "warn"
same_functions_in_if_condition = "warn"
semicolon_if_nothing_returned = "warn"
should_panic_without_expect = "warn"
similar_names = "allow" # Too many (subjectively) false positives.
single_char_pattern = "warn"
single_match_else = "warn"
stable_sort_primitive = "warn"
str_split_at_newline = "warn"
string_add_assign = "warn"
struct_excessive_bools = "warn"
struct_field_names = "allow" # TODO: Triggers warning for `witness_elements`.
too_many_lines = "warn"
transmute_ptr_to_ptr = "warn"
trivially_copy_pass_by_ref = "warn"
unchecked_duration_subtraction = "warn"
unicode_not_nfc = "warn"
uninlined_format_args = "allow" # This is a subjective style choice.
unnecessary_box_returns = "warn"
unnecessary_join = "warn"
unnecessary_literal_bound = "warn"
unnecessary_wraps = "warn"
unnested_or_patterns = "allow" # TODO
unreadable_literal = "warn"
unsafe_derive_deserialize = "warn"
unused_async = "warn"
unused_self = "warn"
used_underscore_binding = "warn"
used_underscore_items = "warn"
verbose_bit_mask = "warn"
wildcard_imports = "warn"
zero_sized_map_values = "warn"

View File

@ -281,7 +281,7 @@ impl Version {
///
/// A block is signalling for a soft fork under BIP-9 if the first 3 bits are `001` and
/// the version bit for the specific soft fork is toggled on.
pub fn is_signalling_soft_fork(&self, bit: u8) -> bool {
pub fn is_signalling_soft_fork(self, bit: u8) -> bool {
// Only bits [0, 28] inclusive are used for signalling.
if bit > 28 {
return false;
@ -362,36 +362,36 @@ mod tests {
#[test]
fn version_is_not_signalling_with_invalid_bit() {
let arbitrary_version = Version::from_consensus(1234567890);
let arbitrary_version = Version::from_consensus(1_234_567_890);
// The max bit number to signal is 28.
assert!(!Version::is_signalling_soft_fork(&arbitrary_version, 29));
assert!(!Version::is_signalling_soft_fork(arbitrary_version, 29));
}
#[test]
fn version_is_not_signalling_when_use_version_bit_not_set() {
let version = Version::from_consensus(0b01000000000000000000000000000000);
let version = Version::from_consensus(0b0100_0000_0000_0000_0000_0000_0000_0000);
// Top three bits must be 001 to signal.
assert!(!Version::is_signalling_soft_fork(&version, 1));
assert!(!Version::is_signalling_soft_fork(version, 1));
}
#[test]
fn version_is_signalling() {
let version = Version::from_consensus(0b00100000000000000000000000000010);
assert!(Version::is_signalling_soft_fork(&version, 1));
let version = Version::from_consensus(0b00110000000000000000000000000000);
assert!(Version::is_signalling_soft_fork(&version, 28));
let version = Version::from_consensus(0b0010_0000_0000_0000_0000_0000_0000_0010);
assert!(Version::is_signalling_soft_fork(version, 1));
let version = Version::from_consensus(0b0011_0000_0000_0000_0000_0000_0000_0000);
assert!(Version::is_signalling_soft_fork(version, 28));
}
#[test]
fn version_is_not_signalling() {
let version = Version::from_consensus(0b00100000000000000000000000000010);
assert!(!Version::is_signalling_soft_fork(&version, 0));
let version = Version::from_consensus(0b0010_0000_0000_0000_0000_0000_0000_0010);
assert!(!Version::is_signalling_soft_fork(version, 0));
}
#[test]
fn version_to_consensus() {
let version = Version::from_consensus(1234567890);
assert_eq!(version.to_consensus(), 1234567890);
let version = Version::from_consensus(1_234_567_890);
assert_eq!(version.to_consensus(), 1_234_567_890);
}
// Check that the size of the header consensus serialization matches the const SIZE value

View File

@ -16,12 +16,6 @@
#![warn(missing_docs)]
#![warn(deprecated_in_future)]
#![doc(test(attr(warn(unused))))]
// Pedantic lints that we enforce.
// #![warn(clippy::must_use_candidate)]
#![warn(clippy::return_self_not_must_use)]
// Exclude lints we don't think are valuable.
#![allow(clippy::needless_question_mark)] // https://github.com/rust-bitcoin/rust-bitcoin/pull/2134
#![allow(clippy::manual_range_contains)] // More readable than clippy's format.
#[cfg(feature = "alloc")]
extern crate alloc;

View File

@ -1,6 +1,6 @@
// SPDX-License-Identifier: CC0-1.0
//! Provides type [`LockTime`] that implements the logic around nLockTime/OP_CHECKLOCKTIMEVERIFY.
//! Provides type [`LockTime`] that implements the logic around `nLockTime`/`OP_CHECKLOCKTIMEVERIFY`.
//!
//! There are two types of lock time: lock-by-blockheight and lock-by-blocktime, distinguished by
//! whether `LockTime < LOCKTIME_THRESHOLD`.
@ -22,7 +22,7 @@ pub use units::locktime::absolute::{ConversionError, Height, ParseHeightError, P
/// since epoch).
///
/// Used for transaction lock time (`nLockTime` in Bitcoin Core and [`Transaction::lock_time`]
/// in this library) and also for the argument to opcode 'OP_CHECKLOCKTIMEVERIFY`.
/// in this library) and also for the argument to opcode `OP_CHECKLOCKTIMEVERIFY`.
///
/// ### Note on ordering
///
@ -42,13 +42,13 @@ pub use units::locktime::absolute::{ConversionError, Height, ParseHeightError, P
/// # Examples
///
/// ```
/// # use bitcoin_primitives::absolute::{self, LockTime::*};
/// use bitcoin_primitives::absolute::{self, LockTime as L};
/// # let n = absolute::LockTime::from_consensus(741521); // n OP_CHECKLOCKTIMEVERIFY
/// # let lock_time = absolute::LockTime::from_consensus(741521); // nLockTime
/// // To compare absolute lock times there are various `is_satisfied_*` methods, you may also use:
/// let _is_satisfied = match (n, lock_time) {
/// (Blocks(n), Blocks(lock_time)) => n <= lock_time,
/// (Seconds(n), Seconds(lock_time)) => n <= lock_time,
/// (L::Blocks(n), L::Blocks(lock_time)) => n <= lock_time,
/// (L::Seconds(n), L::Seconds(lock_time)) => n <= lock_time,
/// _ => panic!("handle invalid comparison error"),
/// };
/// ```
@ -126,7 +126,7 @@ impl LockTime {
Ok(Self::from_consensus(lock_time))
}
/// Constructs a new `LockTime` from an nLockTime value or the argument to OP_CHEKCLOCKTIMEVERIFY.
/// Constructs a new `LockTime` from an `nLockTime` value or the argument to `OP_CHEKCLOCKTIMEVERIFY`.
///
/// # Examples
///
@ -138,6 +138,7 @@ impl LockTime {
/// let lock_time = absolute::LockTime::from_consensus(n_lock_time);
/// assert_eq!(lock_time.to_consensus_u32(), n_lock_time);
#[inline]
#[allow(clippy::missing_panics_doc)]
pub fn from_consensus(n: u32) -> Self {
if units::locktime::absolute::is_block_height(n) {
Self::Blocks(Height::from_consensus(n).expect("n is valid"))
@ -197,7 +198,7 @@ impl LockTime {
/// Returns true if both lock times use the same unit i.e., both height based or both time based.
#[inline]
pub const fn is_same_unit(&self, other: LockTime) -> bool {
pub const fn is_same_unit(self, other: LockTime) -> bool {
matches!(
(self, other),
(LockTime::Blocks(_), LockTime::Blocks(_))
@ -207,11 +208,11 @@ impl LockTime {
/// Returns true if this lock time value is a block height.
#[inline]
pub const fn is_block_height(&self) -> bool { matches!(*self, LockTime::Blocks(_)) }
pub const fn is_block_height(self) -> bool { matches!(self, LockTime::Blocks(_)) }
/// Returns true if this lock time value is a block time (UNIX timestamp).
#[inline]
pub const fn is_block_time(&self) -> bool { !self.is_block_height() }
pub const fn is_block_time(self) -> bool { !self.is_block_height() }
/// Returns true if this timelock constraint is satisfied by the respective `height`/`time`.
///
@ -219,7 +220,7 @@ impl LockTime {
/// blocktime based lock it is checked against `time`.
///
/// A 'timelock constraint' refers to the `n` from `n OP_CHEKCLOCKTIMEVERIFY`, this constraint
/// is satisfied if a transaction with nLockTime ([`Transaction::lock_time`]) set to
/// is satisfied if a transaction with `nLockTime` ([`Transaction::lock_time`]) set to
/// `height`/`time` is valid.
///
/// # Examples
@ -236,12 +237,12 @@ impl LockTime {
/// }
/// ````
#[inline]
pub fn is_satisfied_by(&self, height: Height, time: Time) -> bool {
use LockTime::*;
pub fn is_satisfied_by(self, height: Height, time: Time) -> bool {
use LockTime as L;
match *self {
Blocks(n) => n <= height,
Seconds(n) => n <= time,
match self {
L::Blocks(n) => n <= height,
L::Seconds(n) => n <= time,
}
}
@ -265,18 +266,18 @@ impl LockTime {
/// assert!(lock_time.is_implied_by(check));
/// ```
#[inline]
pub fn is_implied_by(&self, other: LockTime) -> bool {
use LockTime::*;
pub fn is_implied_by(self, other: LockTime) -> bool {
use LockTime as L;
match (*self, other) {
(Blocks(this), Blocks(other)) => this <= other,
(Seconds(this), Seconds(other)) => this <= other,
match (self, other) {
(L::Blocks(this), L::Blocks(other)) => this <= other,
(L::Seconds(this), L::Seconds(other)) => this <= other,
_ => false, // Not the same units.
}
}
/// Returns the inner `u32` value. This is the value used when creating this `LockTime`
/// i.e., `n OP_CHECKLOCKTIMEVERIFY` or nLockTime.
/// i.e., `n OP_CHECKLOCKTIMEVERIFY` or `nLockTime`.
///
/// # Warning
///
@ -287,13 +288,13 @@ impl LockTime {
/// # Examples
///
/// ```rust
/// # use bitcoin_primitives::absolute::{self, LockTime::*};
/// use bitcoin_primitives::absolute::{self, LockTime as L};
/// # let n = absolute::LockTime::from_consensus(741521); // n OP_CHECKLOCKTIMEVERIFY
/// # let lock_time = absolute::LockTime::from_consensus(741521 + 1); // nLockTime
///
/// let _is_satisfied = match (n, lock_time) {
/// (Blocks(n), Blocks(lock_time)) => n <= lock_time,
/// (Seconds(n), Seconds(lock_time)) => n <= lock_time,
/// (L::Blocks(n), L::Blocks(lock_time)) => n <= lock_time,
/// (L::Seconds(n), L::Seconds(lock_time)) => n <= lock_time,
/// _ => panic!("invalid comparison"),
/// };
///
@ -324,28 +325,28 @@ impl From<Time> for LockTime {
impl fmt::Debug for LockTime {
#[inline]
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
use LockTime::*;
use LockTime as L;
match *self {
Blocks(ref h) => write!(f, "{} blocks", h),
Seconds(ref t) => write!(f, "{} seconds", t),
L::Blocks(ref h) => write!(f, "{} blocks", h),
L::Seconds(ref t) => write!(f, "{} seconds", t),
}
}
}
impl fmt::Display for LockTime {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
use LockTime::*;
use LockTime as L;
if f.alternate() {
match *self {
Blocks(ref h) => write!(f, "block-height {}", h),
Seconds(ref t) => write!(f, "block-time {} (seconds since epoch)", t),
L::Blocks(ref h) => write!(f, "block-height {}", h),
L::Seconds(ref t) => write!(f, "block-time {} (seconds since epoch)", t),
}
} else {
match *self {
Blocks(ref h) => fmt::Display::fmt(h, f),
Seconds(ref t) => fmt::Display::fmt(t, f),
L::Blocks(ref h) => fmt::Display::fmt(h, f),
L::Seconds(ref t) => fmt::Display::fmt(t, f),
}
}
}
@ -404,7 +405,7 @@ mod tests {
#[test]
fn display_and_alternate() {
let lock_by_height = LockTime::from_consensus(741521);
let lock_by_height = LockTime::from_consensus(741_521);
let s = format!("{}", lock_by_height);
assert_eq!(&s, "741521");
@ -415,25 +416,25 @@ mod tests {
#[test]
fn lock_time_from_hex_lower() {
let lock_by_time = LockTime::from_hex("0x6289c350").unwrap();
assert_eq!(lock_by_time, LockTime::from_consensus(0x6289C350));
assert_eq!(lock_by_time, LockTime::from_consensus(0x6289_C350));
}
#[test]
fn lock_time_from_hex_upper() {
let lock_by_time = LockTime::from_hex("0X6289C350").unwrap();
assert_eq!(lock_by_time, LockTime::from_consensus(0x6289C350));
assert_eq!(lock_by_time, LockTime::from_consensus(0x6289_C350));
}
#[test]
fn lock_time_from_unprefixed_hex_lower() {
let lock_by_time = LockTime::from_unprefixed_hex("6289c350").unwrap();
assert_eq!(lock_by_time, LockTime::from_consensus(0x6289C350));
assert_eq!(lock_by_time, LockTime::from_consensus(0x6289_C350));
}
#[test]
fn lock_time_from_unprefixed_hex_upper() {
let lock_by_time = LockTime::from_unprefixed_hex("6289C350").unwrap();
assert_eq!(lock_by_time, LockTime::from_consensus(0x6289C350));
assert_eq!(lock_by_time, LockTime::from_consensus(0x6289_C350));
}
#[test]
@ -450,7 +451,7 @@ mod tests {
assert!(lock_by_height.is_block_height());
assert!(!lock_by_height.is_block_time());
let t: u32 = 1653195600; // May 22nd, 5am UTC.
let t: u32 = 1_653_195_600; // May 22nd, 5am UTC.
let lock_by_time = LockTime::from_consensus(t);
assert!(!lock_by_time.is_block_height());
@ -459,7 +460,7 @@ mod tests {
// Test is_same_unit() logic
assert!(lock_by_height.is_same_unit(LockTime::from_consensus(800_000)));
assert!(!lock_by_height.is_same_unit(lock_by_time));
assert!(lock_by_time.is_same_unit(LockTime::from_consensus(1653282000)));
assert!(lock_by_time.is_same_unit(LockTime::from_consensus(1_653_282_000)));
assert!(!lock_by_time.is_same_unit(lock_by_height));
}
@ -471,7 +472,7 @@ mod tests {
let height_above = Height::from_consensus(800_000).expect("failed to parse height");
let height_below = Height::from_consensus(700_000).expect("failed to parse height");
let t: u32 = 1653195600; // May 22nd, 5am UTC.
let t: u32 = 1_653_195_600; // May 22nd, 5am UTC.
let time = Time::from_consensus(t).expect("invalid time value");
assert!(lock_by_height.is_satisfied_by(height_same, time));
@ -481,11 +482,11 @@ mod tests {
#[test]
fn satisfied_by_time() {
let lock_by_time = LockTime::from_consensus(1653195600); // May 22nd 2022, 5am UTC.
let lock_by_time = LockTime::from_consensus(1_653_195_600); // May 22nd 2022, 5am UTC.
let time_same = Time::from_consensus(1653195600).expect("May 22nd 2022, 5am UTC");
let time_after = Time::from_consensus(1653282000).expect("May 23rd 2022, 5am UTC");
let time_before = Time::from_consensus(1653109200).expect("May 21th 2022, 5am UTC");
let time_same = Time::from_consensus(1_653_195_600).expect("May 22nd 2022, 5am UTC");
let time_after = Time::from_consensus(1_653_282_000).expect("May 23rd 2022, 5am UTC");
let time_before = Time::from_consensus(1_653_109_200).expect("May 21th 2022, 5am UTC");
let height = Height::from_consensus(800_000).expect("failed to parse height");
@ -505,17 +506,17 @@ mod tests {
#[test]
fn time_correctly_implies() {
let t: u32 = 1700000005;
let t: u32 = 1_700_000_005;
let lock_by_time = LockTime::from_consensus(t);
assert!(!lock_by_time.is_implied_by(LockTime::from_consensus(1700000004)));
assert!(lock_by_time.is_implied_by(LockTime::from_consensus(1700000005)));
assert!(lock_by_time.is_implied_by(LockTime::from_consensus(1700000006)));
assert!(!lock_by_time.is_implied_by(LockTime::from_consensus(1_700_000_004)));
assert!(lock_by_time.is_implied_by(LockTime::from_consensus(1_700_000_005)));
assert!(lock_by_time.is_implied_by(LockTime::from_consensus(1_700_000_006)));
}
#[test]
fn incorrect_units_do_not_imply() {
let lock_by_height = LockTime::from_consensus(750_005);
assert!(!lock_by_height.is_implied_by(LockTime::from_consensus(1700000004)));
assert!(!lock_by_height.is_implied_by(LockTime::from_consensus(1_700_000_004)));
}
}

View File

@ -1,6 +1,6 @@
// SPDX-License-Identifier: CC0-1.0
//! Provides type [`LockTime`] that implements the logic around nSequence/OP_CHECKSEQUENCEVERIFY.
//! Provides type [`LockTime`] that implements the logic around `nSequence`/`OP_CHECKSEQUENCEVERIFY`.
//!
//! There are two types of lock time: lock-by-blockheight and lock-by-blocktime, distinguished by
//! whether bit 22 of the `u32` consensus value is set.
@ -18,7 +18,7 @@ pub use units::locktime::relative::{Height, Time, TimeOverflowError};
/// A relative lock time value, representing either a block height or time (512 second intervals).
///
/// Used for sequence numbers (`nSequence` in Bitcoin Core and [`TxIn::sequence`]
/// in this library) and also for the argument to opcode 'OP_CHECKSEQUENCEVERIFY`.
/// in this library) and also for the argument to opcode `OP_CHECKSEQUENCEVERIFY`.
///
/// ### Note on ordering
///
@ -64,7 +64,7 @@ impl LockTime {
/// The number of bytes that the locktime contributes to the size of a transaction.
pub const SIZE: usize = 4; // Serialized length of a u32.
/// Constructs a new `LockTime` from an nSequence value or the argument to OP_CHECKSEQUENCEVERIFY.
/// Constructs a new `LockTime` from an `nSequence` value or the argument to `OP_CHECKSEQUENCEVERIFY`.
///
/// This method will **not** round-trip with [`Self::to_consensus_u32`], because relative
/// locktimes only use some bits of the underlying `u32` value and discard the rest. If
@ -95,7 +95,7 @@ impl LockTime {
sequence.to_relative_lock_time().ok_or(DisabledLockTimeError(n))
}
/// Returns the `u32` value used to encode this locktime in an nSequence field or
/// Returns the `u32` value used to encode this locktime in an `nSequence` field or
/// argument to `OP_CHECKSEQUENCEVERIFY`.
///
/// # Warning
@ -178,7 +178,7 @@ impl LockTime {
/// Returns true if both lock times use the same unit i.e., both height based or both time based.
#[inline]
pub const fn is_same_unit(&self, other: LockTime) -> bool {
pub const fn is_same_unit(self, other: LockTime) -> bool {
matches!(
(self, other),
(LockTime::Blocks(_), LockTime::Blocks(_)) | (LockTime::Time(_), LockTime::Time(_))
@ -187,11 +187,11 @@ impl LockTime {
/// Returns true if this lock time value is in units of block height.
#[inline]
pub const fn is_block_height(&self) -> bool { matches!(*self, LockTime::Blocks(_)) }
pub const fn is_block_height(self) -> bool { matches!(self, LockTime::Blocks(_)) }
/// Returns true if this lock time value is in units of time.
#[inline]
pub const fn is_block_time(&self) -> bool { !self.is_block_height() }
pub const fn is_block_time(self) -> bool { !self.is_block_height() }
/// Returns true if this [`relative::LockTime`] is satisfied by either height or time.
///
@ -211,7 +211,7 @@ impl LockTime {
/// assert!(lock.is_satisfied_by(current_height(), current_time()));
/// ```
#[inline]
pub fn is_satisfied_by(&self, h: Height, t: Time) -> bool {
pub fn is_satisfied_by(self, h: Height, t: Time) -> bool {
if let Ok(true) = self.is_satisfied_by_height(h) {
true
} else {
@ -249,12 +249,12 @@ impl LockTime {
/// assert!(satisfied);
/// ```
#[inline]
pub fn is_implied_by(&self, other: LockTime) -> bool {
use LockTime::*;
pub fn is_implied_by(self, other: LockTime) -> bool {
use LockTime as L;
match (*self, other) {
(Blocks(this), Blocks(other)) => this.value() <= other.value(),
(Time(this), Time(other)) => this.value() <= other.value(),
match (self, other) {
(L::Blocks(this), L::Blocks(other)) => this.value() <= other.value(),
(L::Time(this), L::Time(other)) => this.value() <= other.value(),
_ => false, // Not the same units.
}
}
@ -280,7 +280,7 @@ impl LockTime {
/// # Ok::<_, bitcoin_primitives::relative::DisabledLockTimeError>(())
/// ```
#[inline]
pub fn is_implied_by_sequence(&self, other: Sequence) -> bool {
pub fn is_implied_by_sequence(self, other: Sequence) -> bool {
if let Ok(other) = LockTime::from_sequence(other) {
self.is_implied_by(other)
} else {
@ -305,12 +305,12 @@ impl LockTime {
/// assert!(lock.is_satisfied_by_height(relative::Height::from(required_height + 1)).expect("a height"));
/// ```
#[inline]
pub fn is_satisfied_by_height(&self, height: Height) -> Result<bool, IncompatibleHeightError> {
use LockTime::*;
pub fn is_satisfied_by_height(self, height: Height) -> Result<bool, IncompatibleHeightError> {
use LockTime as L;
match *self {
Blocks(ref required_height) => Ok(required_height.value() <= height.value()),
Time(time) => Err(IncompatibleHeightError { height, time }),
match self {
L::Blocks(ref required_height) => Ok(required_height.value() <= height.value()),
L::Time(time) => Err(IncompatibleHeightError { height, time }),
}
}
@ -331,12 +331,12 @@ impl LockTime {
/// assert!(lock.is_satisfied_by_time(relative::Time::from_512_second_intervals(intervals + 10)).expect("a time"));
/// ```
#[inline]
pub fn is_satisfied_by_time(&self, time: Time) -> Result<bool, IncompatibleTimeError> {
use LockTime::*;
pub fn is_satisfied_by_time(self, time: Time) -> Result<bool, IncompatibleTimeError> {
use LockTime as L;
match *self {
Time(ref t) => Ok(t.value() <= time.value()),
Blocks(height) => Err(IncompatibleTimeError { time, height }),
match self {
L::Time(ref t) => Ok(t.value() <= time.value()),
L::Blocks(height) => Err(IncompatibleTimeError { time, height }),
}
}
}
@ -353,17 +353,17 @@ impl From<Time> for LockTime {
impl fmt::Display for LockTime {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
use LockTime::*;
use LockTime as L;
if f.alternate() {
match *self {
Blocks(ref h) => write!(f, "block-height {}", h),
Time(ref t) => write!(f, "block-time {} (512 second intervals)", t),
L::Blocks(ref h) => write!(f, "block-height {}", h),
L::Time(ref t) => write!(f, "block-time {} (512 second intervals)", t),
}
} else {
match *self {
Blocks(ref h) => fmt::Display::fmt(h, f),
Time(ref t) => fmt::Display::fmt(t, f),
L::Blocks(ref h) => fmt::Display::fmt(h, f),
L::Time(ref t) => fmt::Display::fmt(t, f),
}
}
}

View File

@ -31,6 +31,7 @@ pub struct Opcode {
code: u8,
}
#[allow(clippy::wildcard_imports)]
use self::all::*;
macro_rules! all_opcodes {
@ -41,7 +42,7 @@ macro_rules! all_opcodes {
/// get all the `OP_FOO` opcodes without getting other types defined in `opcodes` (e.g. `Opcode`, `Class`).
///
/// This module is guaranteed to never contain anything except opcode constants and all opcode
/// constants are guaranteed to begin with OP_.
/// constants are guaranteed to begin with `OP_`.
pub mod all {
use super::Opcode;
$(
@ -52,13 +53,13 @@ macro_rules! all_opcodes {
/// Push an empty array onto the stack.
pub static OP_0: Opcode = OP_PUSHBYTES_0;
/// Empty stack is also FALSE.
/// Empty stack is also `FALSE`.
pub static OP_FALSE: Opcode = OP_PUSHBYTES_0;
/// Number 1 is also TRUE.
pub static OP_TRUE: Opcode = OP_PUSHNUM_1;
/// Previously called OP_NOP2.
/// Previously called `OP_NOP2`.
pub static OP_NOP2: Opcode = OP_CLTV;
/// Previously called OP_NOP3.
/// Previously called `OP_NOP3`.
pub static OP_NOP3: Opcode = OP_CSV;
impl fmt::Display for Opcode {
@ -402,10 +403,10 @@ impl Opcode {
// 16 opcodes of PushNum class
(op, _) if op.code >= OP_PUSHNUM_1.code && op.code <= OP_PUSHNUM_16.code =>
Class::PushNum(1 + self.code as i32 - OP_PUSHNUM_1.code as i32),
Class::PushNum(1 + i32::from(self.code) - i32::from(OP_PUSHNUM_1.code)),
// 76 opcodes of PushBytes class
(op, _) if op.code <= OP_PUSHBYTES_75.code => Class::PushBytes(self.code as u32),
(op, _) if op.code <= OP_PUSHBYTES_75.code => Class::PushBytes(u32::from(self.code)),
// opcodes of Ordinary class: 61 for Legacy and 60 for TapScript context
(_, _) => Class::Ordinary(Ordinary::with(self)),
@ -640,6 +641,7 @@ mod tests {
}
#[test]
#[allow(clippy::too_many_lines)] // This is fine, we never need to read it.
fn str_roundtrip() {
let mut unique = HashSet::new();
roundtrip!(unique, OP_PUSHBYTES_0);

View File

@ -52,9 +52,9 @@ mod tests {
#[test]
fn compact_target_ordering() {
let lower = CompactTarget::from_consensus(0x1d00fffe);
let lower_copy = CompactTarget::from_consensus(0x1d00fffe);
let higher = CompactTarget::from_consensus(0x1d00ffff);
let lower = CompactTarget::from_consensus(0x1d00_fffe);
let lower_copy = CompactTarget::from_consensus(0x1d00_fffe);
let higher = CompactTarget::from_consensus(0x1d00_ffff);
assert!(lower < higher);
assert!(lower == lower_copy);
@ -62,9 +62,9 @@ mod tests {
#[test]
fn compact_target_formatting() {
let compact_target = CompactTarget::from_consensus(0x1d00ffff);
let compact_target = CompactTarget::from_consensus(0x1d00_ffff);
assert_eq!(format!("{:x}", compact_target), "1d00ffff");
assert_eq!(format!("{:X}", compact_target), "1D00FFFF");
assert_eq!(compact_target.to_consensus(), 0x1d00ffff);
assert_eq!(compact_target.to_consensus(), 0x1d00_ffff);
}
}

View File

@ -13,6 +13,7 @@ use hashes::{hash160, sha256};
use hex::DisplayHex;
use internals::script::{self, PushDataLenLen};
#[allow(clippy::wildcard_imports)]
use crate::opcodes::all::*;
use crate::opcodes::{self, Opcode};
use crate::prelude::rc::Rc;
@ -522,14 +523,6 @@ impl<'de> serde::Deserialize<'de> for &'de Script {
where
D: serde::Deserializer<'de>,
{
if deserializer.is_human_readable() {
use crate::serde::de::Error;
return Err(D::Error::custom(
"deserialization of `&Script` from human-readable formats is not possible",
));
}
struct Visitor;
impl<'de> serde::de::Visitor<'de> for Visitor {
type Value = &'de Script;
@ -545,6 +538,15 @@ impl<'de> serde::Deserialize<'de> for &'de Script {
Ok(Script::from_bytes(v))
}
}
if deserializer.is_human_readable() {
use crate::serde::de::Error;
return Err(D::Error::custom(
"deserialization of `&Script` from human-readable formats is not possible",
));
}
deserializer.deserialize_bytes(Visitor)
}
}

View File

@ -36,7 +36,7 @@ impl Sequence {
/// The maximum allowable sequence number.
///
/// The sequence number that disables replace-by-fee, absolute lock time and relative lock time.
pub const MAX: Self = Sequence(0xFFFFFFFF);
pub const MAX: Self = Sequence(0xFFFF_FFFF);
/// Zero value sequence.
///
/// This sequence number enables replace-by-fee and absolute lock time.
@ -49,12 +49,12 @@ impl Sequence {
/// The sequence number that enables replace-by-fee and absolute lock time but
/// disables relative lock time.
#[deprecated(since = "TBD", note = "use `ENABLE_LOCKTIME_AND_RBF` instead")]
pub const ENABLE_RBF_NO_LOCKTIME: Self = Sequence(0xFFFFFFFD);
pub const ENABLE_RBF_NO_LOCKTIME: Self = Sequence(0xFFFF_FFFD);
/// The maximum sequence number that enables replace-by-fee and absolute lock time but
/// disables relative lock time.
///
/// This sequence number has no meaning other than to enable RBF and the absolute locktime.
pub const ENABLE_LOCKTIME_AND_RBF: Self = Sequence(0xFFFFFFFD);
pub const ENABLE_LOCKTIME_AND_RBF: Self = Sequence(0xFFFF_FFFD);
/// The number of bytes that a sequence number contributes to the size of a transaction.
pub const SIZE: usize = 4; // Serialized length of a u32.
@ -66,15 +66,15 @@ impl Sequence {
/// (Explicit Signalling [BIP-125]).
///
/// [BIP-125]: <https://github.com/bitcoin/bips/blob/master/bip-0125.mediawiki]>
const MIN_NO_RBF: Self = Sequence(0xFFFFFFFE);
const MIN_NO_RBF: Self = Sequence(0xFFFF_FFFE);
/// BIP-68 relative lock time disable flag mask.
const LOCK_TIME_DISABLE_FLAG_MASK: u32 = 0x80000000;
const LOCK_TIME_DISABLE_FLAG_MASK: u32 = 0x8000_0000;
/// BIP-68 relative lock time type flag mask.
const LOCK_TYPE_MASK: u32 = 0x00400000;
const LOCK_TYPE_MASK: u32 = 0x0040_0000;
/// Returns `true` if the sequence number enables absolute lock-time ([`Transaction::lock_time`]).
#[inline]
pub fn enables_absolute_lock_time(&self) -> bool { *self != Sequence::MAX }
pub fn enables_absolute_lock_time(self) -> bool { self != Sequence::MAX }
/// Returns `true` if the sequence number indicates that the transaction is finalized.
///
@ -96,30 +96,30 @@ impl Sequence {
///
/// [BIP-112]: <https://github.com/bitcoin/bips/blob/master/bip-0065.mediawiki>
#[inline]
pub fn is_final(&self) -> bool { !self.enables_absolute_lock_time() }
pub fn is_final(self) -> bool { !self.enables_absolute_lock_time() }
/// Returns true if the transaction opted-in to BIP125 replace-by-fee.
///
/// Replace by fee is signaled by the sequence being less than 0xfffffffe which is checked by
/// this method. Note, this is the highest "non-final" value (see [`Sequence::is_final`]).
#[inline]
pub fn is_rbf(&self) -> bool { *self < Sequence::MIN_NO_RBF }
pub fn is_rbf(self) -> bool { self < Sequence::MIN_NO_RBF }
/// Returns `true` if the sequence has a relative lock-time.
#[inline]
pub fn is_relative_lock_time(&self) -> bool {
pub fn is_relative_lock_time(self) -> bool {
self.0 & Sequence::LOCK_TIME_DISABLE_FLAG_MASK == 0
}
/// Returns `true` if the sequence number encodes a block based relative lock-time.
#[inline]
pub fn is_height_locked(&self) -> bool {
pub fn is_height_locked(self) -> bool {
self.is_relative_lock_time() & (self.0 & Sequence::LOCK_TYPE_MASK == 0)
}
/// Returns `true` if the sequence number encodes a time interval based relative lock-time.
#[inline]
pub fn is_time_locked(&self) -> bool {
pub fn is_time_locked(self) -> bool {
self.is_relative_lock_time() & (self.0 & Sequence::LOCK_TYPE_MASK > 0)
}
@ -206,7 +206,7 @@ impl Sequence {
///
/// BIP-68 only uses the low 16 bits for relative lock value.
#[inline]
fn low_u16(&self) -> u16 { self.0 as u16 }
fn low_u16(self) -> u16 { self.0 as u16 }
}
impl Default for Sequence {
@ -319,9 +319,9 @@ mod tests {
#[test]
fn sequence_properties() {
let seq_max = Sequence(0xFFFFFFFF);
let seq_no_rbf = Sequence(0xFFFFFFFE);
let seq_rbf = Sequence(0xFFFFFFFD);
let seq_max = Sequence(0xFFFF_FFFF);
let seq_no_rbf = Sequence(0xFFFF_FFFE);
let seq_rbf = Sequence(0xFFFF_FFFD);
assert!(seq_max.is_final());
assert!(!seq_no_rbf.is_final());
@ -332,12 +332,12 @@ mod tests {
assert!(seq_rbf.is_rbf());
assert!(!seq_no_rbf.is_rbf());
let seq_relative = Sequence(0x7FFFFFFF);
let seq_relative = Sequence(0x7FFF_FFFF);
assert!(seq_relative.is_relative_lock_time());
assert!(!seq_max.is_relative_lock_time());
let seq_height_locked = Sequence(0x00399999);
let seq_time_locked = Sequence(0x00400000);
let seq_height_locked = Sequence(0x0039_9999);
let seq_time_locked = Sequence(0x0040_0000);
assert!(seq_height_locked.is_height_locked());
assert!(seq_time_locked.is_time_locked());
assert!(!seq_time_locked.is_height_locked());
@ -346,12 +346,12 @@ mod tests {
#[test]
fn sequence_formatting() {
let sequence = Sequence(0x7FFFFFFF);
let sequence = Sequence(0x7FFF_FFFF);
assert_eq!(format!("{:x}", sequence), "7fffffff");
assert_eq!(format!("{:X}", sequence), "7FFFFFFF");
// Test From<Sequence> for u32
let sequence_u32: u32 = sequence.into();
assert_eq!(sequence_u32, 0x7FFFFFFF);
assert_eq!(sequence_u32, 0x7FFF_FFFF);
}
}

View File

@ -265,7 +265,7 @@ fn hash_transaction(tx: &Transaction, uses_segwit_serialization: bool) -> sha256
enc.input(compact_size::encode(script_sig_bytes.len()).as_slice());
enc.input(script_sig_bytes);
enc.input(&input.sequence.0.to_le_bytes())
enc.input(&input.sequence.0.to_le_bytes());
}
// Encode outputs with leading compact size encoded int.
@ -285,7 +285,7 @@ fn hash_transaction(tx: &Transaction, uses_segwit_serialization: bool) -> sha256
for input in &tx.input {
// Same as `Encodable for Witness`.
enc.input(compact_size::encode(input.witness.len()).as_slice());
for element in input.witness.iter() {
for element in &input.witness {
enc.input(compact_size::encode(element.len()).as_slice());
enc.input(element);
}
@ -322,9 +322,9 @@ pub struct TxIn {
/// the miner behavior cannot be enforced.
pub sequence: Sequence,
/// Witness data: an array of byte-arrays.
/// Note that this field is *not* (de)serialized with the rest of the TxIn in
/// Note that this field is *not* (de)serialized with the rest of the `TxIn` in
/// Encodable/Decodable, as it is (de)serialized at the end of the full
/// Transaction. It *is* (de)serialized with the rest of the TxIn in other
/// Transaction. It *is* (de)serialized with the rest of the `TxIn` in other
/// (de)serialization routines.
pub witness: Witness,
}
@ -459,14 +459,14 @@ impl From<Infallible> for ParseOutPointError {
#[cfg(feature = "alloc")]
impl fmt::Display for ParseOutPointError {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
use ParseOutPointError::*;
use ParseOutPointError as E;
match *self {
Txid(ref e) => write_err!(f, "error parsing TXID"; e),
Vout(ref e) => write_err!(f, "error parsing vout"; e),
Format => write!(f, "OutPoint not in <txid>:<vout> format"),
TooLong => write!(f, "vout should be at most 10 digits"),
VoutNotCanonical => write!(f, "no leading zeroes or + allowed in vout part"),
E::Txid(ref e) => write_err!(f, "error parsing TXID"; e),
E::Vout(ref e) => write_err!(f, "error parsing vout"; e),
E::Format => write!(f, "OutPoint not in <txid>:<vout> format"),
E::TooLong => write!(f, "vout should be at most 10 digits"),
E::VoutNotCanonical => write!(f, "no leading zeroes or + allowed in vout part"),
}
}
}
@ -474,12 +474,12 @@ impl fmt::Display for ParseOutPointError {
#[cfg(feature = "std")]
impl std::error::Error for ParseOutPointError {
fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
use ParseOutPointError::*;
use ParseOutPointError as E;
match self {
Txid(e) => Some(e),
Vout(e) => Some(e),
Format | TooLong | VoutNotCanonical => None,
E::Txid(e) => Some(e),
E::Vout(e) => Some(e),
E::Format | E::TooLong | E::VoutNotCanonical => None,
}
}
}
@ -561,8 +561,8 @@ impl Version {
/// As of Bitcoin Core 28.0 ([release notes](https://bitcoincore.org/en/releases/28.0/)),
/// versions 1, 2, and 3 are considered standard.
#[inline]
pub fn is_standard(&self) -> bool {
*self == Version::ONE || *self == Version::TWO || *self == Version::THREE
pub fn is_standard(self) -> bool {
self == Version::ONE || self == Version::TWO || self == Version::THREE
}
}
@ -657,11 +657,11 @@ mod tests {
witness: Witness::new(),
};
let txout = TxOut { value: Amount::from_sat(123456789), script_pubkey: ScriptBuf::new() };
let txout = TxOut { value: Amount::from_sat(123_456_789), script_pubkey: ScriptBuf::new() };
let tx_orig = Transaction {
version: Version::ONE,
lock_time: absolute::LockTime::from_consensus(1738968231), // The time this was written
lock_time: absolute::LockTime::from_consensus(1_738_968_231), // The time this was written
input: vec![txin.clone()],
output: vec![txout.clone()],
};
@ -669,9 +669,9 @@ mod tests {
// Test changing the transaction
let mut tx = tx_orig.clone();
tx.inputs_mut()[0].previous_output.txid = Txid::from_byte_array([0xFF; 32]);
tx.outputs_mut()[0].value = Amount::from_sat(987654321);
tx.outputs_mut()[0].value = Amount::from_sat(987_654_321);
assert_eq!(tx.inputs()[0].previous_output.txid.to_byte_array(), [0xFF; 32]);
assert_eq!(tx.outputs()[0].value.to_sat(), 987654321);
assert_eq!(tx.outputs()[0].value.to_sat(), 987_654_321);
// Test uses_segwit_serialization
assert!(!tx.uses_segwit_serialization());

View File

@ -100,7 +100,7 @@ impl Witness {
/// Convenience method to create an array of byte-arrays from this witness.
#[inline]
pub fn to_vec(&self) -> Vec<Vec<u8>> { self.iter().map(|s| s.to_vec()).collect() }
pub fn to_vec(&self) -> Vec<Vec<u8>> { self.iter().map(<[u8]>::to_vec).collect() }
/// Returns `true` if the witness contains no element.
#[inline]
@ -172,17 +172,6 @@ impl Witness {
.copy_from_slice(new_element);
}
/// Note `index` is the index into the `content` vector and should be the result of calling
/// `decode_cursor`, which returns a valid index.
fn element_at(&self, index: usize) -> Option<&[u8]> {
let mut slice = &self.content[index..]; // Start of element.
let element_len = compact_size::decode_unchecked(&mut slice);
// Compact size should always fit into a u32 because of `MAX_SIZE` in Core.
// ref: https://github.com/rust-bitcoin/rust-bitcoin/issues/3264
let end = element_len as usize;
Some(&slice[..end])
}
/// Returns the last element in the witness, if any.
#[inline]
pub fn last(&self) -> Option<&[u8]> {
@ -217,7 +206,13 @@ impl Witness {
#[inline]
pub fn nth(&self, index: usize) -> Option<&[u8]> {
let pos = decode_cursor(&self.content, self.indices_start, index)?;
self.element_at(pos)
let mut slice = &self.content[pos..]; // Start of element.
let element_len = compact_size::decode_unchecked(&mut slice);
// Compact size should always fit into a u32 because of `MAX_SIZE` in Core.
// ref: https://github.com/rust-bitcoin/rust-bitcoin/issues/3264
let end = element_len as usize;
Some(&slice[..end])
}
}
@ -247,9 +242,10 @@ fn decode_cursor(bytes: &[u8], start_of_indices: usize, index: usize) -> Option<
/// - Number of witness elements
/// - Total bytes across all elements
/// - List of hex-encoded witness elements
#[allow(clippy::missing_fields_in_debug)] // We don't want to show `indices_start`.
impl fmt::Debug for Witness {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
let total_bytes: usize = self.iter().map(|elem| elem.len()).sum();
let total_bytes: usize = self.iter().map(<[u8]>::len).sum();
f.debug_struct("Witness")
.field("num_elements", &self.witness_elements)
@ -257,7 +253,7 @@ impl fmt::Debug for Witness {
.field(
"elements",
&WrapDebug(|f| {
f.debug_list().entries(self.iter().map(|elem| elem.as_hex())).finish()
f.debug_list().entries(self.iter().map(DisplayHex::as_hex)).finish()
}),
)
.finish()
@ -323,7 +319,7 @@ impl serde::Serialize for Witness {
let mut seq = serializer.serialize_seq(Some(self.witness_elements))?;
// Note that the `Iter` strips the varints out when iterating.
for elem in self.iter() {
for elem in self {
if human_readable {
seq.serialize_element(&internals::serde::SerializeBytesAsHex(elem))?;
} else {
@ -355,7 +351,7 @@ impl<'de> serde::Deserialize<'de> for Witness {
mut a: A,
) -> Result<Self::Value, A::Error> {
use hex::FromHex;
use hex::HexToBytesError::*;
use hex::HexToBytesError as E;
use serde::de::{self, Unexpected};
let mut ret = match a.size_hint() {
@ -365,7 +361,7 @@ impl<'de> serde::Deserialize<'de> for Witness {
while let Some(elem) = a.next_element::<String>()? {
let vec = Vec::<u8>::from_hex(&elem).map_err(|e| match e {
InvalidChar(ref e) => match core::char::from_u32(e.invalid_char().into()) {
E::InvalidChar(ref e) => match core::char::from_u32(e.invalid_char().into()) {
Some(c) => de::Error::invalid_value(
Unexpected::Char(c),
&"a valid hex character",
@ -375,7 +371,7 @@ impl<'de> serde::Deserialize<'de> for Witness {
&"a valid hex character",
),
},
OddLengthString(ref e) =>
E::OddLengthString(ref e) =>
de::Error::invalid_length(e.length(), &"an even length string"),
})?;
ret.push(vec);
@ -459,7 +455,7 @@ mod test {
let mut got = Witness::new();
got.push([]);
let want = single_empty_element();
assert_eq!(got, want)
assert_eq!(got, want);
}
#[test]