Merge rust-bitcoin/rust-bitcoin#1353: Enable formating of the `network` module

e04a7a926d network: Run cargo fmt (Tobin C. Harding)
dc33c7999f Enable formatting of the network module (Tobin C. Harding)
81f69e846b Exclude from formatting stuff in the network module (Tobin C. Harding)
408d7737fb Run cargo fmt (Tobin C. Harding)
1ecf09359b Add local variable to reduce line length (Tobin C. Harding)
b2e74bc050 Exclude long function call (Tobin C. Harding)
ff5a80dbd3 Exclude formatting of function fmt_satoshi_in (Tobin C. Harding)
308a12b7cf Exclude array from formatting (Tobin C. Harding)
fb7ff46ccc Improve crate root re-exports (Tobin C. Harding)

Pull request description:

  The `network` module is not currently included in formatting. Also, at this point in time not much is happening in the `network` module so formatting it should not cause too many merge conflicts with other in-progress PRs.

  The first 3 patches are formatting preparation of the repo, the next 2 are formatting preparation of the `network` module. The last patch is the result of running `cargo +nightly fmt`. Can one reviewer please verify the last patch consists only of `rustfmt` changes by running the command on their branch. Thanks

  cc luckysori :)

ACKs for top commit:
  apoelstra:
    ACK e04a7a926d

Tree-SHA512: 49b2873f0bfdd448df97073b462fa860c85b7f3c3094fdb0e16fd86aa467156ea8b2ceec61e2ee99848802cd171fd8abbc17e45c66672889a37c413fa4bea636
This commit is contained in:
Andrew Poelstra 2022-11-18 23:46:26 +00:00
commit 99a28db99d
No known key found for this signature in database
GPG Key ID: C588D63CE41B97C1
17 changed files with 1020 additions and 838 deletions

View File

