Merge rust-bitcoin/rust-bitcoin#4178: primitives: Enable pedantic lints
df500e9b71
primitives: Enable pedantic lints (Tobin C. Harding)
Pull request description:
Draft to check the subjective ones please, then I'll squash.
ACKs for top commit:
apoelstra:
ACK df500e9b71187fe658da76adafdb3300a51de2ef; successfully ran local tests
Tree-SHA512: 8cc8c9b369a63c1b2b26461e288a818e3b74e0f9b7359c964c1650028d3161db1d79369c74f18e79958873bf4d223ee72fa481708600f0297d79377d97a84dda
This commit is contained in:
commit
aefcf2bb02
|
@ -1,3 +1,4 @@
|
||||||
msrv = "1.63.0"
|
msrv = "1.63.0"
|
||||||
too-many-arguments-threshold = 13
|
too-many-arguments-threshold = 13
|
||||||
avoid-breaking-exported-api = false
|
avoid-breaking-exported-api = false
|
||||||
|
doc-valid-idents = ["SegWit", "OpenSSL"]
|
||||||
|
|
|
@ -40,3 +40,131 @@ rustdoc-args = ["--cfg", "docsrs"]
|
||||||
|
|
||||||
[lints.rust]
|
[lints.rust]
|
||||||
unexpected_cfgs = { level = "deny", check-cfg = ['cfg(mutate)'] }
|
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"
|
||||||
|
|
|
@ -282,7 +282,7 @@ impl Version {
|
||||||
///
|
///
|
||||||
/// A block is signalling for a soft fork under BIP-9 if the first 3 bits are `001` and
|
/// 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.
|
/// 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.
|
// Only bits [0, 28] inclusive are used for signalling.
|
||||||
if bit > 28 {
|
if bit > 28 {
|
||||||
return false;
|
return false;
|
||||||
|
@ -363,36 +363,36 @@ mod tests {
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn version_is_not_signalling_with_invalid_bit() {
|
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.
|
// 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]
|
#[test]
|
||||||
fn version_is_not_signalling_when_use_version_bit_not_set() {
|
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.
|
// 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]
|
#[test]
|
||||||
fn version_is_signalling() {
|
fn version_is_signalling() {
|
||||||
let version = Version::from_consensus(0b00100000000000000000000000000010);
|
let version = Version::from_consensus(0b0010_0000_0000_0000_0000_0000_0000_0010);
|
||||||
assert!(Version::is_signalling_soft_fork(&version, 1));
|
assert!(Version::is_signalling_soft_fork(version, 1));
|
||||||
let version = Version::from_consensus(0b00110000000000000000000000000000);
|
let version = Version::from_consensus(0b0011_0000_0000_0000_0000_0000_0000_0000);
|
||||||
assert!(Version::is_signalling_soft_fork(&version, 28));
|
assert!(Version::is_signalling_soft_fork(version, 28));
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn version_is_not_signalling() {
|
fn version_is_not_signalling() {
|
||||||
let version = Version::from_consensus(0b00100000000000000000000000000010);
|
let version = Version::from_consensus(0b0010_0000_0000_0000_0000_0000_0000_0010);
|
||||||
assert!(!Version::is_signalling_soft_fork(&version, 0));
|
assert!(!Version::is_signalling_soft_fork(version, 0));
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn version_to_consensus() {
|
fn version_to_consensus() {
|
||||||
let version = Version::from_consensus(1234567890);
|
let version = Version::from_consensus(1_234_567_890);
|
||||||
assert_eq!(version.to_consensus(), 1234567890);
|
assert_eq!(version.to_consensus(), 1_234_567_890);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check that the size of the header consensus serialization matches the const SIZE value
|
// Check that the size of the header consensus serialization matches the const SIZE value
|
||||||
|
|
|
@ -16,12 +16,6 @@
|
||||||
#![warn(missing_docs)]
|
#![warn(missing_docs)]
|
||||||
#![warn(deprecated_in_future)]
|
#![warn(deprecated_in_future)]
|
||||||
#![doc(test(attr(warn(unused))))]
|
#![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")]
|
#[cfg(feature = "alloc")]
|
||||||
extern crate alloc;
|
extern crate alloc;
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
// SPDX-License-Identifier: CC0-1.0
|
// 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
|
//! There are two types of lock time: lock-by-blockheight and lock-by-blocktime, distinguished by
|
||||||
//! whether `LockTime < LOCKTIME_THRESHOLD`.
|
//! whether `LockTime < LOCKTIME_THRESHOLD`.
|
||||||
|
@ -22,7 +22,7 @@ pub use units::locktime::absolute::{ConversionError, Height, ParseHeightError, P
|
||||||
/// since epoch).
|
/// since epoch).
|
||||||
///
|
///
|
||||||
/// Used for transaction lock time (`nLockTime` in Bitcoin Core and [`Transaction::lock_time`]
|
/// 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
|
/// ### Note on ordering
|
||||||
///
|
///
|
||||||
|
@ -42,13 +42,13 @@ pub use units::locktime::absolute::{ConversionError, Height, ParseHeightError, P
|
||||||
/// # Examples
|
/// # 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 n = absolute::LockTime::from_consensus(741521); // n OP_CHECKLOCKTIMEVERIFY
|
||||||
/// # let lock_time = absolute::LockTime::from_consensus(741521); // nLockTime
|
/// # let lock_time = absolute::LockTime::from_consensus(741521); // nLockTime
|
||||||
/// // To compare absolute lock times there are various `is_satisfied_*` methods, you may also use:
|
/// // To compare absolute lock times there are various `is_satisfied_*` methods, you may also use:
|
||||||
/// let _is_satisfied = match (n, lock_time) {
|
/// let _is_satisfied = match (n, lock_time) {
|
||||||
/// (Blocks(n), Blocks(lock_time)) => n <= lock_time,
|
/// (L::Blocks(n), L::Blocks(lock_time)) => n <= lock_time,
|
||||||
/// (Seconds(n), Seconds(lock_time)) => n <= lock_time,
|
/// (L::Seconds(n), L::Seconds(lock_time)) => n <= lock_time,
|
||||||
/// _ => panic!("handle invalid comparison error"),
|
/// _ => panic!("handle invalid comparison error"),
|
||||||
/// };
|
/// };
|
||||||
/// ```
|
/// ```
|
||||||
|
@ -126,7 +126,7 @@ impl LockTime {
|
||||||
Ok(Self::from_consensus(lock_time))
|
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
|
/// # Examples
|
||||||
///
|
///
|
||||||
|
@ -138,6 +138,7 @@ impl LockTime {
|
||||||
/// let lock_time = absolute::LockTime::from_consensus(n_lock_time);
|
/// let lock_time = absolute::LockTime::from_consensus(n_lock_time);
|
||||||
/// assert_eq!(lock_time.to_consensus_u32(), n_lock_time);
|
/// assert_eq!(lock_time.to_consensus_u32(), n_lock_time);
|
||||||
#[inline]
|
#[inline]
|
||||||
|
#[allow(clippy::missing_panics_doc)]
|
||||||
pub fn from_consensus(n: u32) -> Self {
|
pub fn from_consensus(n: u32) -> Self {
|
||||||
if units::locktime::absolute::is_block_height(n) {
|
if units::locktime::absolute::is_block_height(n) {
|
||||||
Self::Blocks(Height::from_consensus(n).expect("n is valid"))
|
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.
|
/// Returns true if both lock times use the same unit i.e., both height based or both time based.
|
||||||
#[inline]
|
#[inline]
|
||||||
pub const fn is_same_unit(&self, other: LockTime) -> bool {
|
pub const fn is_same_unit(self, other: LockTime) -> bool {
|
||||||
matches!(
|
matches!(
|
||||||
(self, other),
|
(self, other),
|
||||||
(LockTime::Blocks(_), LockTime::Blocks(_))
|
(LockTime::Blocks(_), LockTime::Blocks(_))
|
||||||
|
@ -207,11 +208,11 @@ impl LockTime {
|
||||||
|
|
||||||
/// Returns true if this lock time value is a block height.
|
/// Returns true if this lock time value is a block height.
|
||||||
#[inline]
|
#[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).
|
/// Returns true if this lock time value is a block time (UNIX timestamp).
|
||||||
#[inline]
|
#[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`.
|
/// 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`.
|
/// blocktime based lock it is checked against `time`.
|
||||||
///
|
///
|
||||||
/// A 'timelock constraint' refers to the `n` from `n OP_CHEKCLOCKTIMEVERIFY`, this constraint
|
/// 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.
|
/// `height`/`time` is valid.
|
||||||
///
|
///
|
||||||
/// # Examples
|
/// # Examples
|
||||||
|
@ -236,12 +237,12 @@ impl LockTime {
|
||||||
/// }
|
/// }
|
||||||
/// ````
|
/// ````
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn is_satisfied_by(&self, height: Height, time: Time) -> bool {
|
pub fn is_satisfied_by(self, height: Height, time: Time) -> bool {
|
||||||
use LockTime::*;
|
use LockTime as L;
|
||||||
|
|
||||||
match *self {
|
match self {
|
||||||
Blocks(n) => n <= height,
|
L::Blocks(n) => n <= height,
|
||||||
Seconds(n) => n <= time,
|
L::Seconds(n) => n <= time,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -265,18 +266,18 @@ impl LockTime {
|
||||||
/// assert!(lock_time.is_implied_by(check));
|
/// assert!(lock_time.is_implied_by(check));
|
||||||
/// ```
|
/// ```
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn is_implied_by(&self, other: LockTime) -> bool {
|
pub fn is_implied_by(self, other: LockTime) -> bool {
|
||||||
use LockTime::*;
|
use LockTime as L;
|
||||||
|
|
||||||
match (*self, other) {
|
match (self, other) {
|
||||||
(Blocks(this), Blocks(other)) => this <= other,
|
(L::Blocks(this), L::Blocks(other)) => this <= other,
|
||||||
(Seconds(this), Seconds(other)) => this <= other,
|
(L::Seconds(this), L::Seconds(other)) => this <= other,
|
||||||
_ => false, // Not the same units.
|
_ => false, // Not the same units.
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns the inner `u32` value. This is the value used when creating this `LockTime`
|
/// 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
|
/// # Warning
|
||||||
///
|
///
|
||||||
|
@ -287,13 +288,13 @@ impl LockTime {
|
||||||
/// # Examples
|
/// # Examples
|
||||||
///
|
///
|
||||||
/// ```rust
|
/// ```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 n = absolute::LockTime::from_consensus(741521); // n OP_CHECKLOCKTIMEVERIFY
|
||||||
/// # let lock_time = absolute::LockTime::from_consensus(741521 + 1); // nLockTime
|
/// # let lock_time = absolute::LockTime::from_consensus(741521 + 1); // nLockTime
|
||||||
///
|
///
|
||||||
/// let _is_satisfied = match (n, lock_time) {
|
/// let _is_satisfied = match (n, lock_time) {
|
||||||
/// (Blocks(n), Blocks(lock_time)) => n <= lock_time,
|
/// (L::Blocks(n), L::Blocks(lock_time)) => n <= lock_time,
|
||||||
/// (Seconds(n), Seconds(lock_time)) => n <= lock_time,
|
/// (L::Seconds(n), L::Seconds(lock_time)) => n <= lock_time,
|
||||||
/// _ => panic!("invalid comparison"),
|
/// _ => panic!("invalid comparison"),
|
||||||
/// };
|
/// };
|
||||||
///
|
///
|
||||||
|
@ -324,28 +325,28 @@ impl From<Time> for LockTime {
|
||||||
impl fmt::Debug for LockTime {
|
impl fmt::Debug for LockTime {
|
||||||
#[inline]
|
#[inline]
|
||||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||||
use LockTime::*;
|
use LockTime as L;
|
||||||
|
|
||||||
match *self {
|
match *self {
|
||||||
Blocks(ref h) => write!(f, "{} blocks", h),
|
L::Blocks(ref h) => write!(f, "{} blocks", h),
|
||||||
Seconds(ref t) => write!(f, "{} seconds", t),
|
L::Seconds(ref t) => write!(f, "{} seconds", t),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl fmt::Display for LockTime {
|
impl fmt::Display for LockTime {
|
||||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||||
use LockTime::*;
|
use LockTime as L;
|
||||||
|
|
||||||
if f.alternate() {
|
if f.alternate() {
|
||||||
match *self {
|
match *self {
|
||||||
Blocks(ref h) => write!(f, "block-height {}", h),
|
L::Blocks(ref h) => write!(f, "block-height {}", h),
|
||||||
Seconds(ref t) => write!(f, "block-time {} (seconds since epoch)", t),
|
L::Seconds(ref t) => write!(f, "block-time {} (seconds since epoch)", t),
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
match *self {
|
match *self {
|
||||||
Blocks(ref h) => fmt::Display::fmt(h, f),
|
L::Blocks(ref h) => fmt::Display::fmt(h, f),
|
||||||
Seconds(ref t) => fmt::Display::fmt(t, f),
|
L::Seconds(ref t) => fmt::Display::fmt(t, f),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -404,7 +405,7 @@ mod tests {
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn display_and_alternate() {
|
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);
|
let s = format!("{}", lock_by_height);
|
||||||
assert_eq!(&s, "741521");
|
assert_eq!(&s, "741521");
|
||||||
|
|
||||||
|
@ -415,25 +416,25 @@ mod tests {
|
||||||
#[test]
|
#[test]
|
||||||
fn lock_time_from_hex_lower() {
|
fn lock_time_from_hex_lower() {
|
||||||
let lock_by_time = LockTime::from_hex("0x6289c350").unwrap();
|
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]
|
#[test]
|
||||||
fn lock_time_from_hex_upper() {
|
fn lock_time_from_hex_upper() {
|
||||||
let lock_by_time = LockTime::from_hex("0X6289C350").unwrap();
|
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]
|
#[test]
|
||||||
fn lock_time_from_unprefixed_hex_lower() {
|
fn lock_time_from_unprefixed_hex_lower() {
|
||||||
let lock_by_time = LockTime::from_unprefixed_hex("6289c350").unwrap();
|
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]
|
#[test]
|
||||||
fn lock_time_from_unprefixed_hex_upper() {
|
fn lock_time_from_unprefixed_hex_upper() {
|
||||||
let lock_by_time = LockTime::from_unprefixed_hex("6289C350").unwrap();
|
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]
|
#[test]
|
||||||
|
@ -450,7 +451,7 @@ mod tests {
|
||||||
assert!(lock_by_height.is_block_height());
|
assert!(lock_by_height.is_block_height());
|
||||||
assert!(!lock_by_height.is_block_time());
|
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);
|
let lock_by_time = LockTime::from_consensus(t);
|
||||||
|
|
||||||
assert!(!lock_by_time.is_block_height());
|
assert!(!lock_by_time.is_block_height());
|
||||||
|
@ -459,7 +460,7 @@ mod tests {
|
||||||
// Test is_same_unit() logic
|
// Test is_same_unit() logic
|
||||||
assert!(lock_by_height.is_same_unit(LockTime::from_consensus(800_000)));
|
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_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));
|
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_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 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");
|
let time = Time::from_consensus(t).expect("invalid time value");
|
||||||
|
|
||||||
assert!(lock_by_height.is_satisfied_by(height_same, time));
|
assert!(lock_by_height.is_satisfied_by(height_same, time));
|
||||||
|
@ -481,11 +482,11 @@ mod tests {
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn satisfied_by_time() {
|
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_same = Time::from_consensus(1_653_195_600).expect("May 22nd 2022, 5am UTC");
|
||||||
let time_after = Time::from_consensus(1653282000).expect("May 23rd 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(1653109200).expect("May 21th 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");
|
let height = Height::from_consensus(800_000).expect("failed to parse height");
|
||||||
|
|
||||||
|
@ -505,17 +506,17 @@ mod tests {
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn time_correctly_implies() {
|
fn time_correctly_implies() {
|
||||||
let t: u32 = 1700000005;
|
let t: u32 = 1_700_000_005;
|
||||||
let lock_by_time = LockTime::from_consensus(t);
|
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(1_700_000_004)));
|
||||||
assert!(lock_by_time.is_implied_by(LockTime::from_consensus(1700000005)));
|
assert!(lock_by_time.is_implied_by(LockTime::from_consensus(1_700_000_005)));
|
||||||
assert!(lock_by_time.is_implied_by(LockTime::from_consensus(1700000006)));
|
assert!(lock_by_time.is_implied_by(LockTime::from_consensus(1_700_000_006)));
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn incorrect_units_do_not_imply() {
|
fn incorrect_units_do_not_imply() {
|
||||||
let lock_by_height = LockTime::from_consensus(750_005);
|
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)));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
// SPDX-License-Identifier: CC0-1.0
|
// 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
|
//! 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.
|
//! 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).
|
/// 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`]
|
/// 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
|
/// ### Note on ordering
|
||||||
///
|
///
|
||||||
|
@ -64,7 +64,7 @@ impl LockTime {
|
||||||
/// The number of bytes that the locktime contributes to the size of a transaction.
|
/// The number of bytes that the locktime contributes to the size of a transaction.
|
||||||
pub const SIZE: usize = 4; // Serialized length of a u32.
|
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
|
/// 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
|
/// 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))
|
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`.
|
/// argument to `OP_CHECKSEQUENCEVERIFY`.
|
||||||
///
|
///
|
||||||
/// # Warning
|
/// # 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.
|
/// Returns true if both lock times use the same unit i.e., both height based or both time based.
|
||||||
#[inline]
|
#[inline]
|
||||||
pub const fn is_same_unit(&self, other: LockTime) -> bool {
|
pub const fn is_same_unit(self, other: LockTime) -> bool {
|
||||||
matches!(
|
matches!(
|
||||||
(self, other),
|
(self, other),
|
||||||
(LockTime::Blocks(_), LockTime::Blocks(_)) | (LockTime::Time(_), LockTime::Time(_))
|
(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.
|
/// Returns true if this lock time value is in units of block height.
|
||||||
#[inline]
|
#[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.
|
/// Returns true if this lock time value is in units of time.
|
||||||
#[inline]
|
#[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.
|
/// 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()));
|
/// assert!(lock.is_satisfied_by(current_height(), current_time()));
|
||||||
/// ```
|
/// ```
|
||||||
#[inline]
|
#[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) {
|
if let Ok(true) = self.is_satisfied_by_height(h) {
|
||||||
true
|
true
|
||||||
} else {
|
} else {
|
||||||
|
@ -249,12 +249,12 @@ impl LockTime {
|
||||||
/// assert!(satisfied);
|
/// assert!(satisfied);
|
||||||
/// ```
|
/// ```
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn is_implied_by(&self, other: LockTime) -> bool {
|
pub fn is_implied_by(self, other: LockTime) -> bool {
|
||||||
use LockTime::*;
|
use LockTime as L;
|
||||||
|
|
||||||
match (*self, other) {
|
match (self, other) {
|
||||||
(Blocks(this), Blocks(other)) => this.value() <= other.value(),
|
(L::Blocks(this), L::Blocks(other)) => this.value() <= other.value(),
|
||||||
(Time(this), Time(other)) => this.value() <= other.value(),
|
(L::Time(this), L::Time(other)) => this.value() <= other.value(),
|
||||||
_ => false, // Not the same units.
|
_ => false, // Not the same units.
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -280,7 +280,7 @@ impl LockTime {
|
||||||
/// # Ok::<_, bitcoin_primitives::relative::DisabledLockTimeError>(())
|
/// # Ok::<_, bitcoin_primitives::relative::DisabledLockTimeError>(())
|
||||||
/// ```
|
/// ```
|
||||||
#[inline]
|
#[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) {
|
if let Ok(other) = LockTime::from_sequence(other) {
|
||||||
self.is_implied_by(other)
|
self.is_implied_by(other)
|
||||||
} else {
|
} else {
|
||||||
|
@ -305,12 +305,12 @@ impl LockTime {
|
||||||
/// assert!(lock.is_satisfied_by_height(relative::Height::from(required_height + 1)).expect("a height"));
|
/// assert!(lock.is_satisfied_by_height(relative::Height::from(required_height + 1)).expect("a height"));
|
||||||
/// ```
|
/// ```
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn is_satisfied_by_height(&self, height: Height) -> Result<bool, IncompatibleHeightError> {
|
pub fn is_satisfied_by_height(self, height: Height) -> Result<bool, IncompatibleHeightError> {
|
||||||
use LockTime::*;
|
use LockTime as L;
|
||||||
|
|
||||||
match *self {
|
match self {
|
||||||
Blocks(ref required_height) => Ok(required_height.value() <= height.value()),
|
L::Blocks(ref required_height) => Ok(required_height.value() <= height.value()),
|
||||||
Time(time) => Err(IncompatibleHeightError { height, time }),
|
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"));
|
/// assert!(lock.is_satisfied_by_time(relative::Time::from_512_second_intervals(intervals + 10)).expect("a time"));
|
||||||
/// ```
|
/// ```
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn is_satisfied_by_time(&self, time: Time) -> Result<bool, IncompatibleTimeError> {
|
pub fn is_satisfied_by_time(self, time: Time) -> Result<bool, IncompatibleTimeError> {
|
||||||
use LockTime::*;
|
use LockTime as L;
|
||||||
|
|
||||||
match *self {
|
match self {
|
||||||
Time(ref t) => Ok(t.value() <= time.value()),
|
L::Time(ref t) => Ok(t.value() <= time.value()),
|
||||||
Blocks(height) => Err(IncompatibleTimeError { time, height }),
|
L::Blocks(height) => Err(IncompatibleTimeError { time, height }),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -353,17 +353,17 @@ impl From<Time> for LockTime {
|
||||||
|
|
||||||
impl fmt::Display for LockTime {
|
impl fmt::Display for LockTime {
|
||||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||||
use LockTime::*;
|
use LockTime as L;
|
||||||
|
|
||||||
if f.alternate() {
|
if f.alternate() {
|
||||||
match *self {
|
match *self {
|
||||||
Blocks(ref h) => write!(f, "block-height {}", h),
|
L::Blocks(ref h) => write!(f, "block-height {}", h),
|
||||||
Time(ref t) => write!(f, "block-time {} (512 second intervals)", t),
|
L::Time(ref t) => write!(f, "block-time {} (512 second intervals)", t),
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
match *self {
|
match *self {
|
||||||
Blocks(ref h) => fmt::Display::fmt(h, f),
|
L::Blocks(ref h) => fmt::Display::fmt(h, f),
|
||||||
Time(ref t) => fmt::Display::fmt(t, f),
|
L::Time(ref t) => fmt::Display::fmt(t, f),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -31,6 +31,7 @@ pub struct Opcode {
|
||||||
code: u8,
|
code: u8,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[allow(clippy::wildcard_imports)]
|
||||||
use self::all::*;
|
use self::all::*;
|
||||||
|
|
||||||
macro_rules! all_opcodes {
|
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`).
|
/// 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
|
/// 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 {
|
pub mod all {
|
||||||
use super::Opcode;
|
use super::Opcode;
|
||||||
$(
|
$(
|
||||||
|
@ -52,13 +53,13 @@ macro_rules! all_opcodes {
|
||||||
|
|
||||||
/// Push an empty array onto the stack.
|
/// Push an empty array onto the stack.
|
||||||
pub static OP_0: Opcode = OP_PUSHBYTES_0;
|
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;
|
pub static OP_FALSE: Opcode = OP_PUSHBYTES_0;
|
||||||
/// Number 1 is also TRUE.
|
/// Number 1 is also TRUE.
|
||||||
pub static OP_TRUE: Opcode = OP_PUSHNUM_1;
|
pub static OP_TRUE: Opcode = OP_PUSHNUM_1;
|
||||||
/// Previously called OP_NOP2.
|
/// Previously called `OP_NOP2`.
|
||||||
pub static OP_NOP2: Opcode = OP_CLTV;
|
pub static OP_NOP2: Opcode = OP_CLTV;
|
||||||
/// Previously called OP_NOP3.
|
/// Previously called `OP_NOP3`.
|
||||||
pub static OP_NOP3: Opcode = OP_CSV;
|
pub static OP_NOP3: Opcode = OP_CSV;
|
||||||
|
|
||||||
impl fmt::Display for Opcode {
|
impl fmt::Display for Opcode {
|
||||||
|
@ -402,10 +403,10 @@ impl Opcode {
|
||||||
|
|
||||||
// 16 opcodes of PushNum class
|
// 16 opcodes of PushNum class
|
||||||
(op, _) if op.code >= OP_PUSHNUM_1.code && op.code <= OP_PUSHNUM_16.code =>
|
(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
|
// 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
|
// opcodes of Ordinary class: 61 for Legacy and 60 for TapScript context
|
||||||
(_, _) => Class::Ordinary(Ordinary::with(self)),
|
(_, _) => Class::Ordinary(Ordinary::with(self)),
|
||||||
|
@ -640,6 +641,7 @@ mod tests {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
#[allow(clippy::too_many_lines)] // This is fine, we never need to read it.
|
||||||
fn str_roundtrip() {
|
fn str_roundtrip() {
|
||||||
let mut unique = HashSet::new();
|
let mut unique = HashSet::new();
|
||||||
roundtrip!(unique, OP_PUSHBYTES_0);
|
roundtrip!(unique, OP_PUSHBYTES_0);
|
||||||
|
|
|
@ -52,9 +52,9 @@ mod tests {
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn compact_target_ordering() {
|
fn compact_target_ordering() {
|
||||||
let lower = CompactTarget::from_consensus(0x1d00fffe);
|
let lower = CompactTarget::from_consensus(0x1d00_fffe);
|
||||||
let lower_copy = CompactTarget::from_consensus(0x1d00fffe);
|
let lower_copy = CompactTarget::from_consensus(0x1d00_fffe);
|
||||||
let higher = CompactTarget::from_consensus(0x1d00ffff);
|
let higher = CompactTarget::from_consensus(0x1d00_ffff);
|
||||||
|
|
||||||
assert!(lower < higher);
|
assert!(lower < higher);
|
||||||
assert!(lower == lower_copy);
|
assert!(lower == lower_copy);
|
||||||
|
@ -62,9 +62,9 @@ mod tests {
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn compact_target_formatting() {
|
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!(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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -13,6 +13,7 @@ use hashes::{hash160, sha256};
|
||||||
use hex::DisplayHex;
|
use hex::DisplayHex;
|
||||||
use internals::script::{self, PushDataLenLen};
|
use internals::script::{self, PushDataLenLen};
|
||||||
|
|
||||||
|
#[allow(clippy::wildcard_imports)]
|
||||||
use crate::opcodes::all::*;
|
use crate::opcodes::all::*;
|
||||||
use crate::opcodes::{self, Opcode};
|
use crate::opcodes::{self, Opcode};
|
||||||
use crate::prelude::rc::Rc;
|
use crate::prelude::rc::Rc;
|
||||||
|
@ -522,14 +523,6 @@ impl<'de> serde::Deserialize<'de> for &'de Script {
|
||||||
where
|
where
|
||||||
D: serde::Deserializer<'de>,
|
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;
|
struct Visitor;
|
||||||
impl<'de> serde::de::Visitor<'de> for Visitor {
|
impl<'de> serde::de::Visitor<'de> for Visitor {
|
||||||
type Value = &'de Script;
|
type Value = &'de Script;
|
||||||
|
@ -545,6 +538,15 @@ impl<'de> serde::Deserialize<'de> for &'de Script {
|
||||||
Ok(Script::from_bytes(v))
|
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)
|
deserializer.deserialize_bytes(Visitor)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -36,7 +36,7 @@ impl Sequence {
|
||||||
/// The maximum allowable sequence number.
|
/// The maximum allowable sequence number.
|
||||||
///
|
///
|
||||||
/// The sequence number that disables replace-by-fee, absolute lock time and relative lock time.
|
/// 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.
|
/// Zero value sequence.
|
||||||
///
|
///
|
||||||
/// This sequence number enables replace-by-fee and absolute lock time.
|
/// 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
|
/// The sequence number that enables replace-by-fee and absolute lock time but
|
||||||
/// disables relative lock time.
|
/// disables relative lock time.
|
||||||
#[deprecated(since = "TBD", note = "use `ENABLE_LOCKTIME_AND_RBF` instead")]
|
#[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
|
/// The maximum sequence number that enables replace-by-fee and absolute lock time but
|
||||||
/// disables relative lock time.
|
/// disables relative lock time.
|
||||||
///
|
///
|
||||||
/// This sequence number has no meaning other than to enable RBF and the absolute locktime.
|
/// 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.
|
/// 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.
|
pub const SIZE: usize = 4; // Serialized length of a u32.
|
||||||
|
@ -66,15 +66,15 @@ impl Sequence {
|
||||||
/// (Explicit Signalling [BIP-125]).
|
/// (Explicit Signalling [BIP-125]).
|
||||||
///
|
///
|
||||||
/// [BIP-125]: <https://github.com/bitcoin/bips/blob/master/bip-0125.mediawiki]>
|
/// [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.
|
/// 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.
|
/// 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`]).
|
/// Returns `true` if the sequence number enables absolute lock-time ([`Transaction::lock_time`]).
|
||||||
#[inline]
|
#[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.
|
/// 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>
|
/// [BIP-112]: <https://github.com/bitcoin/bips/blob/master/bip-0065.mediawiki>
|
||||||
#[inline]
|
#[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.
|
/// 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
|
/// 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`]).
|
/// this method. Note, this is the highest "non-final" value (see [`Sequence::is_final`]).
|
||||||
#[inline]
|
#[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.
|
/// Returns `true` if the sequence has a relative lock-time.
|
||||||
#[inline]
|
#[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
|
self.0 & Sequence::LOCK_TIME_DISABLE_FLAG_MASK == 0
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns `true` if the sequence number encodes a block based relative lock-time.
|
/// Returns `true` if the sequence number encodes a block based relative lock-time.
|
||||||
#[inline]
|
#[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)
|
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.
|
/// Returns `true` if the sequence number encodes a time interval based relative lock-time.
|
||||||
#[inline]
|
#[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)
|
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.
|
/// BIP-68 only uses the low 16 bits for relative lock value.
|
||||||
#[inline]
|
#[inline]
|
||||||
fn low_u16(&self) -> u16 { self.0 as u16 }
|
fn low_u16(self) -> u16 { self.0 as u16 }
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Default for Sequence {
|
impl Default for Sequence {
|
||||||
|
@ -319,9 +319,9 @@ mod tests {
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn sequence_properties() {
|
fn sequence_properties() {
|
||||||
let seq_max = Sequence(0xFFFFFFFF);
|
let seq_max = Sequence(0xFFFF_FFFF);
|
||||||
let seq_no_rbf = Sequence(0xFFFFFFFE);
|
let seq_no_rbf = Sequence(0xFFFF_FFFE);
|
||||||
let seq_rbf = Sequence(0xFFFFFFFD);
|
let seq_rbf = Sequence(0xFFFF_FFFD);
|
||||||
|
|
||||||
assert!(seq_max.is_final());
|
assert!(seq_max.is_final());
|
||||||
assert!(!seq_no_rbf.is_final());
|
assert!(!seq_no_rbf.is_final());
|
||||||
|
@ -332,12 +332,12 @@ mod tests {
|
||||||
assert!(seq_rbf.is_rbf());
|
assert!(seq_rbf.is_rbf());
|
||||||
assert!(!seq_no_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_relative.is_relative_lock_time());
|
||||||
assert!(!seq_max.is_relative_lock_time());
|
assert!(!seq_max.is_relative_lock_time());
|
||||||
|
|
||||||
let seq_height_locked = Sequence(0x00399999);
|
let seq_height_locked = Sequence(0x0039_9999);
|
||||||
let seq_time_locked = Sequence(0x00400000);
|
let seq_time_locked = Sequence(0x0040_0000);
|
||||||
assert!(seq_height_locked.is_height_locked());
|
assert!(seq_height_locked.is_height_locked());
|
||||||
assert!(seq_time_locked.is_time_locked());
|
assert!(seq_time_locked.is_time_locked());
|
||||||
assert!(!seq_time_locked.is_height_locked());
|
assert!(!seq_time_locked.is_height_locked());
|
||||||
|
@ -346,12 +346,12 @@ mod tests {
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn sequence_formatting() {
|
fn sequence_formatting() {
|
||||||
let sequence = Sequence(0x7FFFFFFF);
|
let sequence = Sequence(0x7FFF_FFFF);
|
||||||
assert_eq!(format!("{:x}", sequence), "7fffffff");
|
assert_eq!(format!("{:x}", sequence), "7fffffff");
|
||||||
assert_eq!(format!("{:X}", sequence), "7FFFFFFF");
|
assert_eq!(format!("{:X}", sequence), "7FFFFFFF");
|
||||||
|
|
||||||
// Test From<Sequence> for u32
|
// Test From<Sequence> for u32
|
||||||
let sequence_u32: u32 = sequence.into();
|
let sequence_u32: u32 = sequence.into();
|
||||||
assert_eq!(sequence_u32, 0x7FFFFFFF);
|
assert_eq!(sequence_u32, 0x7FFF_FFFF);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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(compact_size::encode(script_sig_bytes.len()).as_slice());
|
||||||
enc.input(script_sig_bytes);
|
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.
|
// 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 {
|
for input in &tx.input {
|
||||||
// Same as `Encodable for Witness`.
|
// Same as `Encodable for Witness`.
|
||||||
enc.input(compact_size::encode(input.witness.len()).as_slice());
|
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(compact_size::encode(element.len()).as_slice());
|
||||||
enc.input(element);
|
enc.input(element);
|
||||||
}
|
}
|
||||||
|
@ -322,9 +322,9 @@ pub struct TxIn {
|
||||||
/// the miner behavior cannot be enforced.
|
/// the miner behavior cannot be enforced.
|
||||||
pub sequence: Sequence,
|
pub sequence: Sequence,
|
||||||
/// Witness data: an array of byte-arrays.
|
/// 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
|
/// 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.
|
/// (de)serialization routines.
|
||||||
pub witness: Witness,
|
pub witness: Witness,
|
||||||
}
|
}
|
||||||
|
@ -459,14 +459,14 @@ impl From<Infallible> for ParseOutPointError {
|
||||||
#[cfg(feature = "alloc")]
|
#[cfg(feature = "alloc")]
|
||||||
impl fmt::Display for ParseOutPointError {
|
impl fmt::Display for ParseOutPointError {
|
||||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||||
use ParseOutPointError::*;
|
use ParseOutPointError as E;
|
||||||
|
|
||||||
match *self {
|
match *self {
|
||||||
Txid(ref e) => write_err!(f, "error parsing TXID"; e),
|
E::Txid(ref e) => write_err!(f, "error parsing TXID"; e),
|
||||||
Vout(ref e) => write_err!(f, "error parsing vout"; e),
|
E::Vout(ref e) => write_err!(f, "error parsing vout"; e),
|
||||||
Format => write!(f, "OutPoint not in <txid>:<vout> format"),
|
E::Format => write!(f, "OutPoint not in <txid>:<vout> format"),
|
||||||
TooLong => write!(f, "vout should be at most 10 digits"),
|
E::TooLong => write!(f, "vout should be at most 10 digits"),
|
||||||
VoutNotCanonical => write!(f, "no leading zeroes or + allowed in vout part"),
|
E::VoutNotCanonical => write!(f, "no leading zeroes or + allowed in vout part"),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -474,12 +474,12 @@ impl fmt::Display for ParseOutPointError {
|
||||||
#[cfg(feature = "std")]
|
#[cfg(feature = "std")]
|
||||||
impl std::error::Error for ParseOutPointError {
|
impl std::error::Error for ParseOutPointError {
|
||||||
fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
|
fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
|
||||||
use ParseOutPointError::*;
|
use ParseOutPointError as E;
|
||||||
|
|
||||||
match self {
|
match self {
|
||||||
Txid(e) => Some(e),
|
E::Txid(e) => Some(e),
|
||||||
Vout(e) => Some(e),
|
E::Vout(e) => Some(e),
|
||||||
Format | TooLong | VoutNotCanonical => None,
|
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/)),
|
/// As of Bitcoin Core 28.0 ([release notes](https://bitcoincore.org/en/releases/28.0/)),
|
||||||
/// versions 1, 2, and 3 are considered standard.
|
/// versions 1, 2, and 3 are considered standard.
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn is_standard(&self) -> bool {
|
pub fn is_standard(self) -> bool {
|
||||||
*self == Version::ONE || *self == Version::TWO || *self == Version::THREE
|
self == Version::ONE || self == Version::TWO || self == Version::THREE
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -669,11 +669,11 @@ mod tests {
|
||||||
witness: Witness::new(),
|
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 {
|
let tx_orig = Transaction {
|
||||||
version: Version::ONE,
|
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()],
|
input: vec![txin.clone()],
|
||||||
output: vec![txout.clone()],
|
output: vec![txout.clone()],
|
||||||
};
|
};
|
||||||
|
@ -681,9 +681,9 @@ mod tests {
|
||||||
// Test changing the transaction
|
// Test changing the transaction
|
||||||
let mut tx = tx_orig.clone();
|
let mut tx = tx_orig.clone();
|
||||||
tx.inputs_mut()[0].previous_output.txid = Txid::from_byte_array([0xFF; 32]);
|
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.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
|
// Test uses_segwit_serialization
|
||||||
assert!(!tx.uses_segwit_serialization());
|
assert!(!tx.uses_segwit_serialization());
|
||||||
|
|
|
@ -100,7 +100,7 @@ impl Witness {
|
||||||
|
|
||||||
/// Convenience method to create an array of byte-arrays from this witness.
|
/// Convenience method to create an array of byte-arrays from this witness.
|
||||||
#[inline]
|
#[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.
|
/// Returns `true` if the witness contains no element.
|
||||||
#[inline]
|
#[inline]
|
||||||
|
@ -172,17 +172,6 @@ impl Witness {
|
||||||
.copy_from_slice(new_element);
|
.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.
|
/// Returns the last element in the witness, if any.
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn last(&self) -> Option<&[u8]> { self.get_back(0) }
|
pub fn last(&self) -> Option<&[u8]> { self.get_back(0) }
|
||||||
|
@ -221,7 +210,13 @@ impl Witness {
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn get(&self, index: usize) -> Option<&[u8]> {
|
pub fn get(&self, index: usize) -> Option<&[u8]> {
|
||||||
let pos = decode_cursor(&self.content, self.indices_start, index)?;
|
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])
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -251,9 +246,10 @@ fn decode_cursor(bytes: &[u8], start_of_indices: usize, index: usize) -> Option<
|
||||||
/// - Number of witness elements
|
/// - Number of witness elements
|
||||||
/// - Total bytes across all elements
|
/// - Total bytes across all elements
|
||||||
/// - List of hex-encoded witness 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 {
|
impl fmt::Debug for Witness {
|
||||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
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")
|
f.debug_struct("Witness")
|
||||||
.field("num_elements", &self.witness_elements)
|
.field("num_elements", &self.witness_elements)
|
||||||
|
@ -261,7 +257,7 @@ impl fmt::Debug for Witness {
|
||||||
.field(
|
.field(
|
||||||
"elements",
|
"elements",
|
||||||
&WrapDebug(|f| {
|
&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()
|
.finish()
|
||||||
|
@ -328,7 +324,7 @@ impl serde::Serialize for Witness {
|
||||||
let mut seq = serializer.serialize_seq(Some(self.witness_elements))?;
|
let mut seq = serializer.serialize_seq(Some(self.witness_elements))?;
|
||||||
|
|
||||||
// Note that the `Iter` strips the varints out when iterating.
|
// Note that the `Iter` strips the varints out when iterating.
|
||||||
for elem in self.iter() {
|
for elem in self {
|
||||||
if human_readable {
|
if human_readable {
|
||||||
seq.serialize_element(&internals::serde::SerializeBytesAsHex(elem))?;
|
seq.serialize_element(&internals::serde::SerializeBytesAsHex(elem))?;
|
||||||
} else {
|
} else {
|
||||||
|
@ -360,7 +356,7 @@ impl<'de> serde::Deserialize<'de> for Witness {
|
||||||
mut a: A,
|
mut a: A,
|
||||||
) -> Result<Self::Value, A::Error> {
|
) -> Result<Self::Value, A::Error> {
|
||||||
use hex::FromHex;
|
use hex::FromHex;
|
||||||
use hex::HexToBytesError::*;
|
use hex::HexToBytesError as E;
|
||||||
use serde::de::{self, Unexpected};
|
use serde::de::{self, Unexpected};
|
||||||
|
|
||||||
let mut ret = match a.size_hint() {
|
let mut ret = match a.size_hint() {
|
||||||
|
@ -370,7 +366,7 @@ impl<'de> serde::Deserialize<'de> for Witness {
|
||||||
|
|
||||||
while let Some(elem) = a.next_element::<String>()? {
|
while let Some(elem) = a.next_element::<String>()? {
|
||||||
let vec = Vec::<u8>::from_hex(&elem).map_err(|e| match e {
|
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(
|
Some(c) => de::Error::invalid_value(
|
||||||
Unexpected::Char(c),
|
Unexpected::Char(c),
|
||||||
&"a valid hex character",
|
&"a valid hex character",
|
||||||
|
@ -380,7 +376,7 @@ impl<'de> serde::Deserialize<'de> for Witness {
|
||||||
&"a valid hex character",
|
&"a valid hex character",
|
||||||
),
|
),
|
||||||
},
|
},
|
||||||
OddLengthString(ref e) =>
|
E::OddLengthString(ref e) =>
|
||||||
de::Error::invalid_length(e.length(), &"an even length string"),
|
de::Error::invalid_length(e.length(), &"an even length string"),
|
||||||
})?;
|
})?;
|
||||||
ret.push(vec);
|
ret.push(vec);
|
||||||
|
@ -464,7 +460,7 @@ mod test {
|
||||||
let mut got = Witness::new();
|
let mut got = Witness::new();
|
||||||
got.push([]);
|
got.push([]);
|
||||||
let want = single_empty_element();
|
let want = single_empty_element();
|
||||||
assert_eq!(got, want)
|
assert_eq!(got, want);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
|
Loading…
Reference in New Issue