From f56079186a9830c99136dc27a2a2959290108c28 Mon Sep 17 00:00:00 2001 From: Kittywhiskers Van Gogh <63189531+kwvg@users.noreply.github.com> Date: Mon, 14 Sep 2026 11:56:26 +0530 Subject: [PATCH 01/23] num%chore: drop since base-sdk#27 unused `Hash512` --- pkgs/num/src/hash.rs | 17 ----------------- pkgs/num/src/lib.rs | 4 ++-- pkgs/num/tests/hash.rs | 40 +--------------------------------------- pkgs/num/tests/serde.rs | 12 +----------- 4 files changed, 4 insertions(+), 69 deletions(-) diff --git a/pkgs/num/src/hash.rs b/pkgs/num/src/hash.rs index 8700fee3..e27c8d97 100644 --- a/pkgs/num/src/hash.rs +++ b/pkgs/num/src/hash.rs @@ -334,20 +334,3 @@ macro_rules! define_hash { define_hash!(Hash160, 20); define_hash!(Hash256, 32); -define_hash!(Hash512, 64); - -impl Hash512 { - /// Truncate to 256 bits by taking the first 32 bytes (low half in LE). - /// - /// This is the final step in the proof-of-work daisy chain: the 512-bit - /// intermediate result is truncated to 256 bits. - pub const fn truncate(&self) -> Hash256 { - let mut out = [0u8; 32]; - let mut i = 0; - while i < 32 { - out[i] = self.0[i]; - i += 1; - } - Hash256::from_bytes(out) - } -} diff --git a/pkgs/num/src/lib.rs b/pkgs/num/src/lib.rs index 5b0103d4..0c2008b9 100644 --- a/pkgs/num/src/lib.rs +++ b/pkgs/num/src/lib.rs @@ -6,7 +6,7 @@ //! Consensus-compatible numeric types. //! -//! Provides hash blob types ([`Hash512`], [`Hash256`], [`Hash160`]) +//! Provides hash blob types ([`Hash256`], [`Hash160`]) //! and the [`Arith256`] arithmetic integer type. #![no_std] @@ -37,4 +37,4 @@ pub mod __private { pub use arith::ArithInt; pub use arith256::Arith256; pub use compact::{CompactTarget, DecodedTarget}; -pub use hash::{Hash160, Hash256, Hash512, HashBlob, ParseHexError}; +pub use hash::{Hash160, Hash256, HashBlob, ParseHexError}; diff --git a/pkgs/num/tests/hash.rs b/pkgs/num/tests/hash.rs index 43b3bbef..ca9e3598 100644 --- a/pkgs/num/tests/hash.rs +++ b/pkgs/num/tests/hash.rs @@ -8,7 +8,7 @@ #![expect(clippy::unwrap_used, reason = "test code")] -use dash_num::{Hash160, Hash256, Hash512, ParseHexError}; +use dash_num::{Hash160, Hash256, ParseHexError}; use hex_literal::hex; use rstest::*; @@ -125,18 +125,6 @@ fn hex_errors() { )); } -#[rstest] -fn hash512_roundtrip() { - let mut bytes = [0u8; 64]; - bytes[0] = 0x42; - bytes[63] = 0xff; - let h = Hash512::from_bytes(bytes); - let hex = format!("{h}"); - assert!(hex.starts_with("ff")); - assert!(hex.ends_with("42")); - assert_eq!(Hash512::from_str(&hex).unwrap(), h); -} - #[rstest] fn hash160_roundtrip() { let bytes = hex!("0102030405060708090a0b0c0d0e0f1011121314"); @@ -162,29 +150,3 @@ fn hash160_new_reverses() { assert_eq!(h.to_bytes()[0], 0x14); assert_eq!(h.to_bytes()[19], 0x01); } - -#[rstest] -fn hash512_truncate_takes_first_32_bytes() { - let mut bytes = [0u8; 64]; - // Fill first 32 bytes with a recognizable pattern - for (i, b) in bytes.iter_mut().enumerate().take(32) { - *b = (i + 1) as u8; - } - // Fill last 32 bytes with 0xff - for b in bytes.iter_mut().skip(32) { - *b = 0xff; - } - let h512 = Hash512::from_bytes(bytes); - let h256 = h512.truncate(); - - let mut expected = [0u8; 32]; - for (i, b) in expected.iter_mut().enumerate() { - *b = (i + 1) as u8; - } - assert_eq!(h256.to_bytes(), expected); -} - -#[rstest] -fn hash512_truncate_zero() { - assert_eq!(Hash512::ZERO.truncate(), Hash256::ZERO); -} diff --git a/pkgs/num/tests/serde.rs b/pkgs/num/tests/serde.rs index fbf4287c..0b6bd743 100644 --- a/pkgs/num/tests/serde.rs +++ b/pkgs/num/tests/serde.rs @@ -7,7 +7,7 @@ //! Serde roundtrip tests for all types. use dash_dev::{assert_json_rt, from_json, json_rejects, to_json}; -use dash_num::{Arith256, CompactTarget, Hash160, Hash256, Hash512}; +use dash_num::{Arith256, CompactTarget, Hash160, Hash256}; use hex_literal::hex; #[test] @@ -28,16 +28,6 @@ fn hash160_json_roundtrip() { assert_json_rt(&Hash160::ZERO); } -#[test] -fn hash512_json_roundtrip() { - let mut bytes = [0u8; 64]; - bytes[0] = 0x42; - bytes[63] = 0xff; - let h = Hash512::from_bytes(bytes); - assert_json_rt(&h); - assert_json_rt(&Hash512::ZERO); -} - #[test] fn arith256_json_roundtrip() { let check = |uint: Arith256, hex: &str| { From af02f8a6a6d5bc499ed9f78a1b75d603055644b3 Mon Sep 17 00:00:00 2001 From: Kittywhiskers Van Gogh <63189531+kwvg@users.noreply.github.com> Date: Mon, 14 Sep 2026 11:57:31 +0530 Subject: [PATCH 02/23] num%refac: strip compile-time constness guarantees from API --- pkgs/num/src/arith256.rs | 67 +++++++++++++++++++++++----------------- pkgs/num/src/compact.rs | 6 ++-- pkgs/num/src/hash.rs | 8 ++--- pkgs/num/src/util.rs | 8 ++--- 4 files changed, 49 insertions(+), 40 deletions(-) diff --git a/pkgs/num/src/arith256.rs b/pkgs/num/src/arith256.rs index fd391b0c..aff949e6 100644 --- a/pkgs/num/src/arith256.rs +++ b/pkgs/num/src/arith256.rs @@ -40,13 +40,13 @@ impl Arith256 { /// Create from a `u64`, zero-extending the upper bits. #[inline] - pub const fn from_u64(v: u64) -> Self { + pub fn from_u64(v: u64) -> Self { Self { lo: v as u128, hi: 0 } } /// Create from a `u128`, zero-extending the upper bits. #[inline] - pub const fn from_u128(v: u128) -> Self { + pub fn from_u128(v: u128) -> Self { Self { lo: v, hi: 0 } } @@ -54,7 +54,7 @@ impl Arith256 { /// /// `bytes[0..16]` maps to `lo`, `bytes[16..32]` to `hi`. #[inline] - pub const fn from_le_bytes(bytes: [u8; 32]) -> Self { + pub fn from_le_bytes(bytes: [u8; 32]) -> Self { let lo = u128::from_le_bytes(split_low(bytes)); let hi = u128::from_le_bytes(split_high(bytes)); Self { lo, hi } @@ -62,7 +62,7 @@ impl Arith256 { /// Construct from big-endian bytes. #[inline] - pub const fn from_be_bytes(bytes: [u8; 32]) -> Self { + pub fn from_be_bytes(bytes: [u8; 32]) -> Self { let mut le = [0u8; 32]; let mut i = 0; while i < 32 { @@ -79,12 +79,21 @@ impl Arith256 { /// little-endian, so this reverses the input before decoding. #[inline] pub const fn new(be: [u8; 32]) -> Self { - Self::from_be_bytes(be) + let mut le = [0u8; 32]; + let mut i = 0; + while i < 32 { + le[i] = be[31 - i]; + i += 1; + } + Self { + lo: u128::from_le_bytes(split_low(le)), + hi: u128::from_le_bytes(split_high(le)), + } } /// Convert to little-endian bytes. #[inline] - pub const fn to_le_bytes(self) -> [u8; 32] { + pub fn to_le_bytes(self) -> [u8; 32] { let lo = self.lo.to_le_bytes(); let hi = self.hi.to_le_bytes(); let mut out = [0u8; 32]; @@ -99,7 +108,7 @@ impl Arith256 { /// Convert to big-endian bytes. #[inline] - pub const fn to_be_bytes(self) -> [u8; 32] { + pub fn to_be_bytes(self) -> [u8; 32] { let le = self.to_le_bytes(); let mut be = [0u8; 32]; let mut i = 0; @@ -112,44 +121,44 @@ impl Arith256 { /// Returns `true` if the value is zero. #[inline] - pub const fn is_zero(self) -> bool { + pub fn is_zero(self) -> bool { self.lo == 0 && self.hi == 0 } /// Returns `true` if the value is one. #[inline] - pub const fn is_one(self) -> bool { + pub fn is_one(self) -> bool { self.lo == 1 && self.hi == 0 } /// Returns `true` if the value is MAX (all bits set). #[inline] - pub const fn is_max(self) -> bool { + pub fn is_max(self) -> bool { self.lo == u128::MAX && self.hi == u128::MAX } /// Returns the lowest 32 bits of the value. #[inline] - pub const fn low_u32(self) -> u32 { + pub fn low_u32(self) -> u32 { self.lo as u32 } /// Returns the lowest 64 bits of the value. #[inline] - pub const fn low_u64(self) -> u64 { + pub fn low_u64(self) -> u64 { self.lo as u64 } /// Returns the lowest 128 bits of the value. #[inline] - pub const fn low_u128(self) -> u128 { + pub fn low_u128(self) -> u128 { self.lo } /// Saturating conversion to u128. Returns u128::MAX if value exceeds 128 /// bits. #[inline] - pub const fn saturating_to_u128(self) -> u128 { + pub fn saturating_to_u128(self) -> u128 { if self.hi != 0 { u128::MAX } else { @@ -159,7 +168,7 @@ impl Arith256 { /// Highest set bit position plus one, or zero if zero. #[inline] - pub const fn bits(self) -> u32 { + pub fn bits(self) -> u32 { if self.hi != 0 { 256 - self.hi.leading_zeros() } else if self.lo != 0 { @@ -171,7 +180,7 @@ impl Arith256 { /// Wrapping addition. #[inline] - pub const fn wrapping_add(self, rhs: Self) -> Self { + pub fn wrapping_add(self, rhs: Self) -> Self { let (lo, carry) = self.lo.overflowing_add(rhs.lo); let hi = self.hi.wrapping_add(rhs.hi).wrapping_add(carry as u128); Self { lo, hi } @@ -179,7 +188,7 @@ impl Arith256 { /// Wrapping subtraction. #[inline] - pub const fn wrapping_sub(self, rhs: Self) -> Self { + pub fn wrapping_sub(self, rhs: Self) -> Self { let (lo, borrow) = self.lo.overflowing_sub(rhs.lo); let hi = self.hi.wrapping_sub(rhs.hi).wrapping_sub(borrow as u128); Self { lo, hi } @@ -187,19 +196,19 @@ impl Arith256 { /// Two's complement negation. #[inline] - pub const fn wrapping_neg(self) -> Self { + pub fn wrapping_neg(self) -> Self { self.bitwise_not().wrapping_add(Self::ONE) } /// Wrapping increment (add one). #[inline] - pub const fn wrapping_inc(self) -> Self { + pub fn wrapping_inc(self) -> Self { self.wrapping_add(Self::ONE) } /// Bitwise NOT. #[inline] - pub const fn bitwise_not(self) -> Self { + pub fn bitwise_not(self) -> Self { Self { lo: !self.lo, hi: !self.hi, @@ -207,7 +216,7 @@ impl Arith256 { } /// Wrapping multiply via 64-bit limb decomposition. - pub const fn wrapping_mul(self, rhs: Self) -> Self { + pub fn wrapping_mul(self, rhs: Self) -> Self { let a0 = self.lo as u64 as u128; let a1 = (self.lo >> 64) as u64 as u128; let a2 = self.hi as u64 as u128; @@ -258,7 +267,7 @@ impl Arith256 { } /// Checked division. Returns `None` on divide-by-zero. - pub const fn checked_div(self, rhs: Self) -> Option { + pub fn checked_div(self, rhs: Self) -> Option { if rhs.is_zero() { return None; } @@ -268,7 +277,7 @@ impl Arith256 { /// Quotient and remainder via bitwise long division. /// /// Returns `(ZERO, ZERO)` when `rhs` is zero. - pub const fn div_rem(self, rhs: Self) -> (Self, Self) { + pub fn div_rem(self, rhs: Self) -> (Self, Self) { if rhs.is_zero() { return (Self::ZERO, Self::ZERO); } @@ -306,7 +315,7 @@ impl Arith256 { /// Wrapping left shift. #[inline] - pub const fn wrapping_shl(self, shift: u32) -> Self { + pub fn wrapping_shl(self, shift: u32) -> Self { if shift >= 256 { return Self::ZERO; } @@ -328,7 +337,7 @@ impl Arith256 { /// Wrapping right shift. #[inline] - pub const fn wrapping_shr(self, shift: u32) -> Self { + pub fn wrapping_shr(self, shift: u32) -> Self { if shift >= 256 { return Self::ZERO; } @@ -349,7 +358,7 @@ impl Arith256 { } /// Wrapping multiply by a `u32` scalar. - pub const fn wrapping_mul_u32(self, b: u32) -> Self { + pub fn wrapping_mul_u32(self, b: u32) -> Self { let b = b as u128; let a0 = self.lo as u64 as u128; let a1 = (self.lo >> 64) as u64 as u128; @@ -377,7 +386,7 @@ impl Arith256 { } /// Multiply by a `u64` scalar, returning the result and an overflow flag. - pub const fn mul_u64(self, b: u64) -> (Self, bool) { + pub fn mul_u64(self, b: u64) -> (Self, bool) { let b = b as u128; let a0 = self.lo as u64 as u128; let a1 = (self.lo >> 64) as u64 as u128; @@ -410,7 +419,7 @@ impl Arith256 { } /// Compute `2^256 / (self + 1)`. Returns MAX when self is zero or one. - pub const fn inverse(self) -> Self { + pub fn inverse(self) -> Self { if self.is_zero() || self.is_one() { return Self::MAX; } @@ -423,7 +432,7 @@ impl Arith256 { } /// Approximate conversion to `f64`. - pub const fn to_f64(self) -> f64 { + pub fn to_f64(self) -> f64 { let a0 = self.lo as u64; let a1 = (self.lo >> 64) as u64; let a2 = self.hi as u64; diff --git a/pkgs/num/src/compact.rs b/pkgs/num/src/compact.rs index f9f404fa..d28b9f01 100644 --- a/pkgs/num/src/compact.rs +++ b/pkgs/num/src/compact.rs @@ -49,7 +49,7 @@ impl_num!(CompactTarget, u32); impl CompactTarget { /// Decode this compact (nBits) representation into a 256-bit target value. - pub const fn decode(self) -> DecodedTarget { + pub fn decode(self) -> DecodedTarget { let compact = self.0; let size = (compact >> 24) as usize; let mut word = compact & 0x007f_ffff; @@ -83,12 +83,12 @@ impl Arith256 { /// Decode a compact (nBits) representation into a 256-bit target value. /// /// Convenience method that delegates to [`CompactTarget::decode`]. - pub const fn from_compact(ct: CompactTarget) -> DecodedTarget { + pub fn from_compact(ct: CompactTarget) -> DecodedTarget { ct.decode() } /// Encode this value as a compact (nBits) representation. - pub const fn to_compact(self, negative: bool) -> CompactTarget { + pub fn to_compact(self, negative: bool) -> CompactTarget { let mut size = self.bits().div_ceil(8); let mut compact: u32 = if size <= 3 { (self.low_u64() << (8 * (3 - size as u64))) as u32 diff --git a/pkgs/num/src/hash.rs b/pkgs/num/src/hash.rs index e27c8d97..e00b81c1 100644 --- a/pkgs/num/src/hash.rs +++ b/pkgs/num/src/hash.rs @@ -89,19 +89,19 @@ macro_rules! define_hash { /// Wrap raw little-endian bytes into a hash. #[inline] - pub const fn from_bytes(bytes: [u8; $n]) -> Self { + pub fn from_bytes(bytes: [u8; $n]) -> Self { Self(bytes) } /// Return the raw little-endian bytes. #[inline] - pub const fn to_bytes(self) -> [u8; $n] { + pub fn to_bytes(self) -> [u8; $n] { self.0 } /// Borrow the raw little-endian bytes. #[inline] - pub const fn as_bytes(&self) -> &[u8; $n] { + pub fn as_bytes(&self) -> &[u8; $n] { &self.0 } @@ -122,7 +122,7 @@ macro_rules! define_hash { } /// Returns `true` if every byte is zero. - pub const fn is_null(&self) -> bool { + pub fn is_null(&self) -> bool { let mut i = 0; while i < $n { if self.0[i] != 0 { diff --git a/pkgs/num/src/util.rs b/pkgs/num/src/util.rs index 02f7ecd8..89b721d3 100644 --- a/pkgs/num/src/util.rs +++ b/pkgs/num/src/util.rs @@ -112,19 +112,19 @@ macro_rules! make_hash { /// Wrap raw little-endian bytes into a hash. #[inline] - pub const fn from_bytes(bytes: [u8; { <$base>::LEN }]) -> Self { + pub fn from_bytes(bytes: [u8; { <$base>::LEN }]) -> Self { Self(<$base>::from_bytes(bytes)) } /// Return the raw little-endian bytes. #[inline] - pub const fn to_bytes(self) -> [u8; { <$base>::LEN }] { + pub fn to_bytes(self) -> [u8; { <$base>::LEN }] { self.0.to_bytes() } /// Borrow the raw little-endian bytes. #[inline] - pub const fn as_bytes(&self) -> &[u8; { <$base>::LEN }] { + pub fn as_bytes(&self) -> &[u8; { <$base>::LEN }] { self.0.as_bytes() } @@ -136,7 +136,7 @@ macro_rules! make_hash { /// Returns `true` if every byte is zero. #[inline] - pub const fn is_null(&self) -> bool { + pub fn is_null(&self) -> bool { self.0.is_null() } From df76b5fbb97389a636e233d467453192c6b22c0f Mon Sep 17 00:00:00 2001 From: Kittywhiskers Van Gogh <63189531+kwvg@users.noreply.github.com> Date: Mon, 14 Sep 2026 12:00:01 +0530 Subject: [PATCH 03/23] num%refac: shave dead `ArithInt` and `HashBlob` traits --- pkgs/num/src/arith.rs | 241 ------------------------------------------ pkgs/num/src/hash.rs | 62 ----------- pkgs/num/src/lib.rs | 4 +- 3 files changed, 1 insertion(+), 306 deletions(-) delete mode 100644 pkgs/num/src/arith.rs diff --git a/pkgs/num/src/arith.rs b/pkgs/num/src/arith.rs deleted file mode 100644 index 8554df1b..00000000 --- a/pkgs/num/src/arith.rs +++ /dev/null @@ -1,241 +0,0 @@ -// -// Copyright (c) 2026-present, The Dash Core developers -// SPDX-License-Identifier: MIT -// See the accompanying file LICENSE or https://opensource.org/license/MIT -// - -//! Unified trait for wide unsigned arithmetic integers. - -use core::fmt; -use core::hash::Hash; -use core::ops::{Add, BitAnd, BitOr, BitXor, Div, Mul, Neg, Not, Rem, Shl, Shr, Sub}; - -/// Shared interface for wide unsigned arithmetic integer types. -/// -/// All operators are **wrapping**. Wide integer types are **never** -/// displayed in decimal; `Display` outputs reversed hex via the -/// corresponding hash type. -pub trait ArithInt: - Copy - + Clone - + Default - + Eq - + Ord - + Hash - + Add - + Sub - + Mul - + Div - + Rem - + Not - + Neg - + BitAnd - + BitOr - + BitXor - + Shl - + Shr - + Mul - + fmt::Debug - + fmt::Display - + fmt::LowerHex - + fmt::UpperHex -{ - /// The fixed-size byte array type. - type Bytes: Copy; - - /// The additive identity (all bits zero). - const ZERO: Self; - /// The multiplicative identity. - const ONE: Self; - /// The largest representable value (all bits set). - const MAX: Self; - /// Byte length. - const LEN: usize; - - /// Create from a `u64`, zero-extending. - fn from_u64(v: u64) -> Self; - /// Create from a `u128`, zero-extending (or truncating for 128-bit). - fn from_u128(v: u128) -> Self; - /// Construct from little-endian bytes. - fn from_le_bytes(bytes: Self::Bytes) -> Self; - /// Construct from big-endian bytes. - fn from_be_bytes(bytes: Self::Bytes) -> Self; - /// Construct from big-endian bytes (alias for `from_be_bytes`). - fn new(be: Self::Bytes) -> Self; - - /// Convert to little-endian bytes. - fn to_le_bytes(self) -> Self::Bytes; - /// Convert to big-endian bytes. - fn to_be_bytes(self) -> Self::Bytes; - /// Returns the lowest 32 bits. - fn low_u32(self) -> u32; - /// Returns the lowest 64 bits. - fn low_u64(self) -> u64; - /// Returns the lowest 128 bits. - fn low_u128(self) -> u128; - /// Saturating conversion to u128. - fn saturating_to_u128(self) -> u128; - /// Approximate conversion to `f64`. - fn to_f64(self) -> f64; - - /// Returns `true` if the value is zero. - fn is_zero(self) -> bool; - /// Returns `true` if the value is one. - fn is_one(self) -> bool; - /// Returns `true` if the value is MAX. - fn is_max(self) -> bool; - /// Highest set bit position plus one, or zero if zero. - fn bits(self) -> u32; - - /// Wrapping addition. - fn wrapping_add(self, rhs: Self) -> Self; - /// Wrapping subtraction. - fn wrapping_sub(self, rhs: Self) -> Self; - /// Wrapping multiplication. - fn wrapping_mul(self, rhs: Self) -> Self; - /// Wrapping negation. - fn wrapping_neg(self) -> Self; - /// Wrapping increment. - fn wrapping_inc(self) -> Self; - /// Wrapping left shift. - fn wrapping_shl(self, shift: u32) -> Self; - /// Wrapping right shift. - fn wrapping_shr(self, shift: u32) -> Self; - /// Wrapping multiply by u32 scalar. - fn wrapping_mul_u32(self, b: u32) -> Self; - /// Multiply by u64 scalar, returning result and overflow flag. - fn mul_u64(self, b: u64) -> (Self, bool); - /// Bitwise NOT. - fn bitwise_not(self) -> Self; - /// Checked division. - fn checked_div(self, rhs: Self) -> Option; - /// Quotient and remainder. - fn div_rem(self, rhs: Self) -> (Self, Self); - /// Compute `2^N / (self + 1)`. - fn inverse(self) -> Self; -} - -impl ArithInt for crate::Arith256 { - type Bytes = [u8; 32]; - const ZERO: Self = Self::ZERO; - const ONE: Self = Self::ONE; - const MAX: Self = Self::MAX; - const LEN: usize = Self::LEN; - - #[inline] - fn from_u64(v: u64) -> Self { - Self::from_u64(v) - } - #[inline] - fn from_u128(v: u128) -> Self { - Self::from_u128(v) - } - #[inline] - fn from_le_bytes(bytes: [u8; 32]) -> Self { - Self::from_le_bytes(bytes) - } - #[inline] - fn from_be_bytes(bytes: [u8; 32]) -> Self { - Self::from_be_bytes(bytes) - } - #[inline] - fn new(be: [u8; 32]) -> Self { - Self::new(be) - } - #[inline] - fn to_le_bytes(self) -> [u8; 32] { - Self::to_le_bytes(self) - } - #[inline] - fn to_be_bytes(self) -> [u8; 32] { - Self::to_be_bytes(self) - } - #[inline] - fn low_u32(self) -> u32 { - Self::low_u32(self) - } - #[inline] - fn low_u64(self) -> u64 { - Self::low_u64(self) - } - #[inline] - fn low_u128(self) -> u128 { - Self::low_u128(self) - } - #[inline] - fn saturating_to_u128(self) -> u128 { - Self::saturating_to_u128(self) - } - #[inline] - fn to_f64(self) -> f64 { - Self::to_f64(self) - } - #[inline] - fn is_zero(self) -> bool { - Self::is_zero(self) - } - #[inline] - fn is_one(self) -> bool { - Self::is_one(self) - } - #[inline] - fn is_max(self) -> bool { - Self::is_max(self) - } - #[inline] - fn bits(self) -> u32 { - Self::bits(self) - } - #[inline] - fn wrapping_add(self, rhs: Self) -> Self { - Self::wrapping_add(self, rhs) - } - #[inline] - fn wrapping_sub(self, rhs: Self) -> Self { - Self::wrapping_sub(self, rhs) - } - #[inline] - fn wrapping_mul(self, rhs: Self) -> Self { - Self::wrapping_mul(self, rhs) - } - #[inline] - fn wrapping_neg(self) -> Self { - Self::wrapping_neg(self) - } - #[inline] - fn wrapping_inc(self) -> Self { - Self::wrapping_inc(self) - } - #[inline] - fn wrapping_shl(self, shift: u32) -> Self { - Self::wrapping_shl(self, shift) - } - #[inline] - fn wrapping_shr(self, shift: u32) -> Self { - Self::wrapping_shr(self, shift) - } - #[inline] - fn wrapping_mul_u32(self, b: u32) -> Self { - Self::wrapping_mul_u32(self, b) - } - #[inline] - fn mul_u64(self, b: u64) -> (Self, bool) { - Self::mul_u64(self, b) - } - #[inline] - fn bitwise_not(self) -> Self { - Self::bitwise_not(self) - } - #[inline] - fn checked_div(self, rhs: Self) -> Option { - Self::checked_div(self, rhs) - } - #[inline] - fn div_rem(self, rhs: Self) -> (Self, Self) { - Self::div_rem(self, rhs) - } - #[inline] - fn inverse(self) -> Self { - Self::inverse(self) - } -} diff --git a/pkgs/num/src/hash.rs b/pkgs/num/src/hash.rs index e00b81c1..1f70d367 100644 --- a/pkgs/num/src/hash.rs +++ b/pkgs/num/src/hash.rs @@ -49,32 +49,6 @@ pub(crate) fn hex_val(c: u8) -> Result { } } -/// Shared interface for all fixed-size hash blob types. -pub trait HashBlob: - Copy + Clone + Default + Eq + Ord + Hash + fmt::Debug + fmt::Display + fmt::LowerHex + FromStr + AsRef<[u8]> -{ - /// The fixed-size byte array type. - type Bytes: Copy; - - /// The all-zeros (null) hash. - const ZERO: Self; - /// Byte length of this hash type. - const LEN: usize; - - /// Wrap raw little-endian bytes into a hash. - fn from_bytes(bytes: Self::Bytes) -> Self; - /// Return the raw little-endian bytes. - fn to_bytes(self) -> Self::Bytes; - /// Borrow the raw little-endian bytes. - fn as_bytes(&self) -> &Self::Bytes; - /// Construct from big-endian bytes (consensus display order). - fn new(be: Self::Bytes) -> Self; - /// Returns `true` if every byte is zero. - fn is_null(&self) -> bool; - /// Parse from a big-endian hex string. - fn from_hex(s: &str) -> Result; -} - macro_rules! define_hash { ($name:ident, $n:literal) => { /// Fixed-size opaque hash blob stored in little-endian byte order. @@ -189,42 +163,6 @@ macro_rules! define_hash { } } - impl HashBlob for $name { - type Bytes = [u8; $n]; - const ZERO: Self = Self::ZERO; - const LEN: usize = $n; - - #[inline] - fn from_bytes(bytes: [u8; $n]) -> Self { - Self::from_bytes(bytes) - } - - #[inline] - fn to_bytes(self) -> [u8; $n] { - Self::to_bytes(self) - } - - #[inline] - fn as_bytes(&self) -> &[u8; $n] { - Self::as_bytes(self) - } - - #[inline] - fn new(be: [u8; $n]) -> Self { - Self::new(be) - } - - #[inline] - fn is_null(&self) -> bool { - Self::is_null(self) - } - - #[inline] - fn from_hex(s: &str) -> Result { - Self::from_hex(s) - } - } - impl Default for $name { fn default() -> Self { Self::ZERO diff --git a/pkgs/num/src/lib.rs b/pkgs/num/src/lib.rs index 0c2008b9..8ec7b545 100644 --- a/pkgs/num/src/lib.rs +++ b/pkgs/num/src/lib.rs @@ -15,7 +15,6 @@ extern crate alloc; #[cfg(feature = "std")] extern crate std; -mod arith; mod arith256; mod compact; mod hash; @@ -34,7 +33,6 @@ pub mod __private { pub use serde; } -pub use arith::ArithInt; pub use arith256::Arith256; pub use compact::{CompactTarget, DecodedTarget}; -pub use hash::{Hash160, Hash256, HashBlob, ParseHexError}; +pub use hash::{Hash160, Hash256, ParseHexError}; From 1d876046e7c69540ea22c3f075a281e7658dfc44 Mon Sep 17 00:00:00 2001 From: Kittywhiskers Van Gogh <63189531+kwvg@users.noreply.github.com> Date: Mon, 14 Sep 2026 12:19:37 +0530 Subject: [PATCH 04/23] num%refac: shave duplicate definitions, inline in trait impls or drop --- pkgs/num/src/arith256.rs | 96 ++++++------------------------------ pkgs/num/src/compact.rs | 7 --- pkgs/num/src/lib.rs | 4 +- pkgs/num/tests/arith.rs | 29 +++-------- pkgs/num/tests/compact.rs | 8 --- pkgs/primitives/src/block.rs | 2 +- 6 files changed, 24 insertions(+), 122 deletions(-) diff --git a/pkgs/num/src/arith256.rs b/pkgs/num/src/arith256.rs index aff949e6..4b7bb37b 100644 --- a/pkgs/num/src/arith256.rs +++ b/pkgs/num/src/arith256.rs @@ -35,9 +35,6 @@ impl Arith256 { lo: u128::MAX, hi: u128::MAX, }; - /// Byte length. - pub const LEN: usize = 32; - /// Create from a `u64`, zero-extending the upper bits. #[inline] pub fn from_u64(v: u64) -> Self { @@ -119,24 +116,6 @@ impl Arith256 { be } - /// Returns `true` if the value is zero. - #[inline] - pub fn is_zero(self) -> bool { - self.lo == 0 && self.hi == 0 - } - - /// Returns `true` if the value is one. - #[inline] - pub fn is_one(self) -> bool { - self.lo == 1 && self.hi == 0 - } - - /// Returns `true` if the value is MAX (all bits set). - #[inline] - pub fn is_max(self) -> bool { - self.lo == u128::MAX && self.hi == u128::MAX - } - /// Returns the lowest 32 bits of the value. #[inline] pub fn low_u32(self) -> u32 { @@ -194,27 +173,6 @@ impl Arith256 { Self { lo, hi } } - /// Two's complement negation. - #[inline] - pub fn wrapping_neg(self) -> Self { - self.bitwise_not().wrapping_add(Self::ONE) - } - - /// Wrapping increment (add one). - #[inline] - pub fn wrapping_inc(self) -> Self { - self.wrapping_add(Self::ONE) - } - - /// Bitwise NOT. - #[inline] - pub fn bitwise_not(self) -> Self { - Self { - lo: !self.lo, - hi: !self.hi, - } - } - /// Wrapping multiply via 64-bit limb decomposition. pub fn wrapping_mul(self, rhs: Self) -> Self { let a0 = self.lo as u64 as u128; @@ -268,7 +226,7 @@ impl Arith256 { /// Checked division. Returns `None` on divide-by-zero. pub fn checked_div(self, rhs: Self) -> Option { - if rhs.is_zero() { + if rhs == Self::ZERO { return None; } Some(self.div_rem(rhs).0) @@ -278,7 +236,7 @@ impl Arith256 { /// /// Returns `(ZERO, ZERO)` when `rhs` is zero. pub fn div_rem(self, rhs: Self) -> (Self, Self) { - if rhs.is_zero() { + if rhs == Self::ZERO { return (Self::ZERO, Self::ZERO); } @@ -357,34 +315,6 @@ impl Arith256 { } } - /// Wrapping multiply by a `u32` scalar. - pub fn wrapping_mul_u32(self, b: u32) -> Self { - let b = b as u128; - let a0 = self.lo as u64 as u128; - let a1 = (self.lo >> 64) as u64 as u128; - let a2 = self.hi as u64 as u128; - let a3 = (self.hi >> 64) as u64 as u128; - - let n0 = a0 * b; - let r0 = n0 as u64 as u128; - let carry = n0 >> 64; - - let n1 = carry + a1 * b; - let r1 = n1 as u64 as u128; - let carry = n1 >> 64; - - let n2 = carry + a2 * b; - let r2 = n2 as u64 as u128; - let carry = n2 >> 64; - - let r3 = (carry + a3 * b) as u64 as u128; - - Self { - lo: r0 | (r1 << 64), - hi: r2 | (r3 << 64), - } - } - /// Multiply by a `u64` scalar, returning the result and an overflow flag. pub fn mul_u64(self, b: u64) -> (Self, bool) { let b = b as u128; @@ -420,15 +350,15 @@ impl Arith256 { /// Compute `2^256 / (self + 1)`. Returns MAX when self is zero or one. pub fn inverse(self) -> Self { - if self.is_zero() || self.is_one() { + if self == Self::ZERO || self == Self::ONE { return Self::MAX; } - if self.is_max() { + if self == Self::MAX { return Self::ONE; } - let d = self.wrapping_inc(); - // !self = 2^256 - 1 - self, so (!self) / (self + 1) + 1 ~ 2^256 / (self + 1) - self.bitwise_not().div_rem(d).0.wrapping_inc() + let d = self.wrapping_add(Self::ONE); + // !self = 2^256 - 1 - self, so (!self) / (self + 1) + 1 = 2^256 / (self + 1) + (!self).div_rem(d).0.wrapping_add(Self::ONE) } /// Approximate conversion to `f64`. @@ -497,8 +427,7 @@ impl fmt::Debug for Arith256 { /// Reversed hex (big-endian display, consensus format). impl fmt::Display for Arith256 { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - let h: Hash256 = (*self).into(); - fmt::Display::fmt(&h, f) + fmt::LowerHex::fmt(self, f) } } @@ -613,7 +542,7 @@ impl Mul for Arith256 { type Output = Self; #[inline] fn mul(self, rhs: u32) -> Self { - self.wrapping_mul_u32(rhs) + self.mul_u64(u64::from(rhs)).0 } } @@ -661,7 +590,7 @@ impl Neg for Arith256 { type Output = Self; #[inline] fn neg(self) -> Self { - self.wrapping_neg() + (!self).wrapping_add(Self::ONE) } } @@ -669,7 +598,10 @@ impl Not for Arith256 { type Output = Self; #[inline] fn not(self) -> Self { - self.bitwise_not() + Self { + lo: !self.lo, + hi: !self.hi, + } } } diff --git a/pkgs/num/src/compact.rs b/pkgs/num/src/compact.rs index d28b9f01..d5ad6fa5 100644 --- a/pkgs/num/src/compact.rs +++ b/pkgs/num/src/compact.rs @@ -80,13 +80,6 @@ impl fmt::Display for CompactTarget { } impl Arith256 { - /// Decode a compact (nBits) representation into a 256-bit target value. - /// - /// Convenience method that delegates to [`CompactTarget::decode`]. - pub fn from_compact(ct: CompactTarget) -> DecodedTarget { - ct.decode() - } - /// Encode this value as a compact (nBits) representation. pub fn to_compact(self, negative: bool) -> CompactTarget { let mut size = self.bits().div_ceil(8); diff --git a/pkgs/num/src/lib.rs b/pkgs/num/src/lib.rs index 8ec7b545..cc018506 100644 --- a/pkgs/num/src/lib.rs +++ b/pkgs/num/src/lib.rs @@ -20,9 +20,7 @@ mod compact; mod hash; #[allow(unused_imports, reason = "ergonomic shim, exports may be unused")] mod prelude; - -#[doc(hidden)] -pub mod util; +mod util; #[doc(hidden)] pub mod __private { diff --git a/pkgs/num/tests/arith.rs b/pkgs/num/tests/arith.rs index f6174cd4..3b1b24d5 100644 --- a/pkgs/num/tests/arith.rs +++ b/pkgs/num/tests/arith.rs @@ -488,7 +488,7 @@ mod divide { let shr = shl >> 40u32; assert_eq!(shr, from_array([0, 0, 0x0001_BD5B_7DDF_BD5B, 0x7DDE_0000_0000_0000])); - let incr = shr.wrapping_inc(); + let incr = shr.wrapping_add(Arith256::ONE); assert_eq!(incr, from_array([0, 0, 0x0001_BD5B_7DDF_BD5B, 0x7DDE_0000_0000_0001])); let sub = incr.wrapping_sub(init); @@ -746,22 +746,9 @@ mod methods { } #[rstest] - fn is_one() { - assert!(Arith256::ONE.is_one()); - assert!(!Arith256::ZERO.is_one()); - assert!(!Arith256::MAX.is_one()); - assert!(!Arith256::from_u64(2).is_one()); - } - - #[rstest] - fn is_max() { - assert!(Arith256::MAX.is_max()); - assert!(!Arith256::ZERO.is_max()); - assert!(!Arith256::ONE.is_max()); - assert!(!Arith256::from_u128(u128::MAX).is_max()); - // Construct MAX from parts + fn max_is_both_halves_set() { let u = Arith256::from_u128(u128::MAX); - assert!(((u << 128u32) + u).is_max()); + assert_eq!((u << 128u32) + u, Arith256::MAX); } #[rstest] @@ -942,13 +929,13 @@ mod mul_u64 { } } -mod wrapping_inc { +mod increment { use super::*; #[rstest] fn basic() { - assert_eq!(Arith256::ZERO.wrapping_inc(), Arith256::ONE); - assert_eq!(Arith256::MAX.wrapping_inc(), Arith256::ZERO); + assert_eq!(Arith256::ZERO.wrapping_add(Arith256::ONE), Arith256::ONE); + assert_eq!(Arith256::MAX.wrapping_add(Arith256::ONE), Arith256::ZERO); } #[rstest] @@ -959,7 +946,7 @@ mod wrapping_inc { 0xFFFF_FFFF_FFFF_FFFF, 0xFFFF_FFFF_FFFF_FFFE, ]); - val = val.wrapping_inc(); + val = val.wrapping_add(Arith256::ONE); assert_eq!( val, from_array([ @@ -969,7 +956,7 @@ mod wrapping_inc { 0xFFFF_FFFF_FFFF_FFFF, ]) ); - val = val.wrapping_inc(); + val = val.wrapping_add(Arith256::ONE); assert_eq!( val, from_array([ diff --git a/pkgs/num/tests/compact.rs b/pkgs/num/tests/compact.rs index 1b0e9cbd..b3d3744b 100644 --- a/pkgs/num/tests/compact.rs +++ b/pkgs/num/tests/compact.rs @@ -120,14 +120,6 @@ fn compact_ff123456_overflow() { assert!(ct.overflow); } -/// Test convenience method on Arith256. -#[rstest] -fn from_compact_convenience() { - let ct = CompactTarget(0x0312_3456); - let decoded = Arith256::from_compact(ct); - assert_eq!(decoded.value, Arith256::from_u64(0x12_3456)); -} - #[rstest] #[case(0x0100_3456_u32, 0x00_u64)] #[case(0x0112_3456_u32, 0x12_u64)] diff --git a/pkgs/primitives/src/block.rs b/pkgs/primitives/src/block.rs index e21a99d3..89babb0a 100644 --- a/pkgs/primitives/src/block.rs +++ b/pkgs/primitives/src/block.rs @@ -140,7 +140,7 @@ impl Checkable for Block { fn check(&self) -> Option { let pow_hash = Arith256::from(Hash256::from(self.header.hash())); let decoded = CompactTarget(self.header.bits).decode(); - if decoded.negative || decoded.value.is_zero() || decoded.overflow || pow_hash > decoded.value { + if decoded.negative || decoded.value == Arith256::ZERO || decoded.overflow || pow_hash > decoded.value { return Some(BlockInvalid::BadProofOfWork); } From 15f45afe89d1aaf045e99d6ee03bdae40106105c Mon Sep 17 00:00:00 2001 From: Kittywhiskers Van Gogh <63189531+kwvg@users.noreply.github.com> Date: Mon, 14 Sep 2026 12:20:28 +0530 Subject: [PATCH 05/23] num%refac(compact): seal the inner type and tidy the target API --- docs/samples/solver/solver.rs | 2 +- pkgs/num/src/compact.rs | 20 ++++++++++------- pkgs/num/tests/compact.rs | 42 +++++++++++++++++------------------ pkgs/num/tests/serde.rs | 6 ++--- pkgs/primitives/src/block.rs | 2 +- 5 files changed, 38 insertions(+), 34 deletions(-) diff --git a/docs/samples/solver/solver.rs b/docs/samples/solver/solver.rs index cb699725..265858ee 100644 --- a/docs/samples/solver/solver.rs +++ b/docs/samples/solver/solver.rs @@ -101,7 +101,7 @@ pub fn scanhash( }; let mut header_buf = encode_to_vec(&header); - let decoded = CompactTarget(bits).decode(); + let decoded = CompactTarget::new(bits).expand(); if decoded.negative || decoded.overflow { return Err("invalid compact target".to_string()); } diff --git a/pkgs/num/src/compact.rs b/pkgs/num/src/compact.rs index d5ad6fa5..b531cd56 100644 --- a/pkgs/num/src/compact.rs +++ b/pkgs/num/src/compact.rs @@ -15,11 +15,9 @@ use dash_types::impl_num; use core::fmt; -/// Compact difficulty target -- a newtype around the consensus `nBits` u32. -/// -/// Construct directly via `CompactTarget(0x1d00ffff)`. +/// Compact difficulty target. #[derive(Clone, Copy, Debug, Default, PartialEq, Eq, PartialOrd, Ord, Hash)] -pub struct CompactTarget(pub u32); +pub struct CompactTarget(u32); /// Result of decoding a compact difficulty target. #[derive(Clone, Copy, Debug, Default, Eq, Hash, PartialEq)] @@ -48,8 +46,14 @@ impl NumCodec for CompactTarget { impl_num!(CompactTarget, u32); impl CompactTarget { - /// Decode this compact (nBits) representation into a 256-bit target value. - pub fn decode(self) -> DecodedTarget { + /// Wraps a raw `nBits` word. + #[inline] + pub fn new(bits: u32) -> Self { + Self(bits) + } + + /// Expand this compact (nBits) representation to a 256-bit target value. + pub fn expand(self) -> DecodedTarget { let compact = self.0; let size = (compact >> 24) as usize; let mut word = compact & 0x007f_ffff; @@ -80,8 +84,8 @@ impl fmt::Display for CompactTarget { } impl Arith256 { - /// Encode this value as a compact (nBits) representation. - pub fn to_compact(self, negative: bool) -> CompactTarget { + /// Compact this value to its `nBits` representation. + pub fn compact(self, negative: bool) -> CompactTarget { let mut size = self.bits().div_ceil(8); let mut compact: u32 = if size <= 3 { (self.low_u64() << (8 * (3 - size as u64))) as u32 diff --git a/pkgs/num/tests/compact.rs b/pkgs/num/tests/compact.rs index b3d3744b..8f6900d5 100644 --- a/pkgs/num/tests/compact.rs +++ b/pkgs/num/tests/compact.rs @@ -11,7 +11,7 @@ use rstest::*; /// Assert compact decode flags match expectations. fn check_compact(compact: u32, expected_negative: bool, expected_overflow: bool) { - let ct = CompactTarget(compact).decode(); + let ct = CompactTarget::new(compact).expand(); assert_eq!( ct.negative, expected_negative, "negative mismatch for compact {compact:#010x}" @@ -32,9 +32,9 @@ fn check_compact(compact: u32, expected_negative: bool, expected_overflow: bool) #[case(0x0300_0000)] #[case(0x0400_0000)] fn zero_value(#[case] compact: u32) { - let ct = CompactTarget(compact).decode(); + let ct = CompactTarget::new(compact).expand(); assert_eq!(ct.value, Arith256::ZERO); - assert_eq!(ct.value.to_compact(false), CompactTarget(0)); + assert_eq!(ct.value.compact(false), CompactTarget::new(0)); check_compact(compact, false, false); } @@ -47,34 +47,34 @@ fn zero_value(#[case] compact: u32) { #[case(0x0380_0000)] #[case(0x0480_0000)] fn sign_bit_but_zero_word(#[case] compact: u32) { - let ct = CompactTarget(compact).decode(); + let ct = CompactTarget::new(compact).expand(); assert_eq!(ct.value, Arith256::ZERO); - assert_eq!(ct.value.to_compact(false), CompactTarget(0)); + assert_eq!(ct.value.compact(false), CompactTarget::new(0)); check_compact(compact, false, false); } #[rstest] fn compact_01123456() { - let ct = CompactTarget(0x01123456).decode(); + let ct = CompactTarget::new(0x01123456).expand(); assert_eq!(ct.value, Arith256::from_u64(0x12)); - assert_eq!(ct.value.to_compact(false), CompactTarget(0x01120000)); + assert_eq!(ct.value.compact(false), CompactTarget::new(0x01120000)); check_compact(0x01123456, false, false); } #[rstest] fn compact_0x80_avoids_sign_bit() { let num = Arith256::from_u64(0x80); - assert_eq!(num.to_compact(false), CompactTarget(0x02008000)); + assert_eq!(num.compact(false), CompactTarget::new(0x02008000)); } #[rstest] fn compact_01fedcba() { // word=0x7edcba, size=1, shifted=0x7e, sign bit set - let ct = CompactTarget(0x01fedcba).decode(); + let ct = CompactTarget::new(0x01fedcba).expand(); assert_eq!(ct.value, Arith256::from_u64(0x7e)); assert!(ct.negative); assert!(!ct.overflow); - assert_eq!(ct.value.to_compact(true), CompactTarget(0x01fe0000)); + assert_eq!(ct.value.compact(true), CompactTarget::new(0x01fe0000)); } /// Non-zero values with expected compact roundtrips. @@ -83,39 +83,39 @@ fn compact_01fedcba() { #[case(0x0312_3456, 0x12_3456, 0x0312_3456)] #[case(0x0412_3456, 0x1234_5600, 0x0412_3456)] fn positive_values(#[case] compact: u32, #[case] expected_val: u64, #[case] expected_roundtrip: u32) { - let ct = CompactTarget(compact).decode(); + let ct = CompactTarget::new(compact).expand(); assert_eq!(ct.value, Arith256::from_u64(expected_val)); - assert_eq!(ct.value.to_compact(false), CompactTarget(expected_roundtrip)); + assert_eq!(ct.value.compact(false), CompactTarget::new(expected_roundtrip)); check_compact(compact, false, false); } #[rstest] fn compact_04923456_negative() { - let ct = CompactTarget(0x04923456).decode(); + let ct = CompactTarget::new(0x04923456).expand(); assert_eq!(ct.value, Arith256::from_u64(0x12345600)); assert!(ct.negative); assert!(!ct.overflow); - assert_eq!(ct.value.to_compact(true), CompactTarget(0x04923456)); + assert_eq!(ct.value.compact(true), CompactTarget::new(0x04923456)); } #[rstest] fn compact_05009234() { - let ct = CompactTarget(0x05009234).decode(); + let ct = CompactTarget::new(0x05009234).expand(); assert_eq!(ct.value, Arith256::from_u64(0x92340000)); - assert_eq!(ct.value.to_compact(false), CompactTarget(0x05009234)); + assert_eq!(ct.value.compact(false), CompactTarget::new(0x05009234)); check_compact(0x05009234, false, false); } #[rstest] fn compact_20123456() { - let ct = CompactTarget(0x20123456).decode(); - assert_eq!(ct.value.to_compact(false), CompactTarget(0x20123456)); + let ct = CompactTarget::new(0x20123456).expand(); + assert_eq!(ct.value.compact(false), CompactTarget::new(0x20123456)); check_compact(0x20123456, false, false); } #[rstest] fn compact_ff123456_overflow() { - let ct = CompactTarget(0xff123456).decode(); + let ct = CompactTarget::new(0xff123456).expand(); assert!(!ct.negative); assert!(ct.overflow); } @@ -128,7 +128,7 @@ fn compact_ff123456_overflow() { #[case(0x0492_3456_u32, 0x00_u64)] #[case(0x0412_3456_u32, 0x1234_5600_u64)] fn target_from_compact_ported(#[case] n_bits: u32, #[case] target: u64) { - let decoded = CompactTarget(n_bits).decode(); + let decoded = CompactTarget::new(n_bits).expand(); // For negative-flagged values the target is 0. if decoded.negative { assert_eq!(Arith256::from_u64(target), Arith256::ZERO); @@ -140,5 +140,5 @@ fn target_from_compact_ported(#[case] n_bits: u32, #[case] target: u64) { /// CompactTarget display. #[rstest] fn display() { - assert_eq!(format!("{}", CompactTarget(0x1d00ffff)), "0x1d00ffff"); + assert_eq!(format!("{}", CompactTarget::new(0x1d00ffff)), "0x1d00ffff"); } diff --git a/pkgs/num/tests/serde.rs b/pkgs/num/tests/serde.rs index 0b6bd743..a8336c2b 100644 --- a/pkgs/num/tests/serde.rs +++ b/pkgs/num/tests/serde.rs @@ -68,7 +68,7 @@ fn arith256_json_invalid() { #[test] fn compact_target_json_roundtrip() { - assert_json_rt(&CompactTarget(0)); - assert_json_rt(&CompactTarget(0x1d00ffff)); - assert_json_rt(&CompactTarget(0x0412_3456)); + assert_json_rt(&CompactTarget::new(0)); + assert_json_rt(&CompactTarget::new(0x1d00ffff)); + assert_json_rt(&CompactTarget::new(0x0412_3456)); } diff --git a/pkgs/primitives/src/block.rs b/pkgs/primitives/src/block.rs index 89babb0a..abed81b4 100644 --- a/pkgs/primitives/src/block.rs +++ b/pkgs/primitives/src/block.rs @@ -139,7 +139,7 @@ impl Checkable for Block { fn check(&self) -> Option { let pow_hash = Arith256::from(Hash256::from(self.header.hash())); - let decoded = CompactTarget(self.header.bits).decode(); + let decoded = CompactTarget::new(self.header.bits).expand(); if decoded.negative || decoded.value == Arith256::ZERO || decoded.overflow || pow_hash > decoded.value { return Some(BlockInvalid::BadProofOfWork); } From db4bf4a50eeab14fdcd7792749578c3099f60aef Mon Sep 17 00:00:00 2001 From: Kittywhiskers Van Gogh <63189531+kwvg@users.noreply.github.com> Date: Mon, 14 Sep 2026 12:01:28 +0530 Subject: [PATCH 06/23] num%refac(hash): replace manual conversion routines with `type_cvrt!` --- pkgs/num/src/hash.rs | 13 ++----------- pkgs/num/src/util.rs | 23 ++++------------------- 2 files changed, 6 insertions(+), 30 deletions(-) diff --git a/pkgs/num/src/hash.rs b/pkgs/num/src/hash.rs index 1f70d367..3a6514f6 100644 --- a/pkgs/num/src/hash.rs +++ b/pkgs/num/src/hash.rs @@ -215,17 +215,8 @@ macro_rules! define_hash { } } - impl From<[u8; $n]> for $name { - fn from(bytes: [u8; $n]) -> Self { - Self(bytes) - } - } - - impl From<$name> for [u8; $n] { - fn from(h: $name) -> Self { - h.0 - } - } + $crate::__private::dash_types::type_cvrt!(From<[u8; $n]> for $name, |b| Self(*b)); + $crate::__private::dash_types::type_cvrt!(From<$name> for [u8; $n], |h| h.0); impl AsRef<[u8]> for $name { fn as_ref(&self) -> &[u8] { diff --git a/pkgs/num/src/util.rs b/pkgs/num/src/util.rs index 89b721d3..c3f8a7d9 100644 --- a/pkgs/num/src/util.rs +++ b/pkgs/num/src/util.rs @@ -172,25 +172,10 @@ macro_rules! make_hash { } } - impl From<[u8; { <$base>::LEN }]> for $name { - #[inline] - fn from(bytes: [u8; { <$base>::LEN }]) -> Self { Self::from_bytes(bytes) } - } - - impl From<$name> for [u8; { <$base>::LEN }] { - #[inline] - fn from(h: $name) -> Self { h.to_bytes() } - } - - impl From<$base> for $name { - #[inline] - fn from(h: $base) -> Self { Self(h) } - } - - impl From<$name> for $base { - #[inline] - fn from(h: $name) -> Self { h.0 } - } + $crate::__private::dash_types::type_cvrt!(From<[u8; { <$base>::LEN }]> for $name, |b| Self::from_bytes(*b)); + $crate::__private::dash_types::type_cvrt!(From<$name> for [u8; { <$base>::LEN }], |h| h.to_bytes()); + $crate::__private::dash_types::type_cvrt!(From<$base> for $name, |h| Self(*h)); + $crate::__private::dash_types::type_cvrt!(From<$name> for $base, |h| h.0); impl AsRef<[u8]> for $name { #[inline] From f5643c037c29388aecbb2eb9468806d7729dc1e9 Mon Sep 17 00:00:00 2001 From: Kittywhiskers Van Gogh <63189531+kwvg@users.noreply.github.com> Date: Mon, 14 Sep 2026 12:22:07 +0530 Subject: [PATCH 07/23] num%refac(hash): replace manual parsing with `hex-conservative` --- Cargo.lock | 1 + docs/samples/Cargo.lock | 1 + pkgs/num/Cargo.toml | 7 ++++- pkgs/num/src/hash.rs | 66 ++++++++++------------------------------- 4 files changed, 23 insertions(+), 52 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index feffc358..95719ac5 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -492,6 +492,7 @@ dependencies = [ "dash-dev", "dash-types", "divan", + "hex-conservative 0.3.2", "hex-literal", "rstest", "serde", diff --git a/docs/samples/Cargo.lock b/docs/samples/Cargo.lock index a629f9fb..81f0c10d 100644 --- a/docs/samples/Cargo.lock +++ b/docs/samples/Cargo.lock @@ -122,6 +122,7 @@ version = "0.0.0" dependencies = [ "bitcoin-consensus-encoding 1.2.0", "dash-types", + "hex-conservative 0.3.2", "serde", ] diff --git a/pkgs/num/Cargo.toml b/pkgs/num/Cargo.toml index 0696c80d..4a91b668 100644 --- a/pkgs/num/Cargo.toml +++ b/pkgs/num/Cargo.toml @@ -11,7 +11,11 @@ rust-version.workspace = true [features] default = [] -std = ["bitcoin-consensus-encoding?/std", "dash-types/std"] +std = [ + "bitcoin-consensus-encoding?/std", + "dash-types/std", + "hex-conservative/std", +] full = ["std", "codec", "serde"] codec = ["dep:bitcoin-consensus-encoding", "dash-types/codec"] serde = ["dep:serde", "dash-types/serde"] @@ -19,6 +23,7 @@ serde = ["dep:serde", "dash-types/serde"] [dependencies] bitcoin-consensus-encoding = { workspace = true, optional = true } dash-types = { version = "0.0.0", path = "../types", default-features = false } +hex-conservative = { version = "0.3", default-features = false } serde = { version = "1", default-features = false, features = [ "derive", "alloc", diff --git a/pkgs/num/src/hash.rs b/pkgs/num/src/hash.rs index 3a6514f6..9ecc8855 100644 --- a/pkgs/num/src/hash.rs +++ b/pkgs/num/src/hash.rs @@ -6,12 +6,12 @@ //! Fixed-size opaque hash blob types. -use core::fmt; +use hex_conservative::{BytesToHexIter, Case, HexToBytesIter}; + +use core::fmt::{self, Write as _}; use core::hash::Hash; use core::str::FromStr; -pub(crate) const HEX_LOWER: [u8; 16] = *b"0123456789abcdef"; - /// Error returned when parsing a hex string fails. #[derive(Clone, Debug, PartialEq, Eq)] pub enum ParseHexError { @@ -40,15 +40,6 @@ impl fmt::Display for ParseHexError { #[cfg(feature = "std")] impl std::error::Error for ParseHexError {} -pub(crate) fn hex_val(c: u8) -> Result { - match c { - b'0'..=b'9' => Ok(c - b'0'), - b'a'..=b'f' => Ok(c - b'a' + 10), - b'A'..=b'F' => Ok(c - b'A' + 10), - _ => Err(ParseHexError::InvalidChar(c)), - } -} - macro_rules! define_hash { ($name:ident, $n:literal) => { /// Fixed-size opaque hash blob stored in little-endian byte order. @@ -110,53 +101,29 @@ macro_rules! define_hash { /// Parse from a big-endian hex string. /// /// Accepts an optional `0x`/`0X` prefix followed by optional leading - /// spaces before the hex digits. The digits are big-endian (most - /// significant byte first), mirroring the consensus display convention. + /// spaces before the hex digits. The digits are big-endian (MSB first), + /// mirroring the consensus display convention. /// /// # Errors /// - /// Returns `OddLength` when the input has an odd - /// number of hex characters, `InvalidLength` when the - /// decoded byte count exceeds the type width, or + /// Returns `OddLength` when input has an odd number of hex characters, + /// `InvalidLength` when the decoded byte count exceeds the type width, or /// `InvalidChar` on a non-hex digit. pub fn from_hex(s: &str) -> Result { - let s = s.as_bytes(); - - // strip optional 0x prefix - let s = if s.len() >= 2 && s[0] == b'0' && (s[1] == b'x' || s[1] == b'X') { - &s[2..] - } else { - s - }; - - // skip leading whitespace - let mut start = 0; - while start < s.len() && s[start] == b' ' { - start += 1; - } - let s = &s[start..]; - - if s.len() % 2 != 0 { - return Err(ParseHexError::OddLength); - } + let s = s.strip_prefix("0x").or_else(|| s.strip_prefix("0X")).unwrap_or(s); + let s = s.trim_start_matches(' '); - let byte_len = s.len() / 2; - if byte_len > $n { + if s.len() > $n * 2 { return Err(ParseHexError::InvalidLength { expected: $n * 2, got: s.len(), }); } + let digits = HexToBytesIter::new(s).map_err(|_| ParseHexError::OddLength)?; let mut bytes = [0u8; $n]; - // Big-endian hex: first byte is most significant, - // stored last in the little-endian array. - let mut i = 0; - while i < byte_len { - let hi = hex_val(s[i * 2])?; - let lo = hex_val(s[i * 2 + 1])?; - bytes[byte_len - 1 - i] = (hi << 4) | lo; - i += 1; + for (slot, byte) in bytes.iter_mut().zip(digits.rev()) { + *slot = byte.map_err(|e| ParseHexError::InvalidChar(e.invalid_char()))?; } Ok(Self(bytes)) @@ -185,11 +152,8 @@ macro_rules! define_hash { /// Reversed hex (big-endian display, consensus format). impl fmt::Display for $name { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - for i in (0..$n).rev() { - let b = self.0[i]; - let c1 = HEX_LOWER[(b >> 4) as usize] as char; - let c2 = HEX_LOWER[(b & 0x0f) as usize] as char; - f.write_fmt(format_args!("{c1}{c2}"))?; + for c in BytesToHexIter::new(self.0.iter().rev().copied(), Case::Lower) { + f.write_char(c)?; } Ok(()) } From a2e26faeb7ae1336207943c7495d6955d9bac16f Mon Sep 17 00:00:00 2001 From: Kittywhiskers Van Gogh <63189531+kwvg@users.noreply.github.com> Date: Sun, 13 Sep 2026 22:54:56 +0530 Subject: [PATCH 08/23] types%refac: `uint` -> `numeric`,`codec::NumCodec` -> `numeric::Numeric` --- maint/codeql/rust/lib/policy.qll | 8 ++++---- maint/semgrep/rust/types.yml | 2 +- pkgs/num/src/compact.rs | 6 +++--- pkgs/primitives/src/types/netinfo.rs | 5 +++-- pkgs/types/src/codec.rs | 9 --------- pkgs/types/src/lib.rs | 3 ++- pkgs/types/src/macros.rs | 10 +++++----- pkgs/types/src/{uint.rs => numeric.rs} | 21 +++++++++++++++------ 8 files changed, 33 insertions(+), 31 deletions(-) rename pkgs/types/src/{uint.rs => numeric.rs} (86%) diff --git a/maint/codeql/rust/lib/policy.qll b/maint/codeql/rust/lib/policy.qll index d2e1a260..adb4bf26 100644 --- a/maint/codeql/rust/lib/policy.qll +++ b/maint/codeql/rust/lib/policy.qll @@ -295,7 +295,7 @@ predicate isUnencodableCrate(File f) { /** Declaration slots that define the required source ordering. */ newtype TDeclSlot = TDefinition() or - TNumCodecImpl() or + TNumericImpl() or TBaseCodecImpl() or TCheckableImpl() or THashableImpl() or @@ -308,7 +308,7 @@ class DeclSlot extends TDeclSlot { int getOrder() { this = TDefinition() and result = 0 or - this = TNumCodecImpl() and result = 1 + this = TNumericImpl() and result = 1 or this = TBaseCodecImpl() and result = 2 or @@ -325,7 +325,7 @@ class DeclSlot extends TDeclSlot { string toString() { this = TDefinition() and result = "definition" or - this = TNumCodecImpl() and result = "NumCodec impl" + this = TNumericImpl() and result = "Numeric impl" or this = TBaseCodecImpl() and result = "BaseCodec/Encode/Decode impl" @@ -342,7 +342,7 @@ class DeclSlot extends TDeclSlot { /** Maps a trait name to its declaration slot. */ DeclSlot traitSlot(string traitName) { - traitName = "NumCodec" and result = TNumCodecImpl() + traitName = "Numeric" and result = TNumericImpl() or traitName = "BaseCodec" and result = TBaseCodecImpl() or diff --git a/maint/semgrep/rust/types.yml b/maint/semgrep/rust/types.yml index de12fe8d..0ba84086 100644 --- a/maint/semgrep/rust/types.yml +++ b/maint/semgrep/rust/types.yml @@ -9,7 +9,7 @@ rules: - /pkgs/types/src/entity.rs - /pkgs/types/src/macros.rs - /pkgs/types/src/secret.rs - - /pkgs/types/src/uint.rs + - /pkgs/types/src/numeric.rs pattern-regex: '\b(?:make|impl)_(?:bytes|num|type)!\s*[({]' - id: types-macro-generics-bracketed diff --git a/pkgs/num/src/compact.rs b/pkgs/num/src/compact.rs index b531cd56..71319437 100644 --- a/pkgs/num/src/compact.rs +++ b/pkgs/num/src/compact.rs @@ -8,10 +8,10 @@ use crate::Arith256; -#[cfg(feature = "codec")] -use dash_types::codec::NumCodec; #[cfg(feature = "codec")] use dash_types::impl_num; +#[cfg(feature = "codec")] +use dash_types::Numeric; use core::fmt; @@ -32,7 +32,7 @@ pub struct DecodedTarget { } #[cfg(feature = "codec")] -impl NumCodec for CompactTarget { +impl Numeric for CompactTarget { fn from_base(v: u32) -> Self { Self(v) } diff --git a/pkgs/primitives/src/types/netinfo.rs b/pkgs/primitives/src/types/netinfo.rs index 1c9f85c2..db681486 100644 --- a/pkgs/primitives/src/types/netinfo.rs +++ b/pkgs/primitives/src/types/netinfo.rs @@ -11,8 +11,9 @@ use super::{AddrV2, NetAddrError, ServiceV1, ServiceV2}; use crate::hash_impl; use crate::prelude::*; -use dash_types::codec::{self, BaseCodec, Checkable, DecodeError, EncodeBuf, NumCodec}; +use dash_types::codec::{self, BaseCodec, Checkable, DecodeError, EncodeBuf}; use dash_types::type_id::{TypeId, Unencodable}; +use dash_types::Numeric; use dash_types::{enum_map, impl_num, impl_type, CompactSize}; use core::fmt; @@ -163,7 +164,7 @@ impl BaseCodec for NIEntry { NIEntryCode::Unknown(t) => Err(DecodeError::InvalidValue { expected: NIEntryCode::variants() .iter() - .map(|v| u64::from(NumCodec::::to_base(v))) + .map(|v| u64::from(Numeric::::to_base(v))) .collect(), actual: u64::from(t), }), diff --git a/pkgs/types/src/codec.rs b/pkgs/types/src/codec.rs index 62e072a0..efaf9b50 100644 --- a/pkgs/types/src/codec.rs +++ b/pkgs/types/src/codec.rs @@ -180,15 +180,6 @@ impl EncodeBuf for Vec { } } -/// Links a type to its underlying base integer type. -pub trait NumCodec: Sized { - /// Constructs from the base integer. - fn from_base(v: N) -> Self; - - /// Returns the base integer. - fn to_base(&self) -> N; -} - /// The widest wire image a type's buffering decoder will accept. pub trait SerBound { /// Upper bound on the encoded width, in bytes. diff --git a/pkgs/types/src/lib.rs b/pkgs/types/src/lib.rs index 7e1a83d7..f4ec536a 100644 --- a/pkgs/types/src/lib.rs +++ b/pkgs/types/src/lib.rs @@ -31,13 +31,14 @@ cfg_if::cfg_if! { #[allow(unused_macros, reason = "used by feature-gated submodules")] mod adapters; mod compact; - mod uint; + mod numeric; pub mod codec; pub mod type_id; pub use compact::CompactSize; pub use entity::{VecDecoder, VecEncoder, MAX_SER_SIZE}; + pub use numeric::Numeric; pub use secret::{ArrDecoder, ArrEncoder, ArrayBuf, MAX_ARR_SIZE}; } } diff --git a/pkgs/types/src/macros.rs b/pkgs/types/src/macros.rs index 2cdc3334..98d0f907 100644 --- a/pkgs/types/src/macros.rs +++ b/pkgs/types/src/macros.rs @@ -85,13 +85,13 @@ pub fn qtypestr(f: &mut fmt::Formatter<'_>, path: &str) -> fmt::Result { f.write_str(&path[seg..]) } -/// Generates `NumCodec<$base>` for an enum that already carries the inherent +/// Generates `Numeric<$base>` for an enum that already carries the inherent /// `fn {from,to}_base` pair. #[cfg(feature = "codec")] #[macro_export] macro_rules! impl_enum { ($enum:ident, $base:ty) => { - impl $crate::codec::NumCodec<$base> for $enum { + impl $crate::Numeric<$base> for $enum { fn from_base(val: $base) -> Self { $enum::from_base(val) } @@ -513,10 +513,10 @@ mod tests { #[cfg(feature = "codec")] #[rstest] fn open_maps_through_the_codec_trait() { - use crate::codec::NumCodec; + use crate::Numeric; - assert_eq!(>::from_base(1), Open::One); - assert_eq!(NumCodec::::to_base(&Open::Two), 2); + assert_eq!(>::from_base(1), Open::One); + assert_eq!(Numeric::::to_base(&Open::Two), 2); } struct Qtype<'a>(&'a str); diff --git a/pkgs/types/src/uint.rs b/pkgs/types/src/numeric.rs similarity index 86% rename from pkgs/types/src/uint.rs rename to pkgs/types/src/numeric.rs index d4ded221..b1f6a94d 100644 --- a/pkgs/types/src/uint.rs +++ b/pkgs/types/src/numeric.rs @@ -6,8 +6,17 @@ //! Fixed-size integer newtype macros. +/// Links a type to its underlying base integer type. +pub trait Numeric: Sized { + /// Constructs from the base integer. + fn from_base(v: N) -> Self; + + /// Returns the base integer. + fn to_base(&self) -> N; +} + /// Generates `BaseCodec` + `Encode` + `Decode` + serde for a type -/// that already implements `NumCodec<$uint>`. +/// that already implements `Numeric<$uint>`. #[macro_export] macro_rules! impl_num { ($name:tt, i8) => { $crate::impl_num!(@codec $name, i8, 1); }; @@ -24,7 +33,7 @@ macro_rules! impl_num { data: &mut &[u8], ) -> Result { $crate::codec::take::<$n>(data).map(|b| { - >::from_base( + >::from_base( <$uint>::from_le_bytes(b), ) }) @@ -32,7 +41,7 @@ macro_rules! impl_num { fn encode(&self, buf: &mut impl $crate::codec::EncodeBuf) { buf.extend_from_slice( - &>::to_base(self) + &>::to_base(self) .to_le_bytes(), ); } @@ -46,7 +55,7 @@ macro_rules! impl_num { &self, serializer: S, ) -> Result { $crate::__private::serde::Serialize::serialize( - &>::to_base(self), + &>::to_base(self), serializer, ) } @@ -57,7 +66,7 @@ macro_rules! impl_num { deserializer: D, ) -> Result { <$uint as $crate::__private::serde::Deserialize>::deserialize(deserializer) - .map(>::from_base) + .map(>::from_base) } } } @@ -76,7 +85,7 @@ macro_rules! make_num { #[derive(Clone, Copy, Default, PartialEq, Eq, PartialOrd, Ord, Hash, $crate::type_id::TypeId)] pub struct $name(pub $uint); - impl $crate::codec::NumCodec<$uint> for $name { + impl $crate::Numeric<$uint> for $name { fn from_base(v: $uint) -> Self { Self(v) } From 3b88753804466a2bd53d9e7e45582fa9694ca335 Mon Sep 17 00:00:00 2001 From: Kittywhiskers Van Gogh <63189531+kwvg@users.noreply.github.com> Date: Sun, 13 Sep 2026 22:55:25 +0530 Subject: [PATCH 09/23] types%refac(numeric): decouple `Numeric` trait with `codec` feature --- pkgs/types/src/lib.rs | 4 ++-- pkgs/types/src/numeric.rs | 33 ++++++++++++++++++++++++++------- 2 files changed, 28 insertions(+), 9 deletions(-) diff --git a/pkgs/types/src/lib.rs b/pkgs/types/src/lib.rs index f4ec536a..5161cdd0 100644 --- a/pkgs/types/src/lib.rs +++ b/pkgs/types/src/lib.rs @@ -15,6 +15,7 @@ extern crate std; mod entity; mod macros; +mod numeric; #[allow(unused_imports, reason = "ergonomic shim, exports may be unused")] mod prelude; mod secret; @@ -24,6 +25,7 @@ mod traits; pub mod serialize; pub use macros::qtypestr; +pub use numeric::Numeric; pub use traits::{Checkable, Hashable}; cfg_if::cfg_if! { @@ -31,14 +33,12 @@ cfg_if::cfg_if! { #[allow(unused_macros, reason = "used by feature-gated submodules")] mod adapters; mod compact; - mod numeric; pub mod codec; pub mod type_id; pub use compact::CompactSize; pub use entity::{VecDecoder, VecEncoder, MAX_SER_SIZE}; - pub use numeric::Numeric; pub use secret::{ArrDecoder, ArrEncoder, ArrayBuf, MAX_ARR_SIZE}; } } diff --git a/pkgs/types/src/numeric.rs b/pkgs/types/src/numeric.rs index b1f6a94d..332a913c 100644 --- a/pkgs/types/src/numeric.rs +++ b/pkgs/types/src/numeric.rs @@ -17,6 +17,7 @@ pub trait Numeric: Sized { /// Generates `BaseCodec` + `Encode` + `Decode` + serde for a type /// that already implements `Numeric<$uint>`. +#[cfg(feature = "codec")] #[macro_export] macro_rules! impl_num { ($name:tt, i8) => { $crate::impl_num!(@codec $name, i8, 1); }; @@ -73,17 +74,37 @@ macro_rules! impl_num { }; } -/// Generates a fixed-size integer newtype with consensus encoding traits and -/// standard trait implementations. +/// Generates a fixed-size integer newtype with its base integer conversions +/// and standard trait implementations. +/// +/// With `codec` the newtype also gains a `TypeId` and the consensus encoding +/// traits generated by [`impl_num!`](crate::impl_num). #[macro_export] macro_rules! make_num { + (@struct {$($attr:tt)*} $(#[$derive:meta])? $name:ident, $uint:tt) => { + $($attr)* + #[derive(Clone, Copy, Default, PartialEq, Eq, PartialOrd, Ord, Hash)] + $(#[$derive])? + pub struct $name(pub $uint); + }; + (@decl $attrs:tt $name:ident, $uint:tt) => { + $crate::cfg_codec! { + { + $crate::make_num!( + @struct $attrs #[derive($crate::type_id::TypeId)] $name, $uint + ); + + $crate::impl_num!($name, $uint); + } else { + $crate::make_num!(@struct $attrs $name, $uint); + } + } + }; ( $(#[$attr:meta])* $name:ident, $uint:tt, $n:literal ) => { - $(#[$attr])* - #[derive(Clone, Copy, Default, PartialEq, Eq, PartialOrd, Ord, Hash, $crate::type_id::TypeId)] - pub struct $name(pub $uint); + $crate::make_num!(@decl {$(#[$attr])*} $name, $uint); impl $crate::Numeric<$uint> for $name { fn from_base(v: $uint) -> Self { @@ -95,8 +116,6 @@ macro_rules! make_num { } } - $crate::impl_num!($name, $uint); - impl $name { /// Constructs from the raw integer value. pub const fn new(v: $uint) -> Self { From e066bc76e825f55a2702f9c1e55241de0f7c5050 Mon Sep 17 00:00:00 2001 From: Kittywhiskers Van Gogh <63189531+kwvg@users.noreply.github.com> Date: Mon, 14 Sep 2026 19:31:43 +0530 Subject: [PATCH 10/23] types%refac: restore `enum_map!` usage of `Numeric` for open enums --- pkgs/p2p_core/src/msg/mn_list.rs | 2 +- pkgs/pkc/src/ecdsa/public_bytes.rs | 6 +- pkgs/pkc/src/ecdsa/public_ops.rs | 2 +- pkgs/pkc/src/ecdsa/sig_rec_bytes.rs | 6 +- pkgs/primitives/src/payload/proregtx.rs | 2 +- pkgs/primitives/src/payload/proupservtx.rs | 2 +- pkgs/primitives/src/payload/quorum.rs | 1 + pkgs/primitives/src/transaction.rs | 2 +- pkgs/primitives/src/types/addrv2.rs | 3 +- pkgs/script/src/addrs.rs | 3 +- pkgs/script/src/opcode.rs | 3 +- pkgs/script/src/sigops.rs | 2 + pkgs/types/src/macros.rs | 80 +++++++--------------- 13 files changed, 44 insertions(+), 70 deletions(-) diff --git a/pkgs/p2p_core/src/msg/mn_list.rs b/pkgs/p2p_core/src/msg/mn_list.rs index ca08dbe7..70674b31 100644 --- a/pkgs/p2p_core/src/msg/mn_list.rs +++ b/pkgs/p2p_core/src/msg/mn_list.rs @@ -15,7 +15,7 @@ use dash_primitives::{ }; use dash_script::PubKeyHash; use dash_types::codec::{BaseCodec, DecodeError, EncodeBuf}; -use dash_types::type_id::TypeId; +use dash_types::{type_id::TypeId, Numeric}; use core::fmt; diff --git a/pkgs/pkc/src/ecdsa/public_bytes.rs b/pkgs/pkc/src/ecdsa/public_bytes.rs index 0fe910eb..baee658e 100644 --- a/pkgs/pkc/src/ecdsa/public_bytes.rs +++ b/pkgs/pkc/src/ecdsa/public_bytes.rs @@ -73,7 +73,7 @@ impl BaseCodec for EcdsaPkBytes { let raw = read_bytes(data, n)?; let prefix = raw .first() - .and_then(|&b| Sec1Byte::from_base(b)) + .and_then(|&b| Sec1Byte::try_from_base(b)) .ok_or_else(|| DecodeError::InvalidValue { expected: Sec1Byte::variants().iter().map(|p| u64::from(p.to_base())).collect(), actual: raw.first().map_or(0, |&b| u64::from(b)), @@ -126,7 +126,7 @@ impl EcdsaPkBytes { /// Constructs from raw SEC1 bytes. pub fn from_bytes(bytes: &[u8]) -> Option { - let prefix = Sec1Byte::from_base(*bytes.first()?)?; + let prefix = Sec1Byte::try_from_base(*bytes.first()?)?; if bytes.len() != prefix.size() { return None; } @@ -258,6 +258,6 @@ mod tests { #[case(0x00)] #[case(0x05)] fn sec1_byte_rejects_invalid(#[case] byte: u8) { - assert!(Sec1Byte::from_base(byte).is_none()); + assert!(Sec1Byte::try_from_base(byte).is_none()); } } diff --git a/pkgs/pkc/src/ecdsa/public_ops.rs b/pkgs/pkc/src/ecdsa/public_ops.rs index f241dec5..b74a4de9 100644 --- a/pkgs/pkc/src/ecdsa/public_ops.rs +++ b/pkgs/pkc/src/ecdsa/public_ops.rs @@ -91,7 +91,7 @@ impl EcdsaPublicKey { /// contradicts the Y coordinate's parity, or the coordinates do not lie on /// the curve. pub fn from_bytes(bytes: &[u8]) -> Result { - let prefix = bytes.first().and_then(|&b| Sec1Byte::from_base(b)); + let prefix = bytes.first().and_then(|&b| Sec1Byte::try_from_base(b)); match prefix { Some(p @ (Sec1Byte::HybridEven | Sec1Byte::HybridOdd)) => { if bytes.len() != ECDSA_PK_LEN + 1 || (bytes[ECDSA_PK_LEN] & 1 != 0) != (p == Sec1Byte::HybridOdd) { diff --git a/pkgs/pkc/src/ecdsa/sig_rec_bytes.rs b/pkgs/pkc/src/ecdsa/sig_rec_bytes.rs index 4eb4992e..a0360a91 100644 --- a/pkgs/pkc/src/ecdsa/sig_rec_bytes.rs +++ b/pkgs/pkc/src/ecdsa/sig_rec_bytes.rs @@ -98,7 +98,7 @@ impl BaseCodec for EcdsaRecSigBytes { }); } let raw = read_bytes(data, n)?; - let flags = CompactFlags::from_base(raw[0]).ok_or_else(|| DecodeError::InvalidValue { + let flags = CompactFlags::try_from_base(raw[0]).ok_or_else(|| DecodeError::InvalidValue { expected: CompactFlags::variants() .iter() .map(|f| u64::from(f.to_base())) @@ -163,7 +163,7 @@ impl EcdsaRecSigBytes { /// Returns `None` when the header byte is outside the `27..=34` range that /// encodes a recovery id and compression flag. pub fn from_raw(bytes: [u8; ECDSA_SIG_LEN + 1]) -> Option { - let flags = CompactFlags::from_base(bytes[0])?; + let flags = CompactFlags::try_from_base(bytes[0])?; let mut arr = [0u8; ECDSA_SIG_LEN]; arr.copy_from_slice(&bytes[1..]); Some(Self { @@ -294,7 +294,7 @@ mod tests { let flags = CompactFlags::new(rid, compressed).unwrap(); assert_eq!(flags.recovery_id(), rid); assert_eq!(flags.is_compressed(), compressed.is_compressed()); - assert_eq!(CompactFlags::from_base(flags.to_base()), Some(flags)); + assert_eq!(CompactFlags::try_from_base(flags.to_base()), Some(flags)); } #[rstest] diff --git a/pkgs/primitives/src/payload/proregtx.rs b/pkgs/primitives/src/payload/proregtx.rs index e8c8ccf8..4d90040e 100644 --- a/pkgs/primitives/src/payload/proregtx.rs +++ b/pkgs/primitives/src/payload/proregtx.rs @@ -19,8 +19,8 @@ use bitcoin_primitives::script::ScriptPubKeyBuf; use dash_pkc::bls::{BlsPkBytes, BlsScIetf}; use dash_script::{PubKeyHash, Recipient}; use dash_types::codec::{BaseCodec, Checkable, DecodeError, EncodeBuf}; -use dash_types::make_bytes; use dash_types::type_id::TypeId; +use dash_types::{make_bytes, Numeric}; use core::fmt; diff --git a/pkgs/primitives/src/payload/proupservtx.rs b/pkgs/primitives/src/payload/proupservtx.rs index 57cd12fc..130cef18 100644 --- a/pkgs/primitives/src/payload/proupservtx.rs +++ b/pkgs/primitives/src/payload/proupservtx.rs @@ -15,7 +15,7 @@ use crate::{hash_impl, TxHash}; use bitcoin_primitives::script::ScriptPubKeyBuf; use dash_pkc::bls::{BlsScIetf, BlsSigBytes}; use dash_types::codec::{BaseCodec, Checkable, DecodeError, EncodeBuf}; -use dash_types::type_id::TypeId; +use dash_types::{type_id::TypeId, Numeric}; use core::fmt; diff --git a/pkgs/primitives/src/payload/quorum.rs b/pkgs/primitives/src/payload/quorum.rs index 370d6768..7a7bb83b 100644 --- a/pkgs/primitives/src/payload/quorum.rs +++ b/pkgs/primitives/src/payload/quorum.rs @@ -15,6 +15,7 @@ use dash_num::{make_hash, Hash256}; use dash_pkc::bls::{BlsPkBytes, BlsScIetf, BlsSigBytes}; use dash_types::codec::{BaseCodec, Checkable, DecodeError, EncodeBuf}; use dash_types::type_id::{TypeId, Unencodable}; +use dash_types::Numeric; use core::fmt; diff --git a/pkgs/primitives/src/transaction.rs b/pkgs/primitives/src/transaction.rs index 764a1a9b..907e4634 100644 --- a/pkgs/primitives/src/transaction.rs +++ b/pkgs/primitives/src/transaction.rs @@ -17,7 +17,7 @@ use bitcoin_units::Amount; use dash_num::{make_hash, Hash256}; use dash_types::codec::{self, BaseCodec, Checkable, DecodeError, EncodeBuf, Hashable}; use dash_types::type_id::{TypeId, Unencodable}; -use dash_types::{impl_type, CompactSize}; +use dash_types::{impl_type, CompactSize, Numeric}; use core::fmt; diff --git a/pkgs/primitives/src/types/addrv2.rs b/pkgs/primitives/src/types/addrv2.rs index a03ce87c..e9720422 100644 --- a/pkgs/primitives/src/types/addrv2.rs +++ b/pkgs/primitives/src/types/addrv2.rs @@ -14,8 +14,7 @@ use crate::prelude::*; use bitcoin_hashes::sha3_256; use dash_types::codec::{self, BaseCodec, Checkable, DecodeError, EncodeBuf}; -use dash_types::type_id::TypeId; -use dash_types::{impl_type, type_cvrt, CompactSize}; +use dash_types::{impl_type, type_cvrt, type_id::TypeId, CompactSize, Numeric}; use core::fmt; use core::net::{Ipv4Addr, Ipv6Addr}; diff --git a/pkgs/script/src/addrs.rs b/pkgs/script/src/addrs.rs index de879f60..6c69d95c 100644 --- a/pkgs/script/src/addrs.rs +++ b/pkgs/script/src/addrs.rs @@ -13,8 +13,7 @@ use base58ck::decode_check; use dash_num::Hash160; use dash_pkc::ecdsa::EcdsaPkBytes; use dash_types::codec::{BaseCodec, EncodeBuf, Hashable}; -use dash_types::type_cvrt; -use dash_types::type_id::Unencodable; +use dash_types::{type_cvrt, type_id::Unencodable, Numeric}; /// Network address encoding parameters. #[derive(Clone, Copy, Debug, Eq, Hash, PartialEq, Unencodable)] diff --git a/pkgs/script/src/opcode.rs b/pkgs/script/src/opcode.rs index c3b647ed..66b6719e 100644 --- a/pkgs/script/src/opcode.rs +++ b/pkgs/script/src/opcode.rs @@ -6,7 +6,7 @@ //! Script opcodes as defined by the consensus rules. -use dash_types::enum_map; +use dash_types::{enum_map, Numeric}; use core::fmt; @@ -302,6 +302,7 @@ mod tests { use super::Opcode; use crate::prelude::*; + use dash_types::Numeric; use rstest::*; #[rstest] diff --git a/pkgs/script/src/sigops.rs b/pkgs/script/src/sigops.rs index e57c2445..64dc7147 100644 --- a/pkgs/script/src/sigops.rs +++ b/pkgs/script/src/sigops.rs @@ -8,6 +8,8 @@ use crate::opcode::Opcode; +use dash_types::Numeric; + const MAX_PUBKEYS: usize = 20; /// Count legacy signature operations in a script. diff --git a/pkgs/types/src/macros.rs b/pkgs/types/src/macros.rs index 98d0f907..5473a679 100644 --- a/pkgs/types/src/macros.rs +++ b/pkgs/types/src/macros.rs @@ -85,28 +85,11 @@ pub fn qtypestr(f: &mut fmt::Formatter<'_>, path: &str) -> fmt::Result { f.write_str(&path[seg..]) } -/// Generates `Numeric<$base>` for an enum that already carries the inherent -/// `fn {from,to}_base` pair. -#[cfg(feature = "codec")] -#[macro_export] -macro_rules! impl_enum { - ($enum:ident, $base:ty) => { - impl $crate::Numeric<$base> for $enum { - fn from_base(val: $base) -> Self { - $enum::from_base(val) - } - - fn to_base(&self) -> $base { - $enum::to_base(*self) - } - } - }; -} - /// Maps enum variants to integer constants and display strings. /// -/// Generates the enum definition, inherent `const fn` integer mapping, and -/// `impl Display` from a single table. +/// Generates the enum definition, the integer mapping, and `impl Display` +/// from a single table. An open enum maps through `Numeric`, a closed one +/// through an inherent fallible pair. /// /// # Syntax /// @@ -119,9 +102,8 @@ macro_rules! impl_enum { /// /// ## Infallible /// -/// Generates the enum with a catch-all variant, inherent `fn {to,from}_base` -/// methods and the [`impl_enum!`](crate::impl_enum) impl over them, `new`, -/// `is_canonical`, `variants`, and `impl Display`. +/// Generates the enum with a catch-all variant, a [`Numeric`](crate::Numeric) +/// impl, inherent `new`, `is_canonical`, `variants`, and `impl Display`. /// /// The catch-all displays as `unknown({v})`; build values with `new` so it /// never shadows a named variant. @@ -140,7 +122,7 @@ macro_rules! impl_enum { /// /// ## Fallible /// -/// Generates the enum (closed), inherent `const fn from_base` / `to_base` +/// Generates the enum (closed), inherent `const fn try_from_base` / `to_base` /// methods, and `impl Display`. /// /// ```ignore @@ -254,38 +236,21 @@ macro_rules! enum_map { $($variant:ident = $value:literal),+ }) => { impl $enum { - /// Constructs from the base integer value. - pub const fn from_base(val: $base) -> Self { + /// Canonical constructor. + pub const fn new(val: $base) -> Self { match val { $($value => Self::$variant,)+ other => Self::$catch_all(other), } } - /// Returns the base integer value. - pub const fn to_base(self) -> $base { - match self { - $(Self::$variant => $value,)+ - Self::$catch_all(v) => v, - } - } - - /// Canonical constructor. - /// - /// Routes through `from_base`, so a value a named variant covers yields - /// that variant instead of a catch-all holding the same number. Decoded - /// values already take this path. - pub const fn new(val: $base) -> Self { - Self::from_base(val) - } - /// Whether this value is in canonical form. /// /// False only for a catch-all holding a value that a named variant /// already covers. pub fn is_canonical(&self) -> bool { !matches!(self, Self::$catch_all(v) if matches!( - Self::from_base(*v), + Self::new(*v), $(Self::$variant)|+ )) } @@ -296,8 +261,17 @@ macro_rules! enum_map { } } - $crate::cfg_codec! { - $crate::impl_enum!($enum, $base); + impl $crate::Numeric<$base> for $enum { + fn from_base(val: $base) -> Self { + Self::new(val) + } + + fn to_base(&self) -> $base { + match self { + $(Self::$variant => $value,)+ + Self::$catch_all(v) => *v, + } + } } }; @@ -305,8 +279,8 @@ macro_rules! enum_map { $($variant:ident = $value:literal),+ }) => { impl $enum { - /// Constructs from the base integer value. - pub const fn from_base(v: $base) -> Option { + /// Constructs from the base integer value, if it names a variant. + pub const fn try_from_base(v: $base) -> Option { match v { $($value => Some(Self::$variant),)+ _ => None, @@ -415,6 +389,7 @@ macro_rules! type_cvrt { mod tests { use super::qtypestr; use crate::prelude::*; + use crate::Numeric; use rstest::*; @@ -495,13 +470,13 @@ mod tests { #[case::unmapped(0x0300, None)] #[case::zero(0, None)] fn closed_rejects_unmapped(#[case] raw: u16, #[case] expected: Option) { - assert_eq!(Closed::from_base(raw), expected); + assert_eq!(Closed::try_from_base(raw), expected); } #[rstest] fn closed_roundtrips_every_variant() { for v in Closed::variants() { - assert_eq!(Closed::from_base(v.to_base()), Some(*v)); + assert_eq!(Closed::try_from_base(v.to_base()), Some(*v)); } } @@ -510,11 +485,8 @@ mod tests { assert_eq!(Closed::Lo.to_string(), "Lo"); } - #[cfg(feature = "codec")] #[rstest] - fn open_maps_through_the_codec_trait() { - use crate::Numeric; - + fn open_maps_through_the_shared_trait() { assert_eq!(>::from_base(1), Open::One); assert_eq!(Numeric::::to_base(&Open::Two), 2); } From 2573eb90eb35cb8be63dfd9d46ba351f3fe4b108 Mon Sep 17 00:00:00 2001 From: Kittywhiskers Van Gogh <63189531+kwvg@users.noreply.github.com> Date: Mon, 14 Sep 2026 22:58:51 +0530 Subject: [PATCH 11/23] types%feat: extend `Numeric` trait to define base, byte image and `ZERO` --- pkgs/num/src/arith256.rs | 42 ++++++- pkgs/num/src/compact.rs | 26 ++++- pkgs/num/src/hash.rs | 41 ++++++- pkgs/num/src/util.rs | 43 +++++++- pkgs/num/tests/arith.rs | 1 + pkgs/num/tests/compact.rs | 1 + pkgs/num/tests/hash.rs | 1 + pkgs/num/tests/serde.rs | 1 + pkgs/p2p_core/src/msg/addr.rs | 4 +- pkgs/params/Cargo.toml | 6 +- pkgs/params/src/regtest.rs | 1 + pkgs/params/src/test3.rs | 1 + pkgs/primitives/src/block.rs | 2 +- pkgs/primitives/src/payload/cbtx.rs | 4 +- pkgs/primitives/src/support.rs | 4 +- pkgs/primitives/src/types/netinfo.rs | 5 +- pkgs/types/src/compact.rs | 44 ++++++-- pkgs/types/src/macros.rs | 30 ++++- pkgs/types/src/numeric.rs | 159 +++++++++++++++++++++++---- 19 files changed, 362 insertions(+), 54 deletions(-) diff --git a/pkgs/num/src/arith256.rs b/pkgs/num/src/arith256.rs index 4b7bb37b..e435b915 100644 --- a/pkgs/num/src/arith256.rs +++ b/pkgs/num/src/arith256.rs @@ -8,6 +8,8 @@ use crate::Hash256; +use dash_types::Numeric; + use core::cmp::Ordering; use core::fmt; use core::ops::{ @@ -25,9 +27,45 @@ pub struct Arith256 { hi: u128, } +impl Numeric for Arith256 { + type Base = [u8; 32]; + + type Bytes = [u8; 32]; + + const ZERO: Self = Self { lo: 0, hi: 0 }; + + #[inline] + fn from_base(v: [u8; 32]) -> Self { + Self::from_le_bytes(v) + } + + #[inline] + fn to_base(&self) -> [u8; 32] { + self.to_le_bytes() + } + + #[inline] + fn from_lendian(bytes: [u8; 32]) -> Self { + Self::from_le_bytes(bytes) + } + + #[inline] + fn to_lendian(&self) -> [u8; 32] { + self.to_le_bytes() + } + + #[inline] + fn from_bendian(bytes: [u8; 32]) -> Self { + Self::new(bytes) + } + + #[inline] + fn to_bendian(&self) -> [u8; 32] { + self.to_be_bytes() + } +} + impl Arith256 { - /// The additive identity (all bits zero). - pub const ZERO: Self = Self { lo: 0, hi: 0 }; /// The multiplicative identity. pub const ONE: Self = Self { lo: 1, hi: 0 }; /// The largest representable value (all bits set). diff --git a/pkgs/num/src/compact.rs b/pkgs/num/src/compact.rs index 71319437..040ce0af 100644 --- a/pkgs/num/src/compact.rs +++ b/pkgs/num/src/compact.rs @@ -10,7 +10,6 @@ use crate::Arith256; #[cfg(feature = "codec")] use dash_types::impl_num; -#[cfg(feature = "codec")] use dash_types::Numeric; use core::fmt; @@ -31,8 +30,13 @@ pub struct DecodedTarget { pub overflow: bool, } -#[cfg(feature = "codec")] -impl Numeric for CompactTarget { +impl Numeric for CompactTarget { + type Base = u32; + + type Bytes = [u8; 4]; + + const ZERO: Self = Self(0); + fn from_base(v: u32) -> Self { Self(v) } @@ -40,6 +44,22 @@ impl Numeric for CompactTarget { fn to_base(&self) -> u32 { self.0 } + + fn from_lendian(bytes: [u8; 4]) -> Self { + Self::from_base(u32::from_lendian(bytes)) + } + + fn to_lendian(&self) -> [u8; 4] { + self.0.to_lendian() + } + + fn from_bendian(bytes: [u8; 4]) -> Self { + Self::from_base(u32::from_bendian(bytes)) + } + + fn to_bendian(&self) -> [u8; 4] { + self.0.to_bendian() + } } #[cfg(feature = "codec")] diff --git a/pkgs/num/src/hash.rs b/pkgs/num/src/hash.rs index 9ecc8855..cc42813b 100644 --- a/pkgs/num/src/hash.rs +++ b/pkgs/num/src/hash.rs @@ -6,6 +6,7 @@ //! Fixed-size opaque hash blob types. +use dash_types::Numeric; use hex_conservative::{BytesToHexIter, Case, HexToBytesIter}; use core::fmt::{self, Write as _}; @@ -47,8 +48,6 @@ macro_rules! define_hash { pub struct $name([u8; $n]); impl $name { - /// The all-zeros (null) hash. - pub const ZERO: Self = Self([0u8; $n]); /// Byte length of this hash type. pub const LEN: usize = $n; @@ -130,6 +129,44 @@ macro_rules! define_hash { } } + impl Numeric for $name { + type Base = [u8; $n]; + + type Bytes = [u8; $n]; + + const ZERO: Self = Self([0u8; $n]); + + #[inline] + fn from_base(v: [u8; $n]) -> Self { + Self(v) + } + + #[inline] + fn to_base(&self) -> [u8; $n] { + self.0 + } + + #[inline] + fn from_lendian(bytes: [u8; $n]) -> Self { + Self(bytes) + } + + #[inline] + fn to_lendian(&self) -> [u8; $n] { + self.0 + } + + #[inline] + fn from_bendian(bytes: [u8; $n]) -> Self { + Self::new(bytes) + } + + #[inline] + fn to_bendian(&self) -> [u8; $n] { + <[u8; $n] as Numeric>::to_bendian(&self.0) + } + } + impl Default for $name { fn default() -> Self { Self::ZERO diff --git a/pkgs/num/src/util.rs b/pkgs/num/src/util.rs index c3f8a7d9..354e25db 100644 --- a/pkgs/num/src/util.rs +++ b/pkgs/num/src/util.rs @@ -107,9 +107,6 @@ macro_rules! make_hash { } impl $name { - /// The all-zeros (null) hash. - pub const ZERO: Self = Self(<$base>::ZERO); - /// Wrap raw little-endian bytes into a hash. #[inline] pub fn from_bytes(bytes: [u8; { <$base>::LEN }]) -> Self { @@ -147,9 +144,47 @@ macro_rules! make_hash { } } + impl $crate::__private::dash_types::Numeric for $name { + type Base = $base; + + type Bytes = [u8; { <$base>::LEN }]; + + const ZERO: Self = Self(<$base as $crate::__private::dash_types::Numeric>::ZERO); + + #[inline] + fn from_base(v: $base) -> Self { + Self(v) + } + + #[inline] + fn to_base(&self) -> $base { + self.0 + } + + #[inline] + fn from_lendian(bytes: [u8; { <$base>::LEN }]) -> Self { + Self(<$base as $crate::__private::dash_types::Numeric>::from_lendian(bytes)) + } + + #[inline] + fn to_lendian(&self) -> [u8; { <$base>::LEN }] { + <$base as $crate::__private::dash_types::Numeric>::to_lendian(&self.0) + } + + #[inline] + fn from_bendian(bytes: [u8; { <$base>::LEN }]) -> Self { + Self(<$base as $crate::__private::dash_types::Numeric>::from_bendian(bytes)) + } + + #[inline] + fn to_bendian(&self) -> [u8; { <$base>::LEN }] { + <$base as $crate::__private::dash_types::Numeric>::to_bendian(&self.0) + } + } + impl Default for $name { #[inline] - fn default() -> Self { Self::ZERO } + fn default() -> Self { ::ZERO } } impl ::core::fmt::Display for $name { diff --git a/pkgs/num/tests/arith.rs b/pkgs/num/tests/arith.rs index 3b1b24d5..e7f4867b 100644 --- a/pkgs/num/tests/arith.rs +++ b/pkgs/num/tests/arith.rs @@ -9,6 +9,7 @@ #![expect(clippy::unwrap_used, reason = "test code")] use dash_num::{Arith256, Hash256}; +use dash_types::Numeric; use hex_literal::hex; use rstest::*; diff --git a/pkgs/num/tests/compact.rs b/pkgs/num/tests/compact.rs index 8f6900d5..b26101aa 100644 --- a/pkgs/num/tests/compact.rs +++ b/pkgs/num/tests/compact.rs @@ -7,6 +7,7 @@ //! Compact difficulty target encoding tests. use dash_num::{Arith256, CompactTarget}; +use dash_types::Numeric; use rstest::*; /// Assert compact decode flags match expectations. diff --git a/pkgs/num/tests/hash.rs b/pkgs/num/tests/hash.rs index ca9e3598..ec72a76b 100644 --- a/pkgs/num/tests/hash.rs +++ b/pkgs/num/tests/hash.rs @@ -9,6 +9,7 @@ #![expect(clippy::unwrap_used, reason = "test code")] use dash_num::{Hash160, Hash256, ParseHexError}; +use dash_types::Numeric; use hex_literal::hex; use rstest::*; diff --git a/pkgs/num/tests/serde.rs b/pkgs/num/tests/serde.rs index a8336c2b..0e9f788c 100644 --- a/pkgs/num/tests/serde.rs +++ b/pkgs/num/tests/serde.rs @@ -8,6 +8,7 @@ use dash_dev::{assert_json_rt, from_json, json_rejects, to_json}; use dash_num::{Arith256, CompactTarget, Hash160, Hash256}; +use dash_types::Numeric; use hex_literal::hex; #[test] diff --git a/pkgs/p2p_core/src/msg/addr.rs b/pkgs/p2p_core/src/msg/addr.rs index 79754309..c37157c2 100644 --- a/pkgs/p2p_core/src/msg/addr.rs +++ b/pkgs/p2p_core/src/msg/addr.rs @@ -13,7 +13,7 @@ use crate::prelude::*; use dash_primitives::{hash_impl, AddrV2, ServiceV1}; use dash_types::codec::{self, BaseCodec, DecodeError, EncodeBuf}; use dash_types::type_id::TypeId; -use dash_types::CompactSize; +use dash_types::{CompactSize, Numeric}; use core::fmt; @@ -44,7 +44,7 @@ pub struct AddrV2Entry { impl BaseCodec for AddrV2Entry { fn decode(data: &mut &[u8]) -> Result { let time = u32::decode(data)?; - let services = ServiceFlags(CompactSize::decode(data)?.get()); + let services = ServiceFlags(CompactSize::decode(data)?.to_base()); let addr = AddrV2::decode(data)?; let port = codec::read_u16_be(data)?; Ok(Self { diff --git a/pkgs/params/Cargo.toml b/pkgs/params/Cargo.toml index 29f077bf..0f16b904 100644 --- a/pkgs/params/Cargo.toml +++ b/pkgs/params/Cargo.toml @@ -20,13 +20,13 @@ bitcoin-units = { workspace = true, features = ["alloc"] } dash-num = { version = "0.0.0", path = "../num", features = ["codec"] } dash-primitives = { version = "0.0.0", path = "../primitives" } dash-script = { version = "0.0.0", path = "../script" } +dash-types = { version = "0.0.0", path = "../types", default-features = false, features = [ + "codec", +] } hex-literal = "0.4" [dev-dependencies] bitcoin-consensus-encoding = { workspace = true, features = ["alloc"] } -dash-types = { version = "0.0.0", path = "../types", default-features = false, features = [ - "codec", -] } hex-literal = "0.4" rstest = "0.25" diff --git a/pkgs/params/src/regtest.rs b/pkgs/params/src/regtest.rs index 1b3771a5..2c626688 100644 --- a/pkgs/params/src/regtest.rs +++ b/pkgs/params/src/regtest.rs @@ -13,6 +13,7 @@ use bitcoin_primitives::script::{ScriptPubKeyBuf, ScriptSigBuf}; use dash_num::{Arith256, Hash256}; use dash_primitives::{Block, BlockHash, BlockHeader, MerkleRoot, OutPoint, Transaction, TxHash, TxIn, TxOut, TxType}; use dash_script::AddrParams; +use dash_types::Numeric; use hex_literal::hex; /// Returns the regtest genesis block. diff --git a/pkgs/params/src/test3.rs b/pkgs/params/src/test3.rs index 29fc3433..816eaaaa 100644 --- a/pkgs/params/src/test3.rs +++ b/pkgs/params/src/test3.rs @@ -13,6 +13,7 @@ use bitcoin_primitives::script::{ScriptPubKeyBuf, ScriptSigBuf}; use dash_num::{Arith256, Hash256}; use dash_primitives::{Block, BlockHash, BlockHeader, MerkleRoot, OutPoint, Transaction, TxHash, TxIn, TxOut, TxType}; use dash_script::AddrParams; +use dash_types::Numeric; use hex_literal::hex; /// Returns the testnet genesis block. diff --git a/pkgs/primitives/src/block.rs b/pkgs/primitives/src/block.rs index abed81b4..f2bc59d0 100644 --- a/pkgs/primitives/src/block.rs +++ b/pkgs/primitives/src/block.rs @@ -15,7 +15,7 @@ use dash_num::{make_hash, Arith256, CompactTarget, Hash256}; use dash_pow::hash as pow_hash; use dash_types::codec::{BaseCodec, Checkable, Hashable}; use dash_types::type_id::{TypeId, Unencodable}; -use dash_types::ArrayBuf; +use dash_types::{ArrayBuf, Numeric}; use core::fmt; diff --git a/pkgs/primitives/src/payload/cbtx.rs b/pkgs/primitives/src/payload/cbtx.rs index 22843868..a3c23746 100644 --- a/pkgs/primitives/src/payload/cbtx.rs +++ b/pkgs/primitives/src/payload/cbtx.rs @@ -13,7 +13,7 @@ use bitcoin_units::BlockHeight; use dash_pkc::bls::{BlsScIetf, BlsSigBytes}; use dash_types::codec::{BaseCodec, Checkable, DecodeError, EncodeBuf}; use dash_types::type_id::{TypeId, Unencodable}; -use dash_types::CompactSize; +use dash_types::{CompactSize, Numeric}; use core::fmt; @@ -56,7 +56,7 @@ impl BaseCodec for CoinbaseCommitment { }; let (best_cl_height_diff, best_cl_signature, credit_pool_balance) = if version >= 3 { ( - Some(CompactSize::decode(data)?.get()), + Some(CompactSize::decode(data)?.to_base()), Some(BlsSigBytes::::decode(data)?), Some(i64::decode(data)?), ) diff --git a/pkgs/primitives/src/support.rs b/pkgs/primitives/src/support.rs index 93a14a3d..051c11cb 100644 --- a/pkgs/primitives/src/support.rs +++ b/pkgs/primitives/src/support.rs @@ -11,7 +11,7 @@ use crate::prelude::*; use dash_types::codec::{self, BaseCodec, DecodeError, EncodeBuf}; use dash_types::type_id::{TypeId, Unencodable}; -use dash_types::{enum_map, impl_num, impl_type, CompactSize}; +use dash_types::{enum_map, impl_num, impl_type, CompactSize, Numeric}; enum_map! { /// LLMQ type (quorum size/threshold configuration). @@ -92,7 +92,7 @@ struct DynBitsetSerde { impl BaseCodec for DynBitset { fn decode(data: &mut &[u8]) -> Result { - let num_bits = CompactSize::decode(data)?.get(); + let num_bits = CompactSize::decode(data)?.to_base(); let byte_len = usize::try_from(num_bits.div_ceil(8)).map_err(|_| DecodeError::CompactSizeExceedsLimit { limit: usize::MAX, value: num_bits, diff --git a/pkgs/primitives/src/types/netinfo.rs b/pkgs/primitives/src/types/netinfo.rs index db681486..d5ef0aaf 100644 --- a/pkgs/primitives/src/types/netinfo.rs +++ b/pkgs/primitives/src/types/netinfo.rs @@ -162,10 +162,7 @@ impl BaseCodec for NIEntry { Ok(Self::Domain { name, port }) } NIEntryCode::Unknown(t) => Err(DecodeError::InvalidValue { - expected: NIEntryCode::variants() - .iter() - .map(|v| u64::from(Numeric::::to_base(v))) - .collect(), + expected: NIEntryCode::variants().iter().map(|v| u64::from(v.to_base())).collect(), actual: u64::from(t), }), } diff --git a/pkgs/types/src/compact.rs b/pkgs/types/src/compact.rs index 9cdf78d9..72936cb8 100644 --- a/pkgs/types/src/compact.rs +++ b/pkgs/types/src/compact.rs @@ -7,6 +7,7 @@ //! CompactSize-encoded integers. use crate::codec::{BaseCodec, DecodeError, EncodeBuf}; +use crate::Numeric; /// An unsigned integer encoded in variable-width CompactSize. #[repr(transparent)] @@ -14,6 +15,39 @@ use crate::codec::{BaseCodec, DecodeError, EncodeBuf}; #[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)] pub struct CompactSize(u64); +/// The base is the wrapped integer and the byte image is the integer itself. +impl Numeric for CompactSize { + type Base = u64; + + type Bytes = [u8; 8]; + + const ZERO: Self = Self(0); + + fn from_base(v: u64) -> Self { + Self(v) + } + + fn to_base(&self) -> u64 { + self.0 + } + + fn from_lendian(bytes: [u8; 8]) -> Self { + Self(u64::from_le_bytes(bytes)) + } + + fn to_lendian(&self) -> [u8; 8] { + self.0.to_le_bytes() + } + + fn from_bendian(bytes: [u8; 8]) -> Self { + Self(u64::from_be_bytes(bytes)) + } + + fn to_bendian(&self) -> [u8; 8] { + self.0.to_be_bytes() + } +} + impl BaseCodec for CompactSize { fn decode(data: &mut &[u8]) -> Result { let first = u8::decode(data)?; @@ -73,11 +107,6 @@ impl CompactSize { Self(value) } - /// Returns the wrapped integer. - pub const fn get(self) -> u64 { - self.0 - } - /// Converts the value to a length no greater than `limit`. /// /// # Errors @@ -117,6 +146,7 @@ mod tests { use super::CompactSize; use crate::codec::{BaseCodec, DecodeError}; use crate::prelude::*; + use crate::Numeric; use rstest::*; @@ -135,7 +165,7 @@ mod tests { assert_eq!(buf, wire, "encoding {value:#x}"); let mut cursor = wire; - assert_eq!(CompactSize::decode(&mut cursor).map(CompactSize::get), Ok(value)); + assert_eq!(CompactSize::decode(&mut cursor).map(|v| v.to_base()), Ok(value)); assert!(cursor.is_empty(), "decode left {} bytes", cursor.len()); } @@ -172,6 +202,6 @@ mod tests { #[rstest] fn conversions_preserve_the_value() { assert_eq!(u64::from(CompactSize::from(0xDEAD_u64)), 0xDEAD); - assert_eq!(CompactSize::from(7usize).get(), 7); + assert_eq!(CompactSize::from(7usize).to_base(), 7); } } diff --git a/pkgs/types/src/macros.rs b/pkgs/types/src/macros.rs index 5473a679..82c2c8ef 100644 --- a/pkgs/types/src/macros.rs +++ b/pkgs/types/src/macros.rs @@ -261,7 +261,13 @@ macro_rules! enum_map { } } - impl $crate::Numeric<$base> for $enum { + impl $crate::Numeric for $enum { + type Base = $base; + + type Bytes = <$base as $crate::Numeric>::Bytes; + + const ZERO: Self = Self::new(0); + fn from_base(val: $base) -> Self { Self::new(val) } @@ -272,6 +278,22 @@ macro_rules! enum_map { Self::$catch_all(v) => *v, } } + + fn from_lendian(bytes: Self::Bytes) -> Self { + Self::from_base(<$base as $crate::Numeric>::from_lendian(bytes)) + } + + fn to_lendian(&self) -> Self::Bytes { + <$base as $crate::Numeric>::to_lendian(&self.to_base()) + } + + fn from_bendian(bytes: Self::Bytes) -> Self { + Self::from_base(<$base as $crate::Numeric>::from_bendian(bytes)) + } + + fn to_bendian(&self) -> Self::Bytes { + <$base as $crate::Numeric>::to_bendian(&self.to_base()) + } } }; @@ -487,8 +509,10 @@ mod tests { #[rstest] fn open_maps_through_the_shared_trait() { - assert_eq!(>::from_base(1), Open::One); - assert_eq!(Numeric::::to_base(&Open::Two), 2); + assert_eq!(::from_base(1), Open::One); + assert_eq!(Open::Two.to_base(), 2); + assert_eq!(Open::Two.to_lendian(), [2]); + assert_eq!(::LEN, 1); } struct Qtype<'a>(&'a str); diff --git a/pkgs/types/src/numeric.rs b/pkgs/types/src/numeric.rs index 332a913c..7401503e 100644 --- a/pkgs/types/src/numeric.rs +++ b/pkgs/types/src/numeric.rs @@ -4,19 +4,123 @@ // See the accompanying file LICENSE or https://opensource.org/license/MIT // -//! Fixed-size integer newtype macros. +//! Fixed-width numeric types. -/// Links a type to its underlying base integer type. -pub trait Numeric: Sized { - /// Constructs from the base integer. - fn from_base(v: N) -> Self; +/// Links a type to its underlying representation and byte image. +pub trait Numeric: Sized { + /// The underlying representation. + type Base: Numeric; - /// Returns the base integer. - fn to_base(&self) -> N; + /// The fixed-width byte image, always a `[u8; N]`. + type Bytes: Copy + AsRef<[u8]>; + + /// Byte width of the image, width of [`Bytes`](Self::Bytes). + const LEN: usize = ::core::mem::size_of::(); + + /// The zero value. + const ZERO: Self; + + /// Constructs from the base representation. + fn from_base(v: Self::Base) -> Self; + + /// Returns the base representation. + fn to_base(&self) -> Self::Base; + + /// Constructs from a little-endian byte image. + fn from_lendian(bytes: Self::Bytes) -> Self; + + /// Returns the little-endian byte image. + fn to_lendian(&self) -> Self::Bytes; + + /// Constructs from a big-endian byte image. + fn from_bendian(bytes: Self::Bytes) -> Self; + + /// Returns the big-endian byte image. + fn to_bendian(&self) -> Self::Bytes; +} + +/// A byte array is its own base and its own little-endian image. +impl Numeric for [u8; N] { + type Base = Self; + + type Bytes = Self; + + const ZERO: Self = [0u8; N]; + + fn from_base(v: Self) -> Self { + v + } + + fn to_base(&self) -> Self { + *self + } + + fn from_lendian(bytes: Self) -> Self { + bytes + } + + fn to_lendian(&self) -> Self { + *self + } + + fn from_bendian(bytes: Self) -> Self { + let mut out = bytes; + out.reverse(); + out + } + + fn to_bendian(&self) -> Self { + Self::from_bendian(*self) + } +} + +/// Generates [`Numeric`] for a primitive integer, which is its own base. +macro_rules! numeric_prim { + ($($ty:ty, $n:literal;)+) => { + $( + impl Numeric for $ty { + type Base = Self; + type Bytes = [u8; $n]; + const ZERO: Self = 0; + + fn from_base(v: Self) -> Self { + v + } + + fn to_base(&self) -> Self { + *self + } + + fn from_lendian(bytes: [u8; $n]) -> Self { + Self::from_le_bytes(bytes) + } + + fn to_lendian(&self) -> [u8; $n] { + self.to_le_bytes() + } + + fn from_bendian(bytes: [u8; $n]) -> Self { + Self::from_be_bytes(bytes) + } + + fn to_bendian(&self) -> [u8; $n] { + self.to_be_bytes() + } + } + )+ + }; +} + +numeric_prim! { + i8, 1; u8, 1; + i16, 2; u16, 2; + i32, 4; u32, 4; + i64, 8; u64, 8; + i128, 16; u128, 16; } /// Generates `BaseCodec` + `Encode` + `Decode` + serde for a type -/// that already implements `Numeric<$uint>`. +/// that already implements [`Numeric`] over `$uint`. #[cfg(feature = "codec")] #[macro_export] macro_rules! impl_num { @@ -28,13 +132,15 @@ macro_rules! impl_num { ($name:tt, u32) => { $crate::impl_num!(@codec $name, u32, 4); }; ($name:tt, i64) => { $crate::impl_num!(@codec $name, i64, 8); }; ($name:tt, u64) => { $crate::impl_num!(@codec $name, u64, 8); }; + ($name:tt, i128) => { $crate::impl_num!(@codec $name, i128, 16); }; + ($name:tt, u128) => { $crate::impl_num!(@codec $name, u128, 16); }; (@codec $name:ty, $uint:ty, $n:literal) => { impl $crate::codec::BaseCodec for $name { fn decode( data: &mut &[u8], ) -> Result { $crate::codec::take::<$n>(data).map(|b| { - >::from_base( + ::from_base( <$uint>::from_le_bytes(b), ) }) @@ -42,7 +148,7 @@ macro_rules! impl_num { fn encode(&self, buf: &mut impl $crate::codec::EncodeBuf) { buf.extend_from_slice( - &>::to_base(self) + &::to_base(self) .to_le_bytes(), ); } @@ -56,7 +162,7 @@ macro_rules! impl_num { &self, serializer: S, ) -> Result { $crate::__private::serde::Serialize::serialize( - &>::to_base(self), + &::to_base(self), serializer, ) } @@ -67,7 +173,7 @@ macro_rules! impl_num { deserializer: D, ) -> Result { <$uint as $crate::__private::serde::Deserialize>::deserialize(deserializer) - .map(>::from_base) + .map(::from_base) } } } @@ -106,7 +212,11 @@ macro_rules! make_num { ) => { $crate::make_num!(@decl {$(#[$attr])*} $name, $uint); - impl $crate::Numeric<$uint> for $name { + impl $crate::Numeric for $name { + type Base = $uint; + type Bytes = [u8; $n]; + const ZERO: Self = Self(0); + fn from_base(v: $uint) -> Self { Self(v) } @@ -114,6 +224,22 @@ macro_rules! make_num { fn to_base(&self) -> $uint { self.0 } + + fn from_lendian(bytes: [u8; $n]) -> Self { + Self::from_base(<$uint as $crate::Numeric>::from_lendian(bytes)) + } + + fn to_lendian(&self) -> [u8; $n] { + <$uint as $crate::Numeric>::to_lendian(&self.0) + } + + fn from_bendian(bytes: [u8; $n]) -> Self { + Self::from_base(<$uint as $crate::Numeric>::from_bendian(bytes)) + } + + fn to_bendian(&self) -> [u8; $n] { + <$uint as $crate::Numeric>::to_bendian(&self.0) + } } impl $name { @@ -121,11 +247,6 @@ macro_rules! make_num { pub const fn new(v: $uint) -> Self { Self(v) } - - /// Returns the inner integer value. - pub const fn value(self) -> $uint { - self.0 - } } impl From<$uint> for $name { @@ -138,7 +259,7 @@ macro_rules! make_num { impl From<[u8; $n]> for $name { fn from(bytes: [u8; $n]) -> Self { - Self(<$uint>::from_le_bytes(bytes)) + ::from_lendian(bytes) } } From 8fe44440863e6c8651a0411dba125f088e2b64e4 Mon Sep 17 00:00:00 2001 From: Kittywhiskers Van Gogh <63189531+kwvg@users.noreply.github.com> Date: Mon, 14 Sep 2026 23:21:00 +0530 Subject: [PATCH 12/23] num%refac(hash): replace `define_hash!` with a const-generic blob `git diff --color-moved=dimmed-zebra --color-moved-ws=ignore-all-space` --- pkgs/num/src/hash.rs | 353 ++++++++++++++++++++----------------------- pkgs/num/src/lib.rs | 2 +- 2 files changed, 167 insertions(+), 188 deletions(-) diff --git a/pkgs/num/src/hash.rs b/pkgs/num/src/hash.rs index cc42813b..4ffe65ad 100644 --- a/pkgs/num/src/hash.rs +++ b/pkgs/num/src/hash.rs @@ -6,7 +6,7 @@ //! Fixed-size opaque hash blob types. -use dash_types::Numeric; +use dash_types::{type_cvrt, Numeric}; use hex_conservative::{BytesToHexIter, Case, HexToBytesIter}; use core::fmt::{self, Write as _}; @@ -41,226 +41,205 @@ impl fmt::Display for ParseHexError { #[cfg(feature = "std")] impl std::error::Error for ParseHexError {} -macro_rules! define_hash { - ($name:ident, $n:literal) => { - /// Fixed-size opaque hash blob stored in little-endian byte order. - #[derive(Clone, Copy, PartialEq, Eq, Hash)] - pub struct $name([u8; $n]); +/// Fixed-size opaque hash blob stored in little-endian byte order. +#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)] +pub struct HashBlob([u8; N]); - impl $name { - /// Byte length of this hash type. - pub const LEN: usize = $n; +impl Numeric for HashBlob { + type Base = [u8; N]; - /// Wrap raw little-endian bytes into a hash. - #[inline] - pub fn from_bytes(bytes: [u8; $n]) -> Self { - Self(bytes) - } + type Bytes = [u8; N]; - /// Return the raw little-endian bytes. - #[inline] - pub fn to_bytes(self) -> [u8; $n] { - self.0 - } + const ZERO: Self = Self([0u8; N]); - /// Borrow the raw little-endian bytes. - #[inline] - pub fn as_bytes(&self) -> &[u8; $n] { - &self.0 - } - - /// Construct from big-endian bytes (consensus display order). - /// - /// This is the natural byte order produced by `hex_literal::hex!()` when - /// given a block hash or other consensus hex value. Internally the bytes - /// are stored little-endian, so this reverses the input. - #[inline] - pub const fn new(be: [u8; $n]) -> Self { - let mut le = [0u8; $n]; - let mut i = 0; - while i < $n { - le[i] = be[$n - 1 - i]; - i += 1; - } - Self(le) - } + #[inline] + fn from_base(v: [u8; N]) -> Self { + Self(v) + } - /// Returns `true` if every byte is zero. - pub fn is_null(&self) -> bool { - let mut i = 0; - while i < $n { - if self.0[i] != 0 { - return false; - } - i += 1; - } - true - } + #[inline] + fn to_base(&self) -> [u8; N] { + self.0 + } - /// Parse from a big-endian hex string. - /// - /// Accepts an optional `0x`/`0X` prefix followed by optional leading - /// spaces before the hex digits. The digits are big-endian (MSB first), - /// mirroring the consensus display convention. - /// - /// # Errors - /// - /// Returns `OddLength` when input has an odd number of hex characters, - /// `InvalidLength` when the decoded byte count exceeds the type width, or - /// `InvalidChar` on a non-hex digit. - pub fn from_hex(s: &str) -> Result { - let s = s.strip_prefix("0x").or_else(|| s.strip_prefix("0X")).unwrap_or(s); - let s = s.trim_start_matches(' '); - - if s.len() > $n * 2 { - return Err(ParseHexError::InvalidLength { - expected: $n * 2, - got: s.len(), - }); - } - - let digits = HexToBytesIter::new(s).map_err(|_| ParseHexError::OddLength)?; - let mut bytes = [0u8; $n]; - for (slot, byte) in bytes.iter_mut().zip(digits.rev()) { - *slot = byte.map_err(|e| ParseHexError::InvalidChar(e.invalid_char()))?; - } - - Ok(Self(bytes)) - } - } + #[inline] + fn from_lendian(bytes: [u8; N]) -> Self { + Self(bytes) + } - impl Numeric for $name { - type Base = [u8; $n]; + #[inline] + fn to_lendian(&self) -> [u8; N] { + self.0 + } - type Bytes = [u8; $n]; + #[inline] + fn from_bendian(bytes: [u8; N]) -> Self { + Self::new(bytes) + } - const ZERO: Self = Self([0u8; $n]); + #[inline] + fn to_bendian(&self) -> [u8; N] { + <[u8; N] as Numeric>::to_bendian(&self.0) + } +} - #[inline] - fn from_base(v: [u8; $n]) -> Self { - Self(v) - } +#[cfg(feature = "codec")] +impl dash_types::codec::BaseCodec for HashBlob { + fn decode(data: &mut &[u8]) -> Result { + dash_types::codec::take::(data).map(Self::from_bytes) + } - #[inline] - fn to_base(&self) -> [u8; $n] { - self.0 - } + fn encode(&self, buf: &mut impl dash_types::codec::EncodeBuf) { + buf.extend_from_slice(&self.0); + } +} - #[inline] - fn from_lendian(bytes: [u8; $n]) -> Self { - Self(bytes) - } +#[cfg(feature = "codec")] +dash_types::impl_type!(for[const N: usize] HashBlob, N); - #[inline] - fn to_lendian(&self) -> [u8; $n] { - self.0 - } +impl HashBlob { + /// Byte length of this hash type. + pub const LEN: usize = N; - #[inline] - fn from_bendian(bytes: [u8; $n]) -> Self { - Self::new(bytes) - } + /// Wrap raw little-endian bytes into a hash. + #[inline] + pub fn from_bytes(bytes: [u8; N]) -> Self { + Self(bytes) + } - #[inline] - fn to_bendian(&self) -> [u8; $n] { - <[u8; $n] as Numeric>::to_bendian(&self.0) - } - } + /// Return the raw little-endian bytes. + #[inline] + pub fn to_bytes(self) -> [u8; N] { + self.0 + } - impl Default for $name { - fn default() -> Self { - Self::ZERO - } - } + /// Borrow the raw little-endian bytes. + #[inline] + pub fn as_bytes(&self) -> &[u8; N] { + &self.0 + } - impl Ord for $name { - fn cmp(&self, other: &Self) -> ::core::cmp::Ordering { - // Lexicographic on raw bytes (consensus ordering). - self.0.cmp(&other.0) - } + /// Construct from big-endian bytes (consensus display order). + /// + /// This is the natural byte order produced by `hex_literal::hex!()` when + /// given a block hash or other consensus hex value. Internally the bytes + /// are stored little-endian, so this reverses the input. + #[inline] + pub const fn new(be: [u8; N]) -> Self { + let mut le = [0u8; N]; + let mut i = 0; + while i < N { + le[i] = be[N - 1 - i]; + i += 1; } + Self(le) + } - impl PartialOrd for $name { - fn partial_cmp(&self, other: &Self) -> Option<::core::cmp::Ordering> { - Some(self.cmp(other)) - } - } + /// Returns `true` if every byte is zero. + pub fn is_null(&self) -> bool { + self.0 == [0u8; N] + } - /// Reversed hex (big-endian display, consensus format). - impl fmt::Display for $name { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - for c in BytesToHexIter::new(self.0.iter().rev().copied(), Case::Lower) { - f.write_char(c)?; - } - Ok(()) - } + /// Parse from a big-endian hex string. + /// + /// Accepts an optional `0x`/`0X` prefix followed by optional leading + /// spaces before the hex digits. The digits are big-endian (MSB first), + /// mirroring the consensus display convention. + /// + /// # Errors + /// + /// Returns `OddLength` when input has an odd number of hex characters, + /// `InvalidLength` when the decoded byte count exceeds the type width, or + /// `InvalidChar` on a non-hex digit. + pub fn from_hex(s: &str) -> Result { + let s = s.strip_prefix("0x").or_else(|| s.strip_prefix("0X")).unwrap_or(s); + let s = s.trim_start_matches(' '); + + if s.len() > N * 2 { + return Err(ParseHexError::InvalidLength { + expected: N * 2, + got: s.len(), + }); } - impl fmt::LowerHex for $name { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - fmt::Display::fmt(self, f) - } + let digits = HexToBytesIter::new(s).map_err(|_| ParseHexError::OddLength)?; + let mut bytes = [0u8; N]; + for (slot, byte) in bytes.iter_mut().zip(digits.rev()) { + *slot = byte.map_err(|e| ParseHexError::InvalidChar(e.invalid_char()))?; } - impl fmt::Debug for $name { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!(f, "{}({})", stringify!($name), self) - } - } + Ok(Self(bytes)) + } +} - impl FromStr for $name { - type Err = ParseHexError; +impl Default for HashBlob { + fn default() -> Self { + Self::ZERO + } +} - fn from_str(s: &str) -> Result { - Self::from_hex(s) - } +/// Reversed hex (big-endian display, consensus format). +impl fmt::Display for HashBlob { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + for c in BytesToHexIter::new(self.0.iter().rev().copied(), Case::Lower) { + f.write_char(c)?; } + Ok(()) + } +} - $crate::__private::dash_types::type_cvrt!(From<[u8; $n]> for $name, |b| Self(*b)); - $crate::__private::dash_types::type_cvrt!(From<$name> for [u8; $n], |h| h.0); +impl fmt::LowerHex for HashBlob { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + fmt::Display::fmt(self, f) + } +} - impl AsRef<[u8]> for $name { - fn as_ref(&self) -> &[u8] { - &self.0 - } - } +impl fmt::Debug for HashBlob { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!(f, "HashBlob<{N}>({self})") + } +} - impl AsRef<[u8; $n]> for $name { - fn as_ref(&self) -> &[u8; $n] { - &self.0 - } - } +impl FromStr for HashBlob { + type Err = ParseHexError; - $crate::cfg_codec! { - impl $crate::__private::dash_types::codec::BaseCodec for $name { - fn decode(data: &mut &[u8]) -> Result { - $crate::__private::dash_types::codec::take::<$n>(data).map(Self::from_bytes) - } + fn from_str(s: &str) -> Result { + Self::from_hex(s) + } +} - fn encode(&self, buf: &mut impl $crate::__private::dash_types::codec::EncodeBuf) { - buf.extend_from_slice(&self.0); - } - } +type_cvrt!(for[const N: usize] From<[u8; N]> for HashBlob, |b| Self(*b)); +type_cvrt!(for[const N: usize] From> for [u8; N], |h| h.0); - $crate::__private::dash_types::impl_type!($name); - } +impl AsRef<[u8]> for HashBlob { + fn as_ref(&self) -> &[u8] { + &self.0 + } +} - #[cfg(feature = "serde")] - impl ::serde::Serialize for $name { - fn serialize(&self, serializer: S) -> Result { - serializer.serialize_str(&::alloc::format!("{}", self)) - } - } +impl AsRef<[u8; N]> for HashBlob { + fn as_ref(&self) -> &[u8; N] { + &self.0 + } +} - #[cfg(feature = "serde")] - impl<'de> ::serde::Deserialize<'de> for $name { - fn deserialize>(deserializer: D) -> Result { - let s = <::alloc::string::String as ::serde::Deserialize>::deserialize(deserializer)?; - Self::from_hex(&s).map_err(::serde::de::Error::custom) - } - } - }; +#[cfg(feature = "serde")] +impl ::serde::Serialize for HashBlob { + fn serialize(&self, serializer: S) -> Result { + serializer.serialize_str(&::alloc::format!("{}", self)) + } } -define_hash!(Hash160, 20); -define_hash!(Hash256, 32); +#[cfg(feature = "serde")] +impl<'de, const N: usize> ::serde::Deserialize<'de> for HashBlob { + fn deserialize>(deserializer: D) -> Result { + let s = <::alloc::string::String as ::serde::Deserialize>::deserialize(deserializer)?; + Self::from_hex(&s).map_err(::serde::de::Error::custom) + } +} + +/// 160-bit hash blob. +pub type Hash160 = HashBlob<20>; + +/// 256-bit hash blob. +pub type Hash256 = HashBlob<32>; diff --git a/pkgs/num/src/lib.rs b/pkgs/num/src/lib.rs index cc018506..bfa23cbe 100644 --- a/pkgs/num/src/lib.rs +++ b/pkgs/num/src/lib.rs @@ -33,4 +33,4 @@ pub mod __private { pub use arith256::Arith256; pub use compact::{CompactTarget, DecodedTarget}; -pub use hash::{Hash160, Hash256, ParseHexError}; +pub use hash::{Hash160, Hash256, HashBlob, ParseHexError}; From e776b297b17bb02bfbd000ae8e2d4d6101296659 Mon Sep 17 00:00:00 2001 From: Kittywhiskers Van Gogh <63189531+kwvg@users.noreply.github.com> Date: Mon, 14 Sep 2026 19:39:03 +0530 Subject: [PATCH 13/23] num%fix(hash): align whitespace handling with reference impl --- pkgs/num/src/hash.rs | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/pkgs/num/src/hash.rs b/pkgs/num/src/hash.rs index 4ffe65ad..fdb53086 100644 --- a/pkgs/num/src/hash.rs +++ b/pkgs/num/src/hash.rs @@ -13,6 +13,9 @@ use core::fmt::{self, Write as _}; use core::hash::Hash; use core::str::FromStr; +/// Whitespace skipped before a hex prefix. +const WHITESPACE: [char; 6] = [' ', '\x0c', '\n', '\r', '\t', '\x0b']; + /// Error returned when parsing a hex string fails. #[derive(Clone, Debug, PartialEq, Eq)] pub enum ParseHexError { @@ -142,9 +145,9 @@ impl HashBlob { /// Parse from a big-endian hex string. /// - /// Accepts an optional `0x`/`0X` prefix followed by optional leading - /// spaces before the hex digits. The digits are big-endian (MSB first), - /// mirroring the consensus display convention. + /// Accepts leading whitespace followed by an optional `0x`/`0X` prefix, + /// in that order. The digits are big-endian (MSB first), mirroring the + /// consensus display convention. /// /// # Errors /// @@ -152,8 +155,8 @@ impl HashBlob { /// `InvalidLength` when the decoded byte count exceeds the type width, or /// `InvalidChar` on a non-hex digit. pub fn from_hex(s: &str) -> Result { + let s = s.trim_start_matches(WHITESPACE); let s = s.strip_prefix("0x").or_else(|| s.strip_prefix("0X")).unwrap_or(s); - let s = s.trim_start_matches(' '); if s.len() > N * 2 { return Err(ParseHexError::InvalidLength { From 769cd26c9518bc76e7b712f7858d78a026495412 Mon Sep 17 00:00:00 2001 From: Kittywhiskers Van Gogh <63189531+kwvg@users.noreply.github.com> Date: Mon, 14 Sep 2026 13:25:01 +0530 Subject: [PATCH 14/23] num%refac: reap dead `prelude` module, consolidate `{impl,make}_hash` --- pkgs/num/src/lib.rs | 2 -- pkgs/num/src/prelude.rs | 7 ------- pkgs/num/src/util.rs | 20 +++++++++----------- 3 files changed, 9 insertions(+), 20 deletions(-) delete mode 100644 pkgs/num/src/prelude.rs diff --git a/pkgs/num/src/lib.rs b/pkgs/num/src/lib.rs index bfa23cbe..df555dee 100644 --- a/pkgs/num/src/lib.rs +++ b/pkgs/num/src/lib.rs @@ -18,8 +18,6 @@ extern crate std; mod arith256; mod compact; mod hash; -#[allow(unused_imports, reason = "ergonomic shim, exports may be unused")] -mod prelude; mod util; #[doc(hidden)] diff --git a/pkgs/num/src/prelude.rs b/pkgs/num/src/prelude.rs deleted file mode 100644 index ec322db5..00000000 --- a/pkgs/num/src/prelude.rs +++ /dev/null @@ -1,7 +0,0 @@ -// -// Copyright (c) 2026-present, The Dash Core developers -// SPDX-License-Identifier: MIT -// See the accompanying file LICENSE or https://opensource.org/license/MIT -// - -//! Re-exports for no_std compatibility. diff --git a/pkgs/num/src/util.rs b/pkgs/num/src/util.rs index 354e25db..d45fbbde 100644 --- a/pkgs/num/src/util.rs +++ b/pkgs/num/src/util.rs @@ -43,10 +43,13 @@ macro_rules! cfg_serde { ($($item:tt)*) => {}; } -/// Generates `BaseCodec` + `Encode` + `Decode` for hash newtypes. +/// Generates a newtype wrapping a hash base type with full trait +/// implementations and consensus encoding support. #[macro_export] -macro_rules! impl_hash { - ($base:ty, $($name:ident),* $(,)?) => { $( $crate::cfg_codec! { +macro_rules! make_hash { + // The codec half, split out for gating with `cfg_codec!`. + (@codec $base:ty, $name:ident) => { + $crate::cfg_codec! { impl $crate::__private::dash_types::codec::BaseCodec for $name { fn decode( data: &mut &[u8], @@ -61,13 +64,8 @@ macro_rules! impl_hash { } $crate::__private::dash_types::impl_type!($name); - } )* }; -} - -/// Generates a newtype wrapping a hash base type with full trait -/// implementations and consensus encoding support. -#[macro_export] -macro_rules! make_hash { + } + }; ( $base:ty, $(#[$attr:meta])* @@ -222,6 +220,6 @@ macro_rules! make_hash { fn as_ref(&self) -> &[u8; { <$base>::LEN }] { self.0.as_bytes() } } - $crate::impl_hash!($base, $name); + $crate::make_hash!(@codec $base, $name); }; } From 14cfd7a9bb1269ed59f744b54e3930abb75d65e1 Mon Sep 17 00:00:00 2001 From: Kittywhiskers Van Gogh <63189531+kwvg@users.noreply.github.com> Date: Tue, 15 Sep 2026 00:01:44 +0530 Subject: [PATCH 15/23] num%refac(hash): unify arithmetic and blob types behind `Numeric` trait --- docs/samples/solver/solver.rs | 6 +- maint/codeql/rust/lib/imports.qll | 8 +++ pkgs/num/src/arith256.rs | 85 ++++++++------------------ pkgs/num/src/hash.rs | 26 +++----- pkgs/num/src/lib.rs | 12 ++-- pkgs/num/src/util.rs | 42 ++++--------- pkgs/num/tests/arith.rs | 36 +++++------ pkgs/num/tests/hash.rs | 40 ++++++------- pkgs/num/tests/serde.rs | 6 +- pkgs/params/src/mainnet.rs | 92 +++++++++++++++-------------- pkgs/params/src/regtest.rs | 6 +- pkgs/params/src/test3.rs | 54 +++++++++-------- pkgs/params/tests/genesis_valid.rs | 8 +-- pkgs/pkc/src/bls/ies_bytes.rs | 6 +- pkgs/pkc/src/bls/public_bytes.rs | 3 +- pkgs/pkc/src/bls/secret_bytes.rs | 3 +- pkgs/pkc/src/bls/sig_bytes.rs | 3 +- pkgs/pkc/src/ecdsa/secret_ops.rs | 4 +- pkgs/pkc/src/ecdsa/sig_bytes.rs | 4 +- pkgs/pkc/src/ecdsa/sig_rec_bytes.rs | 4 +- pkgs/primitives/src/block.rs | 6 +- pkgs/primitives/src/codec.rs | 2 +- pkgs/primitives/src/gov.rs | 6 +- pkgs/primitives/src/transaction.rs | 2 +- 24 files changed, 211 insertions(+), 253 deletions(-) diff --git a/docs/samples/solver/solver.rs b/docs/samples/solver/solver.rs index 265858ee..a4381f72 100644 --- a/docs/samples/solver/solver.rs +++ b/docs/samples/solver/solver.rs @@ -15,7 +15,7 @@ use bitcoin_primitives::script::{ScriptPubKeyBuf, ScriptSigBuf}; use bitcoin_units::Amount; use dash_num::{Arith256, CompactTarget, Hash256}; use dash_primitives::{BlockHash, BlockHeader, MerkleRoot, OutPoint, Transaction, TxHash, TxIn, TxOut, TxType}; -use dash_types::codec::Hashable; +use dash_types::{Hashable, Numeric}; use hex_conservative::FromHex; use serde::{Deserialize, Serialize}; use wasm_bindgen::prelude::*; @@ -66,7 +66,7 @@ pub fn merkle_root(script_sig_hex: &str, script_pubkey_hex: &str, amount_duffs: let sig_bytes = Vec::::from_hex(script_sig_hex).map_err(|e| format!("invalid scriptSig hex: {e}"))?; let pk_bytes = Vec::::from_hex(script_pubkey_hex).map_err(|e| format!("invalid scriptPubKey hex: {e}"))?; let coinbase = build_coinbase(sig_bytes, pk_bytes, amount_duffs)?; - let root = MerkleRoot::from_bytes(*coinbase.hash().as_bytes()); + let root = MerkleRoot::from_lendian(*coinbase.hash().as_bytes()); Ok(format!("{root}")) } @@ -89,7 +89,7 @@ pub fn scanhash( let pk_bytes = Vec::::from_hex(script_pubkey_hex).map_err(|e| format!("invalid scriptPubKey hex: {e}"))?; let coinbase = build_coinbase(sig_bytes, pk_bytes, amount_duffs)?; - let merkle_root = MerkleRoot::from_bytes(*coinbase.hash().as_bytes()); + let merkle_root = MerkleRoot::from_lendian(*coinbase.hash().as_bytes()); let header = BlockHeader { version, diff --git a/maint/codeql/rust/lib/imports.qll b/maint/codeql/rust/lib/imports.qll index f56b16e0..9cbe41b3 100644 --- a/maint/codeql/rust/lib/imports.qll +++ b/maint/codeql/rust/lib/imports.qll @@ -67,16 +67,24 @@ predicate isMacroReexport(Use u) { /** Holds if `u` is an allowlisted re-export from a foreign crate. */ private predicate isAllowlistedReexport(Use u) { + // Sub-crate isolation demands re-exports, part of public API usePrefix(u) = "dash_types_marker" and fileOf(u).getAbsolutePath().matches("%pkgs/types/%") or + // Workaround for the orphan rule, not part of public API usePrefix(u) = "dash_pkc" and u.getUseTree().getPath().getSegment().getIdentifier().getText() = "__PubKeyHash" and fileOf(u).getAbsolutePath().matches("%pkgs/script/%") or + // Workaround for the orphan rule, not part of public API usePrefix(u) = "dash_types" and u.getUseTree().getPath().getSegment().getIdentifier().getText() = "__ScriptHash" and fileOf(u).getAbsolutePath().matches("%pkgs/script/%") + or + // Crate emits types relying on traits defined by a dependency, part of public API + usePrefix(u) = "dash_types" and + u.getUseTree().getPath().getSegment().getIdentifier().getText() = "Numeric" and + fileOf(u).getAbsolutePath().matches("%pkgs/num/%") } /** diff --git a/pkgs/num/src/arith256.rs b/pkgs/num/src/arith256.rs index e435b915..f2bfbe8c 100644 --- a/pkgs/num/src/arith256.rs +++ b/pkgs/num/src/arith256.rs @@ -36,32 +36,47 @@ impl Numeric for Arith256 { #[inline] fn from_base(v: [u8; 32]) -> Self { - Self::from_le_bytes(v) + Self::from_lendian(v) } #[inline] fn to_base(&self) -> [u8; 32] { - self.to_le_bytes() + self.to_lendian() } #[inline] fn from_lendian(bytes: [u8; 32]) -> Self { - Self::from_le_bytes(bytes) + Self { + lo: u128::from_le_bytes(split_low(bytes)), + hi: u128::from_le_bytes(split_high(bytes)), + } } #[inline] fn to_lendian(&self) -> [u8; 32] { - self.to_le_bytes() + let lo = self.lo.to_le_bytes(); + let hi = self.hi.to_le_bytes(); + let mut out = [0u8; 32]; + let mut i = 0; + while i < 16 { + out[i] = lo[i]; + out[i + 16] = hi[i]; + i += 1; + } + out } #[inline] fn from_bendian(bytes: [u8; 32]) -> Self { - Self::new(bytes) + // Resolves to the inherent `const` form. + Self::from_bendian(bytes) } #[inline] fn to_bendian(&self) -> [u8; 32] { - self.to_be_bytes() + let mut out = self.to_lendian(); + out.reverse(); + out } } @@ -85,35 +100,15 @@ impl Arith256 { Self { lo: v, hi: 0 } } - /// Construct from little-endian bytes. - /// - /// `bytes[0..16]` maps to `lo`, `bytes[16..32]` to `hi`. - #[inline] - pub fn from_le_bytes(bytes: [u8; 32]) -> Self { - let lo = u128::from_le_bytes(split_low(bytes)); - let hi = u128::from_le_bytes(split_high(bytes)); - Self { lo, hi } - } - - /// Construct from big-endian bytes. - #[inline] - pub fn from_be_bytes(bytes: [u8; 32]) -> Self { - let mut le = [0u8; 32]; - let mut i = 0; - while i < 32 { - le[i] = bytes[31 - i]; - i += 1; - } - Self::from_le_bytes(le) - } - /// Construct from big-endian bytes (consensus display order). /// /// This is the natural byte order produced by `hex_literal::hex!()` when /// given a consensus hex value. Internally the value is stored /// little-endian, so this reverses the input before decoding. + /// + /// Shadows [`Numeric::from_bendian`] with a `const` form. #[inline] - pub const fn new(be: [u8; 32]) -> Self { + pub const fn from_bendian(be: [u8; 32]) -> Self { let mut le = [0u8; 32]; let mut i = 0; while i < 32 { @@ -126,34 +121,6 @@ impl Arith256 { } } - /// Convert to little-endian bytes. - #[inline] - pub fn to_le_bytes(self) -> [u8; 32] { - let lo = self.lo.to_le_bytes(); - let hi = self.hi.to_le_bytes(); - let mut out = [0u8; 32]; - let mut i = 0; - while i < 16 { - out[i] = lo[i]; - out[i + 16] = hi[i]; - i += 1; - } - out - } - - /// Convert to big-endian bytes. - #[inline] - pub fn to_be_bytes(self) -> [u8; 32] { - let le = self.to_le_bytes(); - let mut be = [0u8; 32]; - let mut i = 0; - while i < 32 { - be[i] = le[31 - i]; - i += 1; - } - be - } - /// Returns the lowest 32 bits of the value. #[inline] pub fn low_u32(self) -> u32 { @@ -521,13 +488,13 @@ impl From for Arith256 { impl From for Arith256 { fn from(h: Hash256) -> Self { - Self::from_le_bytes(h.to_bytes()) + Self::from_lendian(h.to_lendian()) } } impl From for Hash256 { fn from(a: Arith256) -> Self { - Hash256::from_bytes(a.to_le_bytes()) + Hash256::from_lendian(a.to_lendian()) } } diff --git a/pkgs/num/src/hash.rs b/pkgs/num/src/hash.rs index fdb53086..2b80933b 100644 --- a/pkgs/num/src/hash.rs +++ b/pkgs/num/src/hash.rs @@ -6,6 +6,8 @@ //! Fixed-size opaque hash blob types. +#[cfg(feature = "codec")] +use dash_types::impl_type; use dash_types::{type_cvrt, Numeric}; use hex_conservative::{BytesToHexIter, Case, HexToBytesIter}; @@ -77,7 +79,8 @@ impl Numeric for HashBlob { #[inline] fn from_bendian(bytes: [u8; N]) -> Self { - Self::new(bytes) + // Resolves to the inherent `const` form. + Self::from_bendian(bytes) } #[inline] @@ -89,7 +92,7 @@ impl Numeric for HashBlob { #[cfg(feature = "codec")] impl dash_types::codec::BaseCodec for HashBlob { fn decode(data: &mut &[u8]) -> Result { - dash_types::codec::take::(data).map(Self::from_bytes) + dash_types::codec::take::(data).map(::from_lendian) } fn encode(&self, buf: &mut impl dash_types::codec::EncodeBuf) { @@ -98,24 +101,9 @@ impl dash_types::codec::BaseCodec for HashBlob { } #[cfg(feature = "codec")] -dash_types::impl_type!(for[const N: usize] HashBlob, N); +impl_type!(for[const N: usize] HashBlob, N); impl HashBlob { - /// Byte length of this hash type. - pub const LEN: usize = N; - - /// Wrap raw little-endian bytes into a hash. - #[inline] - pub fn from_bytes(bytes: [u8; N]) -> Self { - Self(bytes) - } - - /// Return the raw little-endian bytes. - #[inline] - pub fn to_bytes(self) -> [u8; N] { - self.0 - } - /// Borrow the raw little-endian bytes. #[inline] pub fn as_bytes(&self) -> &[u8; N] { @@ -128,7 +116,7 @@ impl HashBlob { /// given a block hash or other consensus hex value. Internally the bytes /// are stored little-endian, so this reverses the input. #[inline] - pub const fn new(be: [u8; N]) -> Self { + pub const fn from_bendian(be: [u8; N]) -> Self { let mut le = [0u8; N]; let mut i = 0; while i < N { diff --git a/pkgs/num/src/lib.rs b/pkgs/num/src/lib.rs index df555dee..c319a6dc 100644 --- a/pkgs/num/src/lib.rs +++ b/pkgs/num/src/lib.rs @@ -6,8 +6,8 @@ //! Consensus-compatible numeric types. //! -//! Provides hash blob types ([`Hash256`], [`Hash160`]) -//! and the [`Arith256`] arithmetic integer type. +//! Provides hash blob types [`Hash256`], [`Hash160`] and the [`Arith256`] +//! arithmetic integer type. #![no_std] @@ -29,6 +29,8 @@ pub mod __private { pub use serde; } -pub use arith256::Arith256; -pub use compact::{CompactTarget, DecodedTarget}; -pub use hash::{Hash160, Hash256, HashBlob, ParseHexError}; +pub use crate::arith256::Arith256; +pub use crate::compact::{CompactTarget, DecodedTarget}; +pub use crate::hash::{Hash160, Hash256, HashBlob, ParseHexError}; + +pub use dash_types::Numeric; diff --git a/pkgs/num/src/util.rs b/pkgs/num/src/util.rs index d45fbbde..bf064c5a 100644 --- a/pkgs/num/src/util.rs +++ b/pkgs/num/src/util.rs @@ -54,8 +54,8 @@ macro_rules! make_hash { fn decode( data: &mut &[u8], ) -> Result { - $crate::__private::dash_types::codec::take::<{ <$base>::LEN }>(data) - .map(Self::from_bytes) + $crate::__private::dash_types::codec::take::<{ <$base as $crate::__private::dash_types::Numeric>::LEN }>(data) + .map(::from_lendian) } fn encode(&self, buf: &mut impl $crate::__private::dash_types::codec::EncodeBuf) { @@ -105,30 +105,12 @@ macro_rules! make_hash { } impl $name { - /// Wrap raw little-endian bytes into a hash. - #[inline] - pub fn from_bytes(bytes: [u8; { <$base>::LEN }]) -> Self { - Self(<$base>::from_bytes(bytes)) - } - - /// Return the raw little-endian bytes. - #[inline] - pub fn to_bytes(self) -> [u8; { <$base>::LEN }] { - self.0.to_bytes() - } - /// Borrow the raw little-endian bytes. #[inline] - pub fn as_bytes(&self) -> &[u8; { <$base>::LEN }] { + pub fn as_bytes(&self) -> &[u8; { <$base as $crate::__private::dash_types::Numeric>::LEN }] { self.0.as_bytes() } - /// Construct from big-endian bytes (consensus display order). - #[inline] - pub const fn new(be: [u8; { <$base>::LEN }]) -> Self { - Self(<$base>::new(be)) - } - /// Returns `true` if every byte is zero. #[inline] pub fn is_null(&self) -> bool { @@ -145,7 +127,7 @@ macro_rules! make_hash { impl $crate::__private::dash_types::Numeric for $name { type Base = $base; - type Bytes = [u8; { <$base>::LEN }]; + type Bytes = [u8; { <$base as $crate::__private::dash_types::Numeric>::LEN }]; const ZERO: Self = Self(<$base as $crate::__private::dash_types::Numeric>::ZERO); @@ -160,22 +142,22 @@ macro_rules! make_hash { } #[inline] - fn from_lendian(bytes: [u8; { <$base>::LEN }]) -> Self { + fn from_lendian(bytes: [u8; { <$base as $crate::__private::dash_types::Numeric>::LEN }]) -> Self { Self(<$base as $crate::__private::dash_types::Numeric>::from_lendian(bytes)) } #[inline] - fn to_lendian(&self) -> [u8; { <$base>::LEN }] { + fn to_lendian(&self) -> [u8; { <$base as $crate::__private::dash_types::Numeric>::LEN }] { <$base as $crate::__private::dash_types::Numeric>::to_lendian(&self.0) } #[inline] - fn from_bendian(bytes: [u8; { <$base>::LEN }]) -> Self { + fn from_bendian(bytes: [u8; { <$base as $crate::__private::dash_types::Numeric>::LEN }]) -> Self { Self(<$base as $crate::__private::dash_types::Numeric>::from_bendian(bytes)) } #[inline] - fn to_bendian(&self) -> [u8; { <$base>::LEN }] { + fn to_bendian(&self) -> [u8; { <$base as $crate::__private::dash_types::Numeric>::LEN }] { <$base as $crate::__private::dash_types::Numeric>::to_bendian(&self.0) } } @@ -205,8 +187,8 @@ macro_rules! make_hash { } } - $crate::__private::dash_types::type_cvrt!(From<[u8; { <$base>::LEN }]> for $name, |b| Self::from_bytes(*b)); - $crate::__private::dash_types::type_cvrt!(From<$name> for [u8; { <$base>::LEN }], |h| h.to_bytes()); + $crate::__private::dash_types::type_cvrt!(From<[u8; { <$base as $crate::__private::dash_types::Numeric>::LEN }]> for $name, |b| ::from_lendian(*b)); + $crate::__private::dash_types::type_cvrt!(From<$name> for [u8; { <$base as $crate::__private::dash_types::Numeric>::LEN }], |h| $crate::__private::dash_types::Numeric::to_lendian(h)); $crate::__private::dash_types::type_cvrt!(From<$base> for $name, |h| Self(*h)); $crate::__private::dash_types::type_cvrt!(From<$name> for $base, |h| h.0); @@ -215,9 +197,9 @@ macro_rules! make_hash { fn as_ref(&self) -> &[u8] { self.0.as_ref() } } - impl AsRef<[u8; { <$base>::LEN }]> for $name { + impl AsRef<[u8; { <$base as $crate::__private::dash_types::Numeric>::LEN }]> for $name { #[inline] - fn as_ref(&self) -> &[u8; { <$base>::LEN }] { self.0.as_bytes() } + fn as_ref(&self) -> &[u8; { <$base as $crate::__private::dash_types::Numeric>::LEN }] { self.0.as_bytes() } } $crate::make_hash!(@codec $base, $name); diff --git a/pkgs/num/tests/arith.rs b/pkgs/num/tests/arith.rs index e7f4867b..953a2895 100644 --- a/pkgs/num/tests/arith.rs +++ b/pkgs/num/tests/arith.rs @@ -16,7 +16,7 @@ use rstest::*; use core::str::FromStr; fn arith_from_le(bytes: &[u8; 32]) -> Arith256 { - Arith256::from(Hash256::from_bytes(*bytes)) + Arith256::from(Hash256::from_lendian(*bytes)) } fn arith_from_hex(s: &str) -> Arith256 { @@ -30,7 +30,7 @@ fn from_array(a: [u64; 4]) -> Arith256 { let mut bytes = [0u8; 32]; bytes[..16].copy_from_slice(&lo.to_le_bytes()); bytes[16..].copy_from_slice(&hi.to_le_bytes()); - Arith256::from_le_bytes(bytes) + Arith256::from_lendian(bytes) } #[fixture] @@ -55,7 +55,7 @@ fn r2_hex() -> &'static str { #[fixture] fn one_hash() -> Hash256 { - Hash256::from_bytes({ + Hash256::from_lendian({ let mut a = [0u8; 32]; a[0] = 1; a @@ -82,8 +82,8 @@ mod conversion { for h in [ Hash256::ZERO, one_hash, - Hash256::from_bytes(r1_bytes), - Hash256::from_bytes(r2_bytes), + Hash256::from_lendian(r1_bytes), + Hash256::from_lendian(r2_bytes), ] { assert_eq!(Hash256::from(Arith256::from(h)), h); } @@ -104,7 +104,7 @@ mod conversion { #[rstest] fn hex_through_arith_matches_hash(r1_bytes: [u8; 32], r2_bytes: [u8; 32]) { for bytes in [r1_bytes, r2_bytes] { - let h = Hash256::from_bytes(bytes); + let h = Hash256::from_lendian(bytes); let a = Arith256::from(h); assert_eq!(format!("{h}"), format!("{a}")); } @@ -179,35 +179,35 @@ mod byte_conversion { } #[rstest] - fn to_be_bytes() { - assert_eq!(want().to_be_bytes(), BE_BYTES); + fn to_bendian() { + assert_eq!(want().to_bendian(), BE_BYTES); } #[rstest] - fn from_be_bytes() { - assert_eq!(Arith256::from_be_bytes(BE_BYTES), want()); + fn from_bendian() { + assert_eq!(Arith256::from_bendian(BE_BYTES), want()); } #[rstest] - fn to_le_bytes() { - assert_eq!(want().to_le_bytes(), LE_BYTES); + fn to_lendian() { + assert_eq!(want().to_lendian(), LE_BYTES); } #[rstest] - fn from_le_bytes() { - assert_eq!(Arith256::from_le_bytes(LE_BYTES), want()); + fn from_lendian() { + assert_eq!(Arith256::from_lendian(LE_BYTES), want()); } #[rstest] fn roundtrip_be() { let v = want(); - assert_eq!(Arith256::from_be_bytes(v.to_be_bytes()), v); + assert_eq!(Arith256::from_bendian(v.to_bendian()), v); } #[rstest] fn roundtrip_le() { let v = want(); - assert_eq!(Arith256::from_le_bytes(v.to_le_bytes()), v); + assert_eq!(Arith256::from_lendian(v.to_lendian()), v); } #[rstest] @@ -372,7 +372,7 @@ mod multiply { #[rstest] fn cross_limb() { let a = Arith256::from_u128(1u128 << 64); - let expected = Arith256::from_le_bytes({ + let expected = Arith256::from_lendian({ let mut bytes = [0u8; 32]; bytes[16] = 1; bytes @@ -704,7 +704,7 @@ mod comparison { #[rstest] fn cross_limb() { let lo_max = Arith256::from_u128(u128::MAX); - let hi_one = Arith256::from_le_bytes({ + let hi_one = Arith256::from_lendian({ let mut b = [0u8; 32]; b[16] = 1; b diff --git a/pkgs/num/tests/hash.rs b/pkgs/num/tests/hash.rs index ec72a76b..4654e8a5 100644 --- a/pkgs/num/tests/hash.rs +++ b/pkgs/num/tests/hash.rs @@ -47,37 +47,37 @@ const ONE_ARRAY: [u8; 32] = { #[rstest] fn from_bytes_to_hex(r1_bytes: [u8; 32], r1_hex: &str, r2_bytes: [u8; 32], r2_hex: &str) { - assert_eq!(format!("{}", Hash256::from_bytes(r1_bytes)), r1_hex); - assert_eq!(format!("{}", Hash256::from_bytes(r2_bytes)), r2_hex); + assert_eq!(format!("{}", Hash256::from_lendian(r1_bytes)), r1_hex); + assert_eq!(format!("{}", Hash256::from_lendian(r2_bytes)), r2_hex); } #[rstest] fn from_hex_to_bytes(r1_bytes: [u8; 32], r1_hex: &str, r2_bytes: [u8; 32], r2_hex: &str) { - assert_eq!(Hash256::from_hex(r1_hex).unwrap().to_bytes(), r1_bytes); - assert_eq!(Hash256::from_hex(r2_hex).unwrap().to_bytes(), r2_bytes); + assert_eq!(Hash256::from_hex(r1_hex).unwrap().to_lendian(), r1_bytes); + assert_eq!(Hash256::from_hex(r2_hex).unwrap().to_lendian(), r2_bytes); } #[rstest] fn roundtrip_hex(r1_bytes: [u8; 32], r2_bytes: [u8; 32]) { - let r1 = Hash256::from_bytes(r1_bytes); + let r1 = Hash256::from_lendian(r1_bytes); assert_eq!(Hash256::from_str(&format!("{r1}")).unwrap(), r1); - let r2 = Hash256::from_bytes(r2_bytes); + let r2 = Hash256::from_lendian(r2_bytes); assert_eq!(Hash256::from_str(&format!("{r2}")).unwrap(), r2); } #[rstest] fn roundtrip_bytes(r1_bytes: [u8; 32], r2_bytes: [u8; 32]) { - assert_eq!(Hash256::from_bytes(r1_bytes).to_bytes(), r1_bytes); - assert_eq!(Hash256::from_bytes(r2_bytes).to_bytes(), r2_bytes); + assert_eq!(Hash256::from_lendian(r1_bytes).to_lendian(), r1_bytes); + assert_eq!(Hash256::from_lendian(r2_bytes).to_lendian(), r2_bytes); } #[rstest] fn zero_one_max() { - assert_eq!(Hash256::ZERO.to_bytes(), [0u8; 32]); + assert_eq!(Hash256::ZERO.to_lendian(), [0u8; 32]); assert!(Hash256::ZERO.is_null()); - let one = Hash256::from_bytes(ONE_ARRAY); + let one = Hash256::from_lendian(ONE_ARRAY); assert!(!one.is_null()); assert_eq!( @@ -89,7 +89,7 @@ fn zero_one_max() { "0000000000000000000000000000000000000000000000000000000000000001" ); assert_eq!( - format!("{}", Hash256::from_bytes([0xff; 32])), + format!("{}", Hash256::from_lendian([0xff; 32])), "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff" ); } @@ -97,8 +97,8 @@ fn zero_one_max() { #[rstest] fn ordering_is_lexicographic() { let zero = Hash256::ZERO; - let one = Hash256::from_bytes(ONE_ARRAY); - let max = Hash256::from_bytes([0xff; 32]); + let one = Hash256::from_lendian(ONE_ARRAY); + let max = Hash256::from_lendian([0xff; 32]); assert!(one > zero); assert!(max > one); @@ -107,12 +107,12 @@ fn ordering_is_lexicographic() { #[rstest] fn from_hex_with_prefix() { - assert_eq!(Hash256::from_hex("0x01").unwrap().to_bytes(), ONE_ARRAY); + assert_eq!(Hash256::from_hex("0x01").unwrap().to_lendian(), ONE_ARRAY); } #[rstest] fn from_hex_short() { - assert_eq!(Hash256::from_hex("01").unwrap().to_bytes(), ONE_ARRAY); + assert_eq!(Hash256::from_hex("01").unwrap().to_lendian(), ONE_ARRAY); } #[rstest] @@ -129,7 +129,7 @@ fn hex_errors() { #[rstest] fn hash160_roundtrip() { let bytes = hex!("0102030405060708090a0b0c0d0e0f1011121314"); - let h = Hash160::from_bytes(bytes); + let h = Hash160::from_lendian(bytes); let hex = format!("{h}"); assert_eq!(hex, "14131211100f0e0d0c0b0a090807060504030201"); assert_eq!(Hash160::from_str(&hex).unwrap(), h); @@ -139,15 +139,15 @@ fn hash160_roundtrip() { fn hash160_zero_and_null() { assert!(Hash160::ZERO.is_null()); assert_eq!(Hash160::LEN, 20); - let h = Hash160::from_bytes([0xff; 20]); + let h = Hash160::from_lendian([0xff; 20]); assert!(!h.is_null()); } #[rstest] fn hash160_new_reverses() { let be = hex!("0102030405060708090a0b0c0d0e0f1011121314"); - let h = Hash160::new(be); + let h = Hash160::from_bendian(be); // new() reverses, so first byte in LE is last byte of BE input - assert_eq!(h.to_bytes()[0], 0x14); - assert_eq!(h.to_bytes()[19], 0x01); + assert_eq!(h.to_lendian()[0], 0x14); + assert_eq!(h.to_lendian()[19], 0x01); } diff --git a/pkgs/num/tests/serde.rs b/pkgs/num/tests/serde.rs index 0e9f788c..1dea7dab 100644 --- a/pkgs/num/tests/serde.rs +++ b/pkgs/num/tests/serde.rs @@ -14,17 +14,17 @@ use hex_literal::hex; #[test] fn hash256_json_roundtrip() { let bytes = hex!("9c524adbcf5611122b29125e5d35d2d22281aab533f00832d556b1f9eae51d7d"); - let h = Hash256::from_bytes(bytes); + let h = Hash256::from_lendian(bytes); assert_json_rt(&h); assert_json_rt(&Hash256::ZERO); - assert_json_rt(&Hash256::from_bytes([0xff; 32])); + assert_json_rt(&Hash256::from_lendian([0xff; 32])); } #[test] fn hash160_json_roundtrip() { let bytes = hex!("0102030405060708090a0b0c0d0e0f1011121314"); - let h = Hash160::from_bytes(bytes); + let h = Hash160::from_lendian(bytes); assert_json_rt(&h); assert_json_rt(&Hash160::ZERO); } diff --git a/pkgs/params/src/mainnet.rs b/pkgs/params/src/mainnet.rs index 404a7975..d8f591eb 100644 --- a/pkgs/params/src/mainnet.rs +++ b/pkgs/params/src/mainnet.rs @@ -68,7 +68,7 @@ pub fn genesis() -> Block { pub static PARAMS: ChainParams = ChainParams { consensus: ConsensusParams { - hash_genesis_block: Hash256::new(hex!("00000ffd590b1485b3caadc19b22e6379c733355108f107a430458cdf3407ab6")), + hash_genesis_block: Hash256::from_bendian(hex!("00000ffd590b1485b3caadc19b22e6379c733355108f107a430458cdf3407ab6")), subsidy_halving_interval: 210_240, masternode_payments_start_block: BlockHeight::from_u32(100_000), masternode_payments_increase_block: BlockHeight::from_u32(158_000), @@ -80,7 +80,7 @@ pub static PARAMS: ChainParams = ChainParams { budget_payments_window_blocks: 100, superblock_start: ( BlockHeight::from_u32(614_820), - Hash256::new(hex!("0000000000020cb27c7ef164d21003d5d20cdca2f54dd9a9ca6d45f4d47f8aa3")), + Hash256::from_bendian(hex!("0000000000020cb27c7ef164d21003d5d20cdca2f54dd9a9ca6d45f4d47f8aa3")), ), superblock_cycle: 16_616, superblock_maturity_window: 1_662, @@ -89,7 +89,7 @@ pub static PARAMS: ChainParams = ChainParams { masternode_minimum_confirmations: 15, bip34: ( BlockHeight::from_u32(951), - Hash256::new(hex!("000001f35e70f7c5705f64c6c5cc3dea9449e74d5b5c7cf74dad1bcca14a8012")), + Hash256::from_bendian(hex!("000001f35e70f7c5705f64c6c5cc3dea9449e74d5b5c7cf74dad1bcca14a8012")), ), bip65_height: BlockHeight::from_u32(619_382), bip66_height: BlockHeight::from_u32(245_817), @@ -99,7 +99,7 @@ pub static PARAMS: ChainParams = ChainParams { dip0003_height: BlockHeight::from_u32(1_028_160), dip0003_enforcement: ( BlockHeight::from_u32(1_047_200), - Hash256::new(hex!("000000000000002d1734087b4c5afc3133e4e1c3e1a89218f62bcd9bb3d17f81")), + Hash256::from_bendian(hex!("000000000000002d1734087b4c5afc3133e4e1c3e1a89218f62bcd9bb3d17f81")), ), dip0008_height: BlockHeight::from_u32(1_088_640), brr_height: BlockHeight::from_u32(1_374_912), @@ -138,15 +138,19 @@ pub static PARAMS: ChainParams = ChainParams { }, }, // ~uint256(0) >> 20 - pow_limit: Arith256::new(hex!("00000fffffffffffffffffffffffffffffffffffffffffffffffffffffffffff")), + pow_limit: Arith256::from_bendian(hex!("00000fffffffffffffffffffffffffffffffffffffffffffffffffffffffffff")), pow_allow_min_difficulty_blocks: false, pow_no_retargeting: false, pow_target_spacing: 150, // 2.5 minutes pow_target_timespan: 86_400, // 1 day pow_kgw_height: BlockHeight::from_u32(15_200), pow_dgw_height: BlockHeight::from_u32(34_140), - minimum_chain_work: Arith256::new(hex!("00000000000000000000000000000000000000000000b567e2d53a06de194061")), - default_assume_valid: Hash256::new(hex!("00000000000000018fb7d55a2d7ab5f3d1369cf0d7eef25db727bf8c9ca7d4b2")), + minimum_chain_work: Arith256::from_bendian(hex!( + "00000000000000000000000000000000000000000000b567e2d53a06de194061" + )), + default_assume_valid: Hash256::from_bendian(hex!( + "00000000000000018fb7d55a2d7ab5f3d1369cf0d7eef25db727bf8c9ca7d4b2" + )), llmq_type_chain_locks: LlmqType::Llmq400_60, llmq_type_dip0024_instant_send: LlmqType::Llmq60_75, llmq_type_platform: LlmqType::Llmq100_67, @@ -188,41 +192,41 @@ pub static PARAMS: ChainParams = ChainParams { #[rustfmt::skip] const CHECKPOINTS: [Checkpoint; 37] = [ - (BlockHeight::from_u32( 1_500), Hash256::new(hex!("000000aaf0300f59f49bc3e970bad15c11f961fe2347accffff19d96ec9778e3"))), - (BlockHeight::from_u32( 4_991), Hash256::new(hex!("000000003b01809551952460744d5dbb8fcbd6cbae3c220267bf7fa43f837367"))), - (BlockHeight::from_u32( 9_918), Hash256::new(hex!("00000000213e229f332c0ffbe34defdaa9e74de87f2d8d1f01af8d121c3c170b"))), - (BlockHeight::from_u32( 16_912), Hash256::new(hex!("00000000075c0d10371d55a60634da70f197548dbbfa4123e12abfcbc5738af9"))), - (BlockHeight::from_u32( 23_912), Hash256::new(hex!("0000000000335eac6703f3b1732ec8b2f89c3ba3a7889e5767b090556bb9a276"))), - (BlockHeight::from_u32( 35_457), Hash256::new(hex!("0000000000b0ae211be59b048df14820475ad0dd53b9ff83b010f71a77342d9f"))), - (BlockHeight::from_u32( 45_479), Hash256::new(hex!("000000000063d411655d590590e16960f15ceea4257122ac430c6fbe39fbf02d"))), - (BlockHeight::from_u32( 55_895), Hash256::new(hex!("0000000000ae4c53a43639a4ca027282f69da9c67ba951768a20415b6439a2d7"))), - (BlockHeight::from_u32( 68_899), Hash256::new(hex!("0000000000194ab4d3d9eeb1f2f792f21bb39ff767cb547fe977640f969d77b7"))), - (BlockHeight::from_u32( 74_619), Hash256::new(hex!("000000000011d28f38f05d01650a502cc3f4d0e793fbc26e2a2ca71f07dc3842"))), - (BlockHeight::from_u32( 75_095), Hash256::new(hex!("0000000000193d12f6ad352a9996ee58ef8bdc4946818a5fec5ce99c11b87f0d"))), - (BlockHeight::from_u32( 88_805), Hash256::new(hex!("00000000001392f1652e9bf45cd8bc79dc60fe935277cd11538565b4a94fa85f"))), - (BlockHeight::from_u32( 107_996), Hash256::new(hex!("00000000000a23840ac16115407488267aa3da2b9bc843e301185b7d17e4dc40"))), - (BlockHeight::from_u32( 137_993), Hash256::new(hex!("00000000000cf69ce152b1bffdeddc59188d7a80879210d6e5c9503011929c3c"))), - (BlockHeight::from_u32( 167_996), Hash256::new(hex!("000000000009486020a80f7f2cc065342b0c2fb59af5e090cd813dba68ab0fed"))), - (BlockHeight::from_u32( 207_992), Hash256::new(hex!("00000000000d85c22be098f74576ef00b7aa00c05777e966aff68a270f1e01a5"))), - (BlockHeight::from_u32( 312_645), Hash256::new(hex!("0000000000059dcb71ad35a9e40526c44e7aae6c99169a9e7017b7d84b1c2daf"))), - (BlockHeight::from_u32( 407_452), Hash256::new(hex!("000000000003c6a87e73623b9d70af7cd908ae22fee466063e4ffc20be1d2dbc"))), - (BlockHeight::from_u32( 523_412), Hash256::new(hex!("000000000000e54f036576a10597e0e42cc22a5159ce572f999c33975e121d4d"))), - (BlockHeight::from_u32( 523_930), Hash256::new(hex!("0000000000000bccdb11c2b1cfb0ecab452abf267d89b7f46eaf2d54ce6e652c"))), - (BlockHeight::from_u32( 750_000), Hash256::new(hex!("00000000000000b4181bbbdddbae464ce11fede5d0292fb63fdede1e7c8ab21c"))), - (BlockHeight::from_u32( 888_900), Hash256::new(hex!("0000000000000026c29d576073ab51ebd1d3c938de02e9a44c7ee9e16f82db28"))), - (BlockHeight::from_u32( 967_800), Hash256::new(hex!("0000000000000024e26c7df7e46d673724d223cf4ca2b2adc21297cc095600f4"))), - (BlockHeight::from_u32(1_067_570), Hash256::new(hex!("000000000000001e09926bcf5fa4513d23e870a34f74e38200db99eb3f5b7a70"))), - (BlockHeight::from_u32(1_167_570), Hash256::new(hex!("000000000000000fb7b1e9b81700283dff0f7d87cf458e5edfdae00c669de661"))), - (BlockHeight::from_u32(1_364_585), Hash256::new(hex!("00000000000000022f355c52417fca9b73306958f7c0832b3a7bce006ca369ef"))), - (BlockHeight::from_u32(1_450_000), Hash256::new(hex!("00000000000000105cfae44a995332d8ec256850ea33a1f7b700474e3dad82bc"))), - (BlockHeight::from_u32(1_796_500), Hash256::new(hex!("000000000000001d531f36005159f19351bd49ca676398a561e55dcccb84eacd"))), - (BlockHeight::from_u32(1_850_400), Hash256::new(hex!("00000000000000261bdbe99c01fcba992e577efa6cc41aae564b8ca9f112b2a3"))), - (BlockHeight::from_u32(1_889_000), Hash256::new(hex!("00000000000000075300e852d5bf5380f905b2768241f8b442498442084807a7"))), - (BlockHeight::from_u32(1_969_000), Hash256::new(hex!("000000000000000c8b7a3bdcd8b9f516462122314529c8342244c685a4c899bf"))), - (BlockHeight::from_u32(2_029_000), Hash256::new(hex!("0000000000000020d5e38b6aef5bc8e430029444d7977b46f710c7d281ef1281"))), - (BlockHeight::from_u32(2_109_672), Hash256::new(hex!("000000000000001889bd33ef019065e250d32bd46911f4003d3fdd8128b5358d"))), - (BlockHeight::from_u32(2_175_051), Hash256::new(hex!("000000000000001cf26547602d982dcaa909231bbcd1e70c0eb3c65de25473ba"))), - (BlockHeight::from_u32(2_216_986), Hash256::new(hex!("0000000000000010b1135dc743f27f6fc8a138c6420a9d963fc676f96c2048f4"))), - (BlockHeight::from_u32(2_361_500), Hash256::new(hex!("0000000000000009ba1e8f47851d036bb618a4f6565eb3c32d1f647d450ff195"))), - (BlockHeight::from_u32(2_421_800), Hash256::new(hex!("000000000000000718ed026ebd644a8b70b42d4cbd7b25304c066c9bf15f85b7"))), + (BlockHeight::from_u32( 1_500), Hash256::from_bendian(hex!("000000aaf0300f59f49bc3e970bad15c11f961fe2347accffff19d96ec9778e3"))), + (BlockHeight::from_u32( 4_991), Hash256::from_bendian(hex!("000000003b01809551952460744d5dbb8fcbd6cbae3c220267bf7fa43f837367"))), + (BlockHeight::from_u32( 9_918), Hash256::from_bendian(hex!("00000000213e229f332c0ffbe34defdaa9e74de87f2d8d1f01af8d121c3c170b"))), + (BlockHeight::from_u32( 16_912), Hash256::from_bendian(hex!("00000000075c0d10371d55a60634da70f197548dbbfa4123e12abfcbc5738af9"))), + (BlockHeight::from_u32( 23_912), Hash256::from_bendian(hex!("0000000000335eac6703f3b1732ec8b2f89c3ba3a7889e5767b090556bb9a276"))), + (BlockHeight::from_u32( 35_457), Hash256::from_bendian(hex!("0000000000b0ae211be59b048df14820475ad0dd53b9ff83b010f71a77342d9f"))), + (BlockHeight::from_u32( 45_479), Hash256::from_bendian(hex!("000000000063d411655d590590e16960f15ceea4257122ac430c6fbe39fbf02d"))), + (BlockHeight::from_u32( 55_895), Hash256::from_bendian(hex!("0000000000ae4c53a43639a4ca027282f69da9c67ba951768a20415b6439a2d7"))), + (BlockHeight::from_u32( 68_899), Hash256::from_bendian(hex!("0000000000194ab4d3d9eeb1f2f792f21bb39ff767cb547fe977640f969d77b7"))), + (BlockHeight::from_u32( 74_619), Hash256::from_bendian(hex!("000000000011d28f38f05d01650a502cc3f4d0e793fbc26e2a2ca71f07dc3842"))), + (BlockHeight::from_u32( 75_095), Hash256::from_bendian(hex!("0000000000193d12f6ad352a9996ee58ef8bdc4946818a5fec5ce99c11b87f0d"))), + (BlockHeight::from_u32( 88_805), Hash256::from_bendian(hex!("00000000001392f1652e9bf45cd8bc79dc60fe935277cd11538565b4a94fa85f"))), + (BlockHeight::from_u32( 107_996), Hash256::from_bendian(hex!("00000000000a23840ac16115407488267aa3da2b9bc843e301185b7d17e4dc40"))), + (BlockHeight::from_u32( 137_993), Hash256::from_bendian(hex!("00000000000cf69ce152b1bffdeddc59188d7a80879210d6e5c9503011929c3c"))), + (BlockHeight::from_u32( 167_996), Hash256::from_bendian(hex!("000000000009486020a80f7f2cc065342b0c2fb59af5e090cd813dba68ab0fed"))), + (BlockHeight::from_u32( 207_992), Hash256::from_bendian(hex!("00000000000d85c22be098f74576ef00b7aa00c05777e966aff68a270f1e01a5"))), + (BlockHeight::from_u32( 312_645), Hash256::from_bendian(hex!("0000000000059dcb71ad35a9e40526c44e7aae6c99169a9e7017b7d84b1c2daf"))), + (BlockHeight::from_u32( 407_452), Hash256::from_bendian(hex!("000000000003c6a87e73623b9d70af7cd908ae22fee466063e4ffc20be1d2dbc"))), + (BlockHeight::from_u32( 523_412), Hash256::from_bendian(hex!("000000000000e54f036576a10597e0e42cc22a5159ce572f999c33975e121d4d"))), + (BlockHeight::from_u32( 523_930), Hash256::from_bendian(hex!("0000000000000bccdb11c2b1cfb0ecab452abf267d89b7f46eaf2d54ce6e652c"))), + (BlockHeight::from_u32( 750_000), Hash256::from_bendian(hex!("00000000000000b4181bbbdddbae464ce11fede5d0292fb63fdede1e7c8ab21c"))), + (BlockHeight::from_u32( 888_900), Hash256::from_bendian(hex!("0000000000000026c29d576073ab51ebd1d3c938de02e9a44c7ee9e16f82db28"))), + (BlockHeight::from_u32( 967_800), Hash256::from_bendian(hex!("0000000000000024e26c7df7e46d673724d223cf4ca2b2adc21297cc095600f4"))), + (BlockHeight::from_u32(1_067_570), Hash256::from_bendian(hex!("000000000000001e09926bcf5fa4513d23e870a34f74e38200db99eb3f5b7a70"))), + (BlockHeight::from_u32(1_167_570), Hash256::from_bendian(hex!("000000000000000fb7b1e9b81700283dff0f7d87cf458e5edfdae00c669de661"))), + (BlockHeight::from_u32(1_364_585), Hash256::from_bendian(hex!("00000000000000022f355c52417fca9b73306958f7c0832b3a7bce006ca369ef"))), + (BlockHeight::from_u32(1_450_000), Hash256::from_bendian(hex!("00000000000000105cfae44a995332d8ec256850ea33a1f7b700474e3dad82bc"))), + (BlockHeight::from_u32(1_796_500), Hash256::from_bendian(hex!("000000000000001d531f36005159f19351bd49ca676398a561e55dcccb84eacd"))), + (BlockHeight::from_u32(1_850_400), Hash256::from_bendian(hex!("00000000000000261bdbe99c01fcba992e577efa6cc41aae564b8ca9f112b2a3"))), + (BlockHeight::from_u32(1_889_000), Hash256::from_bendian(hex!("00000000000000075300e852d5bf5380f905b2768241f8b442498442084807a7"))), + (BlockHeight::from_u32(1_969_000), Hash256::from_bendian(hex!("000000000000000c8b7a3bdcd8b9f516462122314529c8342244c685a4c899bf"))), + (BlockHeight::from_u32(2_029_000), Hash256::from_bendian(hex!("0000000000000020d5e38b6aef5bc8e430029444d7977b46f710c7d281ef1281"))), + (BlockHeight::from_u32(2_109_672), Hash256::from_bendian(hex!("000000000000001889bd33ef019065e250d32bd46911f4003d3fdd8128b5358d"))), + (BlockHeight::from_u32(2_175_051), Hash256::from_bendian(hex!("000000000000001cf26547602d982dcaa909231bbcd1e70c0eb3c65de25473ba"))), + (BlockHeight::from_u32(2_216_986), Hash256::from_bendian(hex!("0000000000000010b1135dc743f27f6fc8a138c6420a9d963fc676f96c2048f4"))), + (BlockHeight::from_u32(2_361_500), Hash256::from_bendian(hex!("0000000000000009ba1e8f47851d036bb618a4f6565eb3c32d1f647d450ff195"))), + (BlockHeight::from_u32(2_421_800), Hash256::from_bendian(hex!("000000000000000718ed026ebd644a8b70b42d4cbd7b25304c066c9bf15f85b7"))), ]; diff --git a/pkgs/params/src/regtest.rs b/pkgs/params/src/regtest.rs index 2c626688..9921295e 100644 --- a/pkgs/params/src/regtest.rs +++ b/pkgs/params/src/regtest.rs @@ -69,7 +69,7 @@ pub fn genesis() -> Block { pub static PARAMS: ChainParams = ChainParams { consensus: ConsensusParams { - hash_genesis_block: Hash256::new(hex!("000008ca1832a4baf228eb1553c03d3a2c8e02399550dd6ea8d65cec3ef23d2e")), + hash_genesis_block: Hash256::from_bendian(hex!("000008ca1832a4baf228eb1553c03d3a2c8e02399550dd6ea8d65cec3ef23d2e")), subsidy_halving_interval: 150, masternode_payments_start_block: BlockHeight::from_u32(240), masternode_payments_increase_block: BlockHeight::from_u32(350), @@ -130,7 +130,7 @@ pub static PARAMS: ChainParams = ChainParams { }, }, // ~uint256(0) >> 1 - pow_limit: Arith256::new(hex!("7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff")), + pow_limit: Arith256::from_bendian(hex!("7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff")), pow_allow_min_difficulty_blocks: true, pow_no_retargeting: true, pow_target_spacing: 150, // 2.5 minutes @@ -180,5 +180,5 @@ pub static PARAMS: ChainParams = ChainParams { #[rustfmt::skip] const CHECKPOINTS: [Checkpoint; 1] = [ - (BlockHeight::from_u32(0), Hash256::new(hex!("000008ca1832a4baf228eb1553c03d3a2c8e02399550dd6ea8d65cec3ef23d2e"))), + (BlockHeight::from_u32(0), Hash256::from_bendian(hex!("000008ca1832a4baf228eb1553c03d3a2c8e02399550dd6ea8d65cec3ef23d2e"))), ]; diff --git a/pkgs/params/src/test3.rs b/pkgs/params/src/test3.rs index 816eaaaa..aa3d509f 100644 --- a/pkgs/params/src/test3.rs +++ b/pkgs/params/src/test3.rs @@ -69,7 +69,7 @@ pub fn genesis() -> Block { pub static PARAMS: ChainParams = ChainParams { consensus: ConsensusParams { - hash_genesis_block: Hash256::new(hex!("00000bafbc94add76cb75e2ec92894837288a481e5c005f6563d91623bf8bc2c")), + hash_genesis_block: Hash256::from_bendian(hex!("00000bafbc94add76cb75e2ec92894837288a481e5c005f6563d91623bf8bc2c")), subsidy_halving_interval: 210_240, masternode_payments_start_block: BlockHeight::from_u32(4010), masternode_payments_increase_block: BlockHeight::from_u32(4030), @@ -87,7 +87,7 @@ pub static PARAMS: ChainParams = ChainParams { masternode_minimum_confirmations: 1, bip34: ( BlockHeight::from_u32(76), - Hash256::new(hex!("000008ebb1db2598e897d17275285767717c6acfeac4c73def49fbea1ddcbcb6")), + Hash256::from_bendian(hex!("000008ebb1db2598e897d17275285767717c6acfeac4c73def49fbea1ddcbcb6")), ), bip65_height: BlockHeight::from_u32(2431), bip66_height: BlockHeight::from_u32(2075), @@ -97,7 +97,7 @@ pub static PARAMS: ChainParams = ChainParams { dip0003_height: BlockHeight::from_u32(7000), dip0003_enforcement: ( BlockHeight::from_u32(7300), - Hash256::new(hex!("00000055ebc0e974ba3a3fb785c5ad4365a39637d4df168169ee80d313612f8f")), + Hash256::from_bendian(hex!("00000055ebc0e974ba3a3fb785c5ad4365a39637d4df168169ee80d313612f8f")), ), dip0008_height: BlockHeight::from_u32(78_800), brr_height: BlockHeight::from_u32(387_500), @@ -136,15 +136,19 @@ pub static PARAMS: ChainParams = ChainParams { }, }, // ~uint256(0) >> 20 - pow_limit: Arith256::new(hex!("00000fffffffffffffffffffffffffffffffffffffffffffffffffffffffffff")), + pow_limit: Arith256::from_bendian(hex!("00000fffffffffffffffffffffffffffffffffffffffffffffffffffffffffff")), pow_allow_min_difficulty_blocks: true, pow_no_retargeting: false, pow_target_spacing: 150, // 2.5 minutes pow_target_timespan: 86_400, // 1 day pow_kgw_height: BlockHeight::from_u32(4002), pow_dgw_height: BlockHeight::from_u32(4002), - minimum_chain_work: Arith256::new(hex!("000000000000000000000000000000000000000000000000036c8f738da818d2")), - default_assume_valid: Hash256::new(hex!("000000541a23f9db7411cddbe50f9f1ebd4aa7108ebdcad62214753f648c0239")), + minimum_chain_work: Arith256::from_bendian(hex!( + "000000000000000000000000000000000000000000000000036c8f738da818d2" + )), + default_assume_valid: Hash256::from_bendian(hex!( + "000000541a23f9db7411cddbe50f9f1ebd4aa7108ebdcad62214753f648c0239" + )), llmq_type_chain_locks: LlmqType::Llmq50_60, llmq_type_dip0024_instant_send: LlmqType::Llmq60_75, llmq_type_platform: LlmqType::Llmq25_67, @@ -186,23 +190,23 @@ pub static PARAMS: ChainParams = ChainParams { #[rustfmt::skip] const CHECKPOINTS: [Checkpoint; 19] = [ - (BlockHeight::from_u32( 255), Hash256::new(hex!("0000080b600e06f4c07880673f027210f9314575f5f875fafe51971e268b886a"))), - (BlockHeight::from_u32( 261), Hash256::new(hex!("00000c26026d0815a7e2ce4fa270775f61403c040647ff2c3091f99e894a4618"))), - (BlockHeight::from_u32( 1_999), Hash256::new(hex!("00000052e538d27fa53693efe6fb6892a0c1d26c0235f599171c48a3cce553b1"))), - (BlockHeight::from_u32( 2_999), Hash256::new(hex!("0000024bc3f4f4cb30d29827c13d921ad77d2c6072e586c7f60d83c2722cdcc5"))), - (BlockHeight::from_u32( 96_090), Hash256::new(hex!("00000000033df4b94d17ab43e999caaf6c4735095cc77703685da81254d09bba"))), - (BlockHeight::from_u32( 200_000), Hash256::new(hex!("000000001015eb5ef86a8fe2b3074d947bc972c5befe32b28dd5ce915dc0d029"))), - (BlockHeight::from_u32( 395_750), Hash256::new(hex!("000008b78b6aef3fd05ab78db8b76c02163e885305545144420cb08704dce538"))), - (BlockHeight::from_u32( 470_000), Hash256::new(hex!("0000009303aeadf8cf3812f5c869691dbd4cb118ad20e9bf553be434bafe6a52"))), - (BlockHeight::from_u32( 794_950), Hash256::new(hex!("000001860e4c7248a9c5cc3bc7106041750560dc5cd9b3a2641b49494bcff5f2"))), - (BlockHeight::from_u32( 808_000), Hash256::new(hex!("00000104cb60a2b5e00a8a4259582756e5bf0dca201c0993c63f0e54971ea91a"))), - (BlockHeight::from_u32( 840_000), Hash256::new(hex!("000000cd7c3084499912ae893125c13e8c3c656abb6e511dcec6619c3d65a510"))), - (BlockHeight::from_u32( 851_000), Hash256::new(hex!("0000014d3b875540ff75517b7fbb1714e25d50ce92f65d7086cfce357928bb02"))), - (BlockHeight::from_u32( 905_100), Hash256::new(hex!("0000020c5e0f86f385cbf8e90210de9a9fd63633f01433bf47a6b3227a2851fd"))), - (BlockHeight::from_u32( 960_000), Hash256::new(hex!("0000000386cf5061ea16404c66deb83eb67892fa4f79b9e58e5eaab097ec2bd6"))), - (BlockHeight::from_u32(1_069_875), Hash256::new(hex!("00000034bfeb926662ba547c0b8dd4ba8cbb6e0c581f4e7d1bddce8f9ca3a608"))), - (BlockHeight::from_u32(1_143_608), Hash256::new(hex!("000000eef20eb0062abd4e799967e98bdebb165dd1c567ab4118c1c86c6e948f"))), - (BlockHeight::from_u32(1_189_000), Hash256::new(hex!("000001690314036dfbbecbdf382b230ead8e9c584241290a51f9f05a87a9cf7e"))), - (BlockHeight::from_u32(1_295_700), Hash256::new(hex!("00000107d42829a38e31c1a38c660d621e1ca376a880df1520e85e38af175d3a"))), - (BlockHeight::from_u32(1_380_000), Hash256::new(hex!("000000a98084beaf77ed26a905a7d59979009e23367a55b5d634962d7d65a1f9"))), + (BlockHeight::from_u32( 255), Hash256::from_bendian(hex!("0000080b600e06f4c07880673f027210f9314575f5f875fafe51971e268b886a"))), + (BlockHeight::from_u32( 261), Hash256::from_bendian(hex!("00000c26026d0815a7e2ce4fa270775f61403c040647ff2c3091f99e894a4618"))), + (BlockHeight::from_u32( 1_999), Hash256::from_bendian(hex!("00000052e538d27fa53693efe6fb6892a0c1d26c0235f599171c48a3cce553b1"))), + (BlockHeight::from_u32( 2_999), Hash256::from_bendian(hex!("0000024bc3f4f4cb30d29827c13d921ad77d2c6072e586c7f60d83c2722cdcc5"))), + (BlockHeight::from_u32( 96_090), Hash256::from_bendian(hex!("00000000033df4b94d17ab43e999caaf6c4735095cc77703685da81254d09bba"))), + (BlockHeight::from_u32( 200_000), Hash256::from_bendian(hex!("000000001015eb5ef86a8fe2b3074d947bc972c5befe32b28dd5ce915dc0d029"))), + (BlockHeight::from_u32( 395_750), Hash256::from_bendian(hex!("000008b78b6aef3fd05ab78db8b76c02163e885305545144420cb08704dce538"))), + (BlockHeight::from_u32( 470_000), Hash256::from_bendian(hex!("0000009303aeadf8cf3812f5c869691dbd4cb118ad20e9bf553be434bafe6a52"))), + (BlockHeight::from_u32( 794_950), Hash256::from_bendian(hex!("000001860e4c7248a9c5cc3bc7106041750560dc5cd9b3a2641b49494bcff5f2"))), + (BlockHeight::from_u32( 808_000), Hash256::from_bendian(hex!("00000104cb60a2b5e00a8a4259582756e5bf0dca201c0993c63f0e54971ea91a"))), + (BlockHeight::from_u32( 840_000), Hash256::from_bendian(hex!("000000cd7c3084499912ae893125c13e8c3c656abb6e511dcec6619c3d65a510"))), + (BlockHeight::from_u32( 851_000), Hash256::from_bendian(hex!("0000014d3b875540ff75517b7fbb1714e25d50ce92f65d7086cfce357928bb02"))), + (BlockHeight::from_u32( 905_100), Hash256::from_bendian(hex!("0000020c5e0f86f385cbf8e90210de9a9fd63633f01433bf47a6b3227a2851fd"))), + (BlockHeight::from_u32( 960_000), Hash256::from_bendian(hex!("0000000386cf5061ea16404c66deb83eb67892fa4f79b9e58e5eaab097ec2bd6"))), + (BlockHeight::from_u32(1_069_875), Hash256::from_bendian(hex!("00000034bfeb926662ba547c0b8dd4ba8cbb6e0c581f4e7d1bddce8f9ca3a608"))), + (BlockHeight::from_u32(1_143_608), Hash256::from_bendian(hex!("000000eef20eb0062abd4e799967e98bdebb165dd1c567ab4118c1c86c6e948f"))), + (BlockHeight::from_u32(1_189_000), Hash256::from_bendian(hex!("000001690314036dfbbecbdf382b230ead8e9c584241290a51f9f05a87a9cf7e"))), + (BlockHeight::from_u32(1_295_700), Hash256::from_bendian(hex!("00000107d42829a38e31c1a38c660d621e1ca376a880df1520e85e38af175d3a"))), + (BlockHeight::from_u32(1_380_000), Hash256::from_bendian(hex!("000000a98084beaf77ed26a905a7d59979009e23367a55b5d634962d7d65a1f9"))), ]; diff --git a/pkgs/params/tests/genesis_valid.rs b/pkgs/params/tests/genesis_valid.rs index c99b31b3..fe2c643e 100644 --- a/pkgs/params/tests/genesis_valid.rs +++ b/pkgs/params/tests/genesis_valid.rs @@ -8,7 +8,7 @@ use dash_params::{ChainParams, Network}; use dash_primitives::{Block, BlockHash, MerkleRoot}; -use dash_types::codec::Hashable; +use dash_types::{Hashable, Numeric}; use hex_literal::hex; use rstest::rstest; @@ -16,17 +16,17 @@ use rstest::rstest; #[case::mainnet( Network::Main.genesis(), Network::Main.chain(), - MerkleRoot::new(hex!("e0028eb9648db56b1ac77cf090b99048a8007e2bb64b68f092c03c7f56a662c7")), + MerkleRoot::from_bendian(hex!("e0028eb9648db56b1ac77cf090b99048a8007e2bb64b68f092c03c7f56a662c7")), )] #[case::testnet( Network::Testnet3.genesis(), Network::Testnet3.chain(), - MerkleRoot::new(hex!("e0028eb9648db56b1ac77cf090b99048a8007e2bb64b68f092c03c7f56a662c7")), + MerkleRoot::from_bendian(hex!("e0028eb9648db56b1ac77cf090b99048a8007e2bb64b68f092c03c7f56a662c7")), )] #[case::regtest( Network::Regtest.genesis(), Network::Regtest.chain(), - MerkleRoot::new(hex!("e0028eb9648db56b1ac77cf090b99048a8007e2bb64b68f092c03c7f56a662c7")), + MerkleRoot::from_bendian(hex!("e0028eb9648db56b1ac77cf090b99048a8007e2bb64b68f092c03c7f56a662c7")), )] fn genesis_block_hash_matches( #[case] genesis: Block, diff --git a/pkgs/pkc/src/bls/ies_bytes.rs b/pkgs/pkc/src/bls/ies_bytes.rs index 7a34c89c..79540a4f 100644 --- a/pkgs/pkc/src/bls/ies_bytes.rs +++ b/pkgs/pkc/src/bls/ies_bytes.rs @@ -21,7 +21,7 @@ use dash_types::codec::{read_bytes, BaseCodec, DecodeError, EncodeBuf}; #[cfg(feature = "codec")] use dash_types::type_id::TypeId; #[cfg(feature = "codec")] -use dash_types::{impl_type, CompactSize}; +use dash_types::{impl_type, CompactSize, Numeric}; #[cfg(feature = "codec")] use dash_types::{Checkable, Hashable}; use hex_conservative::DisplayHex; @@ -90,7 +90,7 @@ impl Hashable for BlsIesBlobBytes { type Hash = Hash256; fn hash(&self) -> Self::Hash { - Hash256::from_bytes(Sha256d::hash(&self.to_bytes()).to_byte_array()) + Hash256::from_lendian(Sha256d::hash(&self.to_bytes()).to_byte_array()) } } @@ -215,7 +215,7 @@ impl Hashable for BlsIesMultiBytes { type Hash = Hash256; fn hash(&self) -> Self::Hash { - Hash256::from_bytes(Sha256d::hash(&self.to_bytes()).to_byte_array()) + Hash256::from_lendian(Sha256d::hash(&self.to_bytes()).to_byte_array()) } } diff --git a/pkgs/pkc/src/bls/public_bytes.rs b/pkgs/pkc/src/bls/public_bytes.rs index 4b3c8df8..7b323e1f 100644 --- a/pkgs/pkc/src/bls/public_bytes.rs +++ b/pkgs/pkc/src/bls/public_bytes.rs @@ -12,6 +12,7 @@ use bitcoin_hashes::sha256d::Hash as Sha256d; use dash_num::Hash256; use dash_types::make_bytes; use dash_types::Hashable; +use dash_types::Numeric; /// Raw BLS public key length (G1 compressed). pub const BLS_PK_LEN: usize = 48; @@ -25,6 +26,6 @@ impl Hashable for BlsPkBytes { type Hash = Hash256; fn hash(&self) -> Self::Hash { - Hash256::from_bytes(Sha256d::hash(self.as_bytes()).to_byte_array()) + Hash256::from_lendian(Sha256d::hash(self.as_bytes()).to_byte_array()) } } diff --git a/pkgs/pkc/src/bls/secret_bytes.rs b/pkgs/pkc/src/bls/secret_bytes.rs index 98fda7b3..995d67dd 100644 --- a/pkgs/pkc/src/bls/secret_bytes.rs +++ b/pkgs/pkc/src/bls/secret_bytes.rs @@ -12,6 +12,7 @@ use bitcoin_hashes::sha256d::Hash as Sha256d; use dash_num::Hash256; use dash_types::make_sbytes; use dash_types::Hashable; +use dash_types::Numeric; /// Raw BLS secret key length (scalar). pub const BLS_SK_LEN: usize = 32; @@ -25,6 +26,6 @@ impl Hashable for BlsSkBytes { type Hash = Hash256; fn hash(&self) -> Self::Hash { - Hash256::from_bytes(Sha256d::hash(self.as_bytes()).to_byte_array()) + Hash256::from_lendian(Sha256d::hash(self.as_bytes()).to_byte_array()) } } diff --git a/pkgs/pkc/src/bls/sig_bytes.rs b/pkgs/pkc/src/bls/sig_bytes.rs index b4d8feb6..93160cb4 100644 --- a/pkgs/pkc/src/bls/sig_bytes.rs +++ b/pkgs/pkc/src/bls/sig_bytes.rs @@ -12,6 +12,7 @@ use bitcoin_hashes::sha256d::Hash as Sha256d; use dash_num::Hash256; use dash_types::make_bytes; use dash_types::Hashable; +use dash_types::Numeric; /// Raw BLS signature length (G2 compressed). pub const BLS_SIG_LEN: usize = 96; @@ -25,6 +26,6 @@ impl Hashable for BlsSigBytes { type Hash = Hash256; fn hash(&self) -> Self::Hash { - Hash256::from_bytes(Sha256d::hash(self.as_bytes()).to_byte_array()) + Hash256::from_lendian(Sha256d::hash(self.as_bytes()).to_byte_array()) } } diff --git a/pkgs/pkc/src/ecdsa/secret_ops.rs b/pkgs/pkc/src/ecdsa/secret_ops.rs index ec497f66..cca3142d 100644 --- a/pkgs/pkc/src/ecdsa/secret_ops.rs +++ b/pkgs/pkc/src/ecdsa/secret_ops.rs @@ -17,7 +17,7 @@ use bitcoin_hashes::sha256d; use dash_num::Hash256; use dash_types::codec::{ensure, BaseCodec, DecodeError, EncodeBuf, Hashable}; use dash_types::type_id::TypeId; -use dash_types::{impl_stype, type_cvrt, ArrayBuf}; +use dash_types::{impl_stype, type_cvrt, ArrayBuf, Numeric}; use hex_conservative::hex; use k256::ecdsa::{signature::hazmat::PrehashSigner, SigningKey}; use k256::elliptic_curve::ops::Neg; @@ -162,7 +162,7 @@ impl Hashable for EcdsaSecretKey { fn hash(&self) -> Hash256 { let mut buf = Zeroizing::new(ArrayBuf::<{ DER_SIZES[1] }>::new()); self.encode(&mut *buf); - Hash256::from_bytes(sha256d::Hash::hash(buf.as_bytes()).to_byte_array()) + Hash256::from_lendian(sha256d::Hash::hash(buf.as_bytes()).to_byte_array()) } } diff --git a/pkgs/pkc/src/ecdsa/sig_bytes.rs b/pkgs/pkc/src/ecdsa/sig_bytes.rs index 2b6e5645..01375315 100644 --- a/pkgs/pkc/src/ecdsa/sig_bytes.rs +++ b/pkgs/pkc/src/ecdsa/sig_bytes.rs @@ -13,7 +13,7 @@ use cfg_if::cfg_if; use dash_num::Hash256; use dash_types::codec::{read_bytes, BaseCodec, DecodeError, EncodeBuf, Hashable}; use dash_types::type_id::TypeId; -use dash_types::{impl_type, type_cvrt, CompactSize}; +use dash_types::{impl_type, type_cvrt, CompactSize, Numeric}; use core::fmt; @@ -50,7 +50,7 @@ impl Hashable for EcdsaSigBytes { type Hash = Hash256; fn hash(&self) -> Hash256 { - Hash256::from_bytes(sha256d::Hash::hash(&self.0).to_byte_array()) + Hash256::from_lendian(sha256d::Hash::hash(&self.0).to_byte_array()) } } diff --git a/pkgs/pkc/src/ecdsa/sig_rec_bytes.rs b/pkgs/pkc/src/ecdsa/sig_rec_bytes.rs index a0360a91..6345f696 100644 --- a/pkgs/pkc/src/ecdsa/sig_rec_bytes.rs +++ b/pkgs/pkc/src/ecdsa/sig_rec_bytes.rs @@ -15,7 +15,7 @@ use cfg_if::cfg_if; use dash_num::Hash256; use dash_types::codec::{read_bytes, BaseCodec, DecodeError, EncodeBuf, Hashable}; use dash_types::type_id::TypeId; -use dash_types::{enum_map, impl_type, type_cvrt, CompactSize}; +use dash_types::{enum_map, impl_type, type_cvrt, CompactSize, Numeric}; use core::fmt; @@ -127,7 +127,7 @@ impl Hashable for EcdsaRecSigBytes { type Hash = Hash256; fn hash(&self) -> Hash256 { - Hash256::from_bytes(sha256d::Hash::hash(&self.to_bytes()).to_byte_array()) + Hash256::from_lendian(sha256d::Hash::hash(&self.to_bytes()).to_byte_array()) } } diff --git a/pkgs/primitives/src/block.rs b/pkgs/primitives/src/block.rs index f2bc59d0..5c9b10b8 100644 --- a/pkgs/primitives/src/block.rs +++ b/pkgs/primitives/src/block.rs @@ -198,7 +198,7 @@ fn compute_merkle_root(leaves: &[TxHash]) -> (MerkleRoot, bool) { return (MerkleRoot::default(), false); } - let mut hashes: Vec = leaves.iter().map(|h| Hash256::from_bytes(*h.as_bytes())).collect(); + let mut hashes: Vec = leaves.iter().map(|h| Hash256::from_lendian(*h.as_bytes())).collect(); let mut mutated = false; while hashes.len() > 1 { @@ -213,12 +213,12 @@ fn compute_merkle_root(leaves: &[TxHash]) -> (MerkleRoot, bool) { let mut combined = [0u8; 64]; combined[..32].copy_from_slice(hashes[left].as_bytes()); combined[32..].copy_from_slice(hashes[right].as_bytes()); - hashes[i] = Hash256::from_bytes(sha256d::Hash::hash(&combined).to_byte_array()); + hashes[i] = Hash256::from_lendian(sha256d::Hash::hash(&combined).to_byte_array()); } hashes.truncate(half); } - (MerkleRoot::from_bytes(*hashes[0].as_bytes()), mutated) + (MerkleRoot::from_lendian(*hashes[0].as_bytes()), mutated) } impl Block { diff --git a/pkgs/primitives/src/codec.rs b/pkgs/primitives/src/codec.rs index e9e69186..15509707 100644 --- a/pkgs/primitives/src/codec.rs +++ b/pkgs/primitives/src/codec.rs @@ -23,7 +23,7 @@ macro_rules! hash_impl { use $crate::__private::dash_types::codec::BaseCodec; let mut buf = ::alloc::vec::Vec::new(); self.encode(&mut buf); - $crate::__private::dash_num::Hash256::from_bytes( + <$crate::__private::dash_num::Hash256 as $crate::__private::dash_types::Numeric>::from_lendian( $crate::__private::bitcoin_hashes::sha256d::Hash::hash(&buf).to_byte_array(), ) } diff --git a/pkgs/primitives/src/gov.rs b/pkgs/primitives/src/gov.rs index ac683fd6..c2615ed7 100644 --- a/pkgs/primitives/src/gov.rs +++ b/pkgs/primitives/src/gov.rs @@ -15,7 +15,7 @@ use bitcoin_units::Amount; use dash_num::Hash256; use dash_types::codec::{BaseCodec, Checkable, Hashable}; use dash_types::type_id::{TypeId, Unencodable}; -use dash_types::{enum_map, impl_num, ArrayBuf}; +use dash_types::{enum_map, impl_num, ArrayBuf, Numeric}; use hex_conservative::DisplayHex; use core::fmt; @@ -179,7 +179,7 @@ impl Hashable for GovObject { 0xFFFF_FFFFu32.encode(&mut buf); self.sig.encode(&mut buf); - Hash256::from_bytes(sha256d::Hash::hash(&buf).to_byte_array()) + Hash256::from_lendian(sha256d::Hash::hash(&buf).to_byte_array()) } } @@ -287,7 +287,7 @@ impl Hashable for GovVote { self.outcome.encode(&mut buf); self.time.encode(&mut buf); - Hash256::from_bytes(sha256d::Hash::hash(&buf.into_array()).to_byte_array()) + Hash256::from_lendian(sha256d::Hash::hash(&buf.into_array()).to_byte_array()) } } diff --git a/pkgs/primitives/src/transaction.rs b/pkgs/primitives/src/transaction.rs index 907e4634..279272a2 100644 --- a/pkgs/primitives/src/transaction.rs +++ b/pkgs/primitives/src/transaction.rs @@ -329,7 +329,7 @@ impl Hashable for Transaction { fn hash(&self) -> TxHash { let mut buf = Vec::new(); self.encode(&mut buf); - TxHash::from_bytes(sha256d::Hash::hash(&buf).to_byte_array()) + TxHash::from_lendian(sha256d::Hash::hash(&buf).to_byte_array()) } } From 640c60ab35054d2fb78be56e2c06c16b795a684f Mon Sep 17 00:00:00 2001 From: Kittywhiskers Van Gogh <63189531+kwvg@users.noreply.github.com> Date: Mon, 14 Sep 2026 13:16:08 +0530 Subject: [PATCH 16/23] sdk%fix(num): extend `make_hash!` and use it to reflect `Hash160` order --- pkgs/num/src/util.rs | 57 ++++++------- pkgs/p2p_core/corpus/mnlistdiff.json5 | 18 ++-- pkgs/pkc/src/ecdsa/public_hash.rs | 5 +- pkgs/primitives/corpus/proregtx.json5 | 104 +++++++++++------------ pkgs/primitives/corpus/proupregtx.json5 | 40 ++++----- pkgs/primitives/corpus/proupservtx.json5 | 26 +++--- pkgs/primitives/src/block.rs | 6 +- pkgs/primitives/src/payload/mod.rs | 8 +- pkgs/primitives/src/payload/proregtx.rs | 5 +- pkgs/primitives/src/payload/quorum.rs | 5 +- pkgs/primitives/src/transaction.rs | 5 +- 11 files changed, 137 insertions(+), 142 deletions(-) diff --git a/pkgs/num/src/util.rs b/pkgs/num/src/util.rs index bf064c5a..5cf4091f 100644 --- a/pkgs/num/src/util.rs +++ b/pkgs/num/src/util.rs @@ -48,13 +48,13 @@ macro_rules! cfg_serde { #[macro_export] macro_rules! make_hash { // The codec half, split out for gating with `cfg_codec!`. - (@codec $base:ty, $name:ident) => { + (@codec $len:literal, $name:ident) => { $crate::cfg_codec! { impl $crate::__private::dash_types::codec::BaseCodec for $name { fn decode( data: &mut &[u8], ) -> Result { - $crate::__private::dash_types::codec::take::<{ <$base as $crate::__private::dash_types::Numeric>::LEN }>(data) + $crate::__private::dash_types::codec::take::<$len>(data) .map(::from_lendian) } @@ -67,9 +67,8 @@ macro_rules! make_hash { } }; ( - $base:ty, $(#[$attr:meta])* - $name:ident + $name:ident, $len:literal ) => { $crate::cfg_codec! { { @@ -78,11 +77,11 @@ macro_rules! make_hash { Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, $crate::__private::dash_types::type_id::TypeId, )] - pub struct $name($base); + pub struct $name($crate::HashBlob<$len>); } else { $(#[$attr])* #[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)] - pub struct $name($base); + pub struct $name($crate::HashBlob<$len>); } } @@ -99,7 +98,7 @@ macro_rules! make_hash { fn deserialize>( deserializer: D, ) -> Result { - <$base as $crate::__private::serde::Deserialize>::deserialize(deserializer).map(Self) + <$crate::HashBlob<$len> as $crate::__private::serde::Deserialize>::deserialize(deserializer).map(Self) } } } @@ -107,7 +106,7 @@ macro_rules! make_hash { impl $name { /// Borrow the raw little-endian bytes. #[inline] - pub fn as_bytes(&self) -> &[u8; { <$base as $crate::__private::dash_types::Numeric>::LEN }] { + pub fn as_bytes(&self) -> &[u8; $len] { self.0.as_bytes() } @@ -120,45 +119,45 @@ macro_rules! make_hash { /// Parse from a big-endian hex string. #[inline] pub fn from_hex(s: &str) -> Result { - <$base>::from_hex(s).map(Self) + <$crate::HashBlob<$len>>::from_hex(s).map(Self) } } impl $crate::__private::dash_types::Numeric for $name { - type Base = $base; + type Base = $crate::HashBlob<$len>; - type Bytes = [u8; { <$base as $crate::__private::dash_types::Numeric>::LEN }]; + type Bytes = [u8; $len]; - const ZERO: Self = Self(<$base as $crate::__private::dash_types::Numeric>::ZERO); + const ZERO: Self = Self(<$crate::HashBlob<$len> as $crate::__private::dash_types::Numeric>::ZERO); #[inline] - fn from_base(v: $base) -> Self { + fn from_base(v: $crate::HashBlob<$len>) -> Self { Self(v) } #[inline] - fn to_base(&self) -> $base { + fn to_base(&self) -> $crate::HashBlob<$len> { self.0 } #[inline] - fn from_lendian(bytes: [u8; { <$base as $crate::__private::dash_types::Numeric>::LEN }]) -> Self { - Self(<$base as $crate::__private::dash_types::Numeric>::from_lendian(bytes)) + fn from_lendian(bytes: [u8; $len]) -> Self { + Self(<$crate::HashBlob<$len> as $crate::__private::dash_types::Numeric>::from_lendian(bytes)) } #[inline] - fn to_lendian(&self) -> [u8; { <$base as $crate::__private::dash_types::Numeric>::LEN }] { - <$base as $crate::__private::dash_types::Numeric>::to_lendian(&self.0) + fn to_lendian(&self) -> [u8; $len] { + <$crate::HashBlob<$len> as $crate::__private::dash_types::Numeric>::to_lendian(&self.0) } #[inline] - fn from_bendian(bytes: [u8; { <$base as $crate::__private::dash_types::Numeric>::LEN }]) -> Self { - Self(<$base as $crate::__private::dash_types::Numeric>::from_bendian(bytes)) + fn from_bendian(bytes: [u8; $len]) -> Self { + Self(<$crate::HashBlob<$len> as $crate::__private::dash_types::Numeric>::from_bendian(bytes)) } #[inline] - fn to_bendian(&self) -> [u8; { <$base as $crate::__private::dash_types::Numeric>::LEN }] { - <$base as $crate::__private::dash_types::Numeric>::to_bendian(&self.0) + fn to_bendian(&self) -> [u8; $len] { + <$crate::HashBlob<$len> as $crate::__private::dash_types::Numeric>::to_bendian(&self.0) } } @@ -187,21 +186,21 @@ macro_rules! make_hash { } } - $crate::__private::dash_types::type_cvrt!(From<[u8; { <$base as $crate::__private::dash_types::Numeric>::LEN }]> for $name, |b| ::from_lendian(*b)); - $crate::__private::dash_types::type_cvrt!(From<$name> for [u8; { <$base as $crate::__private::dash_types::Numeric>::LEN }], |h| $crate::__private::dash_types::Numeric::to_lendian(h)); - $crate::__private::dash_types::type_cvrt!(From<$base> for $name, |h| Self(*h)); - $crate::__private::dash_types::type_cvrt!(From<$name> for $base, |h| h.0); + $crate::__private::dash_types::type_cvrt!(From<[u8; $len]> for $name, |b| ::from_lendian(*b)); + $crate::__private::dash_types::type_cvrt!(From<$name> for [u8; $len], |h| $crate::__private::dash_types::Numeric::to_lendian(h)); + $crate::__private::dash_types::type_cvrt!(From<$crate::HashBlob<$len>> for $name, |h| Self(*h)); + $crate::__private::dash_types::type_cvrt!(From<$name> for $crate::HashBlob<$len>, |h| h.0); impl AsRef<[u8]> for $name { #[inline] fn as_ref(&self) -> &[u8] { self.0.as_ref() } } - impl AsRef<[u8; { <$base as $crate::__private::dash_types::Numeric>::LEN }]> for $name { + impl AsRef<[u8; $len]> for $name { #[inline] - fn as_ref(&self) -> &[u8; { <$base as $crate::__private::dash_types::Numeric>::LEN }] { self.0.as_bytes() } + fn as_ref(&self) -> &[u8; $len] { self.0.as_bytes() } } - $crate::make_hash!(@codec $base, $name); + $crate::make_hash!(@codec $len, $name); }; } diff --git a/pkgs/p2p_core/corpus/mnlistdiff.json5 b/pkgs/p2p_core/corpus/mnlistdiff.json5 index 38363caa..a2c192b4 100644 --- a/pkgs/p2p_core/corpus/mnlistdiff.json5 +++ b/pkgs/p2p_core/corpus/mnlistdiff.json5 @@ -57,7 +57,7 @@ "port": 9999 }, "operatorKey": "b60fba0f9c1a76b69619c17c145f8a7ee9eaa13c214219777d56b15efc68c43f04873f8235b738d8e7b806c4f8afbc4a", - "votingKeyId": "903852cf6c818b2935f110be072b0a0a48cb0b9b", + "votingKeyId": "9b0bcb480a0a2b07be10f135298b816ccf523890", "isValid": false, "mnType": 0, "platformHTTPPort": null, @@ -72,7 +72,7 @@ "port": 9999 }, "operatorKey": "832e090090b5f78ff6be581bd51ddc4511e9ecc5f147cef310ffc2cc452847b4e3f577f1fd84039789e613a41e11ceab", - "votingKeyId": "8855d6ef13eb70da08097075a51d2ad4953f8e98", + "votingKeyId": "988e3f95d42a1da575700908da70eb13efd65588", "isValid": true, "mnType": 0, "platformHTTPPort": null, @@ -87,7 +87,7 @@ "port": 9999 }, "operatorKey": "a0d2cd8b8ff02763ce7ccc19daa78922b79e68e0fe884695680176f4fb7dc96fb77e8bc25f0765b9f9d9ab9e2493ce4b", - "votingKeyId": "ac099cfe8eef1042573fa821537941e3b594c306", + "votingKeyId": "06c394b5e341795321a83f574210ef8efe9c09ac", "isValid": true, "mnType": 0, "platformHTTPPort": null, @@ -102,11 +102,11 @@ "port": 9999 }, "operatorKey": "821c519051c7c590fbbe986a93643b52f66df9a1ed80fa08952e475ec4f1da7f76a78aa0ef8ddf0d2404368ea8e584b6", - "votingKeyId": "8d724c803b333e755fe046c86780baf9b557b165", + "votingKeyId": "65b157b5f9ba8067c846e05f753e333b804c728d", "isValid": true, "mnType": 1, "platformHTTPPort": 443, - "platformNodeId": "5d3c77d719ee6c6558c68f59a9770c4ae85506bb" + "platformNodeId": "bb0655e84a0c77a9598fc658656cee19d7773c5d" }, { "version": 2, @@ -117,7 +117,7 @@ "port": 9999 }, "operatorKey": "802e1e55c506e930327788db0528089a1d48cbc350cfe874514873ac2bcaee483a0f6b225552e6c1b02169d0a7403117", - "votingKeyId": "bf516c77f67340fac3acee0c439c4748e72b76e6", + "votingKeyId": "e6762be748479c430ceeacc3fa4073f6776c51bf", "isValid": true, "mnType": 0, "platformHTTPPort": null, @@ -132,7 +132,7 @@ "port": 9999 }, "operatorKey": "917e3809889b89ac65c6cc2b4544a507656cec1a1040a82662be13cf93bfa1d12f2b5205f3b6b0c5c43571a8eb94709b", - "votingKeyId": "8db7bc2ee991e5c6917fd6627d922f00c958881a", + "votingKeyId": "1a8858c9002f927d62d67f91c6e591e92ebcb78d", "isValid": true, "mnType": 0, "platformHTTPPort": null, @@ -147,7 +147,7 @@ "port": 9999 }, "operatorKey": "b4805c1a34826a5b2d6f610437958ceaeb0e870261ffe97f57c384928c26c1b4f7bff6d024d1311fb6c704cd15a74feb", - "votingKeyId": "5378923253011931f21fb5ae02361baa19180945", + "votingKeyId": "45091819aa1b3602aeb51ff23119015332927853", "isValid": true, "mnType": 0, "platformHTTPPort": null, @@ -162,7 +162,7 @@ "port": 9999 }, "operatorKey": "b838c7baca69548d9a7e2a98385d300e81cc2d738a6444d0cbfce0120689b9f16252308558ea269198407fc22e29897f", - "votingKeyId": "ccfa4fe906ed265f97987677d929adeb50c15ea5", + "votingKeyId": "a55ec150ebad29d9777698975f26ed06e94ffacc", "isValid": true, "mnType": 0, "platformHTTPPort": null, diff --git a/pkgs/pkc/src/ecdsa/public_hash.rs b/pkgs/pkc/src/ecdsa/public_hash.rs index 11d3b89d..28a3c215 100644 --- a/pkgs/pkc/src/ecdsa/public_hash.rs +++ b/pkgs/pkc/src/ecdsa/public_hash.rs @@ -9,10 +9,11 @@ use crate::prelude::*; use base58ck::encode_check; +use dash_num::make_hash; use dash_types::codec::{BaseCodec, EncodeBuf}; -use dash_types::{make_bytes, ArrayBuf}; +use dash_types::ArrayBuf; -make_bytes! { +make_hash! { /// 20-byte public key hash. PubKeyHash, 20 } diff --git a/pkgs/primitives/corpus/proregtx.json5 b/pkgs/primitives/corpus/proregtx.json5 index cc67e99e..b8abe729 100644 --- a/pkgs/primitives/corpus/proregtx.json5 +++ b/pkgs/primitives/corpus/proregtx.json5 @@ -15,13 +15,13 @@ "port": 9999 } }, - "keyIdOwner": "43fa3b0cd9cfcf02334960d49eee58cb56327e8f", + "keyIdOwner": "8f7e3256cb58ee9ed460493302cfcfd90c3bfa43", "pubKeyOperator": "b5972b49674355830eecabdfd8969a407af76a4d2816f5e55d2b5fc892619daf943c3d264b7e7dc806285bd7df130c7a", - "keyIdVoting": "dd04564bdca9a21c215c198ed87288c25a364575", + "keyIdVoting": "7545365ac28872d88e195c211ca2a9dc4b5604dd", "operatorReward": 0, "scriptPayout": "76a91461ba0f43e13c1cdf5bc81db6bc46fdaf162f038c88ac", "inputsHash": "14d1dee1725af3614214f7aff620370b5c02cd0388dfcc645342676905297e5c", - "platformNodeId": "654a3d682a60f7f34b1d86d05deef48c664c4f26", + "platformNodeId": "264f4c668cf4ee5dd0861d4bf3f7602a683d4a65", "platformP2PPort": 26656, "platformHTTPPort": 443, "vchSig": "1f16db0ccc66182d4b27f3dabe5aa8b3b1a0d4bf62cc54a7d2a153ba1bc5116fd70ad026a738de888709c08828dec37dfdada63cb2e0016c74fe7c5f2a0d313b11" @@ -42,13 +42,13 @@ "port": 9999 } }, - "keyIdOwner": "82f4b2b1b363694b3e64a38b379ada86d9bde58a", + "keyIdOwner": "8ae5bdd986da9a378ba3643e4b6963b3b1b2f482", "pubKeyOperator": "85d45e8d7a9d0efb98cf59fb0d4e57740592c4d420c36e7b10a8e3f52e35f2b4ea12d82a0a5e437f1b46408455b8b42b", - "keyIdVoting": "2d6a6e7b75e71c48dae0668a7a71875ac4d6740f", + "keyIdVoting": "0f74d6c45a87717a8a66e0da481ce7757b6e6a2d", "operatorReward": 0, "scriptPayout": "76a914483e7a329d883f9a2d2d27dddbec545141a2eafa88ac", "inputsHash": "79815061cda3266f1c0348b2e924f8e5e3c2a91539baa4a94305e88e01857b1b", - "platformNodeId": "49a4722949519fbfb7c3a0fdb971780eb336eaf7", + "platformNodeId": "f7ea36b30e7871b9fda0c3b7bf9f51492972a449", "platformP2PPort": 26656, "platformHTTPPort": 443, "vchSig": "1fd49c9e563301d7835ec173f1465e59e821166ef6c4db0f704f648908dda8d1ae30f635d6d5989c6a704274a56f709d58c0f1231fcf1a42e6a8bcdea540af238d" @@ -69,9 +69,9 @@ "port": 9999 } }, - "keyIdOwner": "f1af9cc7c4f0cf1fd124db0a107e3642fde3d9e4", + "keyIdOwner": "e4d9e3fd42367e100adb24d11fcff0c4c79caff1", "pubKeyOperator": "a6c4b0fc1f58323fe68110914c3043507061b5d4ec10fa88cde3da9b1cef31d02ff08751011f02893d97ed30c0fa816c", - "keyIdVoting": "f1af9cc7c4f0cf1fd124db0a107e3642fde3d9e4", + "keyIdVoting": "e4d9e3fd42367e100adb24d11fcff0c4c79caff1", "operatorReward": 0, "scriptPayout": "76a91479792439badb2bfc00f975b6b2ec1ff7fa72433688ac", "inputsHash": "424b7a9112588ba4423f327953197481152d107558d9b185ea8362923c87bf74", @@ -96,9 +96,9 @@ "port": 9999 } }, - "keyIdOwner": "8237e982f95b0bf0ea818027776e52ed5c17b28b", + "keyIdOwner": "8bb2175ced526e77278081eaf00b5bf982e93782", "pubKeyOperator": "b96245aecc59b154054815558fb6d95a75ab0460f704015eba82d8912380af70436557abc2972d7b3f1ff67451696f15", - "keyIdVoting": "ad9a1bf8855b4929ce375384c47cc3214f74abd5", + "keyIdVoting": "d5ab744f21c37cc4845337ce29495b85f81b9aad", "operatorReward": 0, "scriptPayout": "76a91414198a0a98002ed96e5bc64e756f4aea2912945f88ac", "inputsHash": "95135d08fc3c00e3cf13037c43560ed02afac18a363b67e0593d5e19cf766612", @@ -123,9 +123,9 @@ "port": 9999 } }, - "keyIdOwner": "c4ff47c02e84d3096c80d01df6f816b9b3a388a6", + "keyIdOwner": "a688a3b3b916f8f61dd0806c09d3842ec047ffc4", "pubKeyOperator": "a35a0a201413c35d1138d30c4d9500cbe48fce23c9f310e2029c9cf00f724a78fa70fe5fb1f870a207f8ddde4931dcab", - "keyIdVoting": "c4ff47c02e84d3096c80d01df6f816b9b3a388a6", + "keyIdVoting": "a688a3b3b916f8f61dd0806c09d3842ec047ffc4", "operatorReward": 0, "scriptPayout": "76a9146d4d1fe9a69b18c3c73d77982b1b8e4359ab672a88ac", "inputsHash": "9ecdd64634e071b599abebfa3a88df8274488057101c5418082053a5f2cdcb36", @@ -150,9 +150,9 @@ "port": 9999 } }, - "keyIdOwner": "e22a4e009ce5598cb7e1020e06373556657a2b25", + "keyIdOwner": "252b7a65563537060e02e1b78c59e59c004e2ae2", "pubKeyOperator": "b11aeeafcb4d4e6f3256798249d4bd34160e3e2caafb4060a04c233f2cc472b8baa9a8c4ec0044b5b58bd1ac06e9727a", - "keyIdVoting": "e22a4e009ce5598cb7e1020e06373556657a2b25", + "keyIdVoting": "252b7a65563537060e02e1b78c59e59c004e2ae2", "operatorReward": 0, "scriptPayout": "76a91454b36fbe92b19ff994e6e418ab2868dcc624d6d588ac", "inputsHash": "e2f32379c60b58c74eae64a866305e7ac528adf981fc0b927384628a018a4c80", @@ -177,9 +177,9 @@ "port": 9999 } }, - "keyIdOwner": "907e27d09f3723c5e0fe816acd13fbf7e5679085", + "keyIdOwner": "859067e5f7fb13cd6a81fee0c523379fd0277e90", "pubKeyOperator": "aa8130c2fdcf9dd9acf7164823a825c09295280a4d21889d70aaa2118feabb5a4919052bb91720e82116a4ab47f9e146", - "keyIdVoting": "3e4bc16d9aff17ec19c803139871336ed284b058", + "keyIdVoting": "58b084d26e3371981303c819ec17ff9a6dc14b3e", "operatorReward": 0, "scriptPayout": "76a914a5fb7f82e3cd6a7509aa1eea433d10c5995fb36d88ac", "inputsHash": "7b0e72ab455ed2bfe2cc986fe5193860dbd3536816807ea837c729c9f3095156", @@ -204,13 +204,13 @@ "port": 9999 } }, - "keyIdOwner": "2ba6ed4e78dd031a81b362bb20177d40eb7fd948", + "keyIdOwner": "48d97feb407d1720bb62b3811a03dd784eeda62b", "pubKeyOperator": "957a95e21066b5fba59f1f12a68a6ea3f00d067ec7dfd20a12e01295100b323f646735324dbe02c935532667ea29a4a9", - "keyIdVoting": "8bcde470a76ee6c0a902f8f96a81d1a30ea0548e", + "keyIdVoting": "8e54a00ea3d1816af9f802a9c0e66ea770e4cd8b", "operatorReward": 0, "scriptPayout": "76a9149206aaa8d9786f268744e6c6476ffcbba10a3e3e88ac", "inputsHash": "903802edb9c408c51eadb85cd3b3a06126da9f16f2540a1a945b2f3cfe6eb8e0", - "platformNodeId": "c7cb4a5860a570e71f9c0ffe66720ab4781f99b6", + "platformNodeId": "b6991f78b40a7266fe0f9c1fe770a560584acbc7", "platformP2PPort": 26656, "platformHTTPPort": 443, "vchSig": "1f413375dab8d08586ff58f1711367e8e3b395520bb9e965e347991d7e6ad743544ce3d5a59be075151e48975f6f00c538f01fcb6d5c641aeada584f2d5306dc5d" @@ -231,9 +231,9 @@ "port": 9999 } }, - "keyIdOwner": "c8e3db358775199e796677b06705cbba2c34d75f", + "keyIdOwner": "5fd7342cbacb0567b07766799e19758735dbe3c8", "pubKeyOperator": "a668b8b61f7b540a0e002789b4349c0331d3c23c69019855194bbbbeea1432b65befe8273ee51c906e9481ea5f9aa97c", - "keyIdVoting": "c8e3db358775199e796677b06705cbba2c34d75f", + "keyIdVoting": "5fd7342cbacb0567b07766799e19758735dbe3c8", "operatorReward": 0, "scriptPayout": "76a9142b567ee71b12a3b472cfe91f3265061e2e10587888ac", "inputsHash": "6d986728e764ee5ce2a5b3fa5d0149018d0ecd3b432f9b55bd2cfd7850fff217", @@ -258,9 +258,9 @@ "port": 9999 } }, - "keyIdOwner": "3ac3116b38fcbeb40db4568f4e4936b323cf7b2c", + "keyIdOwner": "2c7bcf23b336494e8f56b40db4befc386b11c33a", "pubKeyOperator": "a181aeb564815cf48f58e2b8d611fd6b2e9eda6e5608839ebbce5951ee4e6aa04884f43a795701af63853292d415c960", - "keyIdVoting": "3ac3116b38fcbeb40db4568f4e4936b323cf7b2c", + "keyIdVoting": "2c7bcf23b336494e8f56b40db4befc386b11c33a", "operatorReward": 0, "scriptPayout": "76a91433a9ad4b5cae7054d1753920764d5560ec0ba7ac88ac", "inputsHash": "62b7825efe7f7365d592ffd4cfd7fc25b2b116797ff303c52b5acc84e04b54b8", @@ -285,9 +285,9 @@ "port": 9999 } }, - "keyIdOwner": "162e5e22b8ed8cc75848e5813d1d7f6e62359c1d", + "keyIdOwner": "1d9c35626e7f1d3d81e54858c78cedb8225e2e16", "pubKeyOperator": "931184a9141a21bf1ec6421abf8f61508aac8087f42574fae79ad8bcb2c7de79dfad7ba63e21dbcf7dfb5936c59b6d16", - "keyIdVoting": "162e5e22b8ed8cc75848e5813d1d7f6e62359c1d", + "keyIdVoting": "1d9c35626e7f1d3d81e54858c78cedb8225e2e16", "operatorReward": 0, "scriptPayout": "76a914050b269f170bd20d52b937fd8bc9514cd3cbe4cd88ac", "inputsHash": "6ef76e314e9c6a24da67ba6b86d2d86479cc6593c66c0e7d018c35ff08d8aebd", @@ -312,9 +312,9 @@ "port": 9999 } }, - "keyIdOwner": "6728ae525355fd4533c543854e64a4de9a08404e", + "keyIdOwner": "4e40089adea4644e8543c53345fd555352ae2867", "pubKeyOperator": "a46d14b890aa6816f6e3a778ff5cc9dda7157ab4a06367a868045c0094574147abad3b59a6076edd5b17c8391d5be160", - "keyIdVoting": "ef8999978e48ec9c5281c66bbedfa6b83e65b40b", + "keyIdVoting": "0bb4653eb8a6dfbe6bc681529cec488e979989ef", "operatorReward": 0, "scriptPayout": "76a91496996ca8110c4630ceebc02c70962ef8be717c7d88ac", "inputsHash": "db9dfa96f39763f775897e63066aafb12f48d3ce941d5ca917e0fdae1e73499b", @@ -339,9 +339,9 @@ "port": 9999 } }, - "keyIdOwner": "075ea155956d8ada128c3be1ecf71655158fdc8d", + "keyIdOwner": "8ddc8f155516f7ece13b8c12da8a6d9555a15e07", "pubKeyOperator": "b3e117dae2c2476e80fe8b2a79f5fb4f26b36de88913239ccea60df5b51f2f0e70c53fc8494ef913c01e160533f19c55", - "keyIdVoting": "075ea155956d8ada128c3be1ecf71655158fdc8d", + "keyIdVoting": "8ddc8f155516f7ece13b8c12da8a6d9555a15e07", "operatorReward": 0, "scriptPayout": "76a91490d6e9c81a813309b0eab1bd243191337e9f9d0b88ac", "inputsHash": "3b30b278bf8845ba6d4a2c7bacf54a8ee8a3bc00800f717bee43e0b874778102", @@ -366,9 +366,9 @@ "port": 9999 } }, - "keyIdOwner": "fe6d9d930b0c8e63cf1e3e98b42c31f8f7dfc140", + "keyIdOwner": "40c1dff7f8312cb4983e1ecf638e0c0b939d6dfe", "pubKeyOperator": "839e4e2fbd42f8265255b5c2a3d235111ab1618a5e8394d5edd7856c7a01180c9aba83f4219fe62a44034c90db6e5e75", - "keyIdVoting": "fe6d9d930b0c8e63cf1e3e98b42c31f8f7dfc140", + "keyIdVoting": "40c1dff7f8312cb4983e1ecf638e0c0b939d6dfe", "operatorReward": 0, "scriptPayout": "76a914da8e302a76b166f3977f31fcde0841af5d6d7c8988ac", "inputsHash": "cdae76bced287a20a79c0fe556b81be5ba7252606935e951a1e645a2a99d67b3", @@ -393,9 +393,9 @@ "port": 9999 } }, - "keyIdOwner": "1c8d29a7e9d7922f87879cd6d39cf799034a2e96", + "keyIdOwner": "962e4a0399f79cd3d69c87872f92d7e9a7298d1c", "pubKeyOperator": "8bef6831d3930dd85da8875e711f0a984dc85467f0a8fe29c3b76bfa7d037d884d10717a22c52df02527bed5698b876d", - "keyIdVoting": "1c8d29a7e9d7922f87879cd6d39cf799034a2e96", + "keyIdVoting": "962e4a0399f79cd3d69c87872f92d7e9a7298d1c", "operatorReward": 0, "scriptPayout": "76a914a09f657dec791e21cf184fd7770c21194bb90e1688ac", "inputsHash": "47653790a93ff3ef16b10c9412619fb8fe120e96d31697e43b59bf40a7d0235e", @@ -420,9 +420,9 @@ "port": 9999 } }, - "keyIdOwner": "2859ca0b8ea8afe6dd58bb2deae41b5485e151ef", + "keyIdOwner": "ef51e185541be4ea2dbb58dde6afa88e0bca5928", "pubKeyOperator": "9690d85c0c46b8139897c17adf13166b38d7bb1853cf88c581ed5e04714583ad66b3ca4cdeeee5f4d49b7529ae6a0504", - "keyIdVoting": "a67dc749a04bc47e05a1e16af4ebbeffce0cdbec", + "keyIdVoting": "ecdb0cceffbeebf46ae1a1057ec44ba049c77da6", "operatorReward": 0, "scriptPayout": "76a9143c23989752e45aae7b03bcb4aa5149b17147cec088ac", "inputsHash": "0f274e96d3e0a2b13a35a89c67e4483eb2586295032a0effb372a7e12f4cc75e", @@ -447,9 +447,9 @@ "port": 9999 } }, - "keyIdOwner": "de9c0164b2a9eddec0ee7a34042e0e51723c0793", + "keyIdOwner": "93073c72510e2e04347aeec0deeda9b264019cde", "pubKeyOperator": "82a30aed744984202ad2025e4393431954a755e5108bb209b6799c6f0175cbf163c946ce07c52b6619388770a4e2dda5", - "keyIdVoting": "de9c0164b2a9eddec0ee7a34042e0e51723c0793", + "keyIdVoting": "93073c72510e2e04347aeec0deeda9b264019cde", "operatorReward": 0, "scriptPayout": "76a9141154840e7e8ef3654f5c8dfa91ee07639fc81c6b88ac", "inputsHash": "b3617dd6150f7390de0e16f201792a0a792c72ef1598f86700eda58fe7ea0338", @@ -474,9 +474,9 @@ "port": 9999 } }, - "keyIdOwner": "7460797d306b0c202b6c2565dffc76f7a6d57ba7", + "keyIdOwner": "a77bd5a6f776fcdf65256c2b200c6b307d796074", "pubKeyOperator": "ad5522d6bc1138ec71f5f539d5d4d9077cbd9217f93ffd7e3ad78fb14de2aaa3937366f623f47ebdead83ad8a9d14fb1", - "keyIdVoting": "7460797d306b0c202b6c2565dffc76f7a6d57ba7", + "keyIdVoting": "a77bd5a6f776fcdf65256c2b200c6b307d796074", "operatorReward": 0, "scriptPayout": "76a914d91d60841617c26ad42a255ac4da41e7caeb762c88ac", "inputsHash": "7d30d955b71e968b90e7b8b30c0ad984e52f5ca673e52dfe851218c517ad6a3b", @@ -501,9 +501,9 @@ "port": 9999 } }, - "keyIdOwner": "ba45a43bde7371a7a355dd96d8dd3cef35046ab6", + "keyIdOwner": "b66a0435ef3cddd896dd55a3a77173de3ba445ba", "pubKeyOperator": "92a5bab6d7b31e2fbdf34464d2f68b2cb90846c1082d29dda9639120fad97c51284c514e124dcacb36fb1dbf6bc58653", - "keyIdVoting": "ba45a43bde7371a7a355dd96d8dd3cef35046ab6", + "keyIdVoting": "b66a0435ef3cddd896dd55a3a77173de3ba445ba", "operatorReward": 0, "scriptPayout": "76a9149cd483a32238700565aaf47b1258832be4e97bf688ac", "inputsHash": "d5279de90a1d7b8b3bb03db8051d347344323c7b94a78a69b27eb62d7ef65542", @@ -528,9 +528,9 @@ "port": 9999 } }, - "keyIdOwner": "a9597f70edd2bde53fee9aa64b38eebbcd197a1b", + "keyIdOwner": "1b7a19cdbbee384ba69aee3fe5bdd2ed707f59a9", "pubKeyOperator": "a21023bf3d8ef6570553987f28baa979597c3b125527da5384351175bc52d215706eab8db1a06b3a2c0db9e3283afbe7", - "keyIdVoting": "a9597f70edd2bde53fee9aa64b38eebbcd197a1b", + "keyIdVoting": "1b7a19cdbbee384ba69aee3fe5bdd2ed707f59a9", "operatorReward": 0, "scriptPayout": "76a914c7db8c99504bf14f9d7e6e32c2d28bf00c80031f88ac", "inputsHash": "ac66dfefbe1bd9966548722c7f204251d704485f62d9b2081169379f48f1bc6a", @@ -559,13 +559,13 @@ ] } }, - "keyIdOwner": "a8de9990c0a0676a95450ee59c6032c0222060dc", + "keyIdOwner": "dc602022c032609ce50e45956a67a0c09099dea8", "pubKeyOperator": "a326c971a901c71247043152a691a5a460c79ac9ff83fd876e3c1a6fa3b6734ecc72961438ddfc67049f941b3dfbedea", - "keyIdVoting": "19badc75f739727264b6848edef4e2f97ae303eb", + "keyIdVoting": "eb03e37af9e2f4de8e84b664727239f775dcba19", "operatorReward": 0, "scriptPayout": "76a9142528448b4447518b5eafe16f574661c8e07bb18588ac", "inputsHash": "72ff777cffc971751e903efae0c9af4c0b00add4c20bc4c1bccd12eb39fdae3a", - "platformNodeId": "e5992efdc3d9e31931fb19590b33aaa1b90bb958", + "platformNodeId": "58b90bb9a1aa330b5919fb3119e3d9c3fd2e99e5", "platformP2PPort": null, "platformHTTPPort": null, "vchSig": "20c21b280fb2e8f72f9c46d7af4f78e50f6f6c31f0aeb080c6042879027a096a2b2f29047d0871e506e93c277e37e3ac52a2823cd205fe6051be5539b798d0f08f" @@ -599,13 +599,13 @@ ] } }, - "keyIdOwner": "fd553fc926287871a7dcd71968ad659026c093f7", + "keyIdOwner": "f793c0269065ad6819d7dca771782826c93f55fd", "pubKeyOperator": "95d86735440a8f1f650c1efae172fa21e5ea6cb5edb374e2cb6c3399184a5904f36a35d5969a01c9a15f49d3d4075b73", - "keyIdVoting": "1441c5334f5decfbff85f3e60b1073ee2597c750", + "keyIdVoting": "50c79725ee73100be6f385fffbec5d4f33c54114", "operatorReward": 0, "scriptPayout": "76a9146fcb03df8b448707f27f4adb99bb1ddbf11a561a88ac", "inputsHash": "837a79008934b5202870c11a6fcb6ea8d637e3b770a2816b5596c9088aff4d2b", - "platformNodeId": "44442971737accd3a941166d9b3dc35f619ca10f", + "platformNodeId": "0fa19c615fc33d9b6d1641a9d3cc7a7371294444", "platformP2PPort": null, "platformHTTPPort": null, "vchSig": "20c9582a842b570f95c68246ed563f992328354d3e0ee0d64bba7344278ca2ee93519761d07d315b0108bd4e95487c5e6fdc07970fdf9b528c747b1292cfbe25c7" @@ -626,13 +626,13 @@ "entries": [] } }, - "keyIdOwner": "15dde7c373a14ad16c091f409198b0f40f831b1f", + "keyIdOwner": "1f1b830ff4b09891401f096cd14aa173c3e7dd15", "pubKeyOperator": "87dc4da5b388e0287ef12d48630e441e36baf164e6a2d24f986a4d0584144f879725722d0336c35c4ceaa36aeb607ae0", - "keyIdVoting": "f69375ea93a7fd20b3e2c0e24df9b3aa82613c96", + "keyIdVoting": "963c6182aab3f94de2c0e2b320fda793ea7593f6", "operatorReward": 0, "scriptPayout": "76a9144eb62894923a194f0f56ed20e37ba336b680264c88ac", "inputsHash": "ea85ae259e22e523f2b7e49779c85fd8ed6b628282d90b0fe24c64dd84fea977", - "platformNodeId": "d769470503e89d55001d813fcbb8b3a770f97fe0", + "platformNodeId": "e07ff970a7b3b8cb3f811d00559de803054769d7", "platformP2PPort": null, "platformHTTPPort": null, "vchSig": "1fbeb28ed0e786225ff0bed8b2eb86a3d95929737b25bd0083ecf0efeeabe74b9127a5436866bc2a38af290d64d05d8b77b8ee428337af47a4ca1cd97c3af59297" diff --git a/pkgs/primitives/corpus/proupregtx.json5 b/pkgs/primitives/corpus/proupregtx.json5 index e6606d90..e2213212 100644 --- a/pkgs/primitives/corpus/proupregtx.json5 +++ b/pkgs/primitives/corpus/proupregtx.json5 @@ -8,7 +8,7 @@ "proTxHash": "254e9ab895dbc11281066b2d0d3edcedd741681bfadd40d0c44fdd45c634e827", "mode": 0, "pubKeyOperator": "80777d5d4a837040bd15047a3583b960bd59c28407dc2c359f2ab6a2dc5802545cb53724944a37e316db970cbef0f7af", - "keyIdVoting": "92346e305bf490cfc79fab1f72cc190b2da5b774", + "keyIdVoting": "74b7a52d0b19cc721fab9fc7cf90f45b306e3492", "scriptPayout": "76a914695a20b9b16659d4da796f71d539a5221f35865f88ac", "inputsHash": "5295009f6298e4050a8c44bd388f6d1f9c18bf9873b021613d5ca5d4df339b58", "vchSig": "1f63e1cfabd0b69e1a367da1f6fa50a1639d3467817f0827c1a6957aef2d56e86f60e81b9020b46784ef05c85deaba3bced309bdd4f660de9089c2c7237edacc23" @@ -22,7 +22,7 @@ "proTxHash": "8185dd58f231dd9e26491667f29b0438a94849f0883b88d518a7b00588312bac", "mode": 0, "pubKeyOperator": "86f925bb639e681242df5e77e11f0a95b3b5bc97b43434c455b9bbd343394816c5b7bf6016f170bc3558a84c7717021a", - "keyIdVoting": "39f293288051d0543bbea1a8670a03820a95014c", + "keyIdVoting": "4c01950a82030a67a8a1be3b54d051802893f239", "scriptPayout": "76a914695a20b9b16659d4da796f71d539a5221f35865f88ac", "inputsHash": "0994f499d646314c933cd89bb7396fae71b527c7c7fe616f8c2f9c3c2e0064b8", "vchSig": "1f8ebec9659d734920e6ca4e9cccf37822b0b22a12985ae5744b096921676cf47f4abefcbf62fe2b65d3a9ab669ac3480278c66c43d6c5087c1dc8b7158d64a18f" @@ -36,7 +36,7 @@ "proTxHash": "9e3ff349fbe7944a99b77764f7d03a3d765ce669bc3c07637014c683ce324cc0", "mode": 0, "pubKeyOperator": "b3291ae3c6fd9be650a427c32f5c46396f2bf1bfd65834ff4cdcd79cafb6d560c8a2e3a365892dd5d6b24fe7cf92d234", - "keyIdVoting": "1d9de926b8f62640f5a9391b13145b0bb262be11", + "keyIdVoting": "11be62b20b5b14131b39a9f54026f6b826e99d1d", "scriptPayout": "76a914695a20b9b16659d4da796f71d539a5221f35865f88ac", "inputsHash": "104168c3b4e2861b3a47b3402e0d914a1f3365eaf90818eb6a866c6c9fe3cf91", "vchSig": "1fce6fa07fd0fd7438812ae8535c574e11c69117b9c45b8b81bda788a4e0e774e6584837d6a51ec62cfcbe6b757e2396cf5fe14cdda7657fd6c24bb3bfe47d2f0b" @@ -50,7 +50,7 @@ "proTxHash": "8ffb6aa3884a23dbf2e1eeb1421fe4eda179a03bda3400df3d4b9c077c676927", "mode": 0, "pubKeyOperator": "aaf6274d78af492579ca0d74e8161517d68efba72a40f258813b44c786806138fc1d99f836462e7622e768b1e02c6989", - "keyIdVoting": "1612a8765289478911d62fe8b64f65d93bb88d80", + "keyIdVoting": "808db83bd9654fb6e82fd6118947895276a81216", "scriptPayout": "76a914695a20b9b16659d4da796f71d539a5221f35865f88ac", "inputsHash": "ba21f1fd49ba3b0dc6e9a59cd3dcbadc572d0105ba6b4ad7843edaf094bf12d8", "vchSig": "1fdbbf81e959799963e78c9dad092b4cabd5ba7119c9490570541c569d952cf3e81baa878cc19197df353f1ccba01ef68437112938718c41f6528bdb76c59e9298" @@ -64,7 +64,7 @@ "proTxHash": "eb47a6322b1317b1d40a1ba53318ab4204866ccd0fc2a9b85974937b143d925f", "mode": 0, "pubKeyOperator": "9690d85c0c46b8139897c17adf13166b38d7bb1853cf88c581ed5e04714583ad66b3ca4cdeeee5f4d49b7529ae6a0504", - "keyIdVoting": "a67dc749a04bc47e05a1e16af4ebbeffce0cdbec", + "keyIdVoting": "ecdb0cceffbeebf46ae1a1057ec44ba049c77da6", "scriptPayout": "76a9145f653444990053babbf3977743ece907a5b7e3cf88ac", "inputsHash": "b90c1d3df0f5a22970e4d6030db2f58b5b23ee22d3791288bcbbded5c35be561", "vchSig": "1f8ed06bd0e57c6aeb6bb9e4448251f218286e7ad7f3b29de81664b4c1e3149ca738259ac23ec04c04632eebe063964d56a4aff98551f8f95440b00b4979571517" @@ -78,7 +78,7 @@ "proTxHash": "74fcea82a8f3a1a34f81d07492e4857d8d82c8eaf0cc41d86659bf0a299f8b88", "mode": 0, "pubKeyOperator": "b3b95a1a6ad8aaaeba9aa8ea3a3e8f0448f271228ea931184480e21e74fd30bc23fb24c87ab35629509a5af7b625e5e9", - "keyIdVoting": "e19b1b34593c154897aea07b95e2ed315afcdbf3", + "keyIdVoting": "f3dbfc5a31ede2957ba0ae9748153c59341b9be1", "scriptPayout": "76a9147ccacc4367427e65fa9b382f67c503fad332aaa988ac", "inputsHash": "073cf78bc60c4b72656052494b8e8cd06ca3c56db99c30da2d3215d93c87fc31", "vchSig": "1fe64b93d7293344598d2377491da7e73a8304ed75d21029cd4a7f2744d6c7047e2f7ccdf9ee9e6b86f86634735aab0d1b8ccf88ace51ea2eaf2e91bf727dc5630" @@ -92,7 +92,7 @@ "proTxHash": "e49623eafa5c717ff1e898fdfd0247bf5f813b8b36debe65976a9e984e79b130", "mode": 0, "pubKeyOperator": "94757380f521b2d5ab06782b48563060987ea2102ab3a97ea9d7eedbae78a493d40e0fd9ae34ee0b9fdb9cab54312cf0", - "keyIdVoting": "8b824d63565b3b4da491def088bd4fef2b9b2932", + "keyIdVoting": "32299b2bef4fbd88f0de91a44d3b5b56634d828b", "scriptPayout": "76a914605857ca7739d8f4043ec61d31899a40b94e07e588ac", "inputsHash": "428881a1a7739859c80501047a20242a01bdb71547171cc752a81f34eaab31a5", "vchSig": "1f7acd9b9ed98d08fb97ad3c3885b68a378b23c0127f960baca8947d0a4766bb4209530892070eaaf6b20032ef6985fb05206430e04c571b070585c55f168cdc4d" @@ -106,7 +106,7 @@ "proTxHash": "fdd66aa5ac54b45e152713385aed1ba97cd599cb917c27efeb6b24721e81d521", "mode": 0, "pubKeyOperator": "b6ec536b38bad5c2482f23836ad9fc1962e46b5906173c758e609db1bd65baef1576ff07e297e36b254d5a9a3b110d17", - "keyIdVoting": "249ef8b84b1ab1944d2e9014860de369467c1792", + "keyIdVoting": "92177c4669e30d8614902e4d94b11a4bb8f89e24", "scriptPayout": "76a9141ae72d32f583eec629b24b25927de260ef46e6bf88ac", "inputsHash": "ebafa725f3f9ff8f877f52768b54e01ba400dc9d8b6ab86f774fb43eb32063af", "vchSig": "20326e9b4b8a92a709d18ca39ad7b7df2edb7dba912af94e0fcf6e3c4b4770ae737ecff022e67ff5593dddc5dc234aa8c38c0b406734a04f332035bc950b2d9031" @@ -120,7 +120,7 @@ "proTxHash": "2ed81baa2bc65631b564a75ce0c5c92d359a1482eb4a9409590c86a2a281df91", "mode": 0, "pubKeyOperator": "86ae0dfe35b272c48274b3a7da09a2343edbbdad8e6feee0feeeaa6b3ee175d7039943ce6fc1733dd68bc8a142080f88", - "keyIdVoting": "2173b3b372b89a57bb8dbd8c4b4cadc46d88d51f", + "keyIdVoting": "1fd5886dc4ad4c4b8cbd8dbb579ab872b3b37321", "scriptPayout": "76a9146826043ad65f3f5cfe72d9c3d09c16218132e9c888ac", "inputsHash": "a2670490c13eb156d0d73fe467f1d82004e2777dae0b8d69c40069ca48534dcc", "vchSig": "1fa8b5a6258bf7ab6ce222c978446e7f975605629b37b58504d2a2fffe648eae29320209563bfacbe110d6c34d2c077fc9e9bb5e810b7873cb95f2725e74ab497b" @@ -134,7 +134,7 @@ "proTxHash": "fbb813674695a79d739d911c5b82d1fd995568d976382345ed9e4aa20b3e3725", "mode": 0, "pubKeyOperator": "8ca717f0fd3b1a25bbb23c5fe0717eeab511c6ee8a3e4dac7ffddec76f503f239047cd09fe6880e63cd13442bb6ce417", - "keyIdVoting": "f923245175d3ebd8cf1686448d756255b341ee94", + "keyIdVoting": "94ee41b35562758d448616cfd8ebd375512423f9", "scriptPayout": "76a914bffff341b7f366f9f963e0816e646ad56ec71df788ac", "inputsHash": "3fa1564099aa80342e1dc3af7a241511e6f6d49143346da417daf3cbf3896f75", "vchSig": "20d73aef231ddd8c6eb279aa2627789db30d07b1f3fdb458f3fb8ef0f5d5ff4af7638879ea51dd9d2b26fbab272e2e1ee7385f7231cf0e16a9af24b547740cc602" @@ -148,7 +148,7 @@ "proTxHash": "74fcea82a8f3a1a34f81d07492e4857d8d82c8eaf0cc41d86659bf0a299f8b88", "mode": 0, "pubKeyOperator": "b3b95a1a6ad8aaaeba9aa8ea3a3e8f0448f271228ea931184480e21e74fd30bc23fb24c87ab35629509a5af7b625e5e9", - "keyIdVoting": "e19b1b34593c154897aea07b95e2ed315afcdbf3", + "keyIdVoting": "f3dbfc5a31ede2957ba0ae9748153c59341b9be1", "scriptPayout": "76a9147ccacc4367427e65fa9b382f67c503fad332aaa988ac", "inputsHash": "b3d0e7160530668bef71025256cdee64c9c4736cecdf12b995fb5ff45d41e75c", "vchSig": "20c15459dddc6baf68cbe9e468207b115c3fc71706f0a8d0008782d2e578fcdcea5a0185d33d08364662c2a8ffdc4fba93d165f361461edbc333d0c46f4d6a4fe5" @@ -162,7 +162,7 @@ "proTxHash": "7284febed5466dbc53852ef3765b6a97762cadc380b9dc9b74234e189f396eee", "mode": 0, "pubKeyOperator": "a882c307cf5f8b5ce2c9c91bcab0715fe30aebee110590bd1a4ec72389470ebc95abd46ab050c01e2ba26652368af166", - "keyIdVoting": "e05ff3210d417fa6c101bc33898d0a455a663648", + "keyIdVoting": "4836665a450a8d8933bc01c1a67f410d21f35fe0", "scriptPayout": "76a914bffff341b7f366f9f963e0816e646ad56ec71df788ac", "inputsHash": "b20ef1260fafe539baa1e60c82dd98f0e83e8b01bb9b3754e2a5828794267867", "vchSig": "1f6704b7a1f005127b5f55429e33835d56ad6e3899c41b0b10b78539fdaff5d9d10ee914daff1429ad2aa32ed0b4c0a3ed18f43196dfe95cee76ccd6c58fce1d0a" @@ -176,7 +176,7 @@ "proTxHash": "723967b09ff1f1c0d99db14affd440ab9308487100f2f649fb921c360d1971a5", "mode": 0, "pubKeyOperator": "8375a7832eff92a818267428982069cd8f821b943374d57f4ea5afb98ca65b5063cfbfdba3dc545182199ab79a7b3edb", - "keyIdVoting": "a1d7dfaa44bd82fc757115bd944bf2b02f45131d", + "keyIdVoting": "1d13452fb0f24b94bd157175fc82bd44aadfd7a1", "scriptPayout": "76a914bffff341b7f366f9f963e0816e646ad56ec71df788ac", "inputsHash": "913af954c9c002650a913c617a606a109b06a74970595c8f340543fd3ade7de1", "vchSig": "20984cf85ff3ff002987f824c70e651999e23f0b5340ead9c857168ae329c4fc1809a4047f7b2c7b5062d9354ef60d6621ea90a654791acb4ddff25ced850bd023" @@ -190,7 +190,7 @@ "proTxHash": "b0fc45ed58f3f026fa133075fa5296564cb60486780c82c01fe99dd1d605db1d", "mode": 0, "pubKeyOperator": "a4921a9097ce1b25b4ea325f71b195f0bd6f5b36bda1d7ce37efa37e235fcb1dff70e89b1967703a4bad8d0812ca1517", - "keyIdVoting": "b3c2f366e6f1474e8a8fb79f989dc94d6b6fdcf0", + "keyIdVoting": "f0dc6f6b4dc99d989fb78f8a4e47f1e666f3c2b3", "scriptPayout": "76a91431ec0c3f5021938701e0208a4d21f34aa6f0a4ea88ac", "inputsHash": "7a5306b6c15feb79a874d0e6027ed9a11d2c9cd866aa6fb9411efcdad02f08e5", "vchSig": "2031f5f0d7f46e88af7086919fe9525bc7318d2a83efa0fa33f84a5e9709df2e22287090c4f1cb03f38d30eff874f7bbf55bea116e71c595968f2e864b52c3ea13" @@ -204,7 +204,7 @@ "proTxHash": "b0fc45ed58f3f026fa133075fa5296564cb60486780c82c01fe99dd1d605db1d", "mode": 0, "pubKeyOperator": "a4921a9097ce1b25b4ea325f71b195f0bd6f5b36bda1d7ce37efa37e235fcb1dff70e89b1967703a4bad8d0812ca1517", - "keyIdVoting": "b3c2f366e6f1474e8a8fb79f989dc94d6b6fdcf0", + "keyIdVoting": "f0dc6f6b4dc99d989fb78f8a4e47f1e666f3c2b3", "scriptPayout": "76a91431ec0c3f5021938701e0208a4d21f34aa6f0a4ea88ac", "inputsHash": "d06971b7785bc3e56673d59da40a26e91a10c3c85190098fea0a1053be73d703", "vchSig": "1fd28854184b200c1c415186579b8432234b88d1bb5c4023ad512b479b72f9259e53cf65408c1cdedeb5755f4e3c25bed7d7326b6dcee1d1008ab7ee4f016d6489" @@ -218,7 +218,7 @@ "proTxHash": "b0fc45ed58f3f026fa133075fa5296564cb60486780c82c01fe99dd1d605db1d", "mode": 0, "pubKeyOperator": "aa9a89cd82a6938ca7c5d6daaebf13f8989021f1bea7d55f66064f5ebb0bcf918cceac6a5189e9459f7cd45cec6a6730", - "keyIdVoting": "b3c2f366e6f1474e8a8fb79f989dc94d6b6fdcf0", + "keyIdVoting": "f0dc6f6b4dc99d989fb78f8a4e47f1e666f3c2b3", "scriptPayout": "76a91431ec0c3f5021938701e0208a4d21f34aa6f0a4ea88ac", "inputsHash": "f771ddd44d234d03c8c88c9cbddf0b61947e8413bd5887bac3a895613f1cccf2", "vchSig": "1fa264d37157463a0c6c724c092e1d5b2b0ffbd31d90e55fe6a404070ed030da757589c0e7043249cf5bdb2540272c021139ba2bd15f4e4db9068d8c98ae5af28d" @@ -232,7 +232,7 @@ "proTxHash": "b0fc45ed58f3f026fa133075fa5296564cb60486780c82c01fe99dd1d605db1d", "mode": 0, "pubKeyOperator": "aa9a89cd82a6938ca7c5d6daaebf13f8989021f1bea7d55f66064f5ebb0bcf918cceac6a5189e9459f7cd45cec6a6730", - "keyIdVoting": "b3c2f366e6f1474e8a8fb79f989dc94d6b6fdcf0", + "keyIdVoting": "f0dc6f6b4dc99d989fb78f8a4e47f1e666f3c2b3", "scriptPayout": "76a91431ec0c3f5021938701e0208a4d21f34aa6f0a4ea88ac", "inputsHash": "7a4f818f14d078fd8aaf6989ef223df5bcfde0a8d7b6f79fdbb448a0bc14ab5c", "vchSig": "1f5cd259d853f3c03c71d04716f450f6fc316d0638f85125fab39790e335d6db670dcde2080e3fa3890166ee0a051978cc30fba16b40917eee412c860be86f9fb7" @@ -246,7 +246,7 @@ "proTxHash": "d5d00cb8101e3aea841972dcb5001ea346729a2b421886dc2ec5837fd9933c0e", "mode": 0, "pubKeyOperator": "acefd02d9bbd4bc824a3817b4c51dc4032e70cfb9540b902bb9ef1af1a2cef995c95dd26e7f041489e142eae31d936c8", - "keyIdVoting": "7291dd09d75d058b18231446f8f1885204107520", + "keyIdVoting": "207510045288f1f8461423188b055dd709dd9172", "scriptPayout": "76a914bdf33ea7da15da7936e665972c9da5e555fbbcc188ac", "inputsHash": "fc2653bdbfcafe1e9aca0ffbf8323313932388df7b9badb4c86927c567ac1b6f", "vchSig": "20c1de37b415e678ca5a1ec98c2283a1a54d4bc715748db0b6b4eae9f9200289e076b90a090a612d1faf223d7fe0d8a44d0a3cda102ab83fa832f65b5bbe2a35b8" @@ -260,7 +260,7 @@ "proTxHash": "d5d00cb8101e3aea841972dcb5001ea346729a2b421886dc2ec5837fd9933c0e", "mode": 0, "pubKeyOperator": "acefd02d9bbd4bc824a3817b4c51dc4032e70cfb9540b902bb9ef1af1a2cef995c95dd26e7f041489e142eae31d936c8", - "keyIdVoting": "7291dd09d75d058b18231446f8f1885204107520", + "keyIdVoting": "207510045288f1f8461423188b055dd709dd9172", "scriptPayout": "76a914bdf33ea7da15da7936e665972c9da5e555fbbcc188ac", "inputsHash": "139d927504691a1b113e97d6607634119e0431fac4c4fa9bbb3b8751784f46d2", "vchSig": "203a06d428c44e760fe1ddc1568577bc771d3e4582ea8961ca8e16277dbee5a4ad66e7a115beeea4968a006fedbe7382c4b416cd1154cfcc177f450069469d57f2" @@ -274,7 +274,7 @@ "proTxHash": "9e56f16533df8aa0d0183335a35102375cdbaa4335267143c9cc7d1088745f3d", "mode": 0, "pubKeyOperator": "8fbcf7cd32d2cc6245250536ea38cb5495025a2d86a38c9193c42c4b62101a3319b72437a693c3b135b98e0ac01e38bc", - "keyIdVoting": "5fc991d467d54c709f9a2894fbcda1e99be0192f", + "keyIdVoting": "2f19e09be9a1cdfb94289a9f704cd567d491c95f", "scriptPayout": "76a91443a85739fe1bcb83f01addf432f340602c059c5f88ac", "inputsHash": "b930af762fa41dd45a11e0bdff36f3e2da1d0c5f994dcb945c0b14b870859e74", "vchSig": "1fa040d812d6c71d5028070dfcbe4670f102a9cee4ec0506fb76c53a1afc32c318259daf122c87332706b330d4f4c5e27ba415a9b1a2ec446949b113f44e427def" diff --git a/pkgs/primitives/corpus/proupservtx.json5 b/pkgs/primitives/corpus/proupservtx.json5 index a6f68021..5682144e 100644 --- a/pkgs/primitives/corpus/proupservtx.json5 +++ b/pkgs/primitives/corpus/proupservtx.json5 @@ -225,7 +225,7 @@ }, "scriptOperatorPayout": "", "inputsHash": "7b1f9767752adfb40f49cece000d666b12df25fa75f8dd5c4b66e535eaf94a94", - "platformNodeId": "4c7e47d459857b8c6e70cf2195998bf1b4e29f6d", + "platformNodeId": "6d9fe2b4f18b999521cf706e8c7b8559d4477e4c", "platformP2PPort": 26656, "platformHTTPPort": 443, "sig": "b9301a6b80ecde2908b573f47eff5c88fbbe513e7203814ef03cc51c061d5a876223daf3af7fcb045730ebe5344a7124196bf0c87a1bab4bb2dcf8d22688491297dd2bec1209ee8d8f13020e8601ec31ab9a48cc058fb52aaf50ed15c023686f" @@ -246,7 +246,7 @@ }, "scriptOperatorPayout": "", "inputsHash": "a81eda28bf3f2b3d67fda43e78d52ae0f3ef1f04e4e5a3973d4d0c4c6de51b08", - "platformNodeId": "24ff591905e75621c902bf6a067ca588456f65c5", + "platformNodeId": "c5656f4588a57c066abf02c92156e7051959ff24", "platformP2PPort": 26656, "platformHTTPPort": 443, "sig": "b4ad337f9c7fd983e3a5f1478041a3bf839f1be8dab2278caab46936926c1fdf229b4c28b233d85726d2f58d2e3edad30d3c5f4ef5911d7dde2b72687e013a9d2d6d0966bab7034246a58ce373d1e58be6db0cd79584c03b67055bb72d9a0b0c" @@ -267,7 +267,7 @@ }, "scriptOperatorPayout": "", "inputsHash": "07e9e7dd1220c5072ad0291202050a71f99c335c7951d703c9cbb329a95a0a6e", - "platformNodeId": "944675af37104f743964a373b025286fa5912359", + "platformNodeId": "592391a56f2825b073a36439744f1037af754694", "platformP2PPort": 26656, "platformHTTPPort": 443, "sig": "a008419108d55938ceed98a4253a22143d2eb57c36666f6aa4cc05b0cc5821f18c7a17d2eca8a7b4ef66c9f5dbf3200202430a10967f1b920ecb8d1db447a42969e95e6ee80c66a64953b858a97d9afad6ac9722ed2b42884835b95a62053b64" @@ -288,7 +288,7 @@ }, "scriptOperatorPayout": "", "inputsHash": "8fd979a0078c4034ba6cb368a56b978451e320e3a01be06f836b6f4b0e4dec9a", - "platformNodeId": "d38d8886bb28489ad58e68a2b655e8bd49fcc1e9", + "platformNodeId": "e9c1fc49bde855b6a2688ed59a4828bb86888dd3", "platformP2PPort": 26656, "platformHTTPPort": 443, "sig": "a07b1a788ab5da703c0f6d1fc3ee928ff8fc3b533674334b3c04b593444ca170228576abae6a067bbcc2949d8ffb4018170eb69caacabb00ed573f06c30fe0441ea1edd890add401577f7e92959c6d11822a535d6cfb286f3ac22341fb7b6a45" @@ -309,7 +309,7 @@ }, "scriptOperatorPayout": "", "inputsHash": "f4c4b4a15392868e50f041021ae57ddec91a6e9452f84d16ae2acf48dfc41eeb", - "platformNodeId": "ec8d1e6c5d2f2f44982c65f2884f1dcfd08683cb", + "platformNodeId": "cb8386d0cf1d4f88f2652c98442f2f5d6c1e8dec", "platformP2PPort": 26656, "platformHTTPPort": 443, "sig": "902e40be051252feb43e6fb42ab12757d41d8c7c859960eef9c281e0aec60506415754b9e1cf8140a36303df446cba16096c30df8599f1e416f09d936b6246dfe1adf8764bdafc21a5929860100f1477fa191c255e01c6d5f842005d1d77a2eb" @@ -330,7 +330,7 @@ }, "scriptOperatorPayout": "", "inputsHash": "bd915184b82f3c62634100c5eb7fed546a97c63f3ccf9848c3ce28b3e1bd4a9b", - "platformNodeId": "c549921c0f97ebdd4777efb41bc99b11945844ee", + "platformNodeId": "ee445894119bc91bb4ef7747ddeb970f1c9249c5", "platformP2PPort": 26656, "platformHTTPPort": 443, "sig": "a813a7a6ac12072b7bc372b46f7da28a6c812aaee9413829ed0283411cb156ff3d954a12267f4bed936da9db56e3485a0c401a49978b74af239b7d5dafc2fcb3f2950bbe108182637f41fa20024b3b3976764dcb4c1c8136d145a9d7fe851c6c" @@ -351,7 +351,7 @@ }, "scriptOperatorPayout": "", "inputsHash": "932f4e65fcd8b2473fd2de050453b796b03b431fbb91543d203821bf7cc50b88", - "platformNodeId": "97e47a754ea361929bcd068c0554bbd59f08663e", + "platformNodeId": "3e66089fd5bb54058c06cd9b9261a34e757ae497", "platformP2PPort": 26656, "platformHTTPPort": 443, "sig": "8da9de39ac15a825c3c0556255f96d25b6c368e7209ef9db209a6c371c318e73d1e10c85a1685fe58351bdfb90ef520508b27e5d017a464e08afe4c790b583571057b173d63a214d70d451def4678923686be84f8afbbab7900bee75f2189b23" @@ -372,7 +372,7 @@ }, "scriptOperatorPayout": "", "inputsHash": "93f2d895627e764e7372899cf88f64061bd113ec43ddd987be2433ca94abb61b", - "platformNodeId": "8abdc35752c65f65d71baed0e6967ddef9d5beae", + "platformNodeId": "aebed5f9de7d96e6d0ae1bd7655fc65257c3bd8a", "platformP2PPort": 26656, "platformHTTPPort": 443, "sig": "8ed262631cd203059fdadc69151f61c8bb5a7ff4ecb80c5aa7a223444141626bc849cb4a0060c49f530f74afc0b184c301763db65fbce3cca72cdcd93623216e922076d26b1757d32b47f13dd3255b0e1ed2801b59e9c3c5613302ac09c6c926" @@ -393,7 +393,7 @@ }, "scriptOperatorPayout": "", "inputsHash": "d7806e25992565d4bfa164a0c738c19ff57db2bb1302180c80951e3cad76ab45", - "platformNodeId": "f2998535db16e2315344befbde1f88f5baaba062", + "platformNodeId": "62a0abbaf5881fdefbbe445331e216db358599f2", "platformP2PPort": 26656, "platformHTTPPort": 443, "sig": "a1327da115ece64bfdd2a9f459ea4cb3b025fb7f4711b687078ae54cb9f053d8bee170cd02e64cc01f76dc9f2f0303c51309917edb76812824757cacafa08bfa53cc650315685f88076e2bdc1a9e44acf6616a1a2ed914e58d3d2e67e601db7d" @@ -414,7 +414,7 @@ }, "scriptOperatorPayout": "", "inputsHash": "b3d90f8582c0b5f478e60655dac9715f0131ff75d7627d556d2eff42cec62ac0", - "platformNodeId": "8a84d43d1195c9ba1d0e7dd3764365efbfbd6ee3", + "platformNodeId": "e36ebdbfef654376d37d0e1dbac995113dd4848a", "platformP2PPort": 26656, "platformHTTPPort": 443, "sig": "84daa3b3afd35091f2db2837ce74b0392783dfe9f08787310ddbda953613846175ef67c5af77831d685fa44c2c3b43a8122a5b08898304830af8aa5766551d19a50fe202189f36dd2eddb242fcde98d515e183e6cfb414e4f1e87439f700da64" @@ -439,7 +439,7 @@ }, "scriptOperatorPayout": "", "inputsHash": "772ea8ff4660de8fdb74df33eaf7d8404793338f79cd242c13b20c81b9ee9707", - "platformNodeId": "e5992efdc3d9e31931fb19590b33aaa1b90bb958", + "platformNodeId": "58b90bb9a1aa330b5919fb3119e3d9c3fd2e99e5", "platformP2PPort": null, "platformHTTPPort": null, "sig": "82f472080ab9042136ac31bcc3fc0a4339cfb049d65aaa9815449b7f7a07a0413b5537dd8a4571e7813c7db282e55d8d19518e3ad5040646d95b1a721833d40e4199ac1e9c12df262aa54a5cdb958e2f7ca08f0624ef8655c88c83892c47ccee" @@ -473,7 +473,7 @@ }, "scriptOperatorPayout": "", "inputsHash": "e2c4f44326c4518abf50fc55b1c8c86a3a4a7312e5534148bf4e33ba531d8d1a", - "platformNodeId": "e5992efdc3d9e31931fb19590b33aaa1b90bb958", + "platformNodeId": "58b90bb9a1aa330b5919fb3119e3d9c3fd2e99e5", "platformP2PPort": null, "platformHTTPPort": null, "sig": "9792fe587c23c184602bc283e5f0e133b5a4cb3b9f8b00937947b7fd77968880dde692fc93de16bbcdf7bcfc20e5547b14ff016e2530cf6aa2f2d0e69af5bf6ffea3fcc8121dc0398485a23889607afb3f259396c875267d4013723aa3239c5e" @@ -511,7 +511,7 @@ }, "scriptOperatorPayout": "", "inputsHash": "42b7423c5ee93cc20ac235040d696369884cca1ff43aa4287bb0645062012c16", - "platformNodeId": "e5992efdc3d9e31931fb19590b33aaa1b90bb958", + "platformNodeId": "58b90bb9a1aa330b5919fb3119e3d9c3fd2e99e5", "platformP2PPort": null, "platformHTTPPort": null, "sig": "a962a6fba440cc328e9acb9c06d3a487d08b635008d7af5aba040a5ef53656f974ac492e235ab757504b709ba80b530007e92cea0aa4455dbe1eac9ed67f57d1ba46ed4e324b83d896832c05afc260970cdbbc9837c75cce573b25b45f1de799" diff --git a/pkgs/primitives/src/block.rs b/pkgs/primitives/src/block.rs index 5c9b10b8..0adfc55e 100644 --- a/pkgs/primitives/src/block.rs +++ b/pkgs/primitives/src/block.rs @@ -26,17 +26,15 @@ pub const MAX_LEGACY_BLOCK_SIZE: usize = 1_000_000; pub const MAX_DIP0001_BLOCK_SIZE: usize = 2_000_000; make_hash! { - Hash256, /// Hash of a block header. - BlockHash + BlockHash, 32 } hash_impl!(BlockHash); make_hash! { - Hash256, /// Merkle tree root hash. - MerkleRoot + MerkleRoot, 32 } hash_impl!(MerkleRoot); diff --git a/pkgs/primitives/src/payload/mod.rs b/pkgs/primitives/src/payload/mod.rs index 31f365c6..e45830d9 100644 --- a/pkgs/primitives/src/payload/mod.rs +++ b/pkgs/primitives/src/payload/mod.rs @@ -23,7 +23,7 @@ use crate::hash_impl; use crate::prelude::*; use crate::types::{NIError, NIPurpose, NITrait, NetInfoV2}; -use dash_num::{make_hash, Hash256}; +use dash_num::make_hash; use dash_types::codec::Checkable; use dash_types::type_id::{TypeId, Unencodable}; use dash_types::{enum_map, impl_num}; @@ -44,17 +44,15 @@ pub(crate) const PROTX_VERSION_BASIC_BLS: u16 = 2; pub(crate) const PROTX_VERSION_EXT_ADDR: u16 = 3; make_hash! { - Hash256, /// LLMQ quorum identifier. - QuorumHash + QuorumHash, 32 } hash_impl!(QuorumHash); make_hash! { - Hash256, /// Hash of serialized transaction inputs. - InputsHash + InputsHash, 32 } hash_impl!(InputsHash); diff --git a/pkgs/primitives/src/payload/proregtx.rs b/pkgs/primitives/src/payload/proregtx.rs index 4d90040e..a713db34 100644 --- a/pkgs/primitives/src/payload/proregtx.rs +++ b/pkgs/primitives/src/payload/proregtx.rs @@ -16,11 +16,12 @@ use crate::types::{NITrait, NetInfo, NetInfoV1, NetInfoV2, ServiceV1}; use crate::{hash_impl, TxHash}; use bitcoin_primitives::script::ScriptPubKeyBuf; +use dash_num::make_hash; use dash_pkc::bls::{BlsPkBytes, BlsScIetf}; use dash_script::{PubKeyHash, Recipient}; use dash_types::codec::{BaseCodec, Checkable, DecodeError, EncodeBuf}; use dash_types::type_id::TypeId; -use dash_types::{make_bytes, Numeric}; +use dash_types::Numeric; use core::fmt; @@ -264,7 +265,7 @@ impl fmt::Display for ProRegTx { } } -make_bytes! { +make_hash! { /// Platform node identifier for Evo masternodes. PlatformNodeId, 20 } diff --git a/pkgs/primitives/src/payload/quorum.rs b/pkgs/primitives/src/payload/quorum.rs index 7a7bb83b..1ca90323 100644 --- a/pkgs/primitives/src/payload/quorum.rs +++ b/pkgs/primitives/src/payload/quorum.rs @@ -11,7 +11,7 @@ use crate::codec::impl_payload; use crate::hash_impl; use crate::support::{DynBitset, LlmqType}; -use dash_num::{make_hash, Hash256}; +use dash_num::make_hash; use dash_pkc::bls::{BlsPkBytes, BlsScIetf, BlsSigBytes}; use dash_types::codec::{BaseCodec, Checkable, DecodeError, EncodeBuf}; use dash_types::type_id::{TypeId, Unencodable}; @@ -20,9 +20,8 @@ use dash_types::Numeric; use core::fmt; make_hash! { - Hash256, /// Quorum verification vector hash. - QuorumVvecHash + QuorumVvecHash, 32 } hash_impl!(QuorumVvecHash); diff --git a/pkgs/primitives/src/transaction.rs b/pkgs/primitives/src/transaction.rs index 279272a2..12ce31c2 100644 --- a/pkgs/primitives/src/transaction.rs +++ b/pkgs/primitives/src/transaction.rs @@ -14,7 +14,7 @@ use crate::{codec_type, hash_impl}; use bitcoin_hashes::sha256d; use bitcoin_primitives::script::{ScriptPubKeyBuf, ScriptSigBuf}; use bitcoin_units::Amount; -use dash_num::{make_hash, Hash256}; +use dash_num::make_hash; use dash_types::codec::{self, BaseCodec, Checkable, DecodeError, EncodeBuf, Hashable}; use dash_types::type_id::{TypeId, Unencodable}; use dash_types::{impl_type, CompactSize, Numeric}; @@ -28,9 +28,8 @@ pub const MAX_TX_EXTRA_PAYLOAD: usize = 10_000; pub const MAX_COINBASE_SCRIPT_SIZE: usize = 100; make_hash! { - Hash256, /// SHA256d hash of a serialized transaction. - TxHash + TxHash, 32 } hash_impl!(TxHash); From b0c151bf4497546479aca9119315534252d0ba26 Mon Sep 17 00:00:00 2001 From: Kittywhiskers Van Gogh <63189531+kwvg@users.noreply.github.com> Date: Tue, 15 Sep 2026 00:19:03 +0530 Subject: [PATCH 17/23] types%fix(adapters): render `ScriptHash` like a `Hash160` using `rev` --- pkgs/types/src/adapters.rs | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/pkgs/types/src/adapters.rs b/pkgs/types/src/adapters.rs index a8a6d727..612d3079 100644 --- a/pkgs/types/src/adapters.rs +++ b/pkgs/types/src/adapters.rs @@ -39,10 +39,14 @@ pub mod bitcoin_primitives { adapt_codec!(, ScriptBuf); - // nosemgrep: types-macro-no-codec - make_bytes! { + // `CScriptID` is a `uint160` but the relevant routines are in dash-num, a + // child crate, rendering it unavailable to us. This is worked around by + // using `make_bytes!`'s display reversal but doesn't offer the same surface. + // + // TODO(kwvg): figure out a way to treat ScriptHash as a proper `Hash160` + make_bytes! { // nosemgrep: types-macro-no-codec /// 20-byte script hash. - ScriptHash, 20 + ScriptHash, 20, rev } impl ScriptHash { From c9eefdff3423edbd55b4f09eb591b71a6b8d6198 Mon Sep 17 00:00:00 2001 From: Kittywhiskers Van Gogh <63189531+kwvg@users.noreply.github.com> Date: Mon, 14 Sep 2026 13:48:42 +0530 Subject: [PATCH 18/23] pkc%fix(bls): use `make_hash!` to treat `BlsShareId` as `Hash256` --- pkgs/pkc/corpus/bls_llmq_100.json5 | 12 ++++++------ pkgs/pkc/src/bls/blst_ffi.rs | 2 +- pkgs/pkc/src/bls/mod.rs | 1 - pkgs/pkc/src/bls/scalar.rs | 9 +++++---- pkgs/pkc/src/bls/share_id.rs | 13 +++++++------ pkgs/pkc/src/bls/share_ops.rs | 20 ++++++++++++-------- pkgs/pkc/src/bls/tests.rs | 14 ++++---------- 7 files changed, 35 insertions(+), 36 deletions(-) diff --git a/pkgs/pkc/corpus/bls_llmq_100.json5 b/pkgs/pkc/corpus/bls_llmq_100.json5 index d3c6c152..d1374464 100644 --- a/pkgs/pkc/corpus/bls_llmq_100.json5 +++ b/pkgs/pkc/corpus/bls_llmq_100.json5 @@ -5,9 +5,9 @@ "t": 2, "n": 3, "member_ids": [ - "8ba294ac671bb4f19508b0308afe57cb12edcc9f05d03f4339ca4b6b32732e3c", - "64755b06aa0774424a29b547f06a0f6c554103f3e43c70e68ecaa1b6f4b776d8", - "15d1f68ed3267d3282164450ce8bf86eeb679e9634ea82c43c6b79dbfb1173e0" + "3c2e73326b4bca39433fd0059fcced12cb57fe8a30b00895f1b41b67ac94a28b", + "d876b7f4b6a1ca8ee6703ce4f30341556c0f6af047b5294a427407aa065b7564", + "e07311fbdb796b3cc482ea34969e67eb6ef88bce50441682327d26d38ef6d115" ] }, "contribute": [ @@ -235,9 +235,9 @@ "t": 2, "n": 3, "member_ids": [ - "15d1f68ed3267d3282164450ce8bf86eeb679e9634ea82c43c6b79dbfb1173e0", - "64755b06aa0774424a29b547f06a0f6c554103f3e43c70e68ecaa1b6f4b776d8", - "8ba294ac671bb4f19508b0308afe57cb12edcc9f05d03f4339ca4b6b32732e3c" + "e07311fbdb796b3cc482ea34969e67eb6ef88bce50441682327d26d38ef6d115", + "d876b7f4b6a1ca8ee6703ce4f30341556c0f6af047b5294a427407aa065b7564", + "3c2e73326b4bca39433fd0059fcced12cb57fe8a30b00895f1b41b67ac94a28b" ] }, "contribute": [ diff --git a/pkgs/pkc/src/bls/blst_ffi.rs b/pkgs/pkc/src/bls/blst_ffi.rs index 9e0e6617..0fdf831f 100644 --- a/pkgs/pkc/src/bls/blst_ffi.rs +++ b/pkgs/pkc/src/bls/blst_ffi.rs @@ -112,7 +112,7 @@ impl Fr { } } - /// Reduces a wide little-endian integer into the field. + /// Reduces a little-endian integer of any width into the field. /// /// Wider input than the modulus is the point; reducing 64 bytes into a /// 255-bit field leaves a bias below `2^-250`, where rejection sampling would diff --git a/pkgs/pkc/src/bls/mod.rs b/pkgs/pkc/src/bls/mod.rs index 15331814..b2a859b9 100644 --- a/pkgs/pkc/src/bls/mod.rs +++ b/pkgs/pkc/src/bls/mod.rs @@ -49,7 +49,6 @@ cfg_if::cfg_if! { #[cfg(any(test, feature = "tests"))] #[doc(hidden)] - #[expect(clippy::unwrap_used, reason = "test support code")] pub mod tests; pub use ies_ops::{BlsIesBlob, BlsIesMulti}; diff --git a/pkgs/pkc/src/bls/scalar.rs b/pkgs/pkc/src/bls/scalar.rs index 4bbbe118..966bc6ca 100644 --- a/pkgs/pkc/src/bls/scalar.rs +++ b/pkgs/pkc/src/bls/scalar.rs @@ -49,7 +49,7 @@ impl Fr { /// Returns `InvalidShareId` when the id reduces to zero; the polynomial /// evaluated there yields its constant term, the master secret itself. pub fn from_share_id(id: &BlsShareId) -> Result { - let reduced = Self::from_bendian_reduce(id.as_bytes()); + let reduced = Self::from_lendian_reduce(id.as_bytes()); if bool::from(reduced.is_zero()) { return Err(BlsError::InvalidShareId); } @@ -353,6 +353,7 @@ mod tests { use crate::bls::{BlsScChia, BlsScIetf, BlsScheme, BlsSecretKey}; use crate::prelude::*; + use dash_types::Numeric; use getrandom::SysRng; use rand_core::UnwrapErr; use rstest::rstest; @@ -424,7 +425,7 @@ mod tests { for _ in 0..248 { expected = expected.double(); } - assert_eq!(Fr::from_share_id(&BlsShareId::from_bytes(leading)).unwrap(), expected); + assert_eq!(Fr::from_share_id(&BlsShareId::from_bendian(leading)).unwrap(), expected); } /// An id is an integer rather than an encoding of one, so a value at or @@ -435,7 +436,7 @@ mod tests { let mut order_plus_one = GROUP_ORDER; order_plus_one[31] += 1; assert_eq!( - Fr::from_share_id(&BlsShareId::from_bytes(order_plus_one)).unwrap(), + Fr::from_share_id(&BlsShareId::from_bendian(order_plus_one)).unwrap(), Fr::ONE ); @@ -451,7 +452,7 @@ mod tests { #[case::order(GROUP_ORDER)] fn share_id_rejects_the_zero_residue(#[case] bytes: [u8; 32]) { assert_eq!( - Fr::from_share_id(&BlsShareId::from_bytes(bytes)), + Fr::from_share_id(&BlsShareId::from_bendian(bytes)), Err(BlsError::InvalidShareId) ); } diff --git a/pkgs/pkc/src/bls/share_id.rs b/pkgs/pkc/src/bls/share_id.rs index 83d9f955..2c36eaad 100644 --- a/pkgs/pkc/src/bls/share_id.rs +++ b/pkgs/pkc/src/bls/share_id.rs @@ -6,12 +6,13 @@ //! Threshold participant identifier. -use dash_types::make_bytes; +use dash_num::make_hash; +use dash_types::Numeric; -/// Threshold participant identifier length. -pub const BLS_ID_LEN: usize = 32; - -make_bytes! { +make_hash! { /// Threshold participant identifier. - BlsShareId, BLS_ID_LEN, rev, nocodec + BlsShareId, 32 } + +/// Threshold participant identifier length. +pub const BLS_ID_LEN: usize = ::LEN; diff --git a/pkgs/pkc/src/bls/share_ops.rs b/pkgs/pkc/src/bls/share_ops.rs index 6db12196..2940bdb1 100644 --- a/pkgs/pkc/src/bls/share_ops.rs +++ b/pkgs/pkc/src/bls/share_ops.rs @@ -181,11 +181,12 @@ impl BlsPublicKey { #[expect(clippy::unwrap_used, reason = "test code")] mod tests { use super::*; - use crate::bls::tests::{id_from_hex, make_id, sequential_ids, GROUP_ORDER, MSG_DEADBEEF, RSEED}; + use crate::bls::tests::{make_id, sequential_ids, GROUP_ORDER, MSG_DEADBEEF, RSEED}; use crate::bls::{BlsScChia, BlsScIetf}; use cfg_if::cfg_if; use dash_dev::{arr_from_hex, Corpus, Value}; + use dash_types::Numeric; use getrandom::SysRng; use hex_conservative::DisplayHex; use rand_core::UnwrapErr; @@ -201,7 +202,7 @@ mod tests { break; } } - BlsShareId::from_bytes(bytes) + BlsShareId::from_bendian(bytes) } /// A 1-of-n split hands the master key to every participant, so a `threshold` @@ -234,14 +235,14 @@ mod tests { fn assert_zero_reducing_id_rejected() { let sk = BlsSecretKey::::generate(&RSEED[0]).unwrap(); - let zero = BlsShareId::from_bytes([0u8; 32]); + let zero = BlsShareId::from_bendian([0u8; 32]); let ids = [make_id(1), zero]; assert!(matches!( sk.split(2, &ids, &mut UnwrapErr(SysRng)), Err(BlsError::InvalidShareId) )); - let order = BlsShareId::from_bytes(GROUP_ORDER); + let order = BlsShareId::from_bendian(GROUP_ORDER); let ids = [make_id(1), order]; assert!(matches!( sk.split(2, &ids, &mut UnwrapErr(SysRng)), @@ -298,7 +299,7 @@ mod tests { Err(BlsError::InvalidVerificationVector) )); assert!(matches!( - BlsSecretKey::::derive_share(&master_refs, &BlsShareId::from_bytes([0u8; 32])), + BlsSecretKey::::derive_share(&master_refs, &BlsShareId::from_bendian([0u8; 32])), Err(BlsError::InvalidShareId) )); } @@ -413,7 +414,7 @@ mod tests { let sk_share = BlsSecretKey::::from_bytes(&arr_from_hex(sk_hex.as_str().unwrap())).unwrap(); let pk_from_share = sk_share.public_key(); - let member_id = id_from_hex(&member_ids[member_idx]); + let member_id = BlsShareId::from_hex(&member_ids[member_idx]).unwrap(); let pk_from_vvec = BlsPublicKey::derive_share(&vvec_refs, &member_id).unwrap(); let matches = pk_from_share.to_bytes() == pk_from_vvec.to_bytes(); @@ -565,7 +566,7 @@ mod tests { let sig_shares: Vec> = signer_ids .iter() .map(|sid| { - let member_id = BlsShareId::from_bytes(arr_from_hex::<32>(sid)); + let member_id = BlsShareId::from_bendian(arr_from_hex::<32>(sid)); let sid_display = member_id.to_string(); let idx = member_ids.iter().position(|m| *m == sid_display).unwrap(); let sk = BlsSecretKey::::from_bytes(&arr_from_hex(commits[idx]["sk_share"].as_str().unwrap())).unwrap(); @@ -584,7 +585,10 @@ mod tests { ); // Cross-check: recovery from all members should match the subset recovery. - let all_ids: Vec = member_ids.iter().map(|mid| id_from_hex(mid)).collect(); + let all_ids: Vec = member_ids + .iter() + .map(|mid| BlsShareId::from_hex(mid).unwrap()) + .collect(); let all_shares: Vec> = commits .iter() .zip(all_ids.iter()) diff --git a/pkgs/pkc/src/bls/tests.rs b/pkgs/pkc/src/bls/tests.rs index 3c8d8adc..d94fb830 100644 --- a/pkgs/pkc/src/bls/tests.rs +++ b/pkgs/pkc/src/bls/tests.rs @@ -10,7 +10,8 @@ use crate::bls::BlsShareId; use crate::prelude::*; use cfg_if::cfg_if; -use hex_conservative::{hex, FromHex}; +use dash_types::Numeric; +use hex_conservative::hex; /// BLS12-381 scalar field order r, big-endian. pub const GROUP_ORDER: [u8; 32] = hex!("73eda753299d7d483339d80809a1d80553bda402fffe5bfeffffffff00000001"); @@ -68,18 +69,11 @@ pub const fn ietf_g1_encoding(mut chia: [u8; 48]) -> [u8; 48] { chia } -/// Parse a participant id from a big-endian hex string. -pub fn id_from_hex(s: &str) -> BlsShareId { - let mut bytes = <[u8; 32]>::from_hex(s).unwrap(); - bytes.reverse(); - BlsShareId::from_bytes(bytes) -} - -/// Build a participant id whose low bytes encode `i`. +/// Build a participant id whose field element is `i`. pub fn make_id(i: u32) -> BlsShareId { let mut bytes = [0u8; 32]; bytes[28..32].copy_from_slice(&i.to_be_bytes()); - BlsShareId::from_bytes(bytes) + BlsShareId::from_bendian(bytes) } /// Build `n` sequential participant ids `1..=n`. From 6a00fa106e6f948ffe3269f0a54698db50b395c6 Mon Sep 17 00:00:00 2001 From: Kittywhiskers Van Gogh <63189531+kwvg@users.noreply.github.com> Date: Mon, 14 Sep 2026 13:56:33 +0530 Subject: [PATCH 19/23] sdk%lint(semgrep): discourage `make_bytes!` `rev` directive --- maint/semgrep/rust/workspace.yml | 16 ++++++++++++++++ pkgs/types/src/adapters.rs | 2 +- 2 files changed, 17 insertions(+), 1 deletion(-) diff --git a/maint/semgrep/rust/workspace.yml b/maint/semgrep/rust/workspace.yml index e6d68d4e..bfcaddea 100644 --- a/maint/semgrep/rust/workspace.yml +++ b/maint/semgrep/rust/workspace.yml @@ -237,3 +237,19 @@ rules: include: [/pkgs/**/*.rs, /docs/samples/**/*.rs] exclude: ["**/lib.rs", "**/mod.rs"] pattern-regex: '^\s*pub\s+use\s' + + - id: bytes-rev-means-hash + message: "dash_types::make_bytes! is not suitable for hash types, use dash_num::make_hash! instead" + severity: ERROR + languages: [rust] + paths: + include: [/pkgs/**/*.rs, /docs/samples/**/*.rs] + exclude: + - /pkgs/types/src/entity.rs # declares the generator + - /pkgs/types/src/secret.rs # declares its secret sibling + pattern-regex: |- + (?x) + \b (?: make | derive ) _ s? bytes ! # a byte-bag generator invocation + \s* [({] # ... opening its arguments + (?: [^\n]* \n ){0,6}? # ... over its doc comment, if any + [^\n]* \b rev \b # ... to the order token's line diff --git a/pkgs/types/src/adapters.rs b/pkgs/types/src/adapters.rs index 612d3079..26089efd 100644 --- a/pkgs/types/src/adapters.rs +++ b/pkgs/types/src/adapters.rs @@ -44,7 +44,7 @@ pub mod bitcoin_primitives { // using `make_bytes!`'s display reversal but doesn't offer the same surface. // // TODO(kwvg): figure out a way to treat ScriptHash as a proper `Hash160` - make_bytes! { // nosemgrep: types-macro-no-codec + make_bytes! { // nosemgrep: bytes-rev-means-hash, types-macro-no-codec /// 20-byte script hash. ScriptHash, 20, rev } From f85f1de0dbe3483ea024adefc7f18702fcc78999 Mon Sep 17 00:00:00 2001 From: Kittywhiskers Van Gogh <63189531+kwvg@users.noreply.github.com> Date: Tue, 15 Sep 2026 00:38:09 +0530 Subject: [PATCH 20/23] types%chore: re-export `zeroize` due to usage in public API --- maint/codeql/rust/lib/imports.qll | 40 ++++++++++++++++++------------- pkgs/types/src/lib.rs | 9 +++---- pkgs/types/src/secret.rs | 12 +++++----- 3 files changed, 35 insertions(+), 26 deletions(-) diff --git a/maint/codeql/rust/lib/imports.qll b/maint/codeql/rust/lib/imports.qll index 9cbe41b3..671661c7 100644 --- a/maint/codeql/rust/lib/imports.qll +++ b/maint/codeql/rust/lib/imports.qll @@ -67,24 +67,32 @@ predicate isMacroReexport(Use u) { /** Holds if `u` is an allowlisted re-export from a foreign crate. */ private predicate isAllowlistedReexport(Use u) { - // Sub-crate isolation demands re-exports, part of public API - usePrefix(u) = "dash_types_marker" and - fileOf(u).getAbsolutePath().matches("%pkgs/types/%") - or - // Workaround for the orphan rule, not part of public API - usePrefix(u) = "dash_pkc" and - u.getUseTree().getPath().getSegment().getIdentifier().getText() = "__PubKeyHash" and - fileOf(u).getAbsolutePath().matches("%pkgs/script/%") + fileOf(u).getAbsolutePath().matches("%pkgs/num/%") and + ( + // Crate emits types relying on traits defined by a dependency, part of public API + usePrefix(u) = "dash_types" and + u.getUseTree().getPath().getSegment().getIdentifier().getText() = "Numeric" + ) or - // Workaround for the orphan rule, not part of public API - usePrefix(u) = "dash_types" and - u.getUseTree().getPath().getSegment().getIdentifier().getText() = "__ScriptHash" and - fileOf(u).getAbsolutePath().matches("%pkgs/script/%") + fileOf(u).getAbsolutePath().matches("%pkgs/script/%") and + ( + // Workaround for the orphan rule, not part of public API + usePrefix(u) = "dash_pkc" and + u.getUseTree().getPath().getSegment().getIdentifier().getText() = "__PubKeyHash" + or + // Workaround for the orphan rule, not part of public API + usePrefix(u) = "dash_types" and + u.getUseTree().getPath().getSegment().getIdentifier().getText() = "__ScriptHash" + ) or - // Crate emits types relying on traits defined by a dependency, part of public API - usePrefix(u) = "dash_types" and - u.getUseTree().getPath().getSegment().getIdentifier().getText() = "Numeric" and - fileOf(u).getAbsolutePath().matches("%pkgs/num/%") + fileOf(u).getAbsolutePath().matches("%pkgs/types/%") and + ( + // Sub-crate isolation demands re-exports, part of public API + usePrefix(u) = "dash_types_marker" + or + // Crate emits types relying on types or traits defined by a dependency, part of public API + usePrefix(u) = "zeroize" + ) } /** diff --git a/pkgs/types/src/lib.rs b/pkgs/types/src/lib.rs index 5161cdd0..fb283584 100644 --- a/pkgs/types/src/lib.rs +++ b/pkgs/types/src/lib.rs @@ -24,9 +24,11 @@ mod traits; #[cfg(feature = "serde")] pub mod serialize; -pub use macros::qtypestr; -pub use numeric::Numeric; -pub use traits::{Checkable, Hashable}; +pub use crate::macros::qtypestr; +pub use crate::numeric::Numeric; +pub use crate::traits::{Checkable, Hashable}; + +pub use zeroize; cfg_if::cfg_if! { if #[cfg(feature = "codec")] { @@ -55,5 +57,4 @@ pub mod __private { #[cfg(feature = "serde")] pub use serde; pub use subtle; - pub use zeroize; } diff --git a/pkgs/types/src/secret.rs b/pkgs/types/src/secret.rs index 3fa1e477..ac844183 100644 --- a/pkgs/types/src/secret.rs +++ b/pkgs/types/src/secret.rs @@ -331,11 +331,11 @@ macro_rules! derive_sbytes { (@parse [$($g:tt)*] $ty:ty, $n:expr) => { impl<$($g)*> ::core::ops::Drop for $ty { fn drop(&mut self) { - ::zeroize(self); + ::zeroize(self); } } - impl<$($g)*> $crate::__private::zeroize::ZeroizeOnDrop for $ty {} + impl<$($g)*> $crate::zeroize::ZeroizeOnDrop for $ty {} impl<$($g)*> $ty { /// Returns `true` when every byte is zero. @@ -397,14 +397,14 @@ macro_rules! make_sbytes { $crate::make_bytes!(@accessors [$($g)*] $name $(<$($param),+>)?, $n, { /// Copies out the inner byte array. - pub fn to_bytes(&self) -> $crate::__private::zeroize::Zeroizing<[u8; $n]> { - $crate::__private::zeroize::Zeroizing::new(self.inner) + pub fn to_bytes(&self) -> $crate::zeroize::Zeroizing<[u8; $n]> { + $crate::zeroize::Zeroizing::new(self.inner) } }); - impl<$($g)*> $crate::__private::zeroize::Zeroize for $name $(<$($param),+>)? { + impl<$($g)*> $crate::zeroize::Zeroize for $name $(<$($param),+>)? { fn zeroize(&mut self) { - $crate::__private::zeroize::Zeroize::zeroize(&mut self.inner); + $crate::zeroize::Zeroize::zeroize(&mut self.inner); } } From 3cd13ca0a99218c4269a3fb9b826716eae85f603 Mon Sep 17 00:00:00 2001 From: Kittywhiskers Van Gogh <63189531+kwvg@users.noreply.github.com> Date: Mon, 14 Sep 2026 19:17:37 +0530 Subject: [PATCH 21/23] num%fix(arith): correct `block_proof` at one and zero --- pkgs/num/src/arith256.rs | 8 ++++---- pkgs/num/tests/arith.rs | 15 +++++++++++---- 2 files changed, 15 insertions(+), 8 deletions(-) diff --git a/pkgs/num/src/arith256.rs b/pkgs/num/src/arith256.rs index f2bfbe8c..65513ee8 100644 --- a/pkgs/num/src/arith256.rs +++ b/pkgs/num/src/arith256.rs @@ -353,10 +353,10 @@ impl Arith256 { ) } - /// Compute `2^256 / (self + 1)`. Returns MAX when self is zero or one. - pub fn inverse(self) -> Self { - if self == Self::ZERO || self == Self::ONE { - return Self::MAX; + /// Work contributed by this difficulty target, `2^256 / (self + 1)`. + pub fn block_proof(self) -> Self { + if self == Self::ZERO { + return Self::ZERO; } if self == Self::MAX { return Self::ONE; diff --git a/pkgs/num/tests/arith.rs b/pkgs/num/tests/arith.rs index 953a2895..ffb29395 100644 --- a/pkgs/num/tests/arith.rs +++ b/pkgs/num/tests/arith.rs @@ -970,14 +970,21 @@ mod increment { } } -mod inverse { +mod block_proof { use super::*; #[rstest] fn zero_min_max() { - assert_eq!(Arith256::MAX.inverse(), Arith256::ONE); - assert_eq!(Arith256::ONE.inverse(), Arith256::MAX); - assert_eq!(Arith256::ZERO.inverse(), Arith256::MAX); + assert_eq!(Arith256::MAX.block_proof(), Arith256::ONE); + assert_eq!(Arith256::ONE.block_proof(), Arith256::ONE << 255u32); + assert_eq!(Arith256::ZERO.block_proof(), Arith256::ZERO); + } + + #[rstest] + fn pow_limit() { + let target = (Arith256::ONE << 224u32) - Arith256::ONE; + let expected = Arith256::ONE << 32u32; + assert_eq!(target.block_proof(), expected); } } From 66eb0996cac271d00cb0bd6697f28d4418a6b7e0 Mon Sep 17 00:00:00 2001 From: Kittywhiskers Van Gogh <63189531+kwvg@users.noreply.github.com> Date: Mon, 14 Sep 2026 18:06:52 +0530 Subject: [PATCH 22/23] num%fix(hash): tighten `ParseHexError`'s contract and scope --- pkgs/num/src/hash.rs | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/pkgs/num/src/hash.rs b/pkgs/num/src/hash.rs index 2b80933b..5f721886 100644 --- a/pkgs/num/src/hash.rs +++ b/pkgs/num/src/hash.rs @@ -20,11 +20,17 @@ const WHITESPACE: [char; 6] = [' ', '\x0c', '\n', '\r', '\t', '\x0b']; /// Error returned when parsing a hex string fails. #[derive(Clone, Debug, PartialEq, Eq)] +#[non_exhaustive] pub enum ParseHexError { /// The hex string has an odd number of characters. OddLength, - /// The decoded byte count does not match the expected length. - InvalidLength { expected: usize, got: usize }, + /// The hex character count does not match the expected length. + InvalidLength { + /// Hex characters the target type accepts, twice its byte width. + expected: usize, + /// Hex characters supplied, after any prefix was stripped. + got: usize, + }, /// A non-hex character was encountered. InvalidChar(u8), } @@ -43,8 +49,7 @@ impl fmt::Display for ParseHexError { } } -#[cfg(feature = "std")] -impl std::error::Error for ParseHexError {} +impl core::error::Error for ParseHexError {} /// Fixed-size opaque hash blob stored in little-endian byte order. #[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)] @@ -140,7 +145,7 @@ impl HashBlob { /// # Errors /// /// Returns `OddLength` when input has an odd number of hex characters, - /// `InvalidLength` when the decoded byte count exceeds the type width, or + /// `InvalidLength` when the hex character count exceeds the type width, or /// `InvalidChar` on a non-hex digit. pub fn from_hex(s: &str) -> Result { let s = s.trim_start_matches(WHITESPACE); From 6d21bbfd2d70710b7f1e8a1f7e701f50735e74ed Mon Sep 17 00:00:00 2001 From: Kittywhiskers Van Gogh <63189531+kwvg@users.noreply.github.com> Date: Mon, 14 Sep 2026 19:19:33 +0530 Subject: [PATCH 23/23] num%feat: expand hex formatting surface for `HashBlob` and friends --- pkgs/num/src/arith256.rs | 12 +++++++++++- pkgs/num/src/compact.rs | 32 +++++++++++++++++++++++++++++++- pkgs/num/src/hash.rs | 26 +++++++++++++++++++++----- pkgs/num/src/util.rs | 12 ++++++++++++ pkgs/num/tests/arith.rs | 21 +++++++++++++++++++++ pkgs/num/tests/compact.rs | 29 +++++++++++++++++++++++++++++ pkgs/num/tests/hash.rs | 11 ++++++++++- 7 files changed, 135 insertions(+), 8 deletions(-) diff --git a/pkgs/num/src/arith256.rs b/pkgs/num/src/arith256.rs index 65513ee8..6a92660e 100644 --- a/pkgs/num/src/arith256.rs +++ b/pkgs/num/src/arith256.rs @@ -6,7 +6,7 @@ //! 256-bit unsigned arithmetic integer. -use crate::Hash256; +use crate::{Hash256, ParseHexError}; use dash_types::Numeric; @@ -16,6 +16,7 @@ use core::ops::{ Add, AddAssign, BitAnd, BitAndAssign, BitOr, BitOrAssign, BitXor, BitXorAssign, Div, DivAssign, Mul, MulAssign, Neg, Not, Rem, RemAssign, Shl, ShlAssign, Shr, ShrAssign, Sub, SubAssign, }; +use core::str::FromStr; /// 256-bit unsigned arithmetic integer. /// @@ -456,6 +457,15 @@ impl fmt::UpperHex for Arith256 { } } +/// Parses the big-endian hex rendered by [`Display`](fmt::Display). +impl FromStr for Arith256 { + type Err = ParseHexError; + + fn from_str(s: &str) -> Result { + Hash256::from_hex(s).map(Self::from) + } +} + impl From for Arith256 { fn from(v: u8) -> Self { Self::from_u64(v as u64) diff --git a/pkgs/num/src/compact.rs b/pkgs/num/src/compact.rs index 040ce0af..4b48d6dc 100644 --- a/pkgs/num/src/compact.rs +++ b/pkgs/num/src/compact.rs @@ -6,13 +6,14 @@ //! Compact difficulty target encoding. -use crate::Arith256; +use crate::{Arith256, ParseHexError}; #[cfg(feature = "codec")] use dash_types::impl_num; use dash_types::Numeric; use core::fmt; +use core::str::FromStr; /// Compact difficulty target. #[derive(Clone, Copy, Debug, Default, PartialEq, Eq, PartialOrd, Ord, Hash)] @@ -103,6 +104,35 @@ impl fmt::Display for CompactTarget { } } +/// Parses the `0x`-prefixed hex rendered by [`Display`](fmt::Display). +impl FromStr for CompactTarget { + type Err = ParseHexError; + + fn from_str(s: &str) -> Result { + let digits = s.strip_prefix("0x").or_else(|| s.strip_prefix("0X")).unwrap_or(s); + + if digits.is_empty() || digits.len() > 8 { + return Err(ParseHexError::InvalidLength { + expected: 8, + got: digits.len(), + }); + } + + let mut bits: u32 = 0; + for b in digits.bytes() { + let digit = match b { + b'0'..=b'9' => b - b'0', + b'a'..=b'f' => b - b'a' + 10, + b'A'..=b'F' => b - b'A' + 10, + _ => return Err(ParseHexError::InvalidChar(b)), + }; + bits = (bits << 4) | u32::from(digit); + } + + Ok(Self(bits)) + } +} + impl Arith256 { /// Compact this value to its `nBits` representation. pub fn compact(self, negative: bool) -> CompactTarget { diff --git a/pkgs/num/src/hash.rs b/pkgs/num/src/hash.rs index 5f721886..552295e6 100644 --- a/pkgs/num/src/hash.rs +++ b/pkgs/num/src/hash.rs @@ -177,17 +177,33 @@ impl Default for HashBlob { /// Reversed hex (big-endian display, consensus format). impl fmt::Display for HashBlob { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - for c in BytesToHexIter::new(self.0.iter().rev().copied(), Case::Lower) { - f.write_char(c)?; - } - Ok(()) + write_hex(self.as_bytes(), Case::Lower, f) } } +/// Big-endian hex, `N * 2` chars zero-padded. impl fmt::LowerHex for HashBlob { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - fmt::Display::fmt(self, f) + write_hex(self.as_bytes(), Case::Lower, f) + } +} + +/// Big-endian hex (uppercase), `N * 2` chars zero-padded. +impl fmt::UpperHex for HashBlob { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write_hex(self.as_bytes(), Case::Upper, f) + } +} + +/// Writes little-endian storage as big-endian hex, honouring `{:#x}`. +fn write_hex(bytes: &[u8], case: Case, f: &mut fmt::Formatter<'_>) -> fmt::Result { + if f.alternate() { + f.write_str(if case == Case::Lower { "0x" } else { "0X" })?; + } + for c in BytesToHexIter::new(bytes.iter().rev().copied(), case) { + f.write_char(c)?; } + Ok(()) } impl fmt::Debug for HashBlob { diff --git a/pkgs/num/src/util.rs b/pkgs/num/src/util.rs index 5cf4091f..244563ac 100644 --- a/pkgs/num/src/util.rs +++ b/pkgs/num/src/util.rs @@ -172,6 +172,18 @@ macro_rules! make_hash { } } + impl ::core::fmt::LowerHex for $name { + fn fmt(&self, f: &mut ::core::fmt::Formatter<'_>) -> ::core::fmt::Result { + ::core::fmt::LowerHex::fmt(&self.0, f) + } + } + + impl ::core::fmt::UpperHex for $name { + fn fmt(&self, f: &mut ::core::fmt::Formatter<'_>) -> ::core::fmt::Result { + ::core::fmt::UpperHex::fmt(&self.0, f) + } + } + impl ::core::fmt::Debug for $name { fn fmt(&self, f: &mut ::core::fmt::Formatter<'_>) -> ::core::fmt::Result { write!(f, "{}({})", stringify!($name), self.0) diff --git a/pkgs/num/tests/arith.rs b/pkgs/num/tests/arith.rs index ffb29395..718ce86b 100644 --- a/pkgs/num/tests/arith.rs +++ b/pkgs/num/tests/arith.rs @@ -1031,3 +1031,24 @@ mod formatting { ); } } + +mod from_str { + use super::*; + + #[rstest] + fn display_round_trips(r1: Arith256) { + assert_eq!(Arith256::from_str(&format!("{r1}")).unwrap(), r1); + assert_eq!(Arith256::from_str(&format!("{:#x}", r1)).unwrap(), r1); + } + + #[rstest] + fn short_input_zero_extends() { + assert_eq!(Arith256::from_str("ff").unwrap(), Arith256::from_u64(0xff)); + } + + #[rstest] + fn rejects_over_long() { + let long = "0".repeat(66); + assert!(Arith256::from_str(&long).is_err()); + } +} diff --git a/pkgs/num/tests/compact.rs b/pkgs/num/tests/compact.rs index b26101aa..f90c3d17 100644 --- a/pkgs/num/tests/compact.rs +++ b/pkgs/num/tests/compact.rs @@ -6,10 +6,14 @@ //! Compact difficulty target encoding tests. +#![expect(clippy::unwrap_used, reason = "test code")] + use dash_num::{Arith256, CompactTarget}; use dash_types::Numeric; use rstest::*; +use core::str::FromStr; + /// Assert compact decode flags match expectations. fn check_compact(compact: u32, expected_negative: bool, expected_overflow: bool) { let ct = CompactTarget::new(compact).expand(); @@ -143,3 +147,28 @@ fn target_from_compact_ported(#[case] n_bits: u32, #[case] target: u64) { fn display() { assert_eq!(format!("{}", CompactTarget::new(0x1d00ffff)), "0x1d00ffff"); } + +#[rstest] +#[case("0x1d00ffff", 0x1d00_ffff)] +#[case("1d00ffff", 0x1d00_ffff)] +#[case("0X1D00FFFF", 0x1d00_ffff)] +#[case("1", 1)] +fn from_str_accepts(#[case] text: &str, #[case] want: u32) { + let parsed = CompactTarget::from_str(text).unwrap(); + assert_eq!(parsed, CompactTarget::new(want)); +} + +#[rstest] +#[case("")] +#[case("0x")] +#[case("1d00ffff0")] +#[case("1d00fffg")] +fn from_str_rejects(#[case] text: &str) { + assert!(CompactTarget::from_str(text).is_err()); +} + +#[rstest] +fn display_round_trips() { + let ct = CompactTarget::new(0x1d00_ffff); + assert_eq!(CompactTarget::from_str(&format!("{ct}")).unwrap(), ct); +} diff --git a/pkgs/num/tests/hash.rs b/pkgs/num/tests/hash.rs index 4654e8a5..63f65007 100644 --- a/pkgs/num/tests/hash.rs +++ b/pkgs/num/tests/hash.rs @@ -144,10 +144,19 @@ fn hash160_zero_and_null() { } #[rstest] -fn hash160_new_reverses() { +fn hash160_from_bendian_reverses() { let be = hex!("0102030405060708090a0b0c0d0e0f1011121314"); let h = Hash160::from_bendian(be); // new() reverses, so first byte in LE is last byte of BE input assert_eq!(h.to_lendian()[0], 0x14); assert_eq!(h.to_lendian()[19], 0x01); } + +#[rstest] +fn hex_formatting(r1_bytes: [u8; 32], r1_hex: &str) { + let h = Hash256::from_lendian(r1_bytes); + assert_eq!(format!("{h:x}"), r1_hex); + assert_eq!(format!("{h:X}"), r1_hex.to_uppercase()); + assert_eq!(format!("{h:#x}"), format!("0x{r1_hex}")); + assert_eq!(format!("{h:#X}"), format!("0X{}", r1_hex.to_uppercase())); +}