@ -4,10 +4,10 @@ use std::str::FromStr;
use std::{env, process};
use bitcoin::address::Address;
use bitcoin::bip32::{ChildNumber, DerivationPath, ExtendedPrivKey, ExtendedPubKey};
use bitcoin::hashes::hex::FromHex;
use bitcoin::secp256k1::ffi::types::AlignedType;
use bitcoin::secp256k1::Secp256k1;
use bitcoin::bip32::{ChildNumber, DerivationPath, ExtendedPrivKey, ExtendedPubKey};
use bitcoin::PublicKey;
fn main() {

View File

@ -33,14 +33,14 @@ use std::collections::BTreeMap;
use std::fmt;
use std::str::FromStr;
use bitcoin::consensus::encode;
use bitcoin::hashes::hex::FromHex;
use bitcoin::locktime::absolute;
use bitcoin::secp256k1::{Secp256k1, Signing, Verification};
use bitcoin::bip32::{
ChildNumber, DerivationPath, ExtendedPrivKey, ExtendedPubKey, Fingerprint, IntoDerivationPath,
};
use bitcoin::consensus::encode;
use bitcoin::hashes::hex::FromHex;
use bitcoin::locktime::absolute;
use bitcoin::psbt::{self, Input, Psbt, PsbtSighashType};
use bitcoin::secp256k1::{Secp256k1, Signing, Verification};
use bitcoin::{
Address, Amount, Network, OutPoint, PublicKey, Script, Sequence, Transaction, TxIn, TxOut,
Txid, Witness,

View File

@ -78,6 +78,7 @@ const UTXO_3: P2trUtxo = P2trUtxo {
use std::collections::BTreeMap;
use std::str::FromStr;
use bitcoin::bip32::{ChildNumber, DerivationPath, ExtendedPrivKey, ExtendedPubKey, Fingerprint};
use bitcoin::consensus::encode;
use bitcoin::constants::COIN_VALUE;
use bitcoin::hashes::hex::FromHex;
@ -87,16 +88,13 @@ use bitcoin::psbt::serialize::Serialize;
use bitcoin::psbt::{self, Input, Output, Psbt, PsbtSighashType};
use bitcoin::schnorr::TapTweak;
use bitcoin::secp256k1::{Message, Secp256k1};
use bitcoin::bip32::{
ChildNumber, DerivationPath, ExtendedPrivKey, ExtendedPubKey, Fingerprint,
};
use bitcoin::sighash::{self, SighashCache, SchnorrSighashType};
use bitcoin::sighash::{self, SchnorrSighashType, SighashCache};
use bitcoin::util::taproot::{
LeafVersion, TapLeafHash, TapSighashHash, TaprootBuilder, TaprootSpendInfo,
};
use bitcoin::{
absolute, script, Address, Amount, OutPoint, SchnorrSig, Script,
Transaction, TxIn, TxOut, Txid, Witness, XOnlyPublicKey,
absolute, script, Address, Amount, OutPoint, SchnorrSig, Script, Transaction, TxIn, TxOut,
Txid, Witness, XOnlyPublicKey,
};
fn main() -> Result<(), Box<dyn std::error::Error>> {

View File

@ -34,9 +34,9 @@ use crate::blockdata::constants::{
MAX_SCRIPT_ELEMENT_SIZE, PUBKEY_ADDRESS_PREFIX_MAIN, PUBKEY_ADDRESS_PREFIX_TEST,
SCRIPT_ADDRESS_PREFIX_MAIN, SCRIPT_ADDRESS_PREFIX_TEST,
};
use crate::blockdata::opcodes::all::*;
use crate::blockdata::script::Instruction;
use crate::blockdata::{opcodes, script};
use crate::blockdata::opcodes::all::*;
use crate::error::ParseIntError;
use crate::hash_types::{PubkeyHash, ScriptHash};
use crate::hashes::{sha256, Hash, HashEngine};
@ -324,9 +324,7 @@ impl TryFrom<opcodes::All> for WitnessVersion {
fn try_from(opcode: opcodes::All) -> Result<Self, Self::Error> {
match opcode.to_u8() {
0 => Ok(WitnessVersion::V0),
version
if version >= OP_PUSHNUM_1.to_u8()
&& version <= OP_PUSHNUM_16.to_u8() =>
version if version >= OP_PUSHNUM_1.to_u8() && version <= OP_PUSHNUM_16.to_u8() =>
WitnessVersion::try_from(version - OP_PUSHNUM_1.to_u8() + 1),
_ => Err(Error::MalformedWitnessVersion),
}

View File

@ -6,10 +6,12 @@
//! We refer to the documentation on the types for more information.
//!
use crate::prelude::*;
use core::{ops, default, str::FromStr, cmp::Ordering};
use core::cmp::Ordering;
use core::fmt::{self, Write};
use core::str::FromStr;
use core::{default, ops};
use crate::prelude::*;
/// A set of denominations in which amounts can be expressed.
#[derive(Debug, Clone, Copy, Eq, PartialEq, Hash)]
@ -63,9 +65,7 @@ impl Denomination {
}
impl fmt::Display for Denomination {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
f.write_str(self.as_str())
}
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { f.write_str(self.as_str()) }
}
impl FromStr for Denomination {
@ -79,18 +79,17 @@ impl FromStr for Denomination {
///
/// Due to ambiguity between mega and milli, pico and peta we prohibit usage of leading capital 'M', 'P'.
fn from_str(s: &str) -> Result<Self, Self::Err> {
use self::ParseAmountError::*;
use self::Denomination as D;
use self::ParseAmountError::*;
let starts_with_uppercase = || s.starts_with(char::is_uppercase);
match denomination_from_str(s) {
None => Err(UnknownDenomination(s.to_owned())),
Some(D::MilliBitcoin) | Some(D::PicoBitcoin) | Some(D::MilliSatoshi) if starts_with_uppercase() => {
Err(PossiblyConfusingDenomination(s.to_owned()))
}
Some(D::NanoBitcoin) | Some(D::MicroBitcoin) if starts_with_uppercase() => {
Err(UnknownDenomination(s.to_owned()))
}
Some(D::MilliBitcoin) | Some(D::PicoBitcoin) | Some(D::MilliSatoshi)
if starts_with_uppercase() =>
Err(PossiblyConfusingDenomination(s.to_owned())),
Some(D::NanoBitcoin) | Some(D::MicroBitcoin) if starts_with_uppercase() =>
Err(UnknownDenomination(s.to_owned())),
Some(d) => Ok(d),
}
}
@ -157,7 +156,7 @@ pub enum ParseAmountError {
/// The denomination was unknown.
UnknownDenomination(String),
/// The denomination has multiple possible interpretations.
PossiblyConfusingDenomination(String)
PossiblyConfusingDenomination(String),
}
impl fmt::Display for ParseAmountError {
@ -169,7 +168,8 @@ impl fmt::Display for ParseAmountError {
ParseAmountError::InvalidFormat => f.write_str("invalid number format"),
ParseAmountError::InputTooLarge => f.write_str("input string was too large"),
ParseAmountError::InvalidCharacter(c) => write!(f, "invalid character in input: {}", c),
ParseAmountError::UnknownDenomination(ref d) => write!(f, "unknown denomination: {}", d),
ParseAmountError::UnknownDenomination(ref d) =>
write!(f, "unknown denomination: {}", d),
ParseAmountError::PossiblyConfusingDenomination(ref d) => {
let (letter, upper, lower) = match d.chars().next() {
Some('M') => ('M', "Mega", "milli"),
@ -191,13 +191,13 @@ impl std::error::Error for ParseAmountError {
match *self {
Negative
| TooBig
| TooPrecise
| InvalidFormat
| InputTooLarge
| InvalidCharacter(_)
| UnknownDenomination(_)
| PossiblyConfusingDenomination(_) => None
| TooBig
| TooPrecise
| InvalidFormat
| InputTooLarge
| InvalidCharacter(_)
| UnknownDenomination(_)
| PossiblyConfusingDenomination(_) => None,
}
}
}
@ -337,9 +337,7 @@ fn dec_width(mut num: u64) -> usize {
}
// NIH due to MSRV, impl copied from `core::i8::unsigned_abs` (introduced in Rust 1.51.1).
fn unsigned_abs(x: i8) -> u8 {
x.wrapping_abs() as u8
}
fn unsigned_abs(x: i8) -> u8 { x.wrapping_abs() as u8 }
fn repeat_char(f: &mut dyn fmt::Write, c: char, count: usize) -> fmt::Result {
for _ in 0..count {
@ -372,7 +370,7 @@ fn fmt_satoshi_in(
exp = precision as usize;
}
trailing_decimal_zeros = options.precision.unwrap_or(0);
},
}
Ordering::Less => {
let precision = unsigned_abs(precision);
let divisor = 10u64.pow(precision.into());
@ -391,7 +389,7 @@ fn fmt_satoshi_in(
// compute requested precision
let opt_precision = options.precision.unwrap_or(0);
trailing_decimal_zeros = opt_precision.saturating_sub(norm_nb_decimals);
},
}
Ordering::Equal => trailing_decimal_zeros = options.precision.unwrap_or(0),
}
let total_decimals = norm_nb_decimals + trailing_decimal_zeros;
@ -413,13 +411,15 @@ fn fmt_satoshi_in(
}
let width = options.width.unwrap_or(0);
let (left_pad, pad_right) = match (num_width < width, options.sign_aware_zero_pad, options.align.unwrap_or(fmt::Alignment::Right)) {
let align = options.align.unwrap_or(fmt::Alignment::Right);
let (left_pad, pad_right) = match (num_width < width, options.sign_aware_zero_pad, align) {
(false, _, _) => (0, 0),
// Alignment is always right (ignored) when zero-padding
(true, true, _) | (true, false, fmt::Alignment::Right) => (width - num_width, 0),
(true, false, fmt::Alignment::Left) => (0, width - num_width),
// If the required padding is odd it needs to be skewed to the left
(true, false, fmt::Alignment::Center) => ((width - num_width) / 2, (width - num_width + 1) / 2),
(true, false, fmt::Alignment::Center) =>
((width - num_width) / 2, (width - num_width + 1) / 2),
};
if !options.sign_aware_zero_pad {
@ -487,24 +487,16 @@ impl Amount {
pub const MAX_MONEY: Amount = Amount(21_000_000 * 100_000_000);
/// Create an [Amount] with satoshi precision and the given number of satoshis.
pub const fn from_sat(satoshi: u64) -> Amount {
Amount(satoshi)
}
pub const fn from_sat(satoshi: u64) -> Amount { Amount(satoshi) }
/// Gets the number of satoshis in this [`Amount`].
pub fn to_sat(self) -> u64 {
self.0
}
pub fn to_sat(self) -> u64 { self.0 }
/// The maximum value of an [Amount].
pub fn max_value() -> Amount {
Amount(u64::max_value())
}
pub fn max_value() -> Amount { Amount(u64::max_value()) }
/// The minimum value of an [Amount].
pub fn min_value() -> Amount {
Amount(u64::min_value())
}
pub fn min_value() -> Amount { Amount(u64::min_value()) }
/// Convert from a value expressing bitcoins to an [Amount].
pub fn from_btc(btc: f64) -> Result<Amount, ParseAmountError> {
@ -558,9 +550,7 @@ impl Amount {
/// let amount = Amount::from_sat(100_000);
/// assert_eq!(amount.to_btc(), amount.to_float_in(Denomination::Bitcoin))
/// ```
pub fn to_btc(self) -> f64 {
self.to_float_in(Denomination::Bitcoin)
}
pub fn to_btc(self) -> f64 { self.to_float_in(Denomination::Bitcoin) }
/// Convert this [Amount] in floating-point notation with a given
/// denomination.
@ -581,7 +571,7 @@ impl Amount {
Display {
sats_abs: self.to_sat(),
is_negative: false,
style: DisplayStyle::FixedDenomination { denomination, show_denomination: false, },
style: DisplayStyle::FixedDenomination { denomination, show_denomination: false },
}
}
@ -600,6 +590,7 @@ impl Amount {
/// Format the value of this [Amount] in the given denomination.
///
/// Does not include the denomination.
#[rustfmt::skip]
pub fn fmt_value_in(self, f: &mut dyn fmt::Write, denom: Denomination) -> fmt::Result {
fmt_satoshi_in(self.to_sat(), false, f, denom, false, FormatOptions::default())
}
@ -638,23 +629,17 @@ impl Amount {
/// Checked multiplication.
/// Returns [None] if overflow occurred.
pub fn checked_mul(self, rhs: u64) -> Option<Amount> {
self.0.checked_mul(rhs).map(Amount)
}
pub fn checked_mul(self, rhs: u64) -> Option<Amount> { self.0.checked_mul(rhs).map(Amount) }
/// Checked integer division.
/// Be aware that integer division loses the remainder if no exact division
/// can be made.
/// Returns [None] if overflow occurred.
pub fn checked_div(self, rhs: u64) -> Option<Amount> {
self.0.checked_div(rhs).map(Amount)
}
pub fn checked_div(self, rhs: u64) -> Option<Amount> { self.0.checked_div(rhs).map(Amount) }
/// Checked remainder.
/// Returns [None] if overflow occurred.
pub fn checked_rem(self, rhs: u64) -> Option<Amount> {
self.0.checked_rem(rhs).map(Amount)
}
pub fn checked_rem(self, rhs: u64) -> Option<Amount> { self.0.checked_rem(rhs).map(Amount) }
/// Convert to a signed amount.
pub fn to_signed(self) -> Result<SignedAmount, ParseAmountError> {
@ -667,9 +652,7 @@ impl Amount {
}
impl default::Default for Amount {
fn default() -> Self {
Amount::ZERO
}
fn default() -> Self { Amount::ZERO }
}
impl fmt::Debug for Amount {
@ -696,9 +679,7 @@ impl ops::Add for Amount {
}
impl ops::AddAssign for Amount {
fn add_assign(&mut self, other: Amount) {
*self = *self + other
}
fn add_assign(&mut self, other: Amount) { *self = *self + other }
}
impl ops::Sub for Amount {
@ -710,9 +691,7 @@ impl ops::Sub for Amount {
}
impl ops::SubAssign for Amount {
fn sub_assign(&mut self, other: Amount) {
*self = *self - other
}
fn sub_assign(&mut self, other: Amount) { *self = *self - other }
}
impl ops::Rem<u64> for Amount {
@ -724,9 +703,7 @@ impl ops::Rem<u64> for Amount {
}
impl ops::RemAssign<u64> for Amount {
fn rem_assign(&mut self, modulus: u64) {
*self = *self % modulus
}
fn rem_assign(&mut self, modulus: u64) { *self = *self % modulus }
}
impl ops::Mul<u64> for Amount {
@ -738,31 +715,23 @@ impl ops::Mul<u64> for Amount {
}
impl ops::MulAssign<u64> for Amount {
fn mul_assign(&mut self, rhs: u64) {
*self = *self * rhs
}
fn mul_assign(&mut self, rhs: u64) { *self = *self * rhs }
}
impl ops::Div<u64> for Amount {
type Output = Amount;
fn div(self, rhs: u64) -> Self::Output {
self.checked_div(rhs).expect("Amount division error")
}
fn div(self, rhs: u64) -> Self::Output { self.checked_div(rhs).expect("Amount division error") }
}
impl ops::DivAssign<u64> for Amount {
fn div_assign(&mut self, rhs: u64) {
*self = *self / rhs
}
fn div_assign(&mut self, rhs: u64) { *self = *self / rhs }
}
impl FromStr for Amount {
type Err = ParseAmountError;
fn from_str(s: &str) -> Result<Self, Self::Err> {
Amount::from_str_with_denomination(s)
}
fn from_str(s: &str) -> Result<Self, Self::Err> { Amount::from_str_with_denomination(s) }
}
impl core::iter::Sum for Amount {
@ -808,10 +777,13 @@ impl Display {
}
impl fmt::Display for Display {
#[rustfmt::skip]
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
let format_options = FormatOptions::from_formatter(f);
match &self.style {
DisplayStyle::FixedDenomination { show_denomination, denomination } => fmt_satoshi_in(self.sats_abs, self.is_negative, f, *denomination, *show_denomination, format_options),
DisplayStyle::FixedDenomination { show_denomination, denomination } => {
fmt_satoshi_in(self.sats_abs, self.is_negative, f, *denomination, *show_denomination, format_options)
},
DisplayStyle::DynamicDenomination if self.sats_abs >= Amount::ONE_BTC.to_sat() => {
fmt_satoshi_in(self.sats_abs, self.is_negative, f, Denomination::Bitcoin, true, format_options)
},
@ -824,7 +796,7 @@ impl fmt::Display for Display {
#[derive(Clone, Debug)]
enum DisplayStyle {
FixedDenomination { denomination: Denomination, show_denomination: bool, },
FixedDenomination { denomination: Denomination, show_denomination: bool },
DynamicDenomination,
}
@ -856,24 +828,16 @@ impl SignedAmount {
pub const MAX_MONEY: SignedAmount = SignedAmount(21_000_000 * 100_000_000);
/// Create an [SignedAmount] with satoshi precision and the given number of satoshis.
pub const fn from_sat(satoshi: i64) -> SignedAmount {
SignedAmount(satoshi)
}
pub const fn from_sat(satoshi: i64) -> SignedAmount { SignedAmount(satoshi) }
/// Gets the number of satoshis in this [`SignedAmount`].
pub fn to_sat(self) -> i64 {
self.0
}
pub fn to_sat(self) -> i64 { self.0 }
/// The maximum value of an [SignedAmount].
pub fn max_value() -> SignedAmount {
SignedAmount(i64::max_value())
}
pub fn max_value() -> SignedAmount { SignedAmount(i64::max_value()) }
/// The minimum value of an [SignedAmount].
pub fn min_value() -> SignedAmount {
SignedAmount(i64::min_value())
}
pub fn min_value() -> SignedAmount { SignedAmount(i64::min_value()) }
/// Convert from a value expressing bitcoins to an [SignedAmount].
pub fn from_btc(btc: f64) -> Result<SignedAmount, ParseAmountError> {
@ -922,9 +886,7 @@ impl SignedAmount {
/// Equivalent to `to_float_in(Denomination::Bitcoin)`.
///
/// Please be aware of the risk of using floating-point numbers.
pub fn to_btc(self) -> f64 {
self.to_float_in(Denomination::Bitcoin)
}
pub fn to_btc(self) -> f64 { self.to_float_in(Denomination::Bitcoin) }
/// Convert this [SignedAmount] in floating-point notation with a given
/// denomination.
@ -943,16 +905,14 @@ impl SignedAmount {
/// Returns the absolute value as satoshis.
///
/// This is the implementation of `unsigned_abs()` copied from `core` to support older MSRV.
fn to_sat_abs(self) -> u64 {
self.to_sat().wrapping_abs() as u64
}
fn to_sat_abs(self) -> u64 { self.to_sat().wrapping_abs() as u64 }
/// Create an object that implements [`fmt::Display`] using specified denomination.
pub fn display_in(self, denomination: Denomination) -> Display {
Display {
sats_abs: self.to_sat_abs(),
is_negative: self.is_negative(),
style: DisplayStyle::FixedDenomination { denomination, show_denomination: false, },
style: DisplayStyle::FixedDenomination { denomination, show_denomination: false },
}
}
@ -971,8 +931,8 @@ impl SignedAmount {
/// Format the value of this [SignedAmount] in the given denomination.
///
/// Does not include the denomination.
#[rustfmt::skip]
pub fn fmt_value_in(self, f: &mut dyn fmt::Write, denom: Denomination) -> fmt::Result {
fmt_satoshi_in(self.to_sat_abs(), self.is_negative(), f, denom, false, FormatOptions::default())
}
@ -997,37 +957,26 @@ impl SignedAmount {
// Some arithmetic that doesn't fit in `core::ops` traits.
/// Get the absolute value of this [SignedAmount].
pub fn abs(self) -> SignedAmount {
SignedAmount(self.0.abs())
}
pub fn abs(self) -> SignedAmount { SignedAmount(self.0.abs()) }
/// Returns a number representing sign of this [SignedAmount].
///
/// - `0` if the amount is zero
/// - `1` if the amount is positive
/// - `-1` if the amount is negative
pub fn signum(self) -> i64 {
self.0.signum()
}
pub fn signum(self) -> i64 { self.0.signum() }
/// Returns `true` if this [SignedAmount] is positive and `false` if
/// this [SignedAmount] is zero or negative.
pub fn is_positive(self) -> bool {
self.0.is_positive()
}
pub fn is_positive(self) -> bool { self.0.is_positive() }
/// Returns `true` if this [SignedAmount] is negative and `false` if
/// this [SignedAmount] is zero or positive.
pub fn is_negative(self) -> bool {
self.0.is_negative()
}
pub fn is_negative(self) -> bool { self.0.is_negative() }
/// Get the absolute value of this [SignedAmount].
/// Returns [None] if overflow occurred. (`self == min_value()`)
pub fn checked_abs(self) -> Option<SignedAmount> {
self.0.checked_abs().map(SignedAmount)
}
pub fn checked_abs(self) -> Option<SignedAmount> { self.0.checked_abs().map(SignedAmount) }
/// Checked addition.
/// Returns [None] if overflow occurred.
@ -1082,9 +1031,7 @@ impl SignedAmount {
}
impl default::Default for SignedAmount {
fn default() -> Self {
SignedAmount::ZERO
}
fn default() -> Self { SignedAmount::ZERO }
}
impl fmt::Debug for SignedAmount {
@ -1111,9 +1058,7 @@ impl ops::Add for SignedAmount {
}
impl ops::AddAssign for SignedAmount {
fn add_assign(&mut self, other: SignedAmount) {
*self = *self + other
}
fn add_assign(&mut self, other: SignedAmount) { *self = *self + other }
}
impl ops::Sub for SignedAmount {
@ -1125,9 +1070,7 @@ impl ops::Sub for SignedAmount {
}
impl ops::SubAssign for SignedAmount {
fn sub_assign(&mut self, other: SignedAmount) {
*self = *self - other
}
fn sub_assign(&mut self, other: SignedAmount) { *self = *self - other }
}
impl ops::Rem<i64> for SignedAmount {
@ -1139,9 +1082,7 @@ impl ops::Rem<i64> for SignedAmount {
}
impl ops::RemAssign<i64> for SignedAmount {
fn rem_assign(&mut self, modulus: i64) {
*self = *self % modulus
}
fn rem_assign(&mut self, modulus: i64) { *self = *self % modulus }
}
impl ops::Mul<i64> for SignedAmount {
@ -1153,9 +1094,7 @@ impl ops::Mul<i64> for SignedAmount {
}
impl ops::MulAssign<i64> for SignedAmount {
fn mul_assign(&mut self, rhs: i64) {
*self = *self * rhs
}
fn mul_assign(&mut self, rhs: i64) { *self = *self * rhs }
}
impl ops::Div<i64> for SignedAmount {
@ -1167,17 +1106,13 @@ impl ops::Div<i64> for SignedAmount {
}
impl ops::DivAssign<i64> for SignedAmount {
fn div_assign(&mut self, rhs: i64) {
*self = *self / rhs
}
fn div_assign(&mut self, rhs: i64) { *self = *self / rhs }
}
impl FromStr for SignedAmount {
type Err = ParseAmountError;
fn from_str(s: &str) -> Result<Self, Self::Err> {
SignedAmount::from_str_with_denomination(s)
}
fn from_str(s: &str) -> Result<Self, Self::Err> { SignedAmount::from_str_with_denomination(s) }
}
impl core::iter::Sum for SignedAmount {
@ -1194,18 +1129,21 @@ pub trait CheckedSum<R>: private::SumSeal<R> {
fn checked_sum(self) -> Option<R>;
}
impl<T> CheckedSum<Amount> for T where T: Iterator<Item=Amount> {
impl<T> CheckedSum<Amount> for T
where
T: Iterator<Item = Amount>,
{
fn checked_sum(mut self) -> Option<Amount> {
let first = Some(self.next().unwrap_or_default());
self.fold(
first,
|acc, item| acc.and_then(|acc| acc.checked_add(item))
)
self.fold(first, |acc, item| acc.and_then(|acc| acc.checked_add(item)))
}
}
impl<T> CheckedSum<SignedAmount> for T where T: Iterator<Item=SignedAmount> {
impl<T> CheckedSum<SignedAmount> for T
where
T: Iterator<Item = SignedAmount>,
{
fn checked_sum(mut self) -> Option<SignedAmount> {
let first = Some(self.next().unwrap_or_default());
@ -1219,8 +1157,8 @@ mod private {
/// Used to seal the `CheckedSum` trait
pub trait SumSeal<A> {}
impl<T> SumSeal<Amount> for T where T: Iterator<Item=Amount> {}
impl<T> SumSeal<SignedAmount> for T where T: Iterator<Item=SignedAmount> {}
impl<T> SumSeal<Amount> for T where T: Iterator<Item = Amount> {}
impl<T> SumSeal<SignedAmount> for T where T: Iterator<Item = SignedAmount> {}
}
#[cfg(feature = "serde")]
@ -1247,6 +1185,7 @@ pub mod serde {
//! ```
use serde::{Deserialize, Deserializer, Serialize, Serializer};
use crate::amount::{Amount, Denomination, SignedAmount};
/// This trait is used only to avoid code duplication and naming collisions
@ -1290,9 +1229,7 @@ pub mod serde {
}
impl SerdeAmountForOpt for Amount {
fn type_prefix() -> &'static str {
"u"
}
fn type_prefix() -> &'static str { "u" }
fn ser_sat_opt<S: Serializer>(self, s: S) -> Result<S::Ok, S::Error> {
s.serialize_some(&self.to_sat())
}
@ -1318,9 +1255,7 @@ pub mod serde {
}
impl SerdeAmountForOpt for SignedAmount {
fn type_prefix() -> &'static str {
"i"
}
fn type_prefix() -> &'static str { "i" }
fn ser_sat_opt<S: Serializer>(self, s: S) -> Result<S::Ok, S::Error> {
s.serialize_some(&self.to_sat())
}
@ -1334,6 +1269,7 @@ pub mod serde {
//! Use with `#[serde(with = "amount::serde::as_sat")]`.
use serde::{Deserializer, Serializer};
use crate::amount::serde::SerdeAmount;
pub fn serialize<A: SerdeAmount, S: Serializer>(a: &A, s: S) -> Result<S::Ok, S::Error> {
@ -1348,11 +1284,13 @@ pub mod serde {
//! Serialize and deserialize [`Option<Amount>`](crate::Amount) as real numbers denominated in satoshi.
//! Use with `#[serde(default, with = "amount::serde::as_sat::opt")]`.
use serde::{Deserializer, Serializer, de};
use crate::amount::serde::SerdeAmountForOpt;
use core::fmt;
use core::marker::PhantomData;
use serde::{de, Deserializer, Serializer};
use crate::amount::serde::SerdeAmountForOpt;
pub fn serialize<A: SerdeAmountForOpt, S: Serializer>(
a: &Option<A>,
s: S,
@ -1398,6 +1336,7 @@ pub mod serde {
//! Use with `#[serde(with = "amount::serde::as_btc")]`.
use serde::{Deserializer, Serializer};
use crate::amount::serde::SerdeAmount;
pub fn serialize<A: SerdeAmount, S: Serializer>(a: &A, s: S) -> Result<S::Ok, S::Error> {
@ -1412,11 +1351,13 @@ pub mod serde {
//! Serialize and deserialize [Option<Amount>] as JSON numbers denominated in BTC.
//! Use with `#[serde(default, with = "amount::serde::as_btc::opt")]`.
use serde::{Deserializer, Serializer, de};
use crate::amount::serde::SerdeAmountForOpt;
use core::fmt;
use core::marker::PhantomData;
use serde::{de, Deserializer, Serializer};
use crate::amount::serde::SerdeAmountForOpt;
pub fn serialize<A: SerdeAmountForOpt, S: Serializer>(
a: &Option<A>,
s: S,
@ -1460,14 +1401,15 @@ pub mod serde {
#[cfg(test)]
mod tests {
use super::*;
use core::str::FromStr;
#[cfg(feature = "std")]
use std::panic;
use core::str::FromStr;
#[cfg(feature = "serde")]
use serde_test;
use super::*;
#[test]
fn add_sub_mul_div() {
let sat = Amount::from_sat;
@ -1608,13 +1550,22 @@ mod tests {
// make sure satoshi > i64::max_value() is checked.
let amount = Amount::from_sat(i64::max_value() as u64);
assert_eq!(Amount::from_str_in(&amount.to_string_in(sat), sat), Ok(amount));
assert_eq!(Amount::from_str_in(&(amount+Amount(1)).to_string_in(sat), sat), Err(E::TooBig));
assert_eq!(
Amount::from_str_in(&(amount + Amount(1)).to_string_in(sat), sat),
Err(E::TooBig)
);
assert_eq!(p("12.000", Denomination::MilliSatoshi), Err(E::TooPrecise));
// exactly 50 chars.
assert_eq!(p("100000000000000.0000000000000000000000000000000000", Denomination::Bitcoin), Err(E::TooBig));
assert_eq!(
p("100000000000000.0000000000000000000000000000000000", Denomination::Bitcoin),
Err(E::TooBig)
);
// more than 50 chars.
assert_eq!(p("100000000000000.00000000000000000000000000000000000", Denomination::Bitcoin), Err(E::InputTooLarge));
assert_eq!(
p("100000000000000.00000000000000000000000000000000000", Denomination::Bitcoin),
Err(E::InputTooLarge)
);
}
#[test]
@ -1829,9 +1780,9 @@ mod tests {
let ua = Amount::from_sat;
assert_eq!(Amount::max_value().to_signed(), Err(E::TooBig));
assert_eq!(ua(i64::max_value() as u64).to_signed(), Ok(sa(i64::max_value())));
assert_eq!(ua(i64::max_value() as u64).to_signed(), Ok(sa(i64::max_value())));
assert_eq!(ua(0).to_signed(), Ok(sa(0)));
assert_eq!(ua(1).to_signed(), Ok( sa(1)));
assert_eq!(ua(1).to_signed(), Ok(sa(1)));
assert_eq!(ua(1).to_signed(), Ok(sa(1)));
assert_eq!(ua(i64::max_value() as u64 + 1).to_signed(), Err(E::TooBig));
@ -1840,7 +1791,10 @@ mod tests {
assert_eq!(sa(0).to_unsigned().unwrap().to_signed(), Ok(sa(0)));
assert_eq!(sa(1).to_unsigned().unwrap().to_signed(), Ok(sa(1)));
assert_eq!(sa(i64::max_value()).to_unsigned().unwrap().to_signed(), Ok(sa(i64::max_value())));
assert_eq!(
sa(i64::max_value()).to_unsigned().unwrap().to_signed(),
Ok(sa(i64::max_value()))
);
}
#[test]
@ -1902,34 +1856,73 @@ mod tests {
assert_eq!("2535830000", Amount::from_sat(253583).to_string_in(D::PicoBitcoin));
assert_eq!("-100000000", SignedAmount::from_sat(-10_000).to_string_in(D::PicoBitcoin));
assert_eq!("0.50", format!("{:.2}", Amount::from_sat(50).display_in(D::Bit)));
assert_eq!("-0.50", format!("{:.2}", SignedAmount::from_sat(-50).display_in(D::Bit)));
assert_eq!("0.10000000", format!("{:.8}", Amount::from_sat(100_000_00).display_in(D::Bitcoin)));
assert_eq!(
"0.10000000",
format!("{:.8}", Amount::from_sat(100_000_00).display_in(D::Bitcoin))
);
assert_eq!("-100.00", format!("{:.2}", SignedAmount::from_sat(-10_000).display_in(D::Bit)));
assert_eq!(ua_str(&ua_sat(0).to_string_in(D::Satoshi), D::Satoshi), Ok(ua_sat(0)));
assert_eq!(ua_str(&ua_sat(500).to_string_in(D::Bitcoin), D::Bitcoin), Ok(ua_sat(500)));
assert_eq!(ua_str(&ua_sat(21_000_000).to_string_in(D::Bit), D::Bit), Ok(ua_sat(21_000_000)));
assert_eq!(ua_str(&ua_sat(1).to_string_in(D::MicroBitcoin), D::MicroBitcoin), Ok(ua_sat(1)));
assert_eq!(ua_str(&ua_sat(1_000_000_000_000).to_string_in(D::MilliBitcoin), D::MilliBitcoin), Ok(ua_sat(1_000_000_000_000)));
assert_eq!(ua_str(&ua_sat(u64::max_value()).to_string_in(D::MilliBitcoin), D::MilliBitcoin), Err(ParseAmountError::TooBig));
assert_eq!(
ua_str(&ua_sat(21_000_000).to_string_in(D::Bit), D::Bit),
Ok(ua_sat(21_000_000))
);
assert_eq!(
ua_str(&ua_sat(1).to_string_in(D::MicroBitcoin), D::MicroBitcoin),
Ok(ua_sat(1))
);
assert_eq!(
ua_str(&ua_sat(1_000_000_000_000).to_string_in(D::MilliBitcoin), D::MilliBitcoin),
Ok(ua_sat(1_000_000_000_000))
);
assert_eq!(
ua_str(&ua_sat(u64::max_value()).to_string_in(D::MilliBitcoin), D::MilliBitcoin),
Err(ParseAmountError::TooBig)
);
assert_eq!(sa_str(&sa_sat(-1).to_string_in(D::MicroBitcoin), D::MicroBitcoin), Ok(sa_sat(-1)));
assert_eq!(
sa_str(&sa_sat(-1).to_string_in(D::MicroBitcoin), D::MicroBitcoin),
Ok(sa_sat(-1))
);
assert_eq!(sa_str(&sa_sat(i64::max_value()).to_string_in(D::Satoshi), D::MicroBitcoin), Err(ParseAmountError::TooBig));
assert_eq!(
sa_str(&sa_sat(i64::max_value()).to_string_in(D::Satoshi), D::MicroBitcoin),
Err(ParseAmountError::TooBig)
);
// Test an overflow bug in `abs()`
assert_eq!(sa_str(&sa_sat(i64::min_value()).to_string_in(D::Satoshi), D::MicroBitcoin), Err(ParseAmountError::TooBig));
assert_eq!(sa_str(&sa_sat(-1).to_string_in(D::NanoBitcoin), D::NanoBitcoin), Ok(sa_sat(-1)));
assert_eq!(sa_str(&sa_sat(i64::max_value()).to_string_in(D::Satoshi), D::NanoBitcoin), Err(ParseAmountError::TooPrecise));
assert_eq!(sa_str(&sa_sat(i64::min_value()).to_string_in(D::Satoshi), D::NanoBitcoin), Err(ParseAmountError::TooPrecise));
assert_eq!(sa_str(&sa_sat(-1).to_string_in(D::PicoBitcoin), D::PicoBitcoin), Ok(sa_sat(-1)));
assert_eq!(sa_str(&sa_sat(i64::max_value()).to_string_in(D::Satoshi), D::PicoBitcoin), Err(ParseAmountError::TooPrecise));
assert_eq!(sa_str(&sa_sat(i64::min_value()).to_string_in(D::Satoshi), D::PicoBitcoin), Err(ParseAmountError::TooPrecise));
assert_eq!(
sa_str(&sa_sat(i64::min_value()).to_string_in(D::Satoshi), D::MicroBitcoin),
Err(ParseAmountError::TooBig)
);
assert_eq!(
sa_str(&sa_sat(-1).to_string_in(D::NanoBitcoin), D::NanoBitcoin),
Ok(sa_sat(-1))
);
assert_eq!(
sa_str(&sa_sat(i64::max_value()).to_string_in(D::Satoshi), D::NanoBitcoin),
Err(ParseAmountError::TooPrecise)
);
assert_eq!(
sa_str(&sa_sat(i64::min_value()).to_string_in(D::Satoshi), D::NanoBitcoin),
Err(ParseAmountError::TooPrecise)
);
assert_eq!(
sa_str(&sa_sat(-1).to_string_in(D::PicoBitcoin), D::PicoBitcoin),
Ok(sa_sat(-1))
);
assert_eq!(
sa_str(&sa_sat(i64::max_value()).to_string_in(D::Satoshi), D::PicoBitcoin),
Err(ParseAmountError::TooPrecise)
);
assert_eq!(
sa_str(&sa_sat(i64::min_value()).to_string_in(D::Satoshi), D::PicoBitcoin),
Err(ParseAmountError::TooPrecise)
);
}
#[test]
@ -1953,7 +1946,6 @@ mod tests {
#[cfg(feature = "serde")]
#[test]
fn serde_as_sat() {
#[derive(Serialize, Deserialize, PartialEq, Debug)]
#[serde(crate = "actual_serde")]
struct T {
@ -1964,10 +1956,7 @@ mod tests {
}
serde_test::assert_tokens(
&T {
amt: Amount::from_sat(123456789),
samt: SignedAmount::from_sat(-123456789),
},
&T { amt: Amount::from_sat(123456789), samt: SignedAmount::from_sat(-123456789) },
&[
serde_test::Token::Struct { name: "T", len: 2 },
serde_test::Token::Str("amt"),
@ -2034,15 +2023,12 @@ mod tests {
amt: Some(Amount::from_sat(2_500_000_00)),
samt: Some(SignedAmount::from_sat(-2_500_000_00)),
};
let without = T {
amt: None,
samt: None,
};
let without = T { amt: None, samt: None };
// Test Roundtripping
for s in [&with, &without].iter() {
let v = serde_json::to_string(s).unwrap();
let w : T = serde_json::from_str(&v).unwrap();
let w: T = serde_json::from_str(&v).unwrap();
assert_eq!(w, **s);
}
@ -2079,15 +2065,12 @@ mod tests {
amt: Some(Amount::from_sat(2_500_000_00)),
samt: Some(SignedAmount::from_sat(-2_500_000_00)),
};
let without = T {
amt: None,
samt: None,
};
let without = T { amt: None, samt: None };
// Test Roundtripping
for s in [&with, &without].iter() {
let v = serde_json::to_string(s).unwrap();
let w : T = serde_json::from_str(&v).unwrap();
let w: T = serde_json::from_str(&v).unwrap();
assert_eq!(w, **s);
}
@ -2110,18 +2093,14 @@ mod tests {
assert_eq!(Amount::from_sat(0), vec![].into_iter().sum::<Amount>());
assert_eq!(SignedAmount::from_sat(0), vec![].into_iter().sum::<SignedAmount>());
let amounts = vec![
Amount::from_sat(42),
Amount::from_sat(1337),
Amount::from_sat(21)
];
let amounts = vec![Amount::from_sat(42), Amount::from_sat(1337), Amount::from_sat(21)];
let sum = amounts.into_iter().sum::<Amount>();
assert_eq!(Amount::from_sat(1400), sum);
let amounts = vec![
SignedAmount::from_sat(-42),
SignedAmount::from_sat(1337),
SignedAmount::from_sat(21)
SignedAmount::from_sat(21),
];
let sum = amounts.into_iter().sum::<SignedAmount>();
assert_eq!(SignedAmount::from_sat(1316), sum);
@ -2132,26 +2111,19 @@ mod tests {
assert_eq!(Some(Amount::from_sat(0)), vec![].into_iter().checked_sum());
assert_eq!(Some(SignedAmount::from_sat(0)), vec![].into_iter().checked_sum());
let amounts = vec![
Amount::from_sat(42),
Amount::from_sat(1337),
Amount::from_sat(21)
];
let amounts = vec![Amount::from_sat(42), Amount::from_sat(1337), Amount::from_sat(21)];
let sum = amounts.into_iter().checked_sum();
assert_eq!(Some(Amount::from_sat(1400)), sum);
let amounts = vec![
Amount::from_sat(u64::max_value()),
Amount::from_sat(1337),
Amount::from_sat(21)
];
let amounts =
vec![Amount::from_sat(u64::max_value()), Amount::from_sat(1337), Amount::from_sat(21)];
let sum = amounts.into_iter().checked_sum();
assert_eq!(None, sum);
let amounts = vec![
SignedAmount::from_sat(i64::min_value()),
SignedAmount::from_sat(-1),
SignedAmount::from_sat(21)
SignedAmount::from_sat(21),
];
let sum = amounts.into_iter().checked_sum();
assert_eq!(None, sum);
@ -2159,7 +2131,7 @@ mod tests {
let amounts = vec![
SignedAmount::from_sat(i64::max_value()),
SignedAmount::from_sat(1),
SignedAmount::from_sat(21)
SignedAmount::from_sat(21),
];
let sum = amounts.into_iter().checked_sum();
assert_eq!(None, sum);
@ -2167,7 +2139,7 @@ mod tests {
let amounts = vec![
SignedAmount::from_sat(42),
SignedAmount::from_sat(3301),
SignedAmount::from_sat(21)
SignedAmount::from_sat(21),
];
let sum = amounts.into_iter().checked_sum();
assert_eq!(Some(SignedAmount::from_sat(3364)), sum);
@ -2176,7 +2148,10 @@ mod tests {
#[test]
fn denomination_string_acceptable_forms() {
// Non-exhaustive list of valid forms.
let valid = vec!["BTC", "btc", "mBTC", "mbtc", "uBTC", "ubtc", "SATOSHI","Satoshi", "Satoshis", "satoshis", "SAT", "Sat", "sats", "bit", "bits", "nBTC", "pBTC"];
let valid = vec![
"BTC", "btc", "mBTC", "mbtc", "uBTC", "ubtc", "SATOSHI", "Satoshi", "Satoshis",
"satoshis", "SAT", "Sat", "sats", "bit", "bits", "nBTC", "pBTC",
];
for denom in valid.iter() {
assert!(Denomination::from_str(denom).is_ok());
}
@ -2185,11 +2160,12 @@ mod tests {
#[test]
fn disallow_confusing_forms() {
// Non-exhaustive list of confusing forms.
let confusing = vec!["Msat", "Msats", "MSAT", "MSATS", "MSat", "MSats", "MBTC", "Mbtc", "PBTC"];
let confusing =
vec!["Msat", "Msats", "MSAT", "MSATS", "MSat", "MSats", "MBTC", "Mbtc", "PBTC"];
for denom in confusing.iter() {
match Denomination::from_str(denom) {
match Denomination::from_str(denom) {
Ok(_) => panic!("from_str should error for {}", denom),
Err(ParseAmountError::PossiblyConfusingDenomination(_)) => {},
Err(ParseAmountError::PossiblyConfusingDenomination(_)) => {}
Err(e) => panic!("unexpected error: {}", e),
}
}
@ -2200,9 +2176,9 @@ mod tests {
// Non-exhaustive list of unknown forms.
let unknown = vec!["NBTC", "UBTC", "ABC", "abc"];
for denom in unknown.iter() {
match Denomination::from_str(denom) {
match Denomination::from_str(denom) {
Ok(_) => panic!("from_str should error for {}", denom),
Err(ParseAmountError::UnknownDenomination(_)) => {},
Err(ParseAmountError::UnknownDenomination(_)) => {}
Err(e) => panic!("unexpected error: {}", e),
}
}

View File

@ -16,7 +16,7 @@ use crate::consensus::encode::{self, Decodable, Encodable, VarInt};
use crate::hashes::{sha256, siphash24, Hash};
use crate::internal_macros::{impl_bytes_newtype, impl_consensus_encoding};
use crate::prelude::*;
use crate::{io, block, Block, BlockHash, Transaction};
use crate::{block, io, Block, BlockHash, Transaction};
/// A BIP-152 error
#[derive(Clone, PartialEq, Eq, Debug, Copy, PartialOrd, Ord, Hash)]
@ -111,7 +111,10 @@ impl ShortId {
// 2. Running SipHash-2-4 with the input being the transaction ID and the keys (k0/k1)
// set to the first two little-endian 64-bit integers from the above hash, respectively.
(u64::from_le_bytes(h[0..8].try_into().expect("8 byte slice")), u64::from_le_bytes(h[8..16].try_into().expect("8 byte slice")))
(
u64::from_le_bytes(h[0..8].try_into().expect("8 byte slice")),
u64::from_le_bytes(h[8..16].try_into().expect("8 byte slice")),
)
}
/// Calculate the short ID with the given (w)txid and using the provided SipHash keys.
@ -374,8 +377,8 @@ mod test {
use crate::consensus::encode::{deserialize, serialize};
use crate::hashes::hex::FromHex;
use crate::{
CompactTarget, OutPoint, Script, Sequence,
Transaction, TxIn, TxMerkleNode, TxOut, Txid, Witness,
CompactTarget, OutPoint, Script, Sequence, Transaction, TxIn, TxMerkleNode, TxOut, Txid,
Witness,
};
fn dummy_tx(nonce: &[u8]) -> Transaction {

View File

@ -63,20 +63,18 @@ extern crate test;
#[macro_use]
extern crate alloc;
// Re-export dependencies we control.
#[cfg(feature = "bitcoinconsensus")]
pub use bitcoinconsensus;
pub use {bech32, bitcoin_hashes as hashes, secp256k1};
// Re-export base64 when enabled
#[cfg(feature = "base64")]
#[cfg_attr(docsrs, doc(cfg(feature = "base64")))]
pub use base64;
// Re-export hashbrown when enabled
pub extern crate base64;
pub extern crate bech32;
pub extern crate bitcoin_hashes as hashes;
#[cfg(feature = "bitcoinconsensus")]
#[cfg_attr(docsrs, doc(cfg(feature = "bitcoinconsensus")))]
pub extern crate bitcoinconsensus;
#[cfg(feature = "hashbrown")]
#[cfg_attr(docsrs, doc(cfg(feature = "hashbrown")))]
pub use hashbrown;
pub extern crate hashbrown;
pub extern crate secp256k1;
#[cfg(feature = "serde")]
#[macro_use]
@ -116,6 +114,7 @@ use std::io;
use core2::io;
pub use crate::address::{Address, AddressType};
pub use crate::amount::{Amount, Denomination, SignedAmount};
pub use crate::blockdata::block::{self, Block};
pub use crate::blockdata::locktime::{self, absolute, relative};
pub use crate::blockdata::script::{self, Script};
@ -125,12 +124,11 @@ pub use crate::blockdata::{constants, opcodes};
pub use crate::consensus::encode::VarInt;
pub use crate::error::Error;
pub use crate::hash_types::*;
pub use crate::merkle_tree::MerkleBlock;
pub use crate::network::constants::Network;
pub use crate::pow::{CompactTarget, Target, Work};
pub use crate::amount::{Amount, Denomination, SignedAmount};
pub use crate::util::ecdsa::{self, EcdsaSig, EcdsaSigError};
pub use crate::util::key::{KeyPair, PrivateKey, PublicKey, XOnlyPublicKey};
pub use crate::merkle_tree::MerkleBlock;
pub use crate::util::schnorr::{self, SchnorrSig, SchnorrSigError};
#[cfg(not(feature = "std"))]

View File

@ -7,14 +7,13 @@
//! network addresses in Bitcoin messages.
//!
use crate::prelude::*;
use core::{fmt, iter};
use std::net::{SocketAddr, Ipv6Addr, SocketAddrV4, SocketAddrV6, Ipv4Addr, ToSocketAddrs};
use std::net::{Ipv4Addr, Ipv6Addr, SocketAddr, SocketAddrV4, SocketAddrV6, ToSocketAddrs};
use crate::consensus::encode::{self, Decodable, Encodable, ReadExt, VarInt, WriteExt};
use crate::io;
use crate::network::constants::ServiceFlags;
use crate::consensus::encode::{self, Decodable, Encodable, VarInt, ReadExt, WriteExt};
use crate::prelude::*;
/// A message which can be sent on the Bitcoin network
#[derive(Clone, PartialEq, Eq, Hash)]
@ -24,17 +23,17 @@ pub struct Address {
/// Network byte-order ipv6 address, or ipv4-mapped ipv6 address
pub address: [u16; 8],
/// Network port
pub port: u16
pub port: u16,
}
const ONION: [u16; 3] = [0xFD87, 0xD87E, 0xEB43];
impl Address {
/// Create an address message for a socket
pub fn new(socket :&SocketAddr, services: ServiceFlags) -> Address {
pub fn new(socket: &SocketAddr, services: ServiceFlags) -> Address {
let (address, port) = match *socket {
SocketAddr::V4(addr) => (addr.ip().to_ipv6_mapped().segments(), addr.port()),
SocketAddr::V6(addr) => (addr.ip().segments(), addr.port())
SocketAddr::V6(addr) => (addr.ip().segments(), addr.port()),
};
Address { address, port, services }
}
@ -47,7 +46,8 @@ impl Address {
if addr[0..3] == ONION {
return Err(io::Error::from(io::ErrorKind::AddrNotAvailable));
}
let ipv6 = Ipv6Addr::new(addr[0], addr[1], addr[2], addr[3], addr[4], addr[5], addr[6], addr[7]);
let ipv6 =
Ipv6Addr::new(addr[0], addr[1], addr[2], addr[3], addr[4], addr[5], addr[6], addr[7]);
if let Some(ipv4) = ipv6.to_ipv4() {
Ok(SocketAddr::V4(SocketAddrV4::new(ipv4, self.port)))
} else {
@ -79,7 +79,7 @@ impl Decodable for Address {
Ok(Address {
services: Decodable::consensus_decode(r)?,
address: read_be_address(r)?,
port: u16::swap_bytes(Decodable::consensus_decode(r)?)
port: u16::swap_bytes(Decodable::consensus_decode(r)?),
})
}
}
@ -101,10 +101,16 @@ impl fmt::Debug for Address {
let ipv6 = Ipv6Addr::from(self.address);
match ipv6.to_ipv4() {
Some(addr) => write!(f, "Address {{services: {}, address: {}, port: {}}}",
self.services, addr, self.port),
None => write!(f, "Address {{services: {}, address: {}, port: {}}}",
self.services, ipv6, self.port)
Some(addr) => write!(
f,
"Address {{services: {}, address: {}, port: {}}}",
self.services, addr, self.port
),
None => write!(
f,
"Address {{services: {}, address: {}, port: {}}}",
self.services, ipv6, self.port
),
}
}
}
@ -137,7 +143,11 @@ pub enum AddrV2 {
impl Encodable for AddrV2 {
fn consensus_encode<W: io::Write + ?Sized>(&self, e: &mut W) -> Result<usize, io::Error> {
fn encode_addr<W: io::Write + ?Sized>(w: &mut W, network: u8, bytes: &[u8]) -> Result<usize, io::Error> {
fn encode_addr<W: io::Write + ?Sized>(
w: &mut W,
network: u8,
bytes: &[u8],
) -> Result<usize, io::Error> {
let len = network.consensus_encode(w)?
+ VarInt(bytes.len() as u64).consensus_encode(w)?
+ bytes.len();
@ -151,7 +161,7 @@ impl Encodable for AddrV2 {
AddrV2::TorV3(ref bytes) => encode_addr(e, 4, bytes)?,
AddrV2::I2p(ref bytes) => encode_addr(e, 5, bytes)?,
AddrV2::Cjdns(ref addr) => encode_addr(e, 6, &addr.octets())?,
AddrV2::Unknown(network, ref bytes) => encode_addr(e, network, bytes)?
AddrV2::Unknown(network, ref bytes) => encode_addr(e, network, bytes)?,
})
}
}
@ -170,43 +180,49 @@ impl Decodable for AddrV2 {
}
let addr: [u8; 4] = Decodable::consensus_decode(r)?;
AddrV2::Ipv4(Ipv4Addr::new(addr[0], addr[1], addr[2], addr[3]))
},
}
2 => {
if len != 16 {
return Err(encode::Error::ParseFailed("Invalid IPv6 address"));
}
let addr: [u16; 8] = read_be_address(r)?;
if addr[0..3] == ONION {
return Err(encode::Error::ParseFailed("OnionCat address sent with IPv6 network id"));
return Err(encode::Error::ParseFailed(
"OnionCat address sent with IPv6 network id",
));
}
if addr[0..6] == [0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0xFFFF] {
return Err(encode::Error::ParseFailed("IPV4 wrapped address sent with IPv6 network id"));
return Err(encode::Error::ParseFailed(
"IPV4 wrapped address sent with IPv6 network id",
));
}
AddrV2::Ipv6(Ipv6Addr::new(addr[0], addr[1], addr[2], addr[3], addr[4], addr[5], addr[6], addr[7]))
},
AddrV2::Ipv6(Ipv6Addr::new(
addr[0], addr[1], addr[2], addr[3], addr[4], addr[5], addr[6], addr[7],
))
}
3 => {
if len != 10 {
return Err(encode::Error::ParseFailed("Invalid TorV2 address"));
}
let id = Decodable::consensus_decode(r)?;
AddrV2::TorV2(id)
},
}
4 => {
if len != 32 {
return Err(encode::Error::ParseFailed("Invalid TorV3 address"));
}
let pubkey = Decodable::consensus_decode(r)?;
AddrV2::TorV3(pubkey)
},
}
5 => {
if len != 32 {
return Err(encode::Error::ParseFailed("Invalid I2P address"));
}
let hash = Decodable::consensus_decode(r)?;
AddrV2::I2p(hash)
},
}
6 => {
if len != 16 {
if len != 16 {
return Err(encode::Error::ParseFailed("Invalid CJDNS address"));
}
let addr: [u16; 8] = read_be_address(r)?;
@ -214,8 +230,10 @@ impl Decodable for AddrV2 {
if addr[0] != u16::from_be_bytes([0xFC, 0x00]) {
return Err(encode::Error::ParseFailed("Invalid CJDNS address"));
}
AddrV2::Cjdns(Ipv6Addr::new(addr[0], addr[1], addr[2], addr[3], addr[4], addr[5], addr[6], addr[7]))
},
AddrV2::Cjdns(Ipv6Addr::new(
addr[0], addr[1], addr[2], addr[3], addr[4], addr[5], addr[6], addr[7],
))
}
_ => {
// len already checked above to be <= 512
let mut addr = vec![0u8; len as usize];
@ -236,7 +254,7 @@ pub struct AddrV2Message {
/// Network ID + Network Address
pub addr: AddrV2,
/// Network port, 0 if not applicable
pub port: u16
pub port: u16,
}
impl AddrV2Message {
@ -287,22 +305,26 @@ impl ToSocketAddrs for AddrV2Message {
#[cfg(test)]
mod test {
use core::str::FromStr;
use super::{AddrV2Message, AddrV2, Address};
use crate::network::constants::ServiceFlags;
use std::net::{SocketAddr, IpAddr, Ipv4Addr, Ipv6Addr};
use crate::hashes::hex::FromHex;
use std::net::{IpAddr, Ipv4Addr, Ipv6Addr, SocketAddr};
use super::{AddrV2, AddrV2Message, Address};
use crate::consensus::encode::{deserialize, serialize};
use crate::hashes::hex::FromHex;
use crate::network::constants::ServiceFlags;
#[test]
fn serialize_address_test() {
assert_eq!(serialize(&Address {
services: ServiceFlags::NETWORK,
address: [0, 0, 0, 0, 0, 0xffff, 0x0a00, 0x0001],
port: 8333
}),
vec![1u8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0xff, 0xff, 0x0a, 0, 0, 1, 0x20, 0x8d]);
assert_eq!(
serialize(&Address {
services: ServiceFlags::NETWORK,
address: [0, 0, 0, 0, 0, 0xffff, 0x0a00, 0x0001],
port: 8333
}),
vec![
1u8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xff, 0xff, 0x0a, 0, 0, 1,
0x20, 0x8d
]
);
}
#[test]
@ -329,41 +351,47 @@ mod test {
#[test]
fn deserialize_address_test() {
let mut addr: Result<Address, _> = deserialize(&[1u8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0xff, 0xff, 0x0a, 0,
0, 1, 0x20, 0x8d]);
let mut addr: Result<Address, _> = deserialize(&[
1u8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xff, 0xff, 0x0a, 0, 0, 1,
0x20, 0x8d,
]);
assert!(addr.is_ok());
let full = addr.unwrap();
assert!(match full.socket_addr().unwrap() {
SocketAddr::V4(_) => true,
_ => false
}
);
SocketAddr::V4(_) => true,
_ => false,
});
assert_eq!(full.services, ServiceFlags::NETWORK);
assert_eq!(full.address, [0, 0, 0, 0, 0, 0xffff, 0x0a00, 0x0001]);
assert_eq!(full.port, 8333);
addr = deserialize(&[1u8, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0xff, 0xff, 0x0a, 0, 0, 1]);
addr = deserialize(&[
1u8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xff, 0xff, 0x0a, 0, 0, 1,
]);
assert!(addr.is_err());
}
#[test]
fn test_socket_addr () {
let s4 = SocketAddr::new(IpAddr::V4(Ipv4Addr::new(111,222,123,4)), 5555);
fn test_socket_addr() {
let s4 = SocketAddr::new(IpAddr::V4(Ipv4Addr::new(111, 222, 123, 4)), 5555);
let a4 = Address::new(&s4, ServiceFlags::NETWORK | ServiceFlags::WITNESS);
assert_eq!(a4.socket_addr().unwrap(), s4);
let s6 = SocketAddr::new(IpAddr::V6(Ipv6Addr::new(0x1111, 0x2222, 0x3333, 0x4444,
0x5555, 0x6666, 0x7777, 0x8888)), 9999);
let s6 = SocketAddr::new(
IpAddr::V6(Ipv6Addr::new(
0x1111, 0x2222, 0x3333, 0x4444, 0x5555, 0x6666, 0x7777, 0x8888,
)),
9999,
);
let a6 = Address::new(&s6, ServiceFlags::NETWORK | ServiceFlags::WITNESS);
assert_eq!(a6.socket_addr().unwrap(), s6);
}
#[test]
fn onion_test () {
fn onion_test() {
let onionaddr = SocketAddr::new(
IpAddr::V6(
Ipv6Addr::from_str("FD87:D87E:EB43:edb1:8e4:3588:e546:35ca").unwrap()), 1111);
IpAddr::V6(Ipv6Addr::from_str("FD87:D87E:EB43:edb1:8e4:3588:e546:35ca").unwrap()),
1111,
);
let addr = Address::new(&onionaddr, ServiceFlags::NONE);
assert!(addr.socket_addr().is_err());
}
@ -375,17 +403,32 @@ mod test {
let ip = AddrV2::Ipv4(Ipv4Addr::new(1, 2, 3, 4));
assert_eq!(serialize(&ip), Vec::from_hex("010401020304").unwrap());
let ip = AddrV2::Ipv6(Ipv6Addr::from_str("1a1b:2a2b:3a3b:4a4b:5a5b:6a6b:7a7b:8a8b").unwrap());
let ip =
AddrV2::Ipv6(Ipv6Addr::from_str("1a1b:2a2b:3a3b:4a4b:5a5b:6a6b:7a7b:8a8b").unwrap());
assert_eq!(serialize(&ip), Vec::from_hex("02101a1b2a2b3a3b4a4b5a5b6a6b7a7b8a8b").unwrap());
let ip = AddrV2::TorV2(FromHex::from_hex("f1f2f3f4f5f6f7f8f9fa").unwrap());
assert_eq!(serialize(&ip), Vec::from_hex("030af1f2f3f4f5f6f7f8f9fa").unwrap());
let ip = AddrV2::TorV3(FromHex::from_hex("53cd5648488c4707914182655b7664034e09e66f7e8cbf1084e654eb56c5bd88").unwrap());
assert_eq!(serialize(&ip), Vec::from_hex("042053cd5648488c4707914182655b7664034e09e66f7e8cbf1084e654eb56c5bd88").unwrap());
let ip = AddrV2::TorV3(
FromHex::from_hex("53cd5648488c4707914182655b7664034e09e66f7e8cbf1084e654eb56c5bd88")
.unwrap(),
);
assert_eq!(
serialize(&ip),
Vec::from_hex("042053cd5648488c4707914182655b7664034e09e66f7e8cbf1084e654eb56c5bd88")
.unwrap()
);
let ip = AddrV2::I2p(FromHex::from_hex("a2894dabaec08c0051a481a6dac88b64f98232ae42d4b6fd2fa81952dfe36a87").unwrap());
assert_eq!(serialize(&ip), Vec::from_hex("0520a2894dabaec08c0051a481a6dac88b64f98232ae42d4b6fd2fa81952dfe36a87").unwrap());
let ip = AddrV2::I2p(
FromHex::from_hex("a2894dabaec08c0051a481a6dac88b64f98232ae42d4b6fd2fa81952dfe36a87")
.unwrap(),
);
assert_eq!(
serialize(&ip),
Vec::from_hex("0520a2894dabaec08c0051a481a6dac88b64f98232ae42d4b6fd2fa81952dfe36a87")
.unwrap()
);
let ip = AddrV2::Cjdns(Ipv6Addr::from_str("fc00:1:2:3:4:5:6:7").unwrap());
assert_eq!(serialize(&ip), Vec::from_hex("0610fc000001000200030004000500060007").unwrap());
@ -412,17 +455,27 @@ mod test {
assert!(deserialize::<AddrV2>(&Vec::from_hex("01fd010201020304").unwrap()).is_err());
// Valid IPv6.
let ip: AddrV2 = deserialize(&Vec::from_hex("02100102030405060708090a0b0c0d0e0f10").unwrap()).unwrap();
assert_eq!(ip, AddrV2::Ipv6(Ipv6Addr::from_str("102:304:506:708:90a:b0c:d0e:f10").unwrap()));
let ip: AddrV2 =
deserialize(&Vec::from_hex("02100102030405060708090a0b0c0d0e0f10").unwrap()).unwrap();
assert_eq!(
ip,
AddrV2::Ipv6(Ipv6Addr::from_str("102:304:506:708:90a:b0c:d0e:f10").unwrap())
);
// Invalid IPv6, with bogus length.
assert!(deserialize::<AddrV2>(&Vec::from_hex("020400").unwrap()).is_err());
// Invalid IPv6, contains embedded IPv4.
assert!(deserialize::<AddrV2>(&Vec::from_hex("021000000000000000000000ffff01020304").unwrap()).is_err());
assert!(deserialize::<AddrV2>(
&Vec::from_hex("021000000000000000000000ffff01020304").unwrap()
)
.is_err());
// Invalid IPv6, contains embedded TORv2.
assert!(deserialize::<AddrV2>(&Vec::from_hex("0210fd87d87eeb430102030405060708090a").unwrap()).is_err());
assert!(deserialize::<AddrV2>(
&Vec::from_hex("0210fd87d87eeb430102030405060708090a").unwrap()
)
.is_err());
// Valid TORv2.
let ip: AddrV2 = deserialize(&Vec::from_hex("030af1f2f3f4f5f6f7f8f9fa").unwrap()).unwrap();
@ -432,31 +485,61 @@ mod test {
assert!(deserialize::<AddrV2>(&Vec::from_hex("030700").unwrap()).is_err());
// Valid TORv3.
let ip: AddrV2 = deserialize(&Vec::from_hex("042079bcc625184b05194975c28b66b66b0469f7f6556fb1ac3189a79b40dda32f1f").unwrap()).unwrap();
assert_eq!(ip, AddrV2::TorV3(FromHex::from_hex("79bcc625184b05194975c28b66b66b0469f7f6556fb1ac3189a79b40dda32f1f").unwrap()));
let ip: AddrV2 = deserialize(
&Vec::from_hex("042079bcc625184b05194975c28b66b66b0469f7f6556fb1ac3189a79b40dda32f1f")
.unwrap(),
)
.unwrap();
assert_eq!(
ip,
AddrV2::TorV3(
FromHex::from_hex(
"79bcc625184b05194975c28b66b66b0469f7f6556fb1ac3189a79b40dda32f1f"
)
.unwrap()
)
);
// Invalid TORv3, with bogus length.
assert!(deserialize::<AddrV2>(&Vec::from_hex("040000").unwrap()).is_err());
// Valid I2P.
let ip: AddrV2 = deserialize(&Vec::from_hex("0520a2894dabaec08c0051a481a6dac88b64f98232ae42d4b6fd2fa81952dfe36a87").unwrap()).unwrap();
assert_eq!(ip, AddrV2::I2p(FromHex::from_hex("a2894dabaec08c0051a481a6dac88b64f98232ae42d4b6fd2fa81952dfe36a87").unwrap()));
let ip: AddrV2 = deserialize(
&Vec::from_hex("0520a2894dabaec08c0051a481a6dac88b64f98232ae42d4b6fd2fa81952dfe36a87")
.unwrap(),
)
.unwrap();
assert_eq!(
ip,
AddrV2::I2p(
FromHex::from_hex(
"a2894dabaec08c0051a481a6dac88b64f98232ae42d4b6fd2fa81952dfe36a87"
)
.unwrap()
)
);
// Invalid I2P, with bogus length.
assert!(deserialize::<AddrV2>(&Vec::from_hex("050300").unwrap()).is_err());
// Valid CJDNS.
let ip: AddrV2 = deserialize(&Vec::from_hex("0610fc000001000200030004000500060007").unwrap()).unwrap();
let ip: AddrV2 =
deserialize(&Vec::from_hex("0610fc000001000200030004000500060007").unwrap()).unwrap();
assert_eq!(ip, AddrV2::Cjdns(Ipv6Addr::from_str("fc00:1:2:3:4:5:6:7").unwrap()));
// Invalid CJDNS, incorrect marker
assert!(deserialize::<AddrV2>(&Vec::from_hex("0610fd000001000200030004000500060007").unwrap()).is_err());
assert!(deserialize::<AddrV2>(
&Vec::from_hex("0610fd000001000200030004000500060007").unwrap()
)
.is_err());
// Invalid CJDNS, with bogus length.
assert!(deserialize::<AddrV2>(&Vec::from_hex("060100").unwrap()).is_err());
// Unknown, with extreme length.
assert!(deserialize::<AddrV2>(&Vec::from_hex("aafe0000000201020304050607").unwrap()).is_err());
assert!(
deserialize::<AddrV2>(&Vec::from_hex("aafe0000000201020304050607").unwrap()).is_err()
);
// Unknown, with reasonable length.
let ip: AddrV2 = deserialize(&Vec::from_hex("aa0401020304").unwrap()).unwrap();
@ -472,10 +555,25 @@ mod test {
let raw = Vec::from_hex("0261bc6649019902abab208d79627683fd4804010409090909208d").unwrap();
let addresses: Vec<AddrV2Message> = deserialize(&raw).unwrap();
assert_eq!(addresses, vec![
AddrV2Message{services: ServiceFlags::NETWORK, time: 0x4966bc61, port: 8333, addr: AddrV2::Unknown(153, Vec::from_hex("abab").unwrap())},
AddrV2Message{services: ServiceFlags::NETWORK_LIMITED | ServiceFlags::WITNESS | ServiceFlags::COMPACT_FILTERS, time: 0x83766279, port: 8333, addr: AddrV2::Ipv4(Ipv4Addr::new(9, 9, 9, 9))},
]);
assert_eq!(
addresses,
vec![
AddrV2Message {
services: ServiceFlags::NETWORK,
time: 0x4966bc61,
port: 8333,
addr: AddrV2::Unknown(153, Vec::from_hex("abab").unwrap())
},
AddrV2Message {
services: ServiceFlags::NETWORK_LIMITED
| ServiceFlags::WITNESS
| ServiceFlags::COMPACT_FILTERS,
time: 0x83766279,
port: 8333,
addr: AddrV2::Ipv4(Ipv4Addr::new(9, 9, 9, 9))
},
]
);
assert_eq!(serialize(&addresses), raw);
}

View File

@ -26,19 +26,20 @@
//! assert_eq!(&bytes[..], &[0xF9, 0xBE, 0xB4, 0xD9]);
//! ```
use core::{fmt, ops, convert::TryFrom, borrow::Borrow, borrow::BorrowMut};
use core::borrow::{Borrow, BorrowMut};
use core::convert::TryFrom;
use core::str::FromStr;
use core::{fmt, ops};
use bitcoin_internals::{debug_from_display, write_err};
#[cfg(feature = "serde")]
use serde::{Deserialize, Serialize};
use bitcoin_internals::{debug_from_display, write_err};
use crate::consensus::encode::{self, Decodable, Encodable};
use crate::error::impl_std_error;
use crate::hashes::hex::{Error, FromHex};
use crate::io;
use crate::prelude::{String, ToOwned};
use crate::consensus::encode::{self, Encodable, Decodable};
use crate::hashes::hex::{FromHex, Error};
use crate::error::impl_std_error;
/// Version of the protocol as appearing in network message headers
/// This constant is used to signal to other peers which features you support.
@ -86,9 +87,7 @@ impl Network {
/// assert_eq!(Ok(Network::Bitcoin), Network::try_from(Magic::from_bytes([0xF9, 0xBE, 0xB4, 0xD9])));
/// assert_eq!(None, Network::from_magic(Magic::from_bytes([0xFF, 0xFF, 0xFF, 0xFF])));
/// ```
pub fn from_magic(magic: Magic) -> Option<Network> {
Network::try_from(magic).ok()
}
pub fn from_magic(magic: Magic) -> Option<Network> { Network::try_from(magic).ok() }
/// Return the network magic bytes, which should be encoded little-endian
/// at the start of every message
@ -101,9 +100,7 @@ impl Network {
/// let network = Network::Bitcoin;
/// assert_eq!(network.magic(), Magic::from_bytes([0xF9, 0xBE, 0xB4, 0xD9]));
/// ```
pub fn magic(self) -> Magic {
Magic::from(self)
}
pub fn magic(self) -> Magic { Magic::from(self) }
}
/// An error in parsing network string.
@ -129,7 +126,7 @@ impl FromStr for Network {
"testnet" => Testnet,
"signet" => Signet,
"regtest" => Regtest,
_ => return Err(ParseNetworkError(s.to_owned()))
_ => return Err(ParseNetworkError(s.to_owned())),
};
Ok(network)
}
@ -164,14 +161,10 @@ impl Magic {
pub const REGTEST: Self = Self([0xFA, 0xBF, 0xB5, 0xDA]);
/// Create network magic from bytes.
pub fn from_bytes(bytes: [u8; 4]) -> Magic {
Magic(bytes)
}
pub fn from_bytes(bytes: [u8; 4]) -> Magic { Magic(bytes) }
/// Get network magic bytes.
pub fn to_bytes(self) -> [u8; 4] {
self.0
}
pub fn to_bytes(self) -> [u8; 4] { self.0 }
}
/// An error in parsing magic bytes.
@ -180,7 +173,7 @@ pub struct ParseMagicError {
/// The error that occurred when parsing the string.
error: Error,
/// The byte string that failed to parse.
magic: String
magic: String,
}
impl FromStr for Magic {
@ -189,7 +182,7 @@ impl FromStr for Magic {
fn from_str(s: &str) -> Result<Magic, Self::Err> {
match <[u8; 4]>::from_hex(s) {
Ok(magic) => Ok(Magic::from_bytes(magic)),
Err(e) => Err(ParseMagicError { error: e, magic: s.to_owned() })
Err(e) => Err(ParseMagicError { error: e, magic: s.to_owned() }),
}
}
}
@ -201,7 +194,7 @@ impl From<Network> for Magic {
Network::Bitcoin => Magic::BITCOIN,
Network::Testnet => Magic::TESTNET,
Network::Signet => Magic::SIGNET,
Network::Regtest => Magic::REGTEST
Network::Regtest => Magic::REGTEST,
}
}
}
@ -220,7 +213,7 @@ impl TryFrom<Magic> for Network {
Magic::TESTNET => Ok(Network::Testnet),
Magic::SIGNET => Ok(Network::Signet),
Magic::REGTEST => Ok(Network::Regtest),
_ => Err(UnknownMagic(magic))
_ => Err(UnknownMagic(magic)),
}
}
}
@ -260,51 +253,35 @@ impl Decodable for Magic {
}
impl AsRef<[u8]> for Magic {
fn as_ref(&self) -> &[u8] {
&self.0
}
fn as_ref(&self) -> &[u8] { &self.0 }
}
impl AsRef<[u8; 4]> for Magic {
fn as_ref(&self) -> &[u8; 4] {
&self.0
}
fn as_ref(&self) -> &[u8; 4] { &self.0 }
}
impl AsMut<[u8]> for Magic {
fn as_mut(&mut self) -> &mut [u8] {
&mut self.0
}
fn as_mut(&mut self) -> &mut [u8] { &mut self.0 }
}
impl AsMut<[u8; 4]> for Magic {
fn as_mut(&mut self) -> &mut [u8; 4] {
&mut self.0
}
fn as_mut(&mut self) -> &mut [u8; 4] { &mut self.0 }
}
impl Borrow<[u8]> for Magic {
fn borrow(&self) -> &[u8] {
&self.0
}
fn borrow(&self) -> &[u8] { &self.0 }
}
impl Borrow<[u8; 4]> for Magic {
fn borrow(&self) -> &[u8; 4] {
&self.0
}
fn borrow(&self) -> &[u8; 4] { &self.0 }
}
impl BorrowMut<[u8]> for Magic {
fn borrow_mut(&mut self) -> &mut [u8] {
&mut self.0
}
fn borrow_mut(&mut self) -> &mut [u8] { &mut self.0 }
}
impl BorrowMut<[u8; 4]> for Magic {
fn borrow_mut(&mut self) -> &mut [u8; 4] {
&mut self.0
}
fn borrow_mut(&mut self) -> &mut [u8; 4] { &mut self.0 }
}
impl fmt::Display for ParseMagicError {
@ -376,26 +353,18 @@ impl ServiceFlags {
}
/// Check whether [ServiceFlags] are included in this one.
pub fn has(self, flags: ServiceFlags) -> bool {
(self.0 | flags.0) == self.0
}
pub fn has(self, flags: ServiceFlags) -> bool { (self.0 | flags.0) == self.0 }
/// Gets the integer representation of this [`ServiceFlags`].
pub fn to_u64(self) -> u64 {
self.0
}
pub fn to_u64(self) -> u64 { self.0 }
}
impl fmt::LowerHex for ServiceFlags {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
fmt::LowerHex::fmt(&self.0, f)
}
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { fmt::LowerHex::fmt(&self.0, f) }
}
impl fmt::UpperHex for ServiceFlags {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
fmt::UpperHex::fmt(&self.0, f)
}
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { fmt::UpperHex::fmt(&self.0, f) }
}
impl fmt::Display for ServiceFlags {
@ -415,7 +384,7 @@ impl fmt::Display for ServiceFlags {
write!(f, stringify!($f))?;
flags.remove(ServiceFlags::$f);
}
}
};
}
write!(f, "ServiceFlags(")?;
write_flag!(NETWORK);
@ -436,43 +405,31 @@ impl fmt::Display for ServiceFlags {
}
impl From<u64> for ServiceFlags {
fn from(f: u64) -> Self {
ServiceFlags(f)
}
fn from(f: u64) -> Self { ServiceFlags(f) }
}
impl From<ServiceFlags> for u64 {
fn from(flags: ServiceFlags) -> Self {
flags.0
}
fn from(flags: ServiceFlags) -> Self { flags.0 }
}
impl ops::BitOr for ServiceFlags {
type Output = Self;
fn bitor(mut self, rhs: Self) -> Self {
self.add(rhs)
}
fn bitor(mut self, rhs: Self) -> Self { self.add(rhs) }
}
impl ops::BitOrAssign for ServiceFlags {
fn bitor_assign(&mut self, rhs: Self) {
self.add(rhs);
}
fn bitor_assign(&mut self, rhs: Self) { self.add(rhs); }
}
impl ops::BitXor for ServiceFlags {
type Output = Self;
fn bitxor(mut self, rhs: Self) -> Self {
self.remove(rhs)
}
fn bitxor(mut self, rhs: Self) -> Self { self.remove(rhs) }
}
impl ops::BitXorAssign for ServiceFlags {
fn bitxor_assign(&mut self, rhs: Self) {
self.remove(rhs);
}
fn bitxor_assign(&mut self, rhs: Self) { self.remove(rhs); }
}
impl Encodable for ServiceFlags {
@ -491,11 +448,12 @@ impl Decodable for ServiceFlags {
#[cfg(test)]
mod tests {
use super::{Network, ServiceFlags, Magic};
use crate::consensus::encode::{deserialize, serialize};
use std::convert::TryFrom;
use std::str::FromStr;
use super::{Magic, Network, ServiceFlags};
use crate::consensus::encode::{deserialize, serialize};
#[test]
fn serialize_test() {
assert_eq!(serialize(&Network::Bitcoin.magic()), &[0xf9, 0xbe, 0xb4, 0xd9]);
@ -507,7 +465,6 @@ mod tests {
assert_eq!(deserialize(&[0x0b, 0x11, 0x09, 0x07]).ok(), Some(Network::Testnet.magic()));
assert_eq!(deserialize(&[0x0a, 0x03, 0xcf, 0x40]).ok(), Some(Network::Signet.magic()));
assert_eq!(deserialize(&[0xfa, 0xbf, 0xb5, 0xda]).ok(), Some(Network::Regtest.magic()));
}
#[test]
@ -568,7 +525,12 @@ mod tests {
#[cfg(feature = "serde")]
fn serde_roundtrip() {
use Network::*;
let tests = vec![(Bitcoin, "bitcoin"), (Testnet, "testnet"), (Signet, "signet"), (Regtest, "regtest")];
let tests = vec![
(Bitcoin, "bitcoin"),
(Testnet, "testnet"),
(Signet, "signet"),
(Regtest, "regtest"),
];
for tc in tests {
let network = tc.0;

View File

@ -7,24 +7,22 @@
//! are used for (de)serializing Bitcoin objects for transmission on the network.
//!
use crate::prelude::*;
use core::{fmt, iter};
use core::convert::TryFrom;
use core::{fmt, iter};
use crate::io;
use io::Read as _;
use crate::blockdata::block;
use crate::blockdata::transaction;
use crate::network::address::{Address, AddrV2Message};
use crate::network::{message_network, message_bloom};
use crate::network::message_blockdata;
use crate::network::message_filter;
use crate::network::message_compact_blocks;
use crate::network::constants::Magic;
use crate::blockdata::{block, transaction};
use crate::consensus::encode::{CheckedData, Decodable, Encodable, VarInt};
use crate::consensus::{encode, serialize};
use crate::io;
use crate::merkle_tree::MerkleBlock;
use crate::network::address::{AddrV2Message, Address};
use crate::network::constants::Magic;
use crate::network::{
message_blockdata, message_bloom, message_compact_blocks, message_filter, message_network,
};
use crate::prelude::*;
/// The maximum number of [super::message_blockdata::Inventory] items in an `inv` message.
///
@ -95,15 +93,11 @@ impl core::str::FromStr for CommandString {
}
impl fmt::Display for CommandString {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
f.write_str(self.0.as_ref())
}
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { f.write_str(self.0.as_ref()) }
}
impl AsRef<str> for CommandString {
fn as_ref(&self) -> &str {
self.0.as_ref()
}
fn as_ref(&self) -> &str { self.0.as_ref() }
}
impl Encodable for CommandString {
@ -121,11 +115,13 @@ impl Decodable for CommandString {
#[inline]
fn consensus_decode<R: io::Read + ?Sized>(r: &mut R) -> Result<Self, encode::Error> {
let rawbytes: [u8; 12] = Decodable::consensus_decode(r)?;
let rv = iter::FromIterator::from_iter(
rawbytes
.iter()
.filter_map(|&u| if u > 0 { Some(u as char) } else { None })
);
let rv = iter::FromIterator::from_iter(rawbytes.iter().filter_map(|&u| {
if u > 0 {
Some(u as char)
} else {
None
}
}));
Ok(CommandString(rv))
}
}
@ -140,7 +136,12 @@ pub struct CommandStringError {
impl fmt::Display for CommandStringError {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "the command string '{}' has length {} which is larger than 12", self.cow, self.cow.len())
write!(
f,
"the command string '{}' has length {} which is larger than 12",
self.cow,
self.cow.len()
)
}
}
@ -152,7 +153,7 @@ pub struct RawNetworkMessage {
/// Magic bytes to identify the network these messages are meant for
pub magic: Magic,
/// The actual message data
pub payload: NetworkMessage
pub payload: NetworkMessage,
}
/// A Network message payload. Proper documentation is available on at
@ -241,7 +242,7 @@ pub enum NetworkMessage {
command: CommandString,
/// The payload of this message.
payload: Vec<u8>,
}
},
}
impl NetworkMessage {
@ -253,25 +254,25 @@ impl NetworkMessage {
pub fn cmd(&self) -> &'static str {
match *self {
NetworkMessage::Version(_) => "version",
NetworkMessage::Verack => "verack",
NetworkMessage::Addr(_) => "addr",
NetworkMessage::Inv(_) => "inv",
NetworkMessage::Verack => "verack",
NetworkMessage::Addr(_) => "addr",
NetworkMessage::Inv(_) => "inv",
NetworkMessage::GetData(_) => "getdata",
NetworkMessage::NotFound(_) => "notfound",
NetworkMessage::GetBlocks(_) => "getblocks",
NetworkMessage::GetHeaders(_) => "getheaders",
NetworkMessage::MemPool => "mempool",
NetworkMessage::Tx(_) => "tx",
NetworkMessage::Block(_) => "block",
NetworkMessage::MemPool => "mempool",
NetworkMessage::Tx(_) => "tx",
NetworkMessage::Block(_) => "block",
NetworkMessage::Headers(_) => "headers",
NetworkMessage::SendHeaders => "sendheaders",
NetworkMessage::GetAddr => "getaddr",
NetworkMessage::Ping(_) => "ping",
NetworkMessage::Pong(_) => "pong",
NetworkMessage::GetAddr => "getaddr",
NetworkMessage::Ping(_) => "ping",
NetworkMessage::Pong(_) => "pong",
NetworkMessage::MerkleBlock(_) => "merkleblock",
NetworkMessage::FilterLoad(_) => "filterload",
NetworkMessage::FilterAdd(_) => "filteradd",
NetworkMessage::FilterClear => "filterclear",
NetworkMessage::FilterAdd(_) => "filteradd",
NetworkMessage::FilterClear => "filterclear",
NetworkMessage::GetCFilters(_) => "getcfilters",
NetworkMessage::CFilter(_) => "cfilter",
NetworkMessage::GetCFHeaders(_) => "getcfheaders",
@ -282,8 +283,8 @@ impl NetworkMessage {
NetworkMessage::CmpctBlock(_) => "cmpctblock",
NetworkMessage::GetBlockTxn(_) => "getblocktxn",
NetworkMessage::BlockTxn(_) => "blocktxn",
NetworkMessage::Alert(_) => "alert",
NetworkMessage::Reject(_) => "reject",
NetworkMessage::Alert(_) => "alert",
NetworkMessage::Reject(_) => "reject",
NetworkMessage::FeeFilter(_) => "feefilter",
NetworkMessage::WtxidRelay => "wtxidrelay",
NetworkMessage::AddrV2(_) => "addrv2",
@ -296,7 +297,7 @@ impl NetworkMessage {
pub fn command(&self) -> CommandString {
match *self {
NetworkMessage::Unknown { command: ref c, .. } => c.clone(),
_ => CommandString::try_from_static(self.cmd()).expect("cmd returns valid commands")
_ => CommandString::try_from_static(self.cmd()).expect("cmd returns valid commands"),
}
}
}
@ -307,14 +308,10 @@ impl RawNetworkMessage {
/// This returns `"unknown"` for [NetworkMessage::Unknown],
/// regardless of the actual command in the unknown message.
/// Use the [Self::command] method to get the command for unknown messages.
pub fn cmd(&self) -> &'static str {
self.payload.cmd()
}
pub fn cmd(&self) -> &'static str { self.payload.cmd() }
/// Return the CommandString for the message command.
pub fn command(&self) -> CommandString {
self.payload.command()
}
pub fn command(&self) -> CommandString { self.payload.command() }
}
struct HeaderSerializationWrapper<'a>(&'a Vec<block::Header>);
@ -339,20 +336,20 @@ impl Encodable for RawNetworkMessage {
len += self.command().consensus_encode(w)?;
len += CheckedData(match self.payload {
NetworkMessage::Version(ref dat) => serialize(dat),
NetworkMessage::Addr(ref dat) => serialize(dat),
NetworkMessage::Inv(ref dat) => serialize(dat),
NetworkMessage::Addr(ref dat) => serialize(dat),
NetworkMessage::Inv(ref dat) => serialize(dat),
NetworkMessage::GetData(ref dat) => serialize(dat),
NetworkMessage::NotFound(ref dat) => serialize(dat),
NetworkMessage::GetBlocks(ref dat) => serialize(dat),
NetworkMessage::GetHeaders(ref dat) => serialize(dat),
NetworkMessage::Tx(ref dat) => serialize(dat),
NetworkMessage::Block(ref dat) => serialize(dat),
NetworkMessage::Tx(ref dat) => serialize(dat),
NetworkMessage::Block(ref dat) => serialize(dat),
NetworkMessage::Headers(ref dat) => serialize(&HeaderSerializationWrapper(dat)),
NetworkMessage::Ping(ref dat) => serialize(dat),
NetworkMessage::Pong(ref dat) => serialize(dat),
NetworkMessage::MerkleBlock(ref dat) => serialize(dat),
NetworkMessage::FilterLoad(ref dat) => serialize(dat),
NetworkMessage::FilterAdd(ref dat) => serialize(dat),
NetworkMessage::Ping(ref dat) => serialize(dat),
NetworkMessage::Pong(ref dat) => serialize(dat),
NetworkMessage::MerkleBlock(ref dat) => serialize(dat),
NetworkMessage::FilterLoad(ref dat) => serialize(dat),
NetworkMessage::FilterAdd(ref dat) => serialize(dat),
NetworkMessage::GetCFilters(ref dat) => serialize(dat),
NetworkMessage::CFilter(ref dat) => serialize(dat),
NetworkMessage::GetCFHeaders(ref dat) => serialize(dat),
@ -363,7 +360,7 @@ impl Encodable for RawNetworkMessage {
NetworkMessage::CmpctBlock(ref dat) => serialize(dat),
NetworkMessage::GetBlockTxn(ref dat) => serialize(dat),
NetworkMessage::BlockTxn(ref dat) => serialize(dat),
NetworkMessage::Alert(ref dat) => serialize(dat),
NetworkMessage::Alert(ref dat) => serialize(dat),
NetworkMessage::Reject(ref dat) => serialize(dat),
NetworkMessage::FeeFilter(ref data) => serialize(data),
NetworkMessage::AddrV2(ref dat) => serialize(dat),
@ -375,7 +372,8 @@ impl Encodable for RawNetworkMessage {
| NetworkMessage::FilterClear
| NetworkMessage::SendAddrV2 => vec![],
NetworkMessage::Unknown { payload: ref data, .. } => serialize(data),
}).consensus_encode(w)?;
})
.consensus_encode(w)?;
Ok(len)
}
}
@ -384,7 +382,9 @@ struct HeaderDeserializationWrapper(Vec<block::Header>);
impl Decodable for HeaderDeserializationWrapper {
#[inline]
fn consensus_decode_from_finite_reader<R: io::Read + ?Sized>(r: &mut R) -> Result<Self, encode::Error> {
fn consensus_decode_from_finite_reader<R: io::Read + ?Sized>(
r: &mut R,
) -> Result<Self, encode::Error> {
let len = VarInt::consensus_decode(r)?.0;
// should be above usual number of items to avoid
// allocation
@ -392,7 +392,9 @@ impl Decodable for HeaderDeserializationWrapper {
for _ in 0..len {
ret.push(Decodable::consensus_decode(r)?);
if u8::consensus_decode(r)? != 0u8 {
return Err(encode::Error::ParseFailed("Headers message should not contain transactions"));
return Err(encode::Error::ParseFailed(
"Headers message should not contain transactions",
));
}
}
Ok(HeaderDeserializationWrapper(ret))
@ -405,60 +407,99 @@ impl Decodable for HeaderDeserializationWrapper {
}
impl Decodable for RawNetworkMessage {
fn consensus_decode_from_finite_reader<R: io::Read + ?Sized>(r: &mut R) -> Result<Self, encode::Error> {
fn consensus_decode_from_finite_reader<R: io::Read + ?Sized>(
r: &mut R,
) -> Result<Self, encode::Error> {
let magic = Decodable::consensus_decode_from_finite_reader(r)?;
let cmd = CommandString::consensus_decode_from_finite_reader(r)?;
let raw_payload = CheckedData::consensus_decode_from_finite_reader(r)?.0;
let mut mem_d = io::Cursor::new(raw_payload);
let payload = match &cmd.0[..] {
"version" => NetworkMessage::Version(Decodable::consensus_decode_from_finite_reader(&mut mem_d)?),
"verack" => NetworkMessage::Verack,
"addr" => NetworkMessage::Addr(Decodable::consensus_decode_from_finite_reader(&mut mem_d)?),
"inv" => NetworkMessage::Inv(Decodable::consensus_decode_from_finite_reader(&mut mem_d)?),
"getdata" => NetworkMessage::GetData(Decodable::consensus_decode_from_finite_reader(&mut mem_d)?),
"notfound" => NetworkMessage::NotFound(Decodable::consensus_decode_from_finite_reader(&mut mem_d)?),
"getblocks" => NetworkMessage::GetBlocks(Decodable::consensus_decode_from_finite_reader(&mut mem_d)?),
"getheaders" => NetworkMessage::GetHeaders(Decodable::consensus_decode_from_finite_reader(&mut mem_d)?),
"version" =>
NetworkMessage::Version(Decodable::consensus_decode_from_finite_reader(&mut mem_d)?),
"verack" => NetworkMessage::Verack,
"addr" =>
NetworkMessage::Addr(Decodable::consensus_decode_from_finite_reader(&mut mem_d)?),
"inv" =>
NetworkMessage::Inv(Decodable::consensus_decode_from_finite_reader(&mut mem_d)?),
"getdata" =>
NetworkMessage::GetData(Decodable::consensus_decode_from_finite_reader(&mut mem_d)?),
"notfound" => NetworkMessage::NotFound(Decodable::consensus_decode_from_finite_reader(
&mut mem_d,
)?),
"getblocks" => NetworkMessage::GetBlocks(
Decodable::consensus_decode_from_finite_reader(&mut mem_d)?,
),
"getheaders" => NetworkMessage::GetHeaders(
Decodable::consensus_decode_from_finite_reader(&mut mem_d)?,
),
"mempool" => NetworkMessage::MemPool,
"block" => NetworkMessage::Block(Decodable::consensus_decode_from_finite_reader(&mut mem_d)?),
"block" =>
NetworkMessage::Block(Decodable::consensus_decode_from_finite_reader(&mut mem_d)?),
"headers" => NetworkMessage::Headers(
HeaderDeserializationWrapper::consensus_decode_from_finite_reader(&mut mem_d)?.0
HeaderDeserializationWrapper::consensus_decode_from_finite_reader(&mut mem_d)?.0,
),
"sendheaders" => NetworkMessage::SendHeaders,
"getaddr" => NetworkMessage::GetAddr,
"ping" => NetworkMessage::Ping(Decodable::consensus_decode_from_finite_reader(&mut mem_d)?),
"pong" => NetworkMessage::Pong(Decodable::consensus_decode_from_finite_reader(&mut mem_d)?),
"merkleblock" => NetworkMessage::MerkleBlock(Decodable::consensus_decode_from_finite_reader(&mut mem_d)?),
"filterload" => NetworkMessage::FilterLoad(Decodable::consensus_decode_from_finite_reader(&mut mem_d)?),
"filteradd" => NetworkMessage::FilterAdd(Decodable::consensus_decode_from_finite_reader(&mut mem_d)?),
"ping" =>
NetworkMessage::Ping(Decodable::consensus_decode_from_finite_reader(&mut mem_d)?),
"pong" =>
NetworkMessage::Pong(Decodable::consensus_decode_from_finite_reader(&mut mem_d)?),
"merkleblock" => NetworkMessage::MerkleBlock(
Decodable::consensus_decode_from_finite_reader(&mut mem_d)?,
),
"filterload" => NetworkMessage::FilterLoad(
Decodable::consensus_decode_from_finite_reader(&mut mem_d)?,
),
"filteradd" => NetworkMessage::FilterAdd(
Decodable::consensus_decode_from_finite_reader(&mut mem_d)?,
),
"filterclear" => NetworkMessage::FilterClear,
"tx" => NetworkMessage::Tx(Decodable::consensus_decode_from_finite_reader(&mut mem_d)?),
"getcfilters" => NetworkMessage::GetCFilters(Decodable::consensus_decode_from_finite_reader(&mut mem_d)?),
"cfilter" => NetworkMessage::CFilter(Decodable::consensus_decode_from_finite_reader(&mut mem_d)?),
"getcfheaders" => NetworkMessage::GetCFHeaders(Decodable::consensus_decode_from_finite_reader(&mut mem_d)?),
"cfheaders" => NetworkMessage::CFHeaders(Decodable::consensus_decode_from_finite_reader(&mut mem_d)?),
"getcfcheckpt" => NetworkMessage::GetCFCheckpt(Decodable::consensus_decode_from_finite_reader(&mut mem_d)?),
"cfcheckpt" => NetworkMessage::CFCheckpt(Decodable::consensus_decode_from_finite_reader(&mut mem_d)?),
"reject" => NetworkMessage::Reject(Decodable::consensus_decode_from_finite_reader(&mut mem_d)?),
"alert" => NetworkMessage::Alert(Decodable::consensus_decode_from_finite_reader(&mut mem_d)?),
"feefilter" => NetworkMessage::FeeFilter(Decodable::consensus_decode_from_finite_reader(&mut mem_d)?),
"sendcmpct" => NetworkMessage::SendCmpct(Decodable::consensus_decode_from_finite_reader(&mut mem_d)?),
"cmpctblock" => NetworkMessage::CmpctBlock(Decodable::consensus_decode_from_finite_reader(&mut mem_d)?),
"getblocktxn" => NetworkMessage::GetBlockTxn(Decodable::consensus_decode_from_finite_reader(&mut mem_d)?),
"blocktxn" => NetworkMessage::BlockTxn(Decodable::consensus_decode_from_finite_reader(&mut mem_d)?),
"tx" => NetworkMessage::Tx(Decodable::consensus_decode_from_finite_reader(&mut mem_d)?),
"getcfilters" => NetworkMessage::GetCFilters(
Decodable::consensus_decode_from_finite_reader(&mut mem_d)?,
),
"cfilter" =>
NetworkMessage::CFilter(Decodable::consensus_decode_from_finite_reader(&mut mem_d)?),
"getcfheaders" => NetworkMessage::GetCFHeaders(
Decodable::consensus_decode_from_finite_reader(&mut mem_d)?,
),
"cfheaders" => NetworkMessage::CFHeaders(
Decodable::consensus_decode_from_finite_reader(&mut mem_d)?,
),
"getcfcheckpt" => NetworkMessage::GetCFCheckpt(
Decodable::consensus_decode_from_finite_reader(&mut mem_d)?,
),
"cfcheckpt" => NetworkMessage::CFCheckpt(
Decodable::consensus_decode_from_finite_reader(&mut mem_d)?,
),
"reject" =>
NetworkMessage::Reject(Decodable::consensus_decode_from_finite_reader(&mut mem_d)?),
"alert" =>
NetworkMessage::Alert(Decodable::consensus_decode_from_finite_reader(&mut mem_d)?),
"feefilter" => NetworkMessage::FeeFilter(
Decodable::consensus_decode_from_finite_reader(&mut mem_d)?,
),
"sendcmpct" => NetworkMessage::SendCmpct(
Decodable::consensus_decode_from_finite_reader(&mut mem_d)?,
),
"cmpctblock" => NetworkMessage::CmpctBlock(
Decodable::consensus_decode_from_finite_reader(&mut mem_d)?,
),
"getblocktxn" => NetworkMessage::GetBlockTxn(
Decodable::consensus_decode_from_finite_reader(&mut mem_d)?,
),
"blocktxn" => NetworkMessage::BlockTxn(Decodable::consensus_decode_from_finite_reader(
&mut mem_d,
)?),
"wtxidrelay" => NetworkMessage::WtxidRelay,
"addrv2" => NetworkMessage::AddrV2(Decodable::consensus_decode_from_finite_reader(&mut mem_d)?),
"addrv2" =>
NetworkMessage::AddrV2(Decodable::consensus_decode_from_finite_reader(&mut mem_d)?),
"sendaddrv2" => NetworkMessage::SendAddrV2,
_ => NetworkMessage::Unknown {
command: cmd,
payload: mem_d.into_inner(),
}
_ => NetworkMessage::Unknown { command: cmd, payload: mem_d.into_inner() },
};
Ok(RawNetworkMessage {
magic,
payload,
})
Ok(RawNetworkMessage { magic, payload })
}
#[inline]
@ -469,29 +510,28 @@ impl Decodable for RawNetworkMessage {
#[cfg(test)]
mod test {
use super::*;
use std::net::Ipv4Addr;
use super::{RawNetworkMessage, NetworkMessage, CommandString};
use crate::network::constants::{ServiceFlags, Magic, Network};
use super::message_network::{Reject, RejectReason, VersionMessage};
use super::{CommandString, NetworkMessage, RawNetworkMessage, *};
use crate::bip152::BlockTransactionsRequest;
use crate::blockdata::block::{self, Block};
use crate::blockdata::script::Script;
use crate::blockdata::transaction::Transaction;
use crate::consensus::encode::{deserialize, deserialize_partial, serialize};
use crate::hashes::hex::FromHex;
use crate::hashes::sha256d::Hash;
use crate::hashes::Hash as HashTrait;
use crate::network::address::{Address, AddrV2, AddrV2Message};
use super::message_network::{Reject, RejectReason, VersionMessage};
use crate::network::message_blockdata::{Inventory, GetBlocksMessage, GetHeadersMessage};
use crate::blockdata::block::{self, Block};
use crate::network::message_filter::{GetCFilters, CFilter, GetCFHeaders, CFHeaders, GetCFCheckpt, CFCheckpt};
use crate::blockdata::transaction::Transaction;
use crate::blockdata::script::Script;
use crate::network::message_bloom::{FilterAdd, FilterLoad, BloomFlags};
use crate::network::address::{AddrV2, AddrV2Message, Address};
use crate::network::constants::{Magic, Network, ServiceFlags};
use crate::network::message_blockdata::{GetBlocksMessage, GetHeadersMessage, Inventory};
use crate::network::message_bloom::{BloomFlags, FilterAdd, FilterLoad};
use crate::network::message_compact_blocks::{GetBlockTxn, SendCmpct};
use crate::bip152::BlockTransactionsRequest;
use crate::network::message_filter::{
CFCheckpt, CFHeaders, CFilter, GetCFCheckpt, GetCFHeaders, GetCFilters,
};
fn hash(slice: [u8;32]) -> Hash {
Hash::from_slice(&slice).unwrap()
}
fn hash(slice: [u8; 32]) -> Hash { Hash::from_slice(&slice).unwrap() }
#[test]
fn full_round_ser_der_raw_network_message_test() {
@ -500,21 +540,32 @@ mod test {
let tx: Transaction = deserialize(&Vec::from_hex("0100000001a15d57094aa7a21a28cb20b59aab8fc7d1149a3bdbcddba9c622e4f5f6a99ece010000006c493046022100f93bb0e7d8db7bd46e40132d1f8242026e045f03a0efe71bbb8e3f475e970d790221009337cd7f1f929f00cc6ff01f03729b069a7c21b59b1736ddfee5db5946c5da8c0121033b9b137ee87d5a812d6f506efdd37f0affa7ffc310711c06c7f3e097c9447c52ffffffff0100e1f505000000001976a9140389035a9225b3839e2bbf32d826a1e222031fd888ac00000000").unwrap()).unwrap();
let block: Block = deserialize(&include_bytes!("../../tests/data/testnet_block_000000000000045e0b1660b6445b5e5c5ab63c9a4f956be7e1e69be04fa4497b.raw")[..]).unwrap();
let header: block::Header = deserialize(&Vec::from_hex("010000004ddccd549d28f385ab457e98d1b11ce80bfea2c5ab93015ade4973e400000000bf4473e53794beae34e64fccc471dace6ae544180816f89591894e0f417a914cd74d6e49ffff001d323b3a7b").unwrap()).unwrap();
let script: Script = deserialize(&Vec::from_hex("1976a91431a420903c05a0a7de2de40c9f02ebedbacdc17288ac").unwrap()).unwrap();
let script: Script = deserialize(
&Vec::from_hex("1976a91431a420903c05a0a7de2de40c9f02ebedbacdc17288ac").unwrap(),
)
.unwrap();
let merkle_block: MerkleBlock = deserialize(&Vec::from_hex("0100000079cda856b143d9db2c1caff01d1aecc8630d30625d10e8b4b8b0000000000000b50cc069d6a3e33e3ff84a5c41d9d3febe7c770fdcc96b2c3ff60abe184f196367291b4d4c86041b8fa45d630100000001b50cc069d6a3e33e3ff84a5c41d9d3febe7c770fdcc96b2c3ff60abe184f19630101").unwrap()).unwrap();
let cmptblock = deserialize(&Vec::from_hex("00000030d923ad36ff2d955abab07f8a0a6e813bc6e066b973e780c5e36674cad5d1cd1f6e265f2a17a0d35cbe701fe9d06e2c6324cfe135f6233e8b767bfa3fb4479b71115dc562ffff7f2006000000000000000000000000010002000000010000000000000000000000000000000000000000000000000000000000000000ffffffff0302ee00ffffffff0100f9029500000000015100000000").unwrap()).unwrap();
let blocktxn = deserialize(&Vec::from_hex("2e93c0cff39ff605020072d96bc3a8d20b8447e294d08092351c8583e08d9b5a01020000000001010000000000000000000000000000000000000000000000000000000000000000ffffffff0402dc0000ffffffff0200f90295000000001976a9142b4569203694fc997e13f2c0a1383b9e16c77a0d88ac0000000000000000266a24aa21a9ede2f61c3f71d1defd3fa999dfa36953755c690689799962b48bebd836974e8cf90120000000000000000000000000000000000000000000000000000000000000000000000000").unwrap()).unwrap();
let msgs = vec![
NetworkMessage::Version(version_msg),
NetworkMessage::Verack,
NetworkMessage::Addr(vec![(45, Address::new(&([123,255,000,100], 833).into(), ServiceFlags::NETWORK))]),
NetworkMessage::Addr(vec![(
45,
Address::new(&([123, 255, 000, 100], 833).into(), ServiceFlags::NETWORK),
)]),
NetworkMessage::Inv(vec![Inventory::Block(hash([8u8; 32]).into())]),
NetworkMessage::GetData(vec![Inventory::Transaction(hash([45u8; 32]).into())]),
NetworkMessage::NotFound(vec![Inventory::Error]),
NetworkMessage::GetBlocks(GetBlocksMessage::new(vec![hash([1u8; 32]).into(), hash([4u8; 32]).into()], hash([5u8; 32]).into())),
NetworkMessage::GetHeaders(GetHeadersMessage::new(vec![hash([10u8; 32]).into(), hash([40u8; 32]).into()], hash([50u8; 32]).into())),
NetworkMessage::GetBlocks(GetBlocksMessage::new(
vec![hash([1u8; 32]).into(), hash([4u8; 32]).into()],
hash([5u8; 32]).into(),
)),
NetworkMessage::GetHeaders(GetHeadersMessage::new(
vec![hash([10u8; 32]).into(), hash([40u8; 32]).into()],
hash([50u8; 32]).into(),
)),
NetworkMessage::MemPool,
NetworkMessage::Tx(tx),
NetworkMessage::Block(block),
@ -524,39 +575,86 @@ mod test {
NetworkMessage::Ping(15),
NetworkMessage::Pong(23),
NetworkMessage::MerkleBlock(merkle_block),
NetworkMessage::FilterLoad(FilterLoad {filter: Vec::from_hex("03614e9b050000000000000001").unwrap(), hash_funcs: 1, tweak: 2, flags: BloomFlags::All}),
NetworkMessage::FilterAdd(FilterAdd {data: script.as_bytes().to_vec()}),
NetworkMessage::FilterAdd(FilterAdd {data: hash([29u8; 32]).to_vec()}),
NetworkMessage::FilterLoad(FilterLoad {
filter: Vec::from_hex("03614e9b050000000000000001").unwrap(),
hash_funcs: 1,
tweak: 2,
flags: BloomFlags::All,
}),
NetworkMessage::FilterAdd(FilterAdd { data: script.as_bytes().to_vec() }),
NetworkMessage::FilterAdd(FilterAdd { data: hash([29u8; 32]).to_vec() }),
NetworkMessage::FilterClear,
NetworkMessage::GetCFilters(GetCFilters{filter_type: 2, start_height: 52, stop_hash: hash([42u8; 32]).into()}),
NetworkMessage::CFilter(CFilter{filter_type: 7, block_hash: hash([25u8; 32]).into(), filter: vec![1,2,3]}),
NetworkMessage::GetCFHeaders(GetCFHeaders{filter_type: 4, start_height: 102, stop_hash: hash([47u8; 32]).into()}),
NetworkMessage::CFHeaders(CFHeaders{filter_type: 13, stop_hash: hash([53u8; 32]).into(), previous_filter_header: hash([12u8; 32]).into(), filter_hashes: vec![hash([4u8; 32]).into(), hash([12u8; 32]).into()]}),
NetworkMessage::GetCFCheckpt(GetCFCheckpt{filter_type: 17, stop_hash: hash([25u8; 32]).into()}),
NetworkMessage::CFCheckpt(CFCheckpt{filter_type: 27, stop_hash: hash([77u8; 32]).into(), filter_headers: vec![hash([3u8; 32]).into(), hash([99u8; 32]).into()]}),
NetworkMessage::Alert(vec![45,66,3,2,6,8,9,12,3,130]),
NetworkMessage::Reject(Reject{message: "Test reject".into(), ccode: RejectReason::Duplicate, reason: "Cause".into(), hash: hash([255u8; 32])}),
NetworkMessage::GetCFilters(GetCFilters {
filter_type: 2,
start_height: 52,
stop_hash: hash([42u8; 32]).into(),
}),
NetworkMessage::CFilter(CFilter {
filter_type: 7,
block_hash: hash([25u8; 32]).into(),
filter: vec![1, 2, 3],
}),
NetworkMessage::GetCFHeaders(GetCFHeaders {
filter_type: 4,
start_height: 102,
stop_hash: hash([47u8; 32]).into(),
}),
NetworkMessage::CFHeaders(CFHeaders {
filter_type: 13,
stop_hash: hash([53u8; 32]).into(),
previous_filter_header: hash([12u8; 32]).into(),
filter_hashes: vec![hash([4u8; 32]).into(), hash([12u8; 32]).into()],
}),
NetworkMessage::GetCFCheckpt(GetCFCheckpt {
filter_type: 17,
stop_hash: hash([25u8; 32]).into(),
}),
NetworkMessage::CFCheckpt(CFCheckpt {
filter_type: 27,
stop_hash: hash([77u8; 32]).into(),
filter_headers: vec![hash([3u8; 32]).into(), hash([99u8; 32]).into()],
}),
NetworkMessage::Alert(vec![45, 66, 3, 2, 6, 8, 9, 12, 3, 130]),
NetworkMessage::Reject(Reject {
message: "Test reject".into(),
ccode: RejectReason::Duplicate,
reason: "Cause".into(),
hash: hash([255u8; 32]),
}),
NetworkMessage::FeeFilter(1000),
NetworkMessage::WtxidRelay,
NetworkMessage::AddrV2(vec![AddrV2Message{ addr: AddrV2::Ipv4(Ipv4Addr::new(127, 0, 0, 1)), port: 0, services: ServiceFlags::NONE, time: 0 }]),
NetworkMessage::AddrV2(vec![AddrV2Message {
addr: AddrV2::Ipv4(Ipv4Addr::new(127, 0, 0, 1)),
port: 0,
services: ServiceFlags::NONE,
time: 0,
}]),
NetworkMessage::SendAddrV2,
NetworkMessage::CmpctBlock(cmptblock),
NetworkMessage::GetBlockTxn(GetBlockTxn { txs_request: BlockTransactionsRequest { block_hash: hash([11u8; 32]).into(), indexes: vec![0, 1, 2, 3, 10, 3002] } }),
NetworkMessage::GetBlockTxn(GetBlockTxn {
txs_request: BlockTransactionsRequest {
block_hash: hash([11u8; 32]).into(),
indexes: vec![0, 1, 2, 3, 10, 3002],
},
}),
NetworkMessage::BlockTxn(blocktxn),
NetworkMessage::SendCmpct(SendCmpct{send_compact: true, version: 8333}),
NetworkMessage::SendCmpct(SendCmpct { send_compact: true, version: 8333 }),
];
for msg in msgs {
let raw_msg = RawNetworkMessage {magic: Magic::from_bytes([57, 0, 0, 0]), payload: msg};
let raw_msg =
RawNetworkMessage { magic: Magic::from_bytes([57, 0, 0, 0]), payload: msg };
assert_eq!(deserialize::<RawNetworkMessage>(&serialize(&raw_msg)).unwrap(), raw_msg);
}
}
#[test]
fn commandstring_test() {
// Test converting.
assert_eq!(CommandString::try_from_static("AndrewAndrew").unwrap().as_ref(), "AndrewAndrew");
assert_eq!(
CommandString::try_from_static("AndrewAndrew").unwrap().as_ref(),
"AndrewAndrew"
);
assert!(CommandString::try_from_static("AndrewAndrewA").is_err());
// Test serializing.
@ -564,101 +662,77 @@ mod test {
assert_eq!(serialize(&cs), vec![0x41u8, 0x6e, 0x64, 0x72, 0x65, 0x77, 0, 0, 0, 0, 0, 0]);
// Test deserializing
let cs: Result<CommandString, _> = deserialize(&[0x41u8, 0x6e, 0x64, 0x72, 0x65, 0x77, 0, 0, 0, 0, 0, 0]);
let cs: Result<CommandString, _> =
deserialize(&[0x41u8, 0x6e, 0x64, 0x72, 0x65, 0x77, 0, 0, 0, 0, 0, 0]);
assert!(cs.is_ok());
assert_eq!(cs.as_ref().unwrap().to_string(), "Andrew".to_owned());
assert_eq!(cs.unwrap(), CommandString::try_from_static("Andrew").unwrap());
let short_cs: Result<CommandString, _> = deserialize(&[0x41u8, 0x6e, 0x64, 0x72, 0x65, 0x77, 0, 0, 0, 0, 0]);
let short_cs: Result<CommandString, _> =
deserialize(&[0x41u8, 0x6e, 0x64, 0x72, 0x65, 0x77, 0, 0, 0, 0, 0]);
assert!(short_cs.is_err());
}
#[test]
#[rustfmt::skip]
fn serialize_verack_test() {
assert_eq!(serialize(&RawNetworkMessage { magic: Magic::from(Network::Bitcoin), payload: NetworkMessage::Verack }),
vec![0xf9, 0xbe, 0xb4, 0xd9, 0x76, 0x65, 0x72, 0x61,
0x63, 0x6B, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x5d, 0xf6, 0xe0, 0xe2]);
vec![0xf9, 0xbe, 0xb4, 0xd9, 0x76, 0x65, 0x72, 0x61,
0x63, 0x6B, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x5d, 0xf6, 0xe0, 0xe2]);
}
#[test]
#[rustfmt::skip]
fn serialize_ping_test() {
assert_eq!(serialize(&RawNetworkMessage { magic: Magic::from(Network::Bitcoin), payload: NetworkMessage::Ping(100) }),
vec![0xf9, 0xbe, 0xb4, 0xd9, 0x70, 0x69, 0x6e, 0x67,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x08, 0x00, 0x00, 0x00, 0x24, 0x67, 0xf1, 0x1d,
0x64, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]);
vec![0xf9, 0xbe, 0xb4, 0xd9, 0x70, 0x69, 0x6e, 0x67,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x08, 0x00, 0x00, 0x00, 0x24, 0x67, 0xf1, 0x1d,
0x64, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]);
}
#[test]
#[rustfmt::skip]
fn serialize_mempool_test() {
assert_eq!(serialize(&RawNetworkMessage { magic: Magic::from(Network::Bitcoin), payload: NetworkMessage::MemPool }),
vec![0xf9, 0xbe, 0xb4, 0xd9, 0x6d, 0x65, 0x6d, 0x70,
0x6f, 0x6f, 0x6c, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x5d, 0xf6, 0xe0, 0xe2]);
vec![0xf9, 0xbe, 0xb4, 0xd9, 0x6d, 0x65, 0x6d, 0x70,
0x6f, 0x6f, 0x6c, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x5d, 0xf6, 0xe0, 0xe2]);
}
#[test]
#[rustfmt::skip]
fn serialize_getaddr_test() {
assert_eq!(serialize(&RawNetworkMessage { magic: Magic::from(Network::Bitcoin), payload: NetworkMessage::GetAddr }),
vec![0xf9, 0xbe, 0xb4, 0xd9, 0x67, 0x65, 0x74, 0x61,
0x64, 0x64, 0x72, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x5d, 0xf6, 0xe0, 0xe2]);
vec![0xf9, 0xbe, 0xb4, 0xd9, 0x67, 0x65, 0x74, 0x61,
0x64, 0x64, 0x72, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x5d, 0xf6, 0xe0, 0xe2]);
}
#[test]
fn deserialize_getaddr_test() {
let msg = deserialize(
&[0xf9, 0xbe, 0xb4, 0xd9, 0x67, 0x65, 0x74, 0x61,
0x64, 0x64, 0x72, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x5d, 0xf6, 0xe0, 0xe2]);
let preimage = RawNetworkMessage { magic: Magic::from(Network::Bitcoin), payload: NetworkMessage::GetAddr };
#[rustfmt::skip]
let msg = deserialize(&[
0xf9, 0xbe, 0xb4, 0xd9, 0x67, 0x65, 0x74, 0x61,
0x64, 0x64, 0x72, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x5d, 0xf6, 0xe0, 0xe2
]);
let preimage = RawNetworkMessage {
magic: Magic::from(Network::Bitcoin),
payload: NetworkMessage::GetAddr,
};
assert!(msg.is_ok());
let msg : RawNetworkMessage = msg.unwrap();
let msg: RawNetworkMessage = msg.unwrap();
assert_eq!(preimage.magic, msg.magic);
assert_eq!(preimage.payload, msg.payload);
}
#[test]
fn deserialize_version_test() {
let msg = deserialize::<RawNetworkMessage>(
&[ 0xf9, 0xbe, 0xb4, 0xd9, 0x76, 0x65, 0x72, 0x73,
0x69, 0x6f, 0x6e, 0x00, 0x00, 0x00, 0x00, 0x00,
0x66, 0x00, 0x00, 0x00, 0xbe, 0x61, 0xb8, 0x27,
0x7f, 0x11, 0x01, 0x00, 0x0d, 0x04, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0xf0, 0x0f, 0x4d, 0x5c,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff,
0x5b, 0xf0, 0x8c, 0x80, 0xb4, 0xbd, 0x0d, 0x04,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0xfa, 0xa9, 0x95, 0x59, 0xcc, 0x68, 0xa1, 0xc1,
0x10, 0x2f, 0x53, 0x61, 0x74, 0x6f, 0x73, 0x68,
0x69, 0x3a, 0x30, 0x2e, 0x31, 0x37, 0x2e, 0x31,
0x2f, 0x93, 0x8c, 0x08, 0x00, 0x01 ]);
assert!(msg.is_ok());
let msg = msg.unwrap();
assert_eq!(msg.magic, Magic::from(Network::Bitcoin));
if let NetworkMessage::Version(version_msg) = msg.payload {
assert_eq!(version_msg.version, 70015);
assert_eq!(version_msg.services, ServiceFlags::NETWORK | ServiceFlags::BLOOM | ServiceFlags::WITNESS | ServiceFlags::NETWORK_LIMITED);
assert_eq!(version_msg.timestamp, 1548554224);
assert_eq!(version_msg.nonce, 13952548347456104954);
assert_eq!(version_msg.user_agent, "/Satoshi:0.17.1/");
assert_eq!(version_msg.start_height, 560275);
assert!(version_msg.relay);
} else {
panic!("Wrong message type");
}
}
#[test]
fn deserialize_partial_message_test() {
let data = [ 0xf9, 0xbe, 0xb4, 0xd9, 0x76, 0x65, 0x72, 0x73,
#[rustfmt::skip]
let msg = deserialize::<RawNetworkMessage>(&[
0xf9, 0xbe, 0xb4, 0xd9, 0x76, 0x65, 0x72, 0x73,
0x69, 0x6f, 0x6e, 0x00, 0x00, 0x00, 0x00, 0x00,
0x66, 0x00, 0x00, 0x00, 0xbe, 0x61, 0xb8, 0x27,
0x7f, 0x11, 0x01, 0x00, 0x0d, 0x04, 0x00, 0x00,
@ -673,7 +747,52 @@ mod test {
0xfa, 0xa9, 0x95, 0x59, 0xcc, 0x68, 0xa1, 0xc1,
0x10, 0x2f, 0x53, 0x61, 0x74, 0x6f, 0x73, 0x68,
0x69, 0x3a, 0x30, 0x2e, 0x31, 0x37, 0x2e, 0x31,
0x2f, 0x93, 0x8c, 0x08, 0x00, 0x01, 0, 0 ];
0x2f, 0x93, 0x8c, 0x08, 0x00, 0x01
]);
assert!(msg.is_ok());
let msg = msg.unwrap();
assert_eq!(msg.magic, Magic::from(Network::Bitcoin));
if let NetworkMessage::Version(version_msg) = msg.payload {
assert_eq!(version_msg.version, 70015);
assert_eq!(
version_msg.services,
ServiceFlags::NETWORK
| ServiceFlags::BLOOM
| ServiceFlags::WITNESS
| ServiceFlags::NETWORK_LIMITED
);
assert_eq!(version_msg.timestamp, 1548554224);
assert_eq!(version_msg.nonce, 13952548347456104954);
assert_eq!(version_msg.user_agent, "/Satoshi:0.17.1/");
assert_eq!(version_msg.start_height, 560275);
assert!(version_msg.relay);
} else {
panic!("Wrong message type");
}
}
#[test]
fn deserialize_partial_message_test() {
#[rustfmt::skip]
let data = [
0xf9, 0xbe, 0xb4, 0xd9, 0x76, 0x65, 0x72, 0x73,
0x69, 0x6f, 0x6e, 0x00, 0x00, 0x00, 0x00, 0x00,
0x66, 0x00, 0x00, 0x00, 0xbe, 0x61, 0xb8, 0x27,
0x7f, 0x11, 0x01, 0x00, 0x0d, 0x04, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0xf0, 0x0f, 0x4d, 0x5c,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff,
0x5b, 0xf0, 0x8c, 0x80, 0xb4, 0xbd, 0x0d, 0x04,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0xfa, 0xa9, 0x95, 0x59, 0xcc, 0x68, 0xa1, 0xc1,
0x10, 0x2f, 0x53, 0x61, 0x74, 0x6f, 0x73, 0x68,
0x69, 0x3a, 0x30, 0x2e, 0x31, 0x37, 0x2e, 0x31,
0x2f, 0x93, 0x8c, 0x08, 0x00, 0x01, 0x00, 0x00
];
let msg = deserialize_partial::<RawNetworkMessage>(&data);
assert!(msg.is_ok());
@ -682,7 +801,13 @@ mod test {
assert_eq!(msg.magic, Magic::from(Network::Bitcoin));
if let NetworkMessage::Version(version_msg) = msg.payload {
assert_eq!(version_msg.version, 70015);
assert_eq!(version_msg.services, ServiceFlags::NETWORK | ServiceFlags::BLOOM | ServiceFlags::WITNESS | ServiceFlags::NETWORK_LIMITED);
assert_eq!(
version_msg.services,
ServiceFlags::NETWORK
| ServiceFlags::BLOOM
| ServiceFlags::WITNESS
| ServiceFlags::NETWORK_LIMITED
);
assert_eq!(version_msg.timestamp, 1548554224);
assert_eq!(version_msg.nonce, 13952548347456104954);
assert_eq!(version_msg.user_agent, "/Satoshi:0.17.1/");

View File

@ -7,16 +7,13 @@
//! Bitcoin data (blocks and transactions) around.
//!
use crate::prelude::*;
use crate::io;
use crate::hashes::{Hash as _, sha256d};
use crate::network::constants;
use crate::consensus::encode::{self, Decodable, Encodable};
use crate::hash_types::{BlockHash, Txid, Wtxid};
use crate::hashes::{sha256d, Hash as _};
use crate::internal_macros::impl_consensus_encoding;
use crate::io;
use crate::network::constants;
use crate::prelude::*;
/// An inventory item.
#[derive(PartialEq, Eq, Clone, Debug, Copy, Hash, PartialOrd, Ord)]
@ -41,7 +38,7 @@ pub enum Inventory {
inv_type: u32,
/// The hash of the inventory item
hash: [u8; 32],
}
},
}
impl Encodable for Inventory {
@ -50,7 +47,7 @@ impl Encodable for Inventory {
macro_rules! encode_inv {
($code:expr, $item:expr) => {
u32::consensus_encode(&$code, w)? + $item.consensus_encode(w)?
}
};
}
Ok(match *self {
Inventory::Error => encode_inv!(0, sha256d::Hash::all_zeros()),
@ -77,10 +74,7 @@ impl Decodable for Inventory {
5 => Inventory::WTx(Decodable::consensus_decode(r)?),
0x40000001 => Inventory::WitnessTransaction(Decodable::consensus_decode(r)?),
0x40000002 => Inventory::WitnessBlock(Decodable::consensus_decode(r)?),
tp => Inventory::Unknown {
inv_type: tp,
hash: Decodable::consensus_decode(r)?,
}
tp => Inventory::Unknown { inv_type: tp, hash: Decodable::consensus_decode(r)? },
})
}
}
@ -110,17 +104,13 @@ pub struct GetHeadersMessage {
/// if possible and block 1 otherwise.
pub locator_hashes: Vec<BlockHash>,
/// References the header to stop at, or zero to just fetch the maximum 2000 headers
pub stop_hash: BlockHash
pub stop_hash: BlockHash,
}
impl GetBlocksMessage {
/// Construct a new `getblocks` message
pub fn new(locator_hashes: Vec<BlockHash>, stop_hash: BlockHash) -> GetBlocksMessage {
GetBlocksMessage {
version: constants::PROTOCOL_VERSION,
locator_hashes,
stop_hash,
}
GetBlocksMessage { version: constants::PROTOCOL_VERSION, locator_hashes, stop_hash }
}
}
@ -129,11 +119,7 @@ impl_consensus_encoding!(GetBlocksMessage, version, locator_hashes, stop_hash);
impl GetHeadersMessage {
/// Construct a new `getheaders` message
pub fn new(locator_hashes: Vec<BlockHash>, stop_hash: BlockHash) -> GetHeadersMessage {
GetHeadersMessage {
version: constants::PROTOCOL_VERSION,
locator_hashes,
stop_hash,
}
GetHeadersMessage { version: constants::PROTOCOL_VERSION, locator_hashes, stop_hash }
}
}
@ -141,16 +127,17 @@ impl_consensus_encoding!(GetHeadersMessage, version, locator_hashes, stop_hash);
#[cfg(test)]
mod tests {
use super::{Vec, GetHeadersMessage, GetBlocksMessage};
use super::{GetBlocksMessage, GetHeadersMessage, Vec};
use crate::consensus::encode::{deserialize, serialize};
use crate::hashes::hex::FromHex;
use crate::hashes::Hash;
use crate::consensus::encode::{deserialize, serialize};
#[test]
fn getblocks_message_test() {
let from_sat = Vec::from_hex("72110100014a5e1e4baab89f3a32518a88c31bc87f618f76673e2cc77ab2127b7afdeda33b0000000000000000000000000000000000000000000000000000000000000000").unwrap();
let genhash = Vec::from_hex("4a5e1e4baab89f3a32518a88c31bc87f618f76673e2cc77ab2127b7afdeda33b").unwrap();
let genhash =
Vec::from_hex("4a5e1e4baab89f3a32518a88c31bc87f618f76673e2cc77ab2127b7afdeda33b")
.unwrap();
let decode: Result<GetBlocksMessage, _> = deserialize(&from_sat);
assert!(decode.is_ok());
@ -166,7 +153,9 @@ mod tests {
#[test]
fn getheaders_message_test() {
let from_sat = Vec::from_hex("72110100014a5e1e4baab89f3a32518a88c31bc87f618f76673e2cc77ab2127b7afdeda33b0000000000000000000000000000000000000000000000000000000000000000").unwrap();
let genhash = Vec::from_hex("4a5e1e4baab89f3a32518a88c31bc87f618f76673e2cc77ab2127b7afdeda33b").unwrap();
let genhash =
Vec::from_hex("4a5e1e4baab89f3a32518a88c31bc87f618f76673e2cc77ab2127b7afdeda33b")
.unwrap();
let decode: Result<GetHeadersMessage, _> = deserialize(&from_sat);
assert!(decode.is_ok());

View File

@ -5,11 +5,11 @@
//! This module describes BIP37 Connection Bloom filtering network messages.
//!
use crate::consensus::encode;
use crate::consensus::{Decodable, Encodable, ReadExt};
use crate::internal_macros::impl_consensus_encoding;
use std::io;
use crate::consensus::{encode, Decodable, Encodable, ReadExt};
use crate::internal_macros::impl_consensus_encoding;
/// `filterload` message sets the current bloom filter
#[derive(Clone, PartialEq, Eq, Debug)]
pub struct FilterLoad {

View File

@ -2,8 +2,8 @@
//! BIP152 Compact Blocks network messages
//!
use crate::internal_macros::impl_consensus_encoding;
use crate::bip152;
use crate::internal_macros::impl_consensus_encoding;
/// sendcmpct message
#[derive(PartialEq, Eq, Clone, Debug, Copy, PartialOrd, Ord, Hash)]

View File

@ -7,16 +7,13 @@
//! capabilities.
//!
use crate::prelude::*;
use crate::io;
use crate::network::address::Address;
use crate::network::constants::{self, ServiceFlags};
use crate::consensus::{Encodable, Decodable, ReadExt};
use crate::consensus::encode;
use crate::consensus::{encode, Decodable, Encodable, ReadExt};
use crate::hashes::sha256d;
use crate::internal_macros::impl_consensus_encoding;
use crate::io;
use crate::network::address::Address;
use crate::network::constants::{self, ServiceFlags};
use crate::prelude::*;
/// Some simple messages
@ -42,7 +39,7 @@ pub struct VersionMessage {
/// Whether the receiving peer should relay messages to the sender; used
/// if the sender is bandwidth-limited and would like to support bloom
/// filtering. Defaults to false.
pub relay: bool
pub relay: bool,
}
impl VersionMessage {
@ -70,9 +67,18 @@ impl VersionMessage {
}
}
impl_consensus_encoding!(VersionMessage, version, services, timestamp,
receiver, sender, nonce,
user_agent, start_height, relay);
impl_consensus_encoding!(
VersionMessage,
version,
services,
timestamp,
receiver,
sender,
nonce,
user_agent,
start_height,
relay
);
/// message rejection reason as a code
#[derive(PartialEq, Eq, Clone, Copy, Debug)]
@ -92,7 +98,7 @@ pub enum RejectReason {
/// insufficient fee
Fee = 0x42,
/// checkpoint
Checkpoint = 0x43
Checkpoint = 0x43,
}
impl Encodable for RejectReason {
@ -113,7 +119,7 @@ impl Decodable for RejectReason {
0x41 => RejectReason::Dust,
0x42 => RejectReason::Fee,
0x43 => RejectReason::Checkpoint,
_ => return Err(encode::Error::ParseFailed("unknown reject code"))
_ => return Err(encode::Error::ParseFailed("unknown reject code")),
})
}
}
@ -128,23 +134,19 @@ pub struct Reject {
/// reason of rejectection
pub reason: Cow<'static, str>,
/// reference to rejected item
pub hash: sha256d::Hash
pub hash: sha256d::Hash,
}
impl_consensus_encoding!(Reject, message, ccode, reason, hash);
#[cfg(test)]
mod tests {
use super::VersionMessage;
use super::Reject;
use super::RejectReason;
use super::{Reject, RejectReason, VersionMessage};
use crate::consensus::encode::{deserialize, serialize};
use crate::hashes::hex::FromHex;
use crate::hashes::sha256d::Hash;
use crate::network::constants::ServiceFlags;
use crate::consensus::encode::{deserialize, serialize};
#[test]
fn version_message_test() {
// This message is from my satoshi node, morning of May 27 2014
@ -181,7 +183,8 @@ mod tests {
assert_eq!(RejectReason::Duplicate, conflict.ccode);
assert_eq!("txn-mempool-conflict", conflict.reason);
assert_eq!(
Hash::from_hex("0470f4f2dc4191221b59884bcffaaf00932748ab46356a80413c0b86d354df05").unwrap(),
Hash::from_hex("0470f4f2dc4191221b59884bcffaaf00932748ab46356a80413c0b86d354df05")
.unwrap(),
conflict.hash
);
@ -190,7 +193,8 @@ mod tests {
assert_eq!(RejectReason::NonStandard, nonfinal.ccode);
assert_eq!("non-final", nonfinal.reason);
assert_eq!(
Hash::from_hex("0b46a539138b5fde4e341b37f2d945c23d41193b30caa7fcbd8bdb836cbe9b25").unwrap(),
Hash::from_hex("0b46a539138b5fde4e341b37f2d945c23d41193b30caa7fcbd8bdb836cbe9b25")
.unwrap(),
nonfinal.hash
);

View File

@ -29,7 +29,7 @@ pub mod message_bloom;
pub mod message_compact_blocks;
#[cfg(feature = "std")]
#[cfg_attr(docsrs, doc(cfg(feature = "std")))]
pub mod message_network;
pub mod message_filter;
#[cfg(feature = "std")]
#[cfg_attr(docsrs, doc(cfg(feature = "std")))]
pub mod message_filter;
pub mod message_network;

View File

@ -8,20 +8,21 @@
//! and legacy (before Bip143).
//!
use core::{str, fmt};
use core::borrow::Borrow;
use core::ops::{Deref, DerefMut};
use core::{fmt, str};
use crate::{io, Script, Transaction, TxIn, TxOut, Sequence, Sighash};
use crate::blockdata::transaction::EncodeSigningDataResult;
use crate::blockdata::witness::Witness;
use crate::consensus::{encode, Encodable};
use crate::error::impl_std_error;
use crate::hashes::{sha256, sha256d, Hash};
use crate::prelude::*;
use crate::util::taproot::{TapLeafHash, TAPROOT_ANNEX_PREFIX, TapSighashHash, LeafVersion};
use crate::util::taproot::{LeafVersion, TapLeafHash, TapSighashHash, TAPROOT_ANNEX_PREFIX};
use crate::{io, Script, Sequence, Sighash, Transaction, TxIn, TxOut};
/// Used for signature hash for invalid use of SIGHASH_SINGLE.
#[rustfmt::skip]
pub(crate) const UINT256_ONE: [u8; 32] = [
1, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
@ -31,7 +32,7 @@ pub(crate) const UINT256_ONE: [u8; 32] = [
/// Efficiently calculates signature hash message for legacy, segwit and taproot inputs.
#[derive(Debug)]
pub struct SighashCache<T: Deref<Target=Transaction>> {
pub struct SighashCache<T: Deref<Target = Transaction>> {
/// Access to transaction required for transaction introspection. Moreover, type
/// `T: Deref<Target=Transaction>` allows us to use borrowed and mutable borrowed types,
/// the latter in particular is necessary for [`SighashCache::witness_mut`].
@ -76,7 +77,10 @@ struct TaprootCache {
/// Contains outputs of previous transactions. In the case [`SchnorrSighashType`] variant is
/// `SIGHASH_ANYONECANPAY`, [`Prevouts::One`] may be used.
#[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)]
pub enum Prevouts<'u, T> where T: 'u + Borrow<TxOut> {
pub enum Prevouts<'u, T>
where
T: 'u + Borrow<TxOut>,
{
/// `One` variant allows provision of the single prevout needed. It's useful, for example, when
/// modifier `SIGHASH_ANYONECANPAY` is provided, only prevout of the current input is needed.
/// The first `usize` argument is the input index this [`TxOut`] is referring to.
@ -149,7 +153,7 @@ impl str::FromStr for SchnorrSighashType {
"SIGHASH_ALL|SIGHASH_ANYONECANPAY" => Ok(SchnorrSighashType::AllPlusAnyoneCanPay),
"SIGHASH_NONE|SIGHASH_ANYONECANPAY" => Ok(SchnorrSighashType::NonePlusAnyoneCanPay),
"SIGHASH_SINGLE|SIGHASH_ANYONECANPAY" => Ok(SchnorrSighashType::SinglePlusAnyoneCanPay),
_ => Err(SighashTypeParseError{ unrecognized: s.to_owned() }),
_ => Err(SighashTypeParseError { unrecognized: s.to_owned() }),
}
}
}
@ -232,7 +236,10 @@ impl std::error::Error for Error {
}
}
impl<'u, T> Prevouts<'u, T> where T: Borrow<TxOut> {
impl<'u, T> Prevouts<'u, T>
where
T: Borrow<TxOut>,
{
fn check_all(&self, tx: &Transaction) -> Result<(), Error> {
if let Prevouts::All(prevouts) = self {
if prevouts.len() != tx.input.len() {
@ -251,17 +258,14 @@ impl<'u, T> Prevouts<'u, T> where T: Borrow<TxOut> {
fn get(&self, input_index: usize) -> Result<&TxOut, Error> {
match self {
Prevouts::One(index, prevout) => {
Prevouts::One(index, prevout) =>
if input_index == *index {
Ok(prevout.borrow())
} else {
Err(Error::PrevoutIndex)
}
}
Prevouts::All(prevouts) => prevouts
.get(input_index)
.map(|x| x.borrow())
.ok_or(Error::PrevoutIndex),
},
Prevouts::All(prevouts) =>
prevouts.get(input_index).map(|x| x.borrow()).ok_or(Error::PrevoutIndex),
}
}
}
@ -269,20 +273,18 @@ impl<'u, T> Prevouts<'u, T> where T: Borrow<TxOut> {
impl<'s> ScriptPath<'s> {
/// Creates a new `ScriptPath` structure.
pub fn new(script: &'s Script, leaf_version: LeafVersion) -> Self {
ScriptPath {
script,
leaf_version,
}
ScriptPath { script, leaf_version }
}
/// Creates a new `ScriptPath` structure using default leaf version value.
pub fn with_defaults(script: &'s Script) -> Self {
Self::new(script, LeafVersion::TapScript)
}
pub fn with_defaults(script: &'s Script) -> Self { Self::new(script, LeafVersion::TapScript) }
/// Computes the leaf hash for this `ScriptPath`.
pub fn leaf_hash(&self) -> TapLeafHash {
let mut enc = TapLeafHash::engine();
self.leaf_version.to_consensus().consensus_encode(&mut enc).expect("Writing to hash enging should never fail");
self.leaf_version
.to_consensus()
.consensus_encode(&mut enc)
.expect("Writing to hash enging should never fail");
self.script.consensus_encode(&mut enc).expect("Writing to hash enging should never fail");
TapLeafHash::from_engine(enc)
@ -290,9 +292,7 @@ impl<'s> ScriptPath<'s> {
}
impl<'s> From<ScriptPath<'s>> for TapLeafHash {
fn from(script_path: ScriptPath<'s>) -> TapLeafHash {
script_path.leaf_hash()
}
fn from(script_path: ScriptPath<'s>) -> TapLeafHash { script_path.leaf_hash() }
}
/// Hashtype of an input's signature, encoded in the last byte of the signature.
@ -302,20 +302,20 @@ impl<'s> From<ScriptPath<'s>> for TapLeafHash {
#[derive(PartialEq, Eq, Debug, Copy, Clone, Hash)]
pub enum EcdsaSighashType {
/// 0x1: Sign all outputs.
All = 0x01,
All = 0x01,
/// 0x2: Sign no outputs --- anyone can choose the destination.
None = 0x02,
None = 0x02,
/// 0x3: Sign the output whose index matches this input's index. If none exists,
/// sign the hash `0000000000000000000000000000000000000000000000000000000000000001`.
/// (This rule is probably an unintentional C++ism, but it's consensus so we have
/// to follow it.)
Single = 0x03,
Single = 0x03,
/// 0x81: Sign all outputs but only this input.
AllPlusAnyoneCanPay = 0x81,
AllPlusAnyoneCanPay = 0x81,
/// 0x82: Sign no outputs and only this input.
NonePlusAnyoneCanPay = 0x82,
NonePlusAnyoneCanPay = 0x82,
/// 0x83: Sign one output and only this input (see `Single` for what "one output" means).
SinglePlusAnyoneCanPay = 0x83
SinglePlusAnyoneCanPay = 0x83,
}
#[cfg(feature = "serde")]
crate::serde_utils::serde_string_impl!(EcdsaSighashType, "a EcdsaSighashType data");
@ -359,7 +359,7 @@ impl EcdsaSighashType {
EcdsaSighashType::Single => (EcdsaSighashType::Single, false),
EcdsaSighashType::AllPlusAnyoneCanPay => (EcdsaSighashType::All, true),
EcdsaSighashType::NonePlusAnyoneCanPay => (EcdsaSighashType::None, true),
EcdsaSighashType::SinglePlusAnyoneCanPay => (EcdsaSighashType::Single, true)
EcdsaSighashType::SinglePlusAnyoneCanPay => (EcdsaSighashType::Single, true),
}
}
@ -388,7 +388,7 @@ impl EcdsaSighashType {
0x83 => EcdsaSighashType::SinglePlusAnyoneCanPay,
// catchalls
x if x & 0x80 == 0x80 => EcdsaSighashType::AllPlusAnyoneCanPay,
_ => EcdsaSighashType::All
_ => EcdsaSighashType::All,
}
}
@ -406,7 +406,7 @@ impl EcdsaSighashType {
0x81 => Ok(EcdsaSighashType::AllPlusAnyoneCanPay),
0x82 => Ok(EcdsaSighashType::NonePlusAnyoneCanPay),
0x83 => Ok(EcdsaSighashType::SinglePlusAnyoneCanPay),
non_standard => Err(NonStandardSighashType(non_standard))
non_standard => Err(NonStandardSighashType(non_standard)),
}
}
@ -445,7 +445,7 @@ impl SchnorrSighashType {
/// Constructs a [`SchnorrSighashType`] from a raw `u8`.
pub fn from_consensus_u8(hash_ty: u8) -> Result<Self, Error> {
use SchnorrSighashType::*;
use SchnorrSighashType::*;
Ok(match hash_ty {
0x00 => Default,
@ -497,12 +497,7 @@ impl<R: Deref<Target = Transaction>> SighashCache<R> {
/// sighashes to be valid, no fields in the transaction may change except for script_sig and
/// witness.
pub fn new(tx: R) -> Self {
SighashCache {
tx,
common_cache: None,
taproot_cache: None,
segwit_cache: None,
}
SighashCache { tx, common_cache: None, taproot_cache: None, segwit_cache: None }
}
/// Encodes the BIP341 signing data for any flag type into a given object implementing a
@ -541,15 +536,9 @@ impl<R: Deref<Target = Transaction>> SighashCache<R> {
// sha_sequences (32): the SHA256 of the serialization of all input nSequence.
if !anyone_can_pay {
self.common_cache().prevouts.consensus_encode(&mut writer)?;
self.taproot_cache(prevouts.get_all()?)
.amounts
.consensus_encode(&mut writer)?;
self.taproot_cache(prevouts.get_all()?)
.script_pubkeys
.consensus_encode(&mut writer)?;
self.common_cache()
.sequences
.consensus_encode(&mut writer)?;
self.taproot_cache(prevouts.get_all()?).amounts.consensus_encode(&mut writer)?;
self.taproot_cache(prevouts.get_all()?).script_pubkeys.consensus_encode(&mut writer)?;
self.common_cache().sequences.consensus_encode(&mut writer)?;
}
// If hash_type & 3 does not equal SIGHASH_NONE or SIGHASH_SINGLE:
@ -576,21 +565,14 @@ impl<R: Deref<Target = Transaction>> SighashCache<R> {
// scriptPubKey (35): scriptPubKey of the previous output spent by this input, serialized as script inside CTxOut. Its size is always 35 bytes.
// nSequence (4): nSequence of this input.
if anyone_can_pay {
let txin =
&self
.tx
.input
.get(input_index)
.ok_or(Error::IndexOutOfInputsBounds {
index: input_index,
inputs_size: self.tx.input.len(),
})?;
let txin = &self.tx.input.get(input_index).ok_or(Error::IndexOutOfInputsBounds {
index: input_index,
inputs_size: self.tx.input.len(),
})?;
let previous_output = prevouts.get(input_index)?;
txin.previous_output.consensus_encode(&mut writer)?;
previous_output.value.consensus_encode(&mut writer)?;
previous_output
.script_pubkey
.consensus_encode(&mut writer)?;
previous_output.script_pubkey.consensus_encode(&mut writer)?;
txin.sequence.consensus_encode(&mut writer)?;
} else {
(input_index as u32).consensus_encode(&mut writer)?;
@ -725,23 +707,16 @@ impl<R: Deref<Target = Transaction>> SighashCache<R> {
&& sighash != EcdsaSighashType::Single
&& sighash != EcdsaSighashType::None
{
self.segwit_cache()
.sequences
.consensus_encode(&mut writer)?;
self.segwit_cache().sequences.consensus_encode(&mut writer)?;
} else {
zero_hash.consensus_encode(&mut writer)?;
}
{
let txin =
&self
.tx
.input
.get(input_index)
.ok_or(Error::IndexOutOfInputsBounds {
index: input_index,
inputs_size: self.tx.input.len(),
})?;
let txin = &self.tx.input.get(input_index).ok_or(Error::IndexOutOfInputsBounds {
index: input_index,
inputs_size: self.tx.input.len(),
})?;
txin.previous_output.consensus_encode(&mut writer)?;
script_code.consensus_encode(&mut writer)?;
@ -835,7 +810,8 @@ impl<R: Deref<Target = Transaction>> SighashCache<R> {
script_pubkey: &Script,
sighash_type: u32,
) -> Result<(), io::Error> {
let (sighash, anyone_can_pay) = EcdsaSighashType::from_consensus(sighash_type).split_anyonecanpay_flag();
let (sighash, anyone_can_pay) =
EcdsaSighashType::from_consensus(sighash_type).split_anyonecanpay_flag();
// Build tx to sign
let mut tx = Transaction {
@ -857,8 +833,19 @@ impl<R: Deref<Target = Transaction>> SighashCache<R> {
for (n, input) in self_.input.iter().enumerate() {
tx.input.push(TxIn {
previous_output: input.previous_output,
script_sig: if n == input_index { script_pubkey.clone() } else { Script::new() },
sequence: if n != input_index && (sighash == EcdsaSighashType::Single || sighash == EcdsaSighashType::None) { Sequence::ZERO } else { input.sequence },
script_sig: if n == input_index {
script_pubkey.clone()
} else {
Script::new()
},
sequence: if n != input_index
&& (sighash == EcdsaSighashType::Single
|| sighash == EcdsaSighashType::None)
{
Sequence::ZERO
} else {
input.sequence
},
witness: Witness::default(),
});
}
@ -867,14 +854,24 @@ impl<R: Deref<Target = Transaction>> SighashCache<R> {
tx.output = match sighash {
EcdsaSighashType::All => self_.output.clone(),
EcdsaSighashType::Single => {
let output_iter = self_.output.iter()
.take(input_index + 1) // sign all outputs up to and including this one, but erase
.enumerate() // all of them except for this one
.map(|(n, out)| if n == input_index { out.clone() } else { TxOut::default() });
let output_iter = self_
.output
.iter()
.take(input_index + 1) // sign all outputs up to and including this one, but erase
.enumerate() // all of them except for this one
.map(
|(n, out)| {
if n == input_index {
out.clone()
} else {
TxOut::default()
}
},
);
output_iter.collect()
}
EcdsaSighashType::None => vec![],
_ => unreachable!()
_ => unreachable!(),
};
// hash the result
tx.consensus_encode(&mut writer)?;
@ -888,8 +885,9 @@ impl<R: Deref<Target = Transaction>> SighashCache<R> {
writer,
input_index,
script_pubkey,
sighash_type
).map_err(|e| Error::Io(e.kind()))
sighash_type,
)
.map_err(|e| Error::Io(e.kind())),
)
}
@ -919,8 +917,10 @@ impl<R: Deref<Target = Transaction>> SighashCache<R> {
sighash_type: u32,
) -> Result<Sighash, Error> {
let mut enc = Sighash::engine();
if self.legacy_encode_signing_data_to(&mut enc, input_index, script_pubkey, sighash_type)
.is_sighash_single_bug()? {
if self
.legacy_encode_signing_data_to(&mut enc, input_index, script_pubkey, sighash_type)
.is_sighash_single_bug()?
{
Ok(Sighash::from_inner(UINT256_ONE))
} else {
Ok(Sighash::from_engine(enc))
@ -940,9 +940,7 @@ impl<R: Deref<Target = Transaction>> SighashCache<R> {
let mut enc_prevouts = sha256::Hash::engine();
let mut enc_sequences = sha256::Hash::engine();
for txin in tx.input.iter() {
txin.previous_output
.consensus_encode(&mut enc_prevouts)
.unwrap();
txin.previous_output.consensus_encode(&mut enc_prevouts).unwrap();
txin.sequence.consensus_encode(&mut enc_sequences).unwrap();
}
CommonCache {
@ -978,18 +976,13 @@ impl<R: Deref<Target = Transaction>> SighashCache<R> {
})
}
fn taproot_cache<T: Borrow<TxOut>>(&mut self, prevouts: &[T]) -> &TaprootCache
{
fn taproot_cache<T: Borrow<TxOut>>(&mut self, prevouts: &[T]) -> &TaprootCache {
self.taproot_cache.get_or_insert_with(|| {
let mut enc_amounts = sha256::Hash::engine();
let mut enc_script_pubkeys = sha256::Hash::engine();
for prevout in prevouts {
prevout.borrow().value.consensus_encode(&mut enc_amounts).unwrap();
prevout
.borrow()
.script_pubkey
.consensus_encode(&mut enc_script_pubkeys)
.unwrap();
prevout.borrow().script_pubkey.consensus_encode(&mut enc_script_pubkeys).unwrap();
}
TaprootCache {
amounts: sha256::Hash::from_engine(enc_amounts),
@ -999,7 +992,7 @@ impl<R: Deref<Target = Transaction>> SighashCache<R> {
}
}
impl<R: DerefMut<Target=Transaction>> SighashCache<R> {
impl<R: DerefMut<Target = Transaction>> SighashCache<R> {
/// When the `SighashCache` is initialized with a mutable reference to a transaction instead of
/// a regular reference, this method is available to allow modification to the witnesses.
///
@ -1025,9 +1018,7 @@ impl<R: DerefMut<Target=Transaction>> SighashCache<R> {
}
impl From<io::Error> for Error {
fn from(e: io::Error) -> Self {
Error::Io(e.kind())
}
fn from(e: io::Error) -> Self { Error::Io(e.kind()) }
}
/// The `Annex` struct is a slice wrapper enforcing first byte is `0x50`.
@ -1045,9 +1036,7 @@ impl<'a> Annex<'a> {
}
/// Returns the Annex bytes data (including first byte `0x50`).
pub fn as_bytes(&self) -> &[u8] {
self.0
}
pub fn as_bytes(&self) -> &[u8] { self.0 }
}
impl<'a> Encodable for Annex<'a> {
@ -1063,23 +1052,22 @@ fn is_invalid_use_of_sighash_single(sighash: u32, input_index: usize, output_len
#[cfg(test)]
mod tests {
use super::*;
use std::str::FromStr;
use secp256k1::{self, SecretKey, XOnlyPublicKey};
use crate::{Script, Transaction, TxIn, TxOut, Address};
use super::*;
use crate::blockdata::locktime::absolute;
use crate::consensus::deserialize;
use crate::hash_types::Sighash;
use crate::hashes::hex::{FromHex, ToHex};
use crate::hashes::{Hash, HashEngine};
use crate::hash_types::Sighash;
use crate::internal_macros::{hex_into, hex_script, hex_decode, hex_from_slice};
use crate::internal_macros::{hex_decode, hex_from_slice, hex_into, hex_script};
use crate::network::constants::Network;
use crate::util::key::PublicKey;
use crate::sighash::{Annex, Error, Prevouts, ScriptPath, SighashCache};
use crate::util::taproot::{TapTweakHash, TapSighashHash, TapBranchHash, TapLeafHash};
use crate::util::key::PublicKey;
use crate::util::taproot::{TapBranchHash, TapLeafHash, TapSighashHash, TapTweakHash};
use crate::{Address, Script, Transaction, TxIn, TxOut};
extern crate serde_json;
@ -1107,9 +1095,16 @@ mod tests {
#[cfg(feature = "serde")]
fn legacy_sighash() {
use serde_json::Value;
use crate::sighash::SighashCache;
fn run_test_sighash(tx: &str, script: &str, input_index: usize, hash_type: i64, expected_result: &str) {
fn run_test_sighash(
tx: &str,
script: &str,
input_index: usize,
hash_type: i64,
expected_result: &str,
) {
let tx: Transaction = deserialize(&Vec::from_hex(tx).unwrap()[..]).unwrap();
let script = Script::from(Vec::from_hex(script).unwrap());
let mut raw_expected = Vec::from_hex(expected_result).unwrap();
@ -1268,6 +1263,7 @@ mod tests {
}
#[test]
#[rustfmt::skip] // Allow long function call `taproot_signature_hash`.
fn test_sighash_errors() {
let dumb_tx = Transaction {
version: 0,
@ -1355,14 +1351,12 @@ mod tests {
None => None,
};
let leaf_hash = match (script_hex, script_leaf_hash) {
let leaf_hash = match (script_hex, script_leaf_hash) {
(Some(script_hex), _) => {
let script_inner = Script::from_hex(script_hex).unwrap();
Some(ScriptPath::with_defaults(&script_inner).leaf_hash())
}
(_, Some(script_leaf_hash)) => {
Some(TapLeafHash::from_hex(script_leaf_hash).unwrap())
}
(_, Some(script_leaf_hash)) => Some(TapLeafHash::from_hex(script_leaf_hash).unwrap()),
_ => None,
};
// All our tests use the default `0xFFFFFFFF` codeseparator value
@ -1387,18 +1381,18 @@ mod tests {
#[test]
fn bip_341_sighash_tests() {
let data = bip_341_read_json();
assert!(data["version"].as_u64().unwrap() == 1u64);
let secp = &secp256k1::Secp256k1::new();
let key_path = &data["keyPathSpending"].as_array().unwrap()[0];
let raw_unsigned_tx = hex_decode!(Transaction, key_path["given"]["rawUnsignedTx"].as_str().unwrap());
let raw_unsigned_tx =
hex_decode!(Transaction, key_path["given"]["rawUnsignedTx"].as_str().unwrap());
let mut utxos = vec![];
for utxo in key_path["given"]["utxosSpent"].as_array().unwrap() {
let spk = hex_script!(utxo["scriptPubKey"].as_str().unwrap());
let amt = utxo["amountSats"].as_u64().unwrap();
utxos.push(TxOut {value: amt, script_pubkey: spk });
utxos.push(TxOut { value: amt, script_pubkey: spk });
}
// Test intermediary
@ -1418,24 +1412,41 @@ mod tests {
for inp in key_path["inputSpending"].as_array().unwrap() {
let tx_ind = inp["given"]["txinIndex"].as_u64().unwrap() as usize;
let internal_priv_key = hex_from_slice!(SecretKey, inp["given"]["internalPrivkey"].as_str().unwrap());
let internal_priv_key =
hex_from_slice!(SecretKey, inp["given"]["internalPrivkey"].as_str().unwrap());
let merkle_root = if inp["given"]["merkleRoot"].is_null() {
None
} else {
Some(hex_into!(TapBranchHash, inp["given"]["merkleRoot"].as_str().unwrap()))
};
let hash_ty = SchnorrSighashType::from_consensus_u8(inp["given"]["hashType"].as_u64().unwrap() as u8).unwrap();
let hash_ty = SchnorrSighashType::from_consensus_u8(
inp["given"]["hashType"].as_u64().unwrap() as u8,
)
.unwrap();
let expected_internal_pk = hex_from_slice!(XOnlyPublicKey, inp["intermediary"]["internalPubkey"].as_str().unwrap());
let expected_tweak = hex_into!(TapTweakHash, inp["intermediary"]["tweak"].as_str().unwrap());
let expected_tweaked_priv_key = hex_from_slice!(SecretKey, inp["intermediary"]["tweakedPrivkey"].as_str().unwrap());
let expected_sig_msg = Vec::<u8>::from_hex(inp["intermediary"]["sigMsg"].as_str().unwrap()).unwrap();
let expected_sighash = hex_into!(TapSighashHash, inp["intermediary"]["sigHash"].as_str().unwrap());
let expected_internal_pk = hex_from_slice!(
XOnlyPublicKey,
inp["intermediary"]["internalPubkey"].as_str().unwrap()
);
let expected_tweak =
hex_into!(TapTweakHash, inp["intermediary"]["tweak"].as_str().unwrap());
let expected_tweaked_priv_key =
hex_from_slice!(SecretKey, inp["intermediary"]["tweakedPrivkey"].as_str().unwrap());
let expected_sig_msg =
Vec::<u8>::from_hex(inp["intermediary"]["sigMsg"].as_str().unwrap()).unwrap();
let expected_sighash =
hex_into!(TapSighashHash, inp["intermediary"]["sigHash"].as_str().unwrap());
let sig_str = inp["expected"]["witness"][0].as_str().unwrap();
let (expected_key_spend_sig, expected_hash_ty) = if sig_str.len() == 128 {
(secp256k1::schnorr::Signature::from_str(sig_str).unwrap(), SchnorrSighashType::Default)
(
secp256k1::schnorr::Signature::from_str(sig_str).unwrap(),
SchnorrSighashType::Default,
)
} else {
let hash_ty = SchnorrSighashType::from_consensus_u8(Vec::<u8>::from_hex(&sig_str[128..]).unwrap()[0]).unwrap();
let hash_ty = SchnorrSighashType::from_consensus_u8(
Vec::<u8>::from_hex(&sig_str[128..]).unwrap()[0],
)
.unwrap();
(secp256k1::schnorr::Signature::from_str(&sig_str[..128]).unwrap(), hash_ty)
};
@ -1445,21 +1456,19 @@ mod tests {
let tweak = TapTweakHash::from_key_and_tweak(internal_key, merkle_root);
let tweaked_keypair = keypair.add_xonly_tweak(secp, &tweak.to_scalar()).unwrap();
let mut sig_msg = Vec::new();
cache.taproot_encode_signing_data_to(
&mut sig_msg,
tx_ind,
&Prevouts::All(&utxos),
None,
None,
hash_ty
).unwrap();
let sighash = cache.taproot_signature_hash(
tx_ind,
&Prevouts::All(&utxos),
None,
None,
hash_ty
).unwrap();
cache
.taproot_encode_signing_data_to(
&mut sig_msg,
tx_ind,
&Prevouts::All(&utxos),
None,
None,
hash_ty,
)
.unwrap();
let sighash = cache
.taproot_signature_hash(tx_ind, &Prevouts::All(&utxos), None, None, hash_ty)
.unwrap();
let msg = secp256k1::Message::from(sighash);
let key_spend_sig = secp.sign_schnorr_with_aux_rand(&msg, &tweaked_keypair, &[0u8; 32]);
@ -1511,7 +1520,10 @@ mod tests {
"SigHash_NONE",
];
for s in sht_mistakes {
assert_eq!(SchnorrSighashType::from_str(s).unwrap_err().to_string(), format!("Unrecognized SIGHASH string '{}'", s));
assert_eq!(
SchnorrSighashType::from_str(s).unwrap_err().to_string(),
format!("Unrecognized SIGHASH string '{}'", s)
);
}
}
@ -1531,25 +1543,32 @@ mod tests {
).unwrap()[..],
).unwrap();
let witness_script = p2pkh_hex("025476c2e83188368da1ff3e292e7acafcdb3566bb0ad253f62fc70f07aeee6357");
let witness_script =
p2pkh_hex("025476c2e83188368da1ff3e292e7acafcdb3566bb0ad253f62fc70f07aeee6357");
let value = 600_000_000;
let mut cache = SighashCache::new(&tx);
assert_eq!(
cache.segwit_signature_hash(1, &witness_script, value, EcdsaSighashType::All).unwrap(),
hex_from_slice!(Sighash, "c37af31116d1b27caf68aae9e3ac82f1477929014d5b917657d0eb49478cb670")
hex_from_slice!(
Sighash,
"c37af31116d1b27caf68aae9e3ac82f1477929014d5b917657d0eb49478cb670"
)
);
let cache = cache.segwit_cache();
assert_eq!(cache.prevouts, hex_from_slice!(
"96b827c8483d4e9b96712b6713a7b68d6e8003a781feba36c31143470b4efd37"
));
assert_eq!(cache.sequences, hex_from_slice!(
"52b0a642eea2fb7ae638c36f6252b6750293dbe574a806984b8e4d8548339a3b"
));
assert_eq!(cache.outputs, hex_from_slice!(
"863ef3e1a92afbfdb97f31ad0fc7683ee943e9abcf2501590ff8f6551f47e5e5"
));
assert_eq!(
cache.prevouts,
hex_from_slice!("96b827c8483d4e9b96712b6713a7b68d6e8003a781feba36c31143470b4efd37")
);
assert_eq!(
cache.sequences,
hex_from_slice!("52b0a642eea2fb7ae638c36f6252b6750293dbe574a806984b8e4d8548339a3b")
);
assert_eq!(
cache.outputs,
hex_from_slice!("863ef3e1a92afbfdb97f31ad0fc7683ee943e9abcf2501590ff8f6551f47e5e5")
);
}
#[test]
@ -1562,25 +1581,32 @@ mod tests {
).unwrap()[..],
).unwrap();
let witness_script = p2pkh_hex("03ad1d8e89212f0b92c74d23bb710c00662ad1470198ac48c43f7d6f93a2a26873");
let witness_script =
p2pkh_hex("03ad1d8e89212f0b92c74d23bb710c00662ad1470198ac48c43f7d6f93a2a26873");
let value = 1_000_000_000;
let mut cache = SighashCache::new(&tx);
assert_eq!(
cache.segwit_signature_hash(0, &witness_script, value, EcdsaSighashType::All).unwrap(),
hex_from_slice!(Sighash, "64f3b0f4dd2bb3aa1ce8566d220cc74dda9df97d8490cc81d89d735c92e59fb6")
hex_from_slice!(
Sighash,
"64f3b0f4dd2bb3aa1ce8566d220cc74dda9df97d8490cc81d89d735c92e59fb6"
)
);
let cache = cache.segwit_cache();
assert_eq!(cache.prevouts, hex_from_slice!(
"b0287b4a252ac05af83d2dcef00ba313af78a3e9c329afa216eb3aa2a7b4613a"
));
assert_eq!(cache.sequences, hex_from_slice!(
"18606b350cd8bf565266bc352f0caddcf01e8fa789dd8a15386327cf8cabe198"
));
assert_eq!(cache.outputs, hex_from_slice!(
"de984f44532e2173ca0d64314fcefe6d30da6f8cf27bafa706da61df8a226c83"
));
assert_eq!(
cache.prevouts,
hex_from_slice!("b0287b4a252ac05af83d2dcef00ba313af78a3e9c329afa216eb3aa2a7b4613a")
);
assert_eq!(
cache.sequences,
hex_from_slice!("18606b350cd8bf565266bc352f0caddcf01e8fa789dd8a15386327cf8cabe198")
);
assert_eq!(
cache.outputs,
hex_from_slice!("de984f44532e2173ca0d64314fcefe6d30da6f8cf27bafa706da61df8a226c83")
);
}
#[test]
@ -1605,18 +1631,24 @@ mod tests {
let mut cache = SighashCache::new(&tx);
assert_eq!(
cache.segwit_signature_hash(0, &witness_script, value, EcdsaSighashType::All).unwrap(),
hex_from_slice!(Sighash, "185c0be5263dce5b4bb50a047973c1b6272bfbd0103a89444597dc40b248ee7c")
hex_from_slice!(
Sighash,
"185c0be5263dce5b4bb50a047973c1b6272bfbd0103a89444597dc40b248ee7c"
)
);
let cache = cache.segwit_cache();
assert_eq!(cache.prevouts, hex_from_slice!(
"74afdc312af5183c4198a40ca3c1a275b485496dd3929bca388c4b5e31f7aaa0"
));
assert_eq!(cache.sequences, hex_from_slice!(
"3bb13029ce7b1f559ef5e747fcac439f1455a2ec7c5f09b72290795e70665044"
));
assert_eq!(cache.outputs, hex_from_slice!(
"bc4d309071414bed932f98832b27b4d76dad7e6c1346f487a8fdbb8eb90307cc"
));
assert_eq!(
cache.prevouts,
hex_from_slice!("74afdc312af5183c4198a40ca3c1a275b485496dd3929bca388c4b5e31f7aaa0")
);
assert_eq!(
cache.sequences,
hex_from_slice!("3bb13029ce7b1f559ef5e747fcac439f1455a2ec7c5f09b72290795e70665044")
);
assert_eq!(
cache.outputs,
hex_from_slice!("bc4d309071414bed932f98832b27b4d76dad7e6c1346f487a8fdbb8eb90307cc")
);
}
}

View File

@ -2,7 +2,6 @@
ignore = [
"bitcoin/src/blockdata",
"bitcoin/src/consensus",
"bitcoin/src/network",
"bitcoin/src/psbt",
"bitcoin/src/util",
"hashes",