blockdata: Run the formatter

Run `cargo +nightly fmt`, no other manual changes.
This commit is contained in:
Tobin C. Harding 2023-02-22 10:01:26 +11:00
parent 0dcbed3c7b
commit 5973dce9db
No known key found for this signature in database
GPG Key ID: 40BF9E4C269D6607
17 changed files with 1181 additions and 1325 deletions

View File

@ -9,24 +9,20 @@
//! these blocks and the blockchain. //! these blocks and the blockchain.
//! //!
use crate::prelude::*;
use core::fmt; use core::fmt;
use crate::merkle_tree;
use crate::error::Error::{self, BlockBadTarget, BlockBadProofOfWork};
use crate::hashes::{Hash, HashEngine};
use crate::hash_types::{Wtxid, TxMerkleNode, WitnessMerkleNode, WitnessCommitment};
use crate::consensus::{encode, Encodable, Decodable};
use crate::blockdata::transaction::Transaction;
use crate::blockdata::script;
use crate::pow::{CompactTarget, Target, Work};
use crate::VarInt;
use crate::internal_macros::impl_consensus_encoding;
use crate::io;
use super::Weight; use super::Weight;
use crate::blockdata::script;
use crate::blockdata::transaction::Transaction;
use crate::consensus::{encode, Decodable, Encodable};
use crate::error::Error::{self, BlockBadProofOfWork, BlockBadTarget};
pub use crate::hash_types::BlockHash; pub use crate::hash_types::BlockHash;
use crate::hash_types::{TxMerkleNode, WitnessCommitment, WitnessMerkleNode, Wtxid};
use crate::hashes::{Hash, HashEngine};
use crate::internal_macros::impl_consensus_encoding;
use crate::pow::{CompactTarget, Target, Work};
use crate::prelude::*;
use crate::{io, merkle_tree, VarInt};
/// Bitcoin block header. /// Bitcoin block header.
/// ///
@ -67,14 +63,10 @@ impl Header {
} }
/// Computes the target (range [0, T] inclusive) that a blockhash must land in to be valid. /// Computes the target (range [0, T] inclusive) that a blockhash must land in to be valid.
pub fn target(&self) -> Target { pub fn target(&self) -> Target { self.bits.into() }
self.bits.into()
}
/// Computes the popular "difficulty" measure for mining. /// Computes the popular "difficulty" measure for mining.
pub fn difficulty(&self) -> u128 { pub fn difficulty(&self) -> u128 { self.target().difficulty() }
self.target().difficulty()
}
/// Checks that the proof-of-work for the block is valid, returning the block hash. /// Checks that the proof-of-work for the block is valid, returning the block hash.
pub fn validate_pow(&self, required_target: Target) -> Result<BlockHash, Error> { pub fn validate_pow(&self, required_target: Target) -> Result<BlockHash, Error> {
@ -91,9 +83,7 @@ impl Header {
} }
/// Returns the total work of the block. /// Returns the total work of the block.
pub fn work(&self) -> Work { pub fn work(&self) -> Work { self.target().to_work() }
self.target().to_work()
}
} }
/// Bitcoin block version number. /// Bitcoin block version number.
@ -135,16 +125,12 @@ impl Version {
/// Creates a [`Version`] from a signed 32 bit integer value. /// Creates a [`Version`] from a signed 32 bit integer value.
/// ///
/// This is the data type used in consensus code in Bitcoin Core. /// This is the data type used in consensus code in Bitcoin Core.
pub fn from_consensus(v: i32) -> Self { pub fn from_consensus(v: i32) -> Self { Version(v) }
Version(v)
}
/// Returns the inner `i32` value. /// Returns the inner `i32` value.
/// ///
/// This is the data type used in consensus code in Bitcoin Core. /// This is the data type used in consensus code in Bitcoin Core.
pub fn to_consensus(self) -> i32 { pub fn to_consensus(self) -> i32 { self.0 }
self.0
}
/// Checks whether the version number is signalling a soft fork at the given bit. /// Checks whether the version number is signalling a soft fork at the given bit.
/// ///
@ -167,9 +153,7 @@ impl Version {
} }
impl Default for Version { impl Default for Version {
fn default() -> Version { fn default() -> Version { Self::NO_SOFT_FORK_SIGNALLING }
Self::NO_SOFT_FORK_SIGNALLING
}
} }
impl Encodable for Version { impl Encodable for Version {
@ -202,16 +186,14 @@ pub struct Block {
/// The block header /// The block header
pub header: Header, pub header: Header,
/// List of transactions contained in the block /// List of transactions contained in the block
pub txdata: Vec<Transaction> pub txdata: Vec<Transaction>,
} }
impl_consensus_encoding!(Block, header, txdata); impl_consensus_encoding!(Block, header, txdata);
impl Block { impl Block {
/// Returns the block hash. /// Returns the block hash.
pub fn block_hash(&self) -> BlockHash { pub fn block_hash(&self) -> BlockHash { self.header.block_hash() }
self.header.block_hash()
}
/// Checks if merkle root of header matches merkle root of the transaction list. /// Checks if merkle root of header matches merkle root of the transaction list.
pub fn check_merkle_root(&self) -> bool { pub fn check_merkle_root(&self) -> bool {
@ -239,15 +221,21 @@ impl Block {
} }
// Commitment is in the last output that starts with magic bytes. // Commitment is in the last output that starts with magic bytes.
if let Some(pos) = coinbase.output.iter() if let Some(pos) = coinbase
.output
.iter()
.rposition(|o| o.script_pubkey.len() >= 38 && o.script_pubkey.as_bytes()[0..6] == MAGIC) .rposition(|o| o.script_pubkey.len() >= 38 && o.script_pubkey.as_bytes()[0..6] == MAGIC)
{ {
let commitment = WitnessCommitment::from_slice(&coinbase.output[pos].script_pubkey.as_bytes()[6..38]).unwrap(); let commitment = WitnessCommitment::from_slice(
&coinbase.output[pos].script_pubkey.as_bytes()[6..38],
)
.unwrap();
// Witness reserved value is in coinbase input witness. // Witness reserved value is in coinbase input witness.
let witness_vec: Vec<_> = coinbase.input[0].witness.iter().collect(); let witness_vec: Vec<_> = coinbase.input[0].witness.iter().collect();
if witness_vec.len() == 1 && witness_vec[0].len() == 32 { if witness_vec.len() == 1 && witness_vec[0].len() == 32 {
if let Some(witness_root) = self.witness_root() { if let Some(witness_root) = self.witness_root() {
return commitment == Self::compute_witness_commitment(&witness_root, witness_vec[0]); return commitment
== Self::compute_witness_commitment(&witness_root, witness_vec[0]);
} }
} }
} }
@ -262,7 +250,10 @@ impl Block {
} }
/// Computes the witness commitment for the block's transaction list. /// Computes the witness commitment for the block's transaction list.
pub fn compute_witness_commitment(witness_root: &WitnessMerkleNode, witness_reserved_value: &[u8]) -> WitnessCommitment { pub fn compute_witness_commitment(
witness_root: &WitnessMerkleNode,
witness_reserved_value: &[u8],
) -> WitnessCommitment {
let mut encoder = WitnessCommitment::engine(); let mut encoder = WitnessCommitment::engine();
witness_root.consensus_encode(&mut encoder).expect("engines don't error"); witness_root.consensus_encode(&mut encoder).expect("engines don't error");
encoder.input(witness_reserved_value); encoder.input(witness_reserved_value);
@ -283,9 +274,7 @@ impl Block {
} }
/// base_size == size of header + size of encoded transaction count. /// base_size == size of header + size of encoded transaction count.
fn base_size(&self) -> usize { fn base_size(&self) -> usize { 80 + VarInt(self.txdata.len() as u64).len() }
80 + VarInt(self.txdata.len() as u64).len()
}
/// Returns the size of the block. /// Returns the size of the block.
/// ///
@ -309,9 +298,7 @@ impl Block {
} }
/// Returns the coinbase transaction, if one is present. /// Returns the coinbase transaction, if one is present.
pub fn coinbase(&self) -> Option<&Transaction> { pub fn coinbase(&self) -> Option<&Transaction> { self.txdata.first() }
self.txdata.first()
}
/// Returns the block height, as encoded in the coinbase transaction according to BIP34. /// Returns the block height, as encoded in the coinbase transaction according to BIP34.
pub fn bip34_block_height(&self) -> Result<u64, Bip34Error> { pub fn bip34_block_height(&self) -> Result<u64, Bip34Error> {
@ -334,7 +321,8 @@ impl Block {
match push.map_err(|_| Bip34Error::NotPresent)? { match push.map_err(|_| Bip34Error::NotPresent)? {
script::Instruction::PushBytes(b) => { script::Instruction::PushBytes(b) => {
// Check that the number is encoded in the minimal way. // Check that the number is encoded in the minimal way.
let h = script::read_scriptint(b.as_bytes()).map_err(|_e| Bip34Error::UnexpectedPush(b.as_bytes().to_vec()))?; let h = script::read_scriptint(b.as_bytes())
.map_err(|_e| Bip34Error::UnexpectedPush(b.as_bytes().to_vec()))?;
if h < 0 { if h < 0 {
Err(Bip34Error::NegativeHeight) Err(Bip34Error::NegativeHeight)
} else { } else {
@ -380,44 +368,32 @@ impl std::error::Error for Bip34Error {
use self::Bip34Error::*; use self::Bip34Error::*;
match self { match self {
Unsupported | Unsupported | NotPresent | UnexpectedPush(_) | NegativeHeight => None,
NotPresent |
UnexpectedPush(_) |
NegativeHeight => None,
} }
} }
} }
impl From<Header> for BlockHash { impl From<Header> for BlockHash {
fn from(header: Header) -> BlockHash { fn from(header: Header) -> BlockHash { header.block_hash() }
header.block_hash()
}
} }
impl From<&Header> for BlockHash { impl From<&Header> for BlockHash {
fn from(header: &Header) -> BlockHash { fn from(header: &Header) -> BlockHash { header.block_hash() }
header.block_hash()
}
} }
impl From<Block> for BlockHash { impl From<Block> for BlockHash {
fn from(block: Block) -> BlockHash { fn from(block: Block) -> BlockHash { block.block_hash() }
block.block_hash()
}
} }
impl From<&Block> for BlockHash { impl From<&Block> for BlockHash {
fn from(block: &Block) -> BlockHash { fn from(block: &Block) -> BlockHash { block.block_hash() }
block.block_hash()
}
} }
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use super::*; use super::*;
use crate::hashes::hex::FromHex;
use crate::consensus::encode::{deserialize, serialize}; use crate::consensus::encode::{deserialize, serialize};
use crate::hashes::hex::FromHex;
use crate::internal_macros::hex; use crate::internal_macros::hex;
#[test] #[test]
@ -431,7 +407,6 @@ mod tests {
assert_eq!(block.bip34_block_height(), Ok(100_000)); assert_eq!(block.bip34_block_height(), Ok(100_000));
// block with 9-byte bip34 push // block with 9-byte bip34 push
const BAD_HEX: &str = "0200000035ab154183570282ce9afc0b494c9fc6a3cfea05aa8c1add2ecc56490000000038ba3d78e4500a5a7570dbe61960398add4410d278b21cd9708e6d9743f374d544fc055227f1001c29c1ea3b0101000000010000000000000000000000000000000000000000000000000000000000000000ffffffff3d09a08601112233445566000427f1001c046a510100522cfabe6d6d0000000000000000000068692066726f6d20706f6f6c7365727665726aac1eeeed88ffffffff0100f2052a010000001976a914912e2b234f941f30b18afbb4fa46171214bf66c888ac00000000"; const BAD_HEX: &str = "0200000035ab154183570282ce9afc0b494c9fc6a3cfea05aa8c1add2ecc56490000000038ba3d78e4500a5a7570dbe61960398add4410d278b21cd9708e6d9743f374d544fc055227f1001c29c1ea3b0101000000010000000000000000000000000000000000000000000000000000000000000000ffffffff3d09a08601112233445566000427f1001c046a510100522cfabe6d6d0000000000000000000068692066726f6d20706f6f6c7365727665726aac1eeeed88ffffffff0100f2052a010000001976a914912e2b234f941f30b18afbb4fa46171214bf66c888ac00000000";
let bad: Block = deserialize(&hex!(BAD_HEX)).unwrap(); let bad: Block = deserialize(&hex!(BAD_HEX)).unwrap();
@ -464,13 +439,19 @@ mod tests {
assert_eq!(real_decode.header.bits, CompactTarget::from_consensus(486604799)); assert_eq!(real_decode.header.bits, CompactTarget::from_consensus(486604799));
assert_eq!(real_decode.header.nonce, 2067413810); assert_eq!(real_decode.header.nonce, 2067413810);
assert_eq!(real_decode.header.work(), work); assert_eq!(real_decode.header.work(), work);
assert_eq!(real_decode.header.validate_pow(real_decode.header.target()).unwrap(), real_decode.block_hash()); assert_eq!(
real_decode.header.validate_pow(real_decode.header.target()).unwrap(),
real_decode.block_hash()
);
assert_eq!(real_decode.header.difficulty(), 1); assert_eq!(real_decode.header.difficulty(), 1);
// [test] TODO: check the transaction data // [test] TODO: check the transaction data
assert_eq!(real_decode.size(), some_block.len()); assert_eq!(real_decode.size(), some_block.len());
assert_eq!(real_decode.strippedsize(), some_block.len()); assert_eq!(real_decode.strippedsize(), some_block.len());
assert_eq!(real_decode.weight(), Weight::from_non_witness_data_size(some_block.len() as u64)); assert_eq!(
real_decode.weight(),
Weight::from_non_witness_data_size(some_block.len() as u64)
);
// should be also ok for a non-witness block as commitment is optional in that case // should be also ok for a non-witness block as commitment is optional in that case
assert!(real_decode.check_witness_commitment()); assert!(real_decode.check_witness_commitment());
@ -499,7 +480,10 @@ mod tests {
assert_eq!(real_decode.header.bits, CompactTarget::from_consensus(0x1a06d450)); assert_eq!(real_decode.header.bits, CompactTarget::from_consensus(0x1a06d450));
assert_eq!(real_decode.header.nonce, 1879759182); assert_eq!(real_decode.header.nonce, 1879759182);
assert_eq!(real_decode.header.work(), work); assert_eq!(real_decode.header.work(), work);
assert_eq!(real_decode.header.validate_pow(real_decode.header.target()).unwrap(), real_decode.block_hash()); assert_eq!(
real_decode.header.validate_pow(real_decode.header.target()).unwrap(),
real_decode.block_hash()
);
assert_eq!(real_decode.header.difficulty(), 2456598); assert_eq!(real_decode.header.difficulty(), 2456598);
// [test] TODO: check the transaction data // [test] TODO: check the transaction data
@ -530,8 +514,12 @@ mod tests {
#[test] #[test]
fn validate_pow_test() { fn validate_pow_test() {
let some_header = hex!("010000004ddccd549d28f385ab457e98d1b11ce80bfea2c5ab93015ade4973e400000000bf4473e53794beae34e64fccc471dace6ae544180816f89591894e0f417a914cd74d6e49ffff001d323b3a7b"); let some_header = hex!("010000004ddccd549d28f385ab457e98d1b11ce80bfea2c5ab93015ade4973e400000000bf4473e53794beae34e64fccc471dace6ae544180816f89591894e0f417a914cd74d6e49ffff001d323b3a7b");
let some_header: Header = deserialize(&some_header).expect("Can't deserialize correct block header"); let some_header: Header =
assert_eq!(some_header.validate_pow(some_header.target()).unwrap(), some_header.block_hash()); deserialize(&some_header).expect("Can't deserialize correct block header");
assert_eq!(
some_header.validate_pow(some_header.target()).unwrap(),
some_header.block_hash()
);
// test with zero target // test with zero target
match some_header.validate_pow(Target::ZERO) { match some_header.validate_pow(Target::ZERO) {
@ -552,7 +540,8 @@ mod tests {
fn compact_roundrtip_test() { fn compact_roundrtip_test() {
let some_header = hex!("010000004ddccd549d28f385ab457e98d1b11ce80bfea2c5ab93015ade4973e400000000bf4473e53794beae34e64fccc471dace6ae544180816f89591894e0f417a914cd74d6e49ffff001d323b3a7b"); let some_header = hex!("010000004ddccd549d28f385ab457e98d1b11ce80bfea2c5ab93015ade4973e400000000bf4473e53794beae34e64fccc471dace6ae544180816f89591894e0f417a914cd74d6e49ffff001d323b3a7b");
let header: Header = deserialize(&some_header).expect("Can't deserialize correct block header"); let header: Header =
deserialize(&some_header).expect("Can't deserialize correct block header");
assert_eq!(header.bits, header.target().to_compact_lossy()); assert_eq!(header.bits, header.target().to_compact_lossy());
} }
@ -578,11 +567,12 @@ mod tests {
#[cfg(bench)] #[cfg(bench)]
mod benches { mod benches {
use super::Block;
use crate::EmptyWrite;
use crate::consensus::{deserialize, Encodable, Decodable};
use test::{black_box, Bencher}; use test::{black_box, Bencher};
use super::Block;
use crate::consensus::{deserialize, Decodable, Encodable};
use crate::EmptyWrite;
#[bench] #[bench]
pub fn bench_stream_reader(bh: &mut Bencher) { pub fn bench_stream_reader(bh: &mut Bencher) {
let big_block = include_bytes!("../../tests/data/mainnet_block_000000000000000000000c835b2adcaedc20fdf6ee440009c249452c726dafae.raw"); let big_block = include_bytes!("../../tests/data/mainnet_block_000000000000000000000c835b2adcaedc20fdf6ee440009c249452c726dafae.raw");

View File

@ -13,16 +13,16 @@ use core::default::Default;
use bitcoin_internals::impl_array_newtype; use bitcoin_internals::impl_array_newtype;
use hex_lit::hex; use hex_lit::hex;
use crate::hashes::{Hash, sha256d};
use crate::blockdata::script;
use crate::blockdata::opcodes::all::*;
use crate::blockdata::locktime::absolute;
use crate::blockdata::transaction::{OutPoint, Transaction, TxOut, TxIn, Sequence};
use crate::blockdata::block::{self, Block}; use crate::blockdata::block::{self, Block};
use crate::blockdata::locktime::absolute;
use crate::blockdata::opcodes::all::*;
use crate::blockdata::script;
use crate::blockdata::transaction::{OutPoint, Sequence, Transaction, TxIn, TxOut};
use crate::blockdata::witness::Witness; use crate::blockdata::witness::Witness;
use crate::hashes::{sha256d, Hash};
use crate::internal_macros::impl_bytes_newtype;
use crate::network::constants::Network; use crate::network::constants::Network;
use crate::pow::CompactTarget; use crate::pow::CompactTarget;
use crate::internal_macros::impl_bytes_newtype;
/// How many satoshis are in "one bitcoin". /// How many satoshis are in "one bitcoin".
pub const COIN_VALUE: u64 = 100_000_000; pub const COIN_VALUE: u64 = 100_000_000;
@ -73,7 +73,8 @@ fn bitcoin_genesis_tx() -> Transaction {
}; };
// Inputs // Inputs
let in_script = script::Builder::new().push_int(486604799) let in_script = script::Builder::new()
.push_int(486604799)
.push_int_non_minimal(4) .push_int_non_minimal(4)
.push_slice(b"The Times 03/Jan/2009 Chancellor on brink of second bailout for banks") .push_slice(b"The Times 03/Jan/2009 Chancellor on brink of second bailout for banks")
.into_script(); .into_script();
@ -86,14 +87,9 @@ fn bitcoin_genesis_tx() -> Transaction {
// Outputs // Outputs
let script_bytes = hex!("04678afdb0fe5548271967f1a67130b7105cd6a828e03909a67962e0ea1f61deb649f6bc3f4cef38c4f35504e51ec112de5c384df7ba0b8d578a4c702b6bf11d5f"); let script_bytes = hex!("04678afdb0fe5548271967f1a67130b7105cd6a828e03909a67962e0ea1f61deb649f6bc3f4cef38c4f35504e51ec112de5c384df7ba0b8d578a4c702b6bf11d5f");
let out_script = script::Builder::new() let out_script =
.push_slice(script_bytes) script::Builder::new().push_slice(script_bytes).push_opcode(OP_CHECKSIG).into_script();
.push_opcode(OP_CHECKSIG) ret.output.push(TxOut { value: 50 * COIN_VALUE, script_pubkey: out_script });
.into_script();
ret.output.push(TxOut {
value: 50 * COIN_VALUE,
script_pubkey: out_script
});
// end // end
ret ret
@ -105,58 +101,50 @@ pub fn genesis_block(network: Network) -> Block {
let hash: sha256d::Hash = txdata[0].txid().into(); let hash: sha256d::Hash = txdata[0].txid().into();
let merkle_root = hash.into(); let merkle_root = hash.into();
match network { match network {
Network::Bitcoin => { Network::Bitcoin => Block {
Block {
header: block::Header { header: block::Header {
version: block::Version::ONE, version: block::Version::ONE,
prev_blockhash: Hash::all_zeros(), prev_blockhash: Hash::all_zeros(),
merkle_root, merkle_root,
time: 1231006505, time: 1231006505,
bits: CompactTarget::from_consensus(0x1d00ffff), bits: CompactTarget::from_consensus(0x1d00ffff),
nonce: 2083236893 nonce: 2083236893,
}, },
txdata, txdata,
} },
} Network::Testnet => Block {
Network::Testnet => {
Block {
header: block::Header { header: block::Header {
version: block::Version::ONE, version: block::Version::ONE,
prev_blockhash: Hash::all_zeros(), prev_blockhash: Hash::all_zeros(),
merkle_root, merkle_root,
time: 1296688602, time: 1296688602,
bits: CompactTarget::from_consensus(0x1d00ffff), bits: CompactTarget::from_consensus(0x1d00ffff),
nonce: 414098458 nonce: 414098458,
}, },
txdata, txdata,
} },
} Network::Signet => Block {
Network::Signet => {
Block {
header: block::Header { header: block::Header {
version: block::Version::ONE, version: block::Version::ONE,
prev_blockhash: Hash::all_zeros(), prev_blockhash: Hash::all_zeros(),
merkle_root, merkle_root,
time: 1598918400, time: 1598918400,
bits: CompactTarget::from_consensus(0x1e0377ae), bits: CompactTarget::from_consensus(0x1e0377ae),
nonce: 52613770 nonce: 52613770,
}, },
txdata, txdata,
} },
} Network::Regtest => Block {
Network::Regtest => {
Block {
header: block::Header { header: block::Header {
version: block::Version::ONE, version: block::Version::ONE,
prev_blockhash: Hash::all_zeros(), prev_blockhash: Hash::all_zeros(),
merkle_root, merkle_root,
time: 1296688602, time: 1296688602,
bits: CompactTarget::from_consensus(0x207fffff), bits: CompactTarget::from_consensus(0x207fffff),
nonce: 2 nonce: 2,
}, },
txdata, txdata,
} },
}
} }
} }
@ -169,13 +157,25 @@ impl_bytes_newtype!(ChainHash, 32);
impl ChainHash { impl ChainHash {
// Mainnet value can be verified at https://github.com/lightning/bolts/blob/master/00-introduction.md // Mainnet value can be verified at https://github.com/lightning/bolts/blob/master/00-introduction.md
/// `ChainHash` for mainnet bitcoin. /// `ChainHash` for mainnet bitcoin.
pub const BITCOIN: Self = Self([111, 226, 140, 10, 182, 241, 179, 114, 193, 166, 162, 70, 174, 99, 247, 79, 147, 30, 131, 101, 225, 90, 8, 156, 104, 214, 25, 0, 0, 0, 0, 0]); pub const BITCOIN: Self = Self([
111, 226, 140, 10, 182, 241, 179, 114, 193, 166, 162, 70, 174, 99, 247, 79, 147, 30, 131,
101, 225, 90, 8, 156, 104, 214, 25, 0, 0, 0, 0, 0,
]);
/// `ChainHash` for testnet bitcoin. /// `ChainHash` for testnet bitcoin.
pub const TESTNET: Self = Self([67, 73, 127, 215, 248, 38, 149, 113, 8, 244, 163, 15, 217, 206, 195, 174, 186, 121, 151, 32, 132, 233, 14, 173, 1, 234, 51, 9, 0, 0, 0, 0]); pub const TESTNET: Self = Self([
67, 73, 127, 215, 248, 38, 149, 113, 8, 244, 163, 15, 217, 206, 195, 174, 186, 121, 151,
32, 132, 233, 14, 173, 1, 234, 51, 9, 0, 0, 0, 0,
]);
/// `ChainHash` for signet bitcoin. /// `ChainHash` for signet bitcoin.
pub const SIGNET: Self = Self([246, 30, 238, 59, 99, 163, 128, 164, 119, 160, 99, 175, 50, 178, 187, 201, 124, 159, 249, 240, 31, 44, 66, 37, 233, 115, 152, 129, 8, 0, 0, 0]); pub const SIGNET: Self = Self([
246, 30, 238, 59, 99, 163, 128, 164, 119, 160, 99, 175, 50, 178, 187, 201, 124, 159, 249,
240, 31, 44, 66, 37, 233, 115, 152, 129, 8, 0, 0, 0,
]);
/// `ChainHash` for regtest bitcoin. /// `ChainHash` for regtest bitcoin.
pub const REGTEST: Self = Self([6, 34, 110, 70, 17, 26, 11, 89, 202, 175, 18, 96, 67, 235, 91, 191, 40, 195, 79, 58, 94, 51, 42, 31, 199, 178, 183, 60, 241, 136, 145, 15]); pub const REGTEST: Self = Self([
6, 34, 110, 70, 17, 26, 11, 89, 202, 175, 18, 96, 67, 235, 91, 191, 40, 195, 79, 58, 94,
51, 42, 31, 199, 178, 183, 60, 241, 136, 145, 15,
]);
/// Returns the hash of the `network` genesis block for use as a chain hash. /// Returns the hash of the `network` genesis block for use as a chain hash.
/// ///
@ -190,10 +190,10 @@ impl ChainHash {
#[cfg(test)] #[cfg(test)]
mod test { mod test {
use super::*; use super::*;
use crate::network::constants::Network;
use crate::consensus::encode::serialize;
use crate::blockdata::locktime::absolute; use crate::blockdata::locktime::absolute;
use crate::consensus::encode::serialize;
use crate::internal_macros::hex; use crate::internal_macros::hex;
use crate::network::constants::Network;
#[test] #[test]
fn bitcoin_genesis_first_transaction() { fn bitcoin_genesis_first_transaction() {
@ -213,7 +213,10 @@ mod test {
assert_eq!(gen.output[0].value, 50 * COIN_VALUE); assert_eq!(gen.output[0].value, 50 * COIN_VALUE);
assert_eq!(gen.lock_time, absolute::LockTime::ZERO); assert_eq!(gen.lock_time, absolute::LockTime::ZERO);
assert_eq!(gen.wtxid().to_string(), "4a5e1e4baab89f3a32518a88c31bc87f618f76673e2cc77ab2127b7afdeda33b"); assert_eq!(
gen.wtxid().to_string(),
"4a5e1e4baab89f3a32518a88c31bc87f618f76673e2cc77ab2127b7afdeda33b"
);
} }
#[test] #[test]
@ -222,12 +225,18 @@ mod test {
assert_eq!(gen.header.version, block::Version::ONE); assert_eq!(gen.header.version, block::Version::ONE);
assert_eq!(gen.header.prev_blockhash, Hash::all_zeros()); assert_eq!(gen.header.prev_blockhash, Hash::all_zeros());
assert_eq!(gen.header.merkle_root.to_string(), "4a5e1e4baab89f3a32518a88c31bc87f618f76673e2cc77ab2127b7afdeda33b"); assert_eq!(
gen.header.merkle_root.to_string(),
"4a5e1e4baab89f3a32518a88c31bc87f618f76673e2cc77ab2127b7afdeda33b"
);
assert_eq!(gen.header.time, 1231006505); assert_eq!(gen.header.time, 1231006505);
assert_eq!(gen.header.bits, CompactTarget::from_consensus(0x1d00ffff)); assert_eq!(gen.header.bits, CompactTarget::from_consensus(0x1d00ffff));
assert_eq!(gen.header.nonce, 2083236893); assert_eq!(gen.header.nonce, 2083236893);
assert_eq!(gen.header.block_hash().to_string(), "000000000019d6689c085ae165831e934ff763ae46a2a6c172b3f1b60a8ce26f"); assert_eq!(
gen.header.block_hash().to_string(),
"000000000019d6689c085ae165831e934ff763ae46a2a6c172b3f1b60a8ce26f"
);
} }
#[test] #[test]
@ -235,11 +244,17 @@ mod test {
let gen = genesis_block(Network::Testnet); let gen = genesis_block(Network::Testnet);
assert_eq!(gen.header.version, block::Version::ONE); assert_eq!(gen.header.version, block::Version::ONE);
assert_eq!(gen.header.prev_blockhash, Hash::all_zeros()); assert_eq!(gen.header.prev_blockhash, Hash::all_zeros());
assert_eq!(gen.header.merkle_root.to_string(), "4a5e1e4baab89f3a32518a88c31bc87f618f76673e2cc77ab2127b7afdeda33b"); assert_eq!(
gen.header.merkle_root.to_string(),
"4a5e1e4baab89f3a32518a88c31bc87f618f76673e2cc77ab2127b7afdeda33b"
);
assert_eq!(gen.header.time, 1296688602); assert_eq!(gen.header.time, 1296688602);
assert_eq!(gen.header.bits, CompactTarget::from_consensus(0x1d00ffff)); assert_eq!(gen.header.bits, CompactTarget::from_consensus(0x1d00ffff));
assert_eq!(gen.header.nonce, 414098458); assert_eq!(gen.header.nonce, 414098458);
assert_eq!(gen.header.block_hash().to_string(), "000000000933ea01ad0ee984209779baaec3ced90fa3f408719526f8d77f4943"); assert_eq!(
gen.header.block_hash().to_string(),
"000000000933ea01ad0ee984209779baaec3ced90fa3f408719526f8d77f4943"
);
} }
#[test] #[test]
@ -247,11 +262,17 @@ mod test {
let gen = genesis_block(Network::Signet); let gen = genesis_block(Network::Signet);
assert_eq!(gen.header.version, block::Version::ONE); assert_eq!(gen.header.version, block::Version::ONE);
assert_eq!(gen.header.prev_blockhash, Hash::all_zeros()); assert_eq!(gen.header.prev_blockhash, Hash::all_zeros());
assert_eq!(gen.header.merkle_root.to_string(), "4a5e1e4baab89f3a32518a88c31bc87f618f76673e2cc77ab2127b7afdeda33b"); assert_eq!(
gen.header.merkle_root.to_string(),
"4a5e1e4baab89f3a32518a88c31bc87f618f76673e2cc77ab2127b7afdeda33b"
);
assert_eq!(gen.header.time, 1598918400); assert_eq!(gen.header.time, 1598918400);
assert_eq!(gen.header.bits, CompactTarget::from_consensus(0x1e0377ae)); assert_eq!(gen.header.bits, CompactTarget::from_consensus(0x1e0377ae));
assert_eq!(gen.header.nonce, 52613770); assert_eq!(gen.header.nonce, 52613770);
assert_eq!(gen.header.block_hash().to_string(), "00000008819873e925422c1ff0f99f7cc9bbb232af63a077a480a3633bee1ef6"); assert_eq!(
gen.header.block_hash().to_string(),
"00000008819873e925422c1ff0f99f7cc9bbb232af63a077a480a3633bee1ef6"
);
} }
// The *_chain_hash tests are sanity/regression tests, they verify that the const byte array // The *_chain_hash tests are sanity/regression tests, they verify that the const byte array

View File

@ -1,11 +1,11 @@
//! Implements `FeeRate` and assoctiated features. //! Implements `FeeRate` and assoctiated features.
use core::fmt; use core::fmt;
use core::ops::{Mul, Div}; use core::ops::{Div, Mul};
use super::Weight;
use crate::prelude::*; use crate::prelude::*;
use crate::Amount; use crate::Amount;
use super::Weight;
/// Represents fee rate. /// Represents fee rate.
/// ///
@ -40,9 +40,7 @@ impl FeeRate {
pub const DUST: FeeRate = FeeRate::from_sat_per_vb_unchecked(3); pub const DUST: FeeRate = FeeRate::from_sat_per_vb_unchecked(3);
/// Constructs `FeeRate` from satoshis per 1000 weight units. /// Constructs `FeeRate` from satoshis per 1000 weight units.
pub const fn from_sat_per_kwu(sat_kwu: u64) -> Self { pub const fn from_sat_per_kwu(sat_kwu: u64) -> Self { FeeRate(sat_kwu) }
FeeRate(sat_kwu)
}
/// Constructs `FeeRate` from satoshis per virtual bytes. /// Constructs `FeeRate` from satoshis per virtual bytes.
/// ///
@ -57,40 +55,28 @@ impl FeeRate {
} }
/// Constructs `FeeRate` from satoshis per virtual bytes without overflow check. /// Constructs `FeeRate` from satoshis per virtual bytes without overflow check.
pub const fn from_sat_per_vb_unchecked(sat_vb: u64) -> Self { pub const fn from_sat_per_vb_unchecked(sat_vb: u64) -> Self { FeeRate(sat_vb * (1000 / 4)) }
FeeRate(sat_vb * (1000 / 4))
}
/// Returns raw fee rate. /// Returns raw fee rate.
/// ///
/// Can be used instead of `into()` to avoid inference issues. /// Can be used instead of `into()` to avoid inference issues.
pub const fn to_sat_per_kwu(self) -> u64 { pub const fn to_sat_per_kwu(self) -> u64 { self.0 }
self.0
}
/// Converts to sat/vB rounding down. /// Converts to sat/vB rounding down.
pub const fn to_sat_per_vb_floor(self) -> u64 { pub const fn to_sat_per_vb_floor(self) -> u64 { self.0 / (1000 / 4) }
self.0 / (1000 / 4)
}
/// Converts to sat/vB rounding up. /// Converts to sat/vB rounding up.
pub const fn to_sat_per_vb_ceil(self) -> u64 { pub const fn to_sat_per_vb_ceil(self) -> u64 { (self.0 + (1000 / 4 - 1)) / (1000 / 4) }
(self.0 + (1000 / 4 - 1)) / (1000 / 4)
}
/// Checked multiplication. /// Checked multiplication.
/// ///
/// Computes `self * rhs` returning `None` if overflow occurred. /// Computes `self * rhs` returning `None` if overflow occurred.
pub fn checked_mul(self, rhs: u64) -> Option<Self> { pub fn checked_mul(self, rhs: u64) -> Option<Self> { self.0.checked_mul(rhs).map(Self) }
self.0.checked_mul(rhs).map(Self)
}
/// Checked division. /// Checked division.
/// ///
/// Computes `self / rhs` returning `None` if `rhs == 0`. /// Computes `self / rhs` returning `None` if `rhs == 0`.
pub fn checked_div(self, rhs: u64) -> Option<Self> { pub fn checked_div(self, rhs: u64) -> Option<Self> { self.0.checked_div(rhs).map(Self) }
self.0.checked_div(rhs).map(Self)
}
} }
/// Alternative will display the unit. /// Alternative will display the unit.
@ -105,9 +91,7 @@ impl fmt::Display for FeeRate {
} }
impl From<FeeRate> for u64 { impl From<FeeRate> for u64 {
fn from(value: FeeRate) -> Self { fn from(value: FeeRate) -> Self { value.to_sat_per_kwu() }
value.to_sat_per_kwu()
}
} }
/// Computes ceiling so that fee computation is conservative. /// Computes ceiling so that fee computation is conservative.
@ -122,26 +106,23 @@ impl Mul<FeeRate> for Weight {
impl Mul<Weight> for FeeRate { impl Mul<Weight> for FeeRate {
type Output = Amount; type Output = Amount;
fn mul(self, rhs: Weight) -> Self::Output { fn mul(self, rhs: Weight) -> Self::Output { rhs * self }
rhs * self
}
} }
impl Div<Weight> for Amount { impl Div<Weight> for Amount {
type Output = FeeRate; type Output = FeeRate;
fn div(self, rhs: Weight) -> Self::Output { fn div(self, rhs: Weight) -> Self::Output { FeeRate(self.to_sat() * 1000 / rhs.to_wu()) }
FeeRate(self.to_sat() * 1000 / rhs.to_wu())
}
} }
crate::parse::impl_parse_str_from_int_infallible!(FeeRate, u64, from_sat_per_kwu); crate::parse::impl_parse_str_from_int_infallible!(FeeRate, u64, from_sat_per_kwu);
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use super::*;
use std::u64; use std::u64;
use super::*;
#[test] #[test]
fn fee_rate_const_test() { fn fee_rate_const_test() {
assert_eq!(0, FeeRate::ZERO.to_sat_per_kwu()); assert_eq!(0, FeeRate::ZERO.to_sat_per_kwu());
@ -171,9 +152,7 @@ mod tests {
#[test] #[test]
#[should_panic] #[should_panic]
fn from_sat_per_vb_unchecked_panic_test() { fn from_sat_per_vb_unchecked_panic_test() { FeeRate::from_sat_per_vb_unchecked(u64::MAX); }
FeeRate::from_sat_per_vb_unchecked(u64::MAX);
}
#[test] #[test]
fn raw_feerate_test() { fn raw_feerate_test() {

View File

@ -7,24 +7,22 @@
//! whether `LockTime < LOCKTIME_THRESHOLD`. //! whether `LockTime < LOCKTIME_THRESHOLD`.
//! //!
use core::{mem, fmt}; use core::cmp::{Ordering, PartialOrd};
use core::cmp::{PartialOrd, Ordering}; use core::{fmt, mem};
use bitcoin_internals::write_err; use bitcoin_internals::write_err;
#[cfg(all(test, mutate))] #[cfg(all(test, mutate))]
use mutagen::mutate; use mutagen::mutate;
#[cfg(doc)]
use crate::absolute;
use crate::consensus::encode::{self, Decodable, Encodable}; use crate::consensus::encode::{self, Decodable, Encodable};
use crate::error::ParseIntError; use crate::error::ParseIntError;
use crate::io::{self, Read, Write}; use crate::io::{self, Read, Write};
use crate::parse::{impl_parse_str_from_int_infallible, impl_parse_str_from_int_fallible}; use crate::parse::{impl_parse_str_from_int_fallible, impl_parse_str_from_int_infallible};
use crate::prelude::*; use crate::prelude::*;
use crate::string::FromHexStr; use crate::string::FromHexStr;
#[cfg(doc)]
use crate::absolute;
/// The Threshold for deciding whether a lock time value is a height or a time (see [Bitcoin Core]). /// The Threshold for deciding whether a lock time value is a height or a time (see [Bitcoin Core]).
/// ///
/// `LockTime` values _below_ the threshold are interpreted as block heights, values _above_ (or /// `LockTime` values _below_ the threshold are interpreted as block heights, values _above_ (or
@ -173,9 +171,7 @@ impl LockTime {
/// Returns true if this lock time value is a block time (UNIX timestamp). /// Returns true if this lock time value is a block time (UNIX timestamp).
#[inline] #[inline]
pub fn is_block_time(&self) -> bool { pub fn is_block_time(&self) -> bool { !self.is_block_height() }
!self.is_block_height()
}
/// Returns true if this timelock constraint is satisfied by the respective `height`/`time`. /// Returns true if this timelock constraint is satisfied by the respective `height`/`time`.
/// ///
@ -278,16 +274,12 @@ impl_parse_str_from_int_infallible!(LockTime, u32, from_consensus);
impl From<Height> for LockTime { impl From<Height> for LockTime {
#[inline] #[inline]
fn from(h: Height) -> Self { fn from(h: Height) -> Self { LockTime::Blocks(h) }
LockTime::Blocks(h)
}
} }
impl From<Time> for LockTime { impl From<Time> for LockTime {
#[inline] #[inline]
fn from(t: Time) -> Self { fn from(t: Time) -> Self { LockTime::Seconds(t) }
LockTime::Seconds(t)
}
} }
impl PartialOrd for LockTime { impl PartialOrd for LockTime {
@ -371,19 +363,22 @@ impl<'de> serde::Deserialize<'de> for LockTime {
// other visit_u*s have default implementations that forward to visit_u64. // other visit_u*s have default implementations that forward to visit_u64.
fn visit_u64<E: serde::de::Error>(self, v: u64) -> Result<u32, E> { fn visit_u64<E: serde::de::Error>(self, v: u64) -> Result<u32, E> {
use core::convert::TryInto; use core::convert::TryInto;
v.try_into().map_err(|_| E::invalid_value(serde::de::Unexpected::Unsigned(v), &"a 32-bit number")) v.try_into().map_err(|_| {
E::invalid_value(serde::de::Unexpected::Unsigned(v), &"a 32-bit number")
})
} }
// Also do the signed version, just for good measure. // Also do the signed version, just for good measure.
fn visit_i64<E: serde::de::Error>(self, v: i64) -> Result<u32, E> { fn visit_i64<E: serde::de::Error>(self, v: i64) -> Result<u32, E> {
use core::convert::TryInto; use core::convert::TryInto;
v.try_into().map_err(|_| E::invalid_value(serde::de::Unexpected::Signed(v), &"a 32-bit number")) v.try_into().map_err(|_| {
E::invalid_value(serde::de::Unexpected::Signed(v), &"a 32-bit number")
})
} }
} }
deserializer.deserialize_u32(Visitor).map(LockTime::from_consensus) deserializer.deserialize_u32(Visitor).map(LockTime::from_consensus)
} }
} }
/// An absolute block height, guaranteed to always contain a valid height value. /// An absolute block height, guaranteed to always contain a valid height value.
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)] #[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
@ -444,17 +439,13 @@ impl Height {
/// assert!(lock_time.is_block_height()); /// assert!(lock_time.is_block_height());
/// assert_eq!(lock_time.to_consensus_u32(), n_lock_time); /// assert_eq!(lock_time.to_consensus_u32(), n_lock_time);
#[inline] #[inline]
pub fn to_consensus_u32(self) -> u32 { pub fn to_consensus_u32(self) -> u32 { self.0 }
self.0
}
} }
impl_parse_str_from_int_fallible!(Height, u32, from_consensus, Error); impl_parse_str_from_int_fallible!(Height, u32, from_consensus, Error);
impl fmt::Display for Height { impl fmt::Display for Height {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { fmt::Display::fmt(&self.0, f) }
fmt::Display::fmt(&self.0, f)
}
} }
impl FromHexStr for Height { impl FromHexStr for Height {
@ -528,17 +519,13 @@ impl Time {
/// assert_eq!(lock_time.to_consensus_u32(), n_lock_time); /// assert_eq!(lock_time.to_consensus_u32(), n_lock_time);
/// ``` /// ```
#[inline] #[inline]
pub fn to_consensus_u32(self) -> u32 { pub fn to_consensus_u32(self) -> u32 { self.0 }
self.0
}
} }
impl_parse_str_from_int_fallible!(Time, u32, from_consensus, Error); impl_parse_str_from_int_fallible!(Time, u32, from_consensus, Error);
impl fmt::Display for Time { impl fmt::Display for Time {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { fmt::Display::fmt(&self.0, f) }
fmt::Display::fmt(&self.0, f)
}
} }
impl FromHexStr for Time { impl FromHexStr for Time {
@ -552,14 +539,10 @@ impl FromHexStr for Time {
} }
/// Returns true if `n` is a block height i.e., less than 500,000,000. /// Returns true if `n` is a block height i.e., less than 500,000,000.
fn is_block_height(n: u32) -> bool { fn is_block_height(n: u32) -> bool { n < LOCK_TIME_THRESHOLD }
n < LOCK_TIME_THRESHOLD
}
/// Returns true if `n` is a UNIX timestamp i.e., greater than or equal to 500,000,000. /// Returns true if `n` is a UNIX timestamp i.e., greater than or equal to 500,000,000.
fn is_block_time(n: u32) -> bool { fn is_block_time(n: u32) -> bool { n >= LOCK_TIME_THRESHOLD }
n >= LOCK_TIME_THRESHOLD
}
/// Catchall type for errors that relate to time locks. /// Catchall type for errors that relate to time locks.
#[derive(Debug, Clone, PartialEq, Eq)] #[derive(Debug, Clone, PartialEq, Eq)]
@ -601,23 +584,17 @@ impl std::error::Error for Error {
impl From<ConversionError> for Error { impl From<ConversionError> for Error {
#[inline] #[inline]
fn from(e: ConversionError) -> Self { fn from(e: ConversionError) -> Self { Error::Conversion(e) }
Error::Conversion(e)
}
} }
impl From<OperationError> for Error { impl From<OperationError> for Error {
#[inline] #[inline]
fn from(e: OperationError) -> Self { fn from(e: OperationError) -> Self { Error::Operation(e) }
Error::Operation(e)
}
} }
impl From<ParseIntError> for Error { impl From<ParseIntError> for Error {
#[inline] #[inline]
fn from(e: ParseIntError) -> Self { fn from(e: ParseIntError) -> Self { Error::Parse(e) }
Error::Parse(e)
}
} }
/// An error that occurs when converting a `u32` to a lock time variant. /// An error that occurs when converting a `u32` to a lock time variant.
@ -631,20 +608,10 @@ pub struct ConversionError {
impl ConversionError { impl ConversionError {
/// Constructs a `ConversionError` from an invalid `n` when expecting a height value. /// Constructs a `ConversionError` from an invalid `n` when expecting a height value.
fn invalid_height(n: u32) -> Self { fn invalid_height(n: u32) -> Self { Self { unit: LockTimeUnit::Blocks, input: n } }
Self {
unit: LockTimeUnit::Blocks,
input: n,
}
}
/// Constructs a `ConversionError` from an invalid `n` when expecting a time value. /// Constructs a `ConversionError` from an invalid `n` when expecting a time value.
fn invalid_time(n: u32) -> Self { fn invalid_time(n: u32) -> Self { Self { unit: LockTimeUnit::Seconds, input: n } }
Self {
unit: LockTimeUnit::Seconds,
input: n,
}
}
} }
impl fmt::Display for ConversionError { impl fmt::Display for ConversionError {
@ -690,7 +657,8 @@ impl fmt::Display for OperationError {
use self::OperationError::*; use self::OperationError::*;
match *self { match *self {
InvalidComparison => f.write_str("cannot compare different lock units (height vs time)"), InvalidComparison =>
f.write_str("cannot compare different lock units (height vs time)"),
} }
} }
} }

View File

@ -7,15 +7,14 @@
//! whether bit 22 of the `u32` consensus value is set. //! whether bit 22 of the `u32` consensus value is set.
//! //!
use core::fmt;
use core::convert::TryFrom; use core::convert::TryFrom;
use core::fmt;
#[cfg(all(test, mutate))] #[cfg(all(test, mutate))]
use mutagen::mutate; use mutagen::mutate;
use crate::parse::impl_parse_str_from_int_infallible; use crate::parse::impl_parse_str_from_int_infallible;
use crate::prelude::*; use crate::prelude::*;
#[cfg(doc)] #[cfg(doc)]
use crate::relative; use crate::relative;
@ -169,16 +168,12 @@ impl LockTime {
impl From<Height> for LockTime { impl From<Height> for LockTime {
#[inline] #[inline]
fn from(h: Height) -> Self { fn from(h: Height) -> Self { LockTime::Blocks(h) }
LockTime::Blocks(h)
}
} }
impl From<Time> for LockTime { impl From<Time> for LockTime {
#[inline] #[inline]
fn from(t: Time) -> Self { fn from(t: Time) -> Self { LockTime::Time(t) }
LockTime::Time(t)
}
} }
impl fmt::Display for LockTime { impl fmt::Display for LockTime {
@ -227,24 +222,18 @@ impl Height {
/// Returns the inner `u16` value. /// Returns the inner `u16` value.
#[inline] #[inline]
pub fn value(self) -> u16 { pub fn value(self) -> u16 { self.0 }
self.0
}
} }
impl From<u16> for Height { impl From<u16> for Height {
#[inline] #[inline]
fn from(value: u16) -> Self { fn from(value: u16) -> Self { Height(value) }
Height(value)
}
} }
impl_parse_str_from_int_infallible!(Height, u16, from); impl_parse_str_from_int_infallible!(Height, u16, from);
impl fmt::Display for Height { impl fmt::Display for Height {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { fmt::Display::fmt(&self.0, f) }
fmt::Display::fmt(&self.0, f)
}
} }
/// A relative lock time lock-by-blocktime value. /// A relative lock time lock-by-blocktime value.
@ -279,9 +268,7 @@ impl Time {
/// ///
/// Encoding finer granularity of time for relative lock-times is not supported in Bitcoin. /// Encoding finer granularity of time for relative lock-times is not supported in Bitcoin.
#[inline] #[inline]
pub fn from_512_second_intervals(intervals: u16) -> Self { pub fn from_512_second_intervals(intervals: u16) -> Self { Time(intervals) }
Time(intervals)
}
/// Create a [`Time`] from seconds, converting the seconds into 512 second interval with ceiling /// Create a [`Time`] from seconds, converting the seconds into 512 second interval with ceiling
/// division. /// division.
@ -300,17 +287,13 @@ impl Time {
/// Returns the inner `u16` value. /// Returns the inner `u16` value.
#[inline] #[inline]
pub fn value(self) -> u16 { pub fn value(self) -> u16 { self.0 }
self.0
}
} }
impl_parse_str_from_int_infallible!(Time, u16, from_512_second_intervals); impl_parse_str_from_int_infallible!(Time, u16, from_512_second_intervals);
impl fmt::Display for Time { impl fmt::Display for Time {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { fmt::Display::fmt(&self.0, f) }
fmt::Display::fmt(&self.0, f)
}
} }
/// Errors related to relative lock times. /// Errors related to relative lock times.
@ -328,9 +311,15 @@ pub enum Error {
impl fmt::Display for Error { impl fmt::Display for Error {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match *self { match *self {
Self::IntegerOverflow(val) => write!(f, "{} seconds is too large to be encoded to a 16 bit 512 second interval", val), Self::IntegerOverflow(val) => write!(
Self::IncompatibleHeight(lock, height) => write!(f, "tried to satisfy lock {} with height: {}", lock, height), f,
Self::IncompatibleTime(lock, time) => write!(f, "tried to satisfy lock {} with time: {}", lock, time), "{} seconds is too large to be encoded to a 16 bit 512 second interval",
val
),
Self::IncompatibleHeight(lock, height) =>
write!(f, "tried to satisfy lock {} with height: {}", lock, height),
Self::IncompatibleTime(lock, time) =>
write!(f, "tried to satisfy lock {} with time: {}", lock, time),
} }
} }
} }

View File

@ -7,15 +7,15 @@
//! transactions which make up the Bitcoin system. //! transactions which make up the Bitcoin system.
//! //!
pub mod block;
pub mod constants; pub mod constants;
pub mod fee_rate;
pub mod locktime; pub mod locktime;
pub mod opcodes; pub mod opcodes;
pub mod script; pub mod script;
pub mod transaction; pub mod transaction;
pub mod block;
pub mod witness;
pub mod weight; pub mod weight;
pub mod fee_rate; pub mod witness;
pub use weight::Weight;
pub use fee_rate::FeeRate; pub use fee_rate::FeeRate;
pub use weight::Weight;

View File

@ -9,12 +9,15 @@
#![allow(non_camel_case_types)] #![allow(non_camel_case_types)]
#[cfg(feature = "serde")] use serde; use core::convert::From;
use core::fmt;
#[cfg(feature = "serde")] use crate::prelude::*;
use core::{fmt, convert::From};
use bitcoin_internals::debug_from_display; use bitcoin_internals::debug_from_display;
#[cfg(feature = "serde")]
use serde;
#[cfg(feature = "serde")]
use crate::prelude::*;
/// A script Opcode. /// A script Opcode.
/// ///
@ -362,13 +365,15 @@ impl All {
// 87 opcodes of SuccessOp class only in TapScript context // 87 opcodes of SuccessOp class only in TapScript context
(op, ClassifyContext::TapScript) (op, ClassifyContext::TapScript)
if op.code == 80 || op.code == 98 || if op.code == 80
(op.code >= 126 && op.code <= 129) || || op.code == 98
(op.code >= 131 && op.code <= 134) || || (op.code >= 126 && op.code <= 129)
(op.code >= 137 && op.code <= 138) || || (op.code >= 131 && op.code <= 134)
(op.code >= 141 && op.code <= 142) || || (op.code >= 137 && op.code <= 138)
(op.code >= 149 && op.code <= 153) || || (op.code >= 141 && op.code <= 142)
(op.code >= 187 && op.code <= 254) => Class::SuccessOp, || (op.code >= 149 && op.code <= 153)
|| (op.code >= 187 && op.code <= 254) =>
Class::SuccessOp,
// 11 opcodes of NoOp class // 11 opcodes of NoOp class
(OP_NOP, _) => Class::NoOp, (OP_NOP, _) => Class::NoOp,
@ -378,9 +383,9 @@ impl All {
(OP_RETURN, _) => Class::ReturnOp, (OP_RETURN, _) => Class::ReturnOp,
// 4 opcodes operating equally to `OP_RETURN` only in Legacy context // 4 opcodes operating equally to `OP_RETURN` only in Legacy context
(OP_RESERVED, ctx) (OP_RESERVED, ctx) | (OP_RESERVED1, ctx) | (OP_RESERVED2, ctx) | (OP_VER, ctx)
| (OP_RESERVED1, ctx) | (OP_RESERVED2, ctx) if ctx == ClassifyContext::Legacy =>
| (OP_VER, ctx) if ctx == ClassifyContext::Legacy => Class::ReturnOp, Class::ReturnOp,
// 71 opcodes operating equally to `OP_RETURN` only in Legacy context // 71 opcodes operating equally to `OP_RETURN` only in Legacy context
(op, ClassifyContext::Legacy) if op.code >= OP_CHECKSIGADD.code => Class::ReturnOp, (op, ClassifyContext::Legacy) if op.code >= OP_CHECKSIGADD.code => Class::ReturnOp,
@ -393,9 +398,8 @@ impl All {
(OP_PUSHNUM_NEG1, _) => Class::PushNum(-1), (OP_PUSHNUM_NEG1, _) => Class::PushNum(-1),
// 16 opcodes of PushNum class // 16 opcodes of PushNum class
(op, _) if op.code >= OP_PUSHNUM_1.code && op.code <= OP_PUSHNUM_16.code => { (op, _) if op.code >= OP_PUSHNUM_1.code && op.code <= OP_PUSHNUM_16.code =>
Class::PushNum(1 + self.code as i32 - OP_PUSHNUM_1.code as i32) Class::PushNum(1 + self.code as i32 - OP_PUSHNUM_1.code as i32),
},
// 76 opcodes of PushBytes class // 76 opcodes of PushBytes class
(op, _) if op.code <= OP_PUSHBYTES_75.code => Class::PushBytes(self.code as u32), (op, _) if op.code <= OP_PUSHBYTES_75.code => Class::PushBytes(self.code as u32),
@ -407,16 +411,12 @@ impl All {
/// Encodes [`All`] as a byte. /// Encodes [`All`] as a byte.
#[inline] #[inline]
pub const fn to_u8(self) -> u8 { pub const fn to_u8(self) -> u8 { self.code }
self.code
}
} }
impl From<u8> for All { impl From<u8> for All {
#[inline] #[inline]
fn from(b: u8) -> All { fn from(b: u8) -> All { All { code: b } }
All {code: b}
}
} }
debug_from_display!(All); debug_from_display!(All);
@ -459,7 +459,7 @@ pub enum Class {
/// Does nothing. /// Does nothing.
NoOp, NoOp,
/// Any opcode not covered above. /// Any opcode not covered above.
Ordinary(Ordinary) Ordinary(Ordinary),
} }
macro_rules! ordinary_opcode { macro_rules! ordinary_opcode {
@ -527,9 +527,7 @@ ordinary_opcode! {
impl Ordinary { impl Ordinary {
/// Encodes [`All`] as a byte. /// Encodes [`All`] as a byte.
#[inline] #[inline]
pub fn to_u8(self) -> u8 { pub fn to_u8(self) -> u8 { self as u8 }
self as u8
}
} }
#[cfg(test)] #[cfg(test)]
@ -547,7 +545,7 @@ mod tests {
assert_eq!(s1, s2); assert_eq!(s1, s2);
assert_eq!(s1, stringify!($op)); assert_eq!(s1, stringify!($op));
assert!($unique.insert(s1)); assert!($unique.insert(s1));
} };
} }
#[test] #[test]
@ -560,16 +558,25 @@ mod tests {
#[test] #[test]
fn classify_test() { fn classify_test() {
let op174 = OP_CHECKMULTISIG; let op174 = OP_CHECKMULTISIG;
assert_eq!(op174.classify(ClassifyContext::Legacy), Class::Ordinary(Ordinary::OP_CHECKMULTISIG)); assert_eq!(
op174.classify(ClassifyContext::Legacy),
Class::Ordinary(Ordinary::OP_CHECKMULTISIG)
);
assert_eq!(op174.classify(ClassifyContext::TapScript), Class::ReturnOp); assert_eq!(op174.classify(ClassifyContext::TapScript), Class::ReturnOp);
let op175 = OP_CHECKMULTISIGVERIFY; let op175 = OP_CHECKMULTISIGVERIFY;
assert_eq!(op175.classify(ClassifyContext::Legacy), Class::Ordinary(Ordinary::OP_CHECKMULTISIGVERIFY)); assert_eq!(
op175.classify(ClassifyContext::Legacy),
Class::Ordinary(Ordinary::OP_CHECKMULTISIGVERIFY)
);
assert_eq!(op175.classify(ClassifyContext::TapScript), Class::ReturnOp); assert_eq!(op175.classify(ClassifyContext::TapScript), Class::ReturnOp);
let op186 = OP_CHECKSIGADD; let op186 = OP_CHECKSIGADD;
assert_eq!(op186.classify(ClassifyContext::Legacy), Class::ReturnOp); assert_eq!(op186.classify(ClassifyContext::Legacy), Class::ReturnOp);
assert_eq!(op186.classify(ClassifyContext::TapScript), Class::Ordinary(Ordinary::OP_CHECKSIGADD)); assert_eq!(
op186.classify(ClassifyContext::TapScript),
Class::Ordinary(Ordinary::OP_CHECKSIGADD)
);
let op187 = OP_RETURN_187; let op187 = OP_RETURN_187;
assert_eq!(op187.classify(ClassifyContext::Legacy), Class::ReturnOp); assert_eq!(op187.classify(ClassifyContext::Legacy), Class::ReturnOp);

View File

@ -5,22 +5,25 @@ use core::convert::{TryFrom, TryInto};
use core::fmt; use core::fmt;
#[cfg(rust_v_1_53)] #[cfg(rust_v_1_53)]
use core::ops::Bound; use core::ops::Bound;
use core::ops::{Index, Range, RangeFull, RangeFrom, RangeTo, RangeInclusive, RangeToInclusive}; use core::ops::{Index, Range, RangeFrom, RangeFull, RangeInclusive, RangeTo, RangeToInclusive};
use secp256k1::{Secp256k1, Verification}; use secp256k1::{Secp256k1, Verification};
use crate::address::WitnessVersion; use crate::address::WitnessVersion;
use crate::blockdata::opcodes::{self, all::*}; use crate::blockdata::opcodes::all::*;
use crate::blockdata::script::{bytes_to_asm_fmt, Builder, Instruction, Instructions, InstructionIndices, ScriptBuf}; use crate::blockdata::opcodes::{self};
#[cfg(feature = "bitcoinconsensus")] #[cfg(feature = "bitcoinconsensus")]
use crate::blockdata::script::Error; use crate::blockdata::script::Error;
use crate::blockdata::script::{
bytes_to_asm_fmt, Builder, Instruction, InstructionIndices, Instructions, ScriptBuf,
};
use crate::consensus::Encodable; use crate::consensus::Encodable;
use crate::hash_types::{ScriptHash, WScriptHash}; use crate::hash_types::{ScriptHash, WScriptHash};
use crate::hashes::Hash; use crate::hashes::Hash;
use crate::key::{PublicKey, UntweakedPublicKey}; use crate::key::{PublicKey, UntweakedPublicKey};
use crate::policy::DUST_RELAY_TX_FEE; use crate::policy::DUST_RELAY_TX_FEE;
use crate::prelude::*; use crate::prelude::*;
use crate::taproot::{LeafVersion, TapNodeHash, TapLeafHash}; use crate::taproot::{LeafVersion, TapLeafHash, TapNodeHash};
/// Bitcoin script slice. /// Bitcoin script slice.
/// ///
@ -74,9 +77,7 @@ pub struct Script(pub (in crate::blockdata::script) [u8]);
impl ToOwned for Script { impl ToOwned for Script {
type Owned = ScriptBuf; type Owned = ScriptBuf;
fn to_owned(&self) -> Self::Owned { fn to_owned(&self) -> Self::Owned { ScriptBuf(self.0.to_owned()) }
ScriptBuf(self.0.to_owned())
}
} }
impl Script { impl Script {
@ -87,9 +88,7 @@ impl Script {
// The pointer was just created from a reference which is still alive. // The pointer was just created from a reference which is still alive.
// Casting slice pointer to a transparent struct wrapping that slice is sound (same // Casting slice pointer to a transparent struct wrapping that slice is sound (same
// layout). // layout).
unsafe { unsafe { &*(bytes as *const [u8] as *const Script) }
&*(bytes as *const [u8] as *const Script)
}
} }
/// Treat mutable byte slice as `Script` /// Treat mutable byte slice as `Script`
@ -101,43 +100,31 @@ impl Script {
// layout). // layout).
// Function signature prevents callers from accessing `bytes` while the returned reference // Function signature prevents callers from accessing `bytes` while the returned reference
// is alive. // is alive.
unsafe { unsafe { &mut *(bytes as *mut [u8] as *mut Script) }
&mut *(bytes as *mut [u8] as *mut Script)
}
} }
/// Returns the script data as a byte slice. /// Returns the script data as a byte slice.
#[inline] #[inline]
pub fn as_bytes(&self) -> &[u8] { pub fn as_bytes(&self) -> &[u8] { &self.0 }
&self.0
}
/// Returns the script data as a mutable byte slice. /// Returns the script data as a mutable byte slice.
#[inline] #[inline]
pub fn as_mut_bytes(&mut self) -> &mut [u8] { pub fn as_mut_bytes(&mut self) -> &mut [u8] { &mut self.0 }
&mut self.0
}
/// Creates a new empty script. /// Creates a new empty script.
#[inline] #[inline]
pub fn empty() -> &'static Script { Script::from_bytes(&[]) } pub fn empty() -> &'static Script { Script::from_bytes(&[]) }
/// Creates a new script builder /// Creates a new script builder
pub fn builder() -> Builder { pub fn builder() -> Builder { Builder::new() }
Builder::new()
}
/// Returns 160-bit hash of the script. /// Returns 160-bit hash of the script.
#[inline] #[inline]
pub fn script_hash(&self) -> ScriptHash { pub fn script_hash(&self) -> ScriptHash { ScriptHash::hash(self.as_bytes()) }
ScriptHash::hash(self.as_bytes())
}
/// Returns 256-bit hash of the script for P2WSH outputs. /// Returns 256-bit hash of the script for P2WSH outputs.
#[inline] #[inline]
pub fn wscript_hash(&self) -> WScriptHash { pub fn wscript_hash(&self) -> WScriptHash { WScriptHash::hash(self.as_bytes()) }
WScriptHash::hash(self.as_bytes())
}
/// Computes leaf hash of tapscript. /// Computes leaf hash of tapscript.
#[inline] #[inline]
@ -159,21 +146,21 @@ impl Script {
/// Returns an iterator over script bytes. /// Returns an iterator over script bytes.
#[inline] #[inline]
pub fn bytes(&self) -> Bytes<'_> { pub fn bytes(&self) -> Bytes<'_> { Bytes(self.as_bytes().iter().copied()) }
Bytes(self.as_bytes().iter().copied())
}
/// Computes the P2WSH output corresponding to this witnessScript (aka the "witness redeem /// Computes the P2WSH output corresponding to this witnessScript (aka the "witness redeem
/// script"). /// script").
#[inline] #[inline]
pub fn to_v0_p2wsh(&self) -> ScriptBuf { pub fn to_v0_p2wsh(&self) -> ScriptBuf { ScriptBuf::new_v0_p2wsh(&self.wscript_hash()) }
ScriptBuf::new_v0_p2wsh(&self.wscript_hash())
}
/// Computes P2TR output with a given internal key and a single script spending path equal to /// Computes P2TR output with a given internal key and a single script spending path equal to
/// the current script, assuming that the script is a Tapscript. /// the current script, assuming that the script is a Tapscript.
#[inline] #[inline]
pub fn to_v1_p2tr<C: Verification>(&self, secp: &Secp256k1<C>, internal_key: UntweakedPublicKey) -> ScriptBuf { pub fn to_v1_p2tr<C: Verification>(
&self,
secp: &Secp256k1<C>,
internal_key: UntweakedPublicKey,
) -> ScriptBuf {
let leaf_hash = self.tapscript_leaf_hash(); let leaf_hash = self.tapscript_leaf_hash();
let merkle_root = TapNodeHash::from(leaf_hash); let merkle_root = TapNodeHash::from(leaf_hash);
ScriptBuf::new_v1_p2tr(secp, internal_key, Some(merkle_root)) ScriptBuf::new_v1_p2tr(secp, internal_key, Some(merkle_root))
@ -210,9 +197,7 @@ impl Script {
/// You can obtain the public key, if its valid, /// You can obtain the public key, if its valid,
/// by calling [`p2pk_public_key()`](Self::p2pk_public_key) /// by calling [`p2pk_public_key()`](Self::p2pk_public_key)
#[inline] #[inline]
pub fn is_p2pk(&self) -> bool { pub fn is_p2pk(&self) -> bool { self.p2pk_pubkey_bytes().is_some() }
self.p2pk_pubkey_bytes().is_some()
}
/// Returns the public key if this script is P2PK with a **valid** public key. /// Returns the public key if this script is P2PK with a **valid** public key.
/// ///
@ -228,15 +213,11 @@ impl Script {
#[inline] #[inline]
pub(in crate::blockdata::script) fn p2pk_pubkey_bytes(&self) -> Option<&[u8]> { pub(in crate::blockdata::script) fn p2pk_pubkey_bytes(&self) -> Option<&[u8]> {
match self.len() { match self.len() {
67 if self.0[0] == OP_PUSHBYTES_65.to_u8() 67 if self.0[0] == OP_PUSHBYTES_65.to_u8() && self.0[66] == OP_CHECKSIG.to_u8() =>
&& self.0[66] == OP_CHECKSIG.to_u8() => { Some(&self.0[1..66]),
Some(&self.0[1..66]) 35 if self.0[0] == OP_PUSHBYTES_33.to_u8() && self.0[34] == OP_CHECKSIG.to_u8() =>
} Some(&self.0[1..34]),
35 if self.0[0] == OP_PUSHBYTES_33.to_u8() _ => None,
&& self.0[34] == OP_CHECKSIG.to_u8() => {
Some(&self.0[1..34])
}
_ => None
} }
} }
@ -249,7 +230,7 @@ impl Script {
// byte vector pushed is called the "witness program". // byte vector pushed is called the "witness program".
let script_len = self.0.len(); let script_len = self.0.len();
if !(4..=42).contains(&script_len) { if !(4..=42).contains(&script_len) {
return false return false;
} }
let ver_opcode = opcodes::All::from(self.0[0]); // Version 0 or PUSHNUM_1-PUSHNUM_16 let ver_opcode = opcodes::All::from(self.0[0]); // Version 0 or PUSHNUM_1-PUSHNUM_16
let push_opbyte = self.0[1]; // Second byte push opcode 2-40 bytes let push_opbyte = self.0[1]; // Second byte push opcode 2-40 bytes
@ -297,14 +278,14 @@ impl Script {
pub fn is_op_return(&self) -> bool { pub fn is_op_return(&self) -> bool {
match self.0.first() { match self.0.first() {
Some(b) => *b == OP_RETURN.to_u8(), Some(b) => *b == OP_RETURN.to_u8(),
None => false None => false,
} }
} }
/// Checks whether a script can be proven to have no satisfying input. /// Checks whether a script can be proven to have no satisfying input.
#[inline] #[inline]
pub fn is_provably_unspendable(&self) -> bool { pub fn is_provably_unspendable(&self) -> bool {
use crate::blockdata::opcodes::Class::{ReturnOp, IllegalOp}; use crate::blockdata::opcodes::Class::{IllegalOp, ReturnOp};
match self.0.first() { match self.0.first() {
Some(b) => { Some(b) => {
@ -312,7 +293,7 @@ impl Script {
let class = first.classify(opcodes::ClassifyContext::Legacy); let class = first.classify(opcodes::ClassifyContext::Legacy);
class == ReturnOp || class == IllegalOp class == ReturnOp || class == IllegalOp
}, }
None => false, None => false,
} }
} }
@ -347,10 +328,7 @@ impl Script {
/// To force minimal pushes, use [`instructions_minimal`](Self::instructions_minimal). /// To force minimal pushes, use [`instructions_minimal`](Self::instructions_minimal).
#[inline] #[inline]
pub fn instructions(&self) -> Instructions { pub fn instructions(&self) -> Instructions {
Instructions { Instructions { data: self.0.iter(), enforce_minimal: false }
data: self.0.iter(),
enforce_minimal: false,
}
} }
/// Iterates over the script instructions while enforcing minimal pushes. /// Iterates over the script instructions while enforcing minimal pushes.
@ -359,10 +337,7 @@ impl Script {
/// is not minimal. /// is not minimal.
#[inline] #[inline]
pub fn instructions_minimal(&self) -> Instructions { pub fn instructions_minimal(&self) -> Instructions {
Instructions { Instructions { data: self.0.iter(), enforce_minimal: true }
data: self.0.iter(),
enforce_minimal: true,
}
} }
/// Iterates over the script instructions and their indices. /// Iterates over the script instructions and their indices.
@ -394,7 +369,12 @@ impl Script {
/// * `spending_tx` - The transaction that attempts to spend the output holding this script. /// * `spending_tx` - The transaction that attempts to spend the output holding this script.
#[cfg(feature = "bitcoinconsensus")] #[cfg(feature = "bitcoinconsensus")]
#[cfg_attr(docsrs, doc(cfg(feature = "bitcoinconsensus")))] #[cfg_attr(docsrs, doc(cfg(feature = "bitcoinconsensus")))]
pub fn verify (&self, index: usize, amount: crate::Amount, spending_tx: &[u8]) -> Result<(), Error> { pub fn verify(
&self,
index: usize,
amount: crate::Amount,
spending_tx: &[u8],
) -> Result<(), Error> {
self.verify_with_flags(index, amount, spending_tx, bitcoinconsensus::VERIFY_ALL) self.verify_with_flags(index, amount, spending_tx, bitcoinconsensus::VERIFY_ALL)
} }
@ -407,8 +387,20 @@ impl Script {
/// * `flags` - Verification flags, see [`bitcoinconsensus::VERIFY_ALL`] and similar. /// * `flags` - Verification flags, see [`bitcoinconsensus::VERIFY_ALL`] and similar.
#[cfg(feature = "bitcoinconsensus")] #[cfg(feature = "bitcoinconsensus")]
#[cfg_attr(docsrs, doc(cfg(feature = "bitcoinconsensus")))] #[cfg_attr(docsrs, doc(cfg(feature = "bitcoinconsensus")))]
pub fn verify_with_flags<F: Into<u32>>(&self, index: usize, amount: crate::Amount, spending_tx: &[u8], flags: F) -> Result<(), Error> { pub fn verify_with_flags<F: Into<u32>>(
Ok(bitcoinconsensus::verify_with_flags (&self.0[..], amount.to_sat(), spending_tx, index, flags.into())?) &self,
index: usize,
amount: crate::Amount,
spending_tx: &[u8],
flags: F,
) -> Result<(), Error> {
Ok(bitcoinconsensus::verify_with_flags(
&self.0[..],
amount.to_sat(),
spending_tx,
index,
flags.into(),
)?)
} }
/// Writes the assembly decoding of the script to the formatter. /// Writes the assembly decoding of the script to the formatter.
@ -428,9 +420,7 @@ impl Script {
/// This is a more convenient and performant way to write `format!("{:x}", script)`. /// This is a more convenient and performant way to write `format!("{:x}", script)`.
/// For better performance you should generally prefer displaying the script but if `String` is /// For better performance you should generally prefer displaying the script but if `String` is
/// required (this is common in tests) this method is can be used. /// required (this is common in tests) this method is can be used.
pub fn to_hex_string(&self) -> String { pub fn to_hex_string(&self) -> String { self.as_bytes().to_lower_hex_string() }
self.as_bytes().to_lower_hex_string()
}
/// Returns the first opcode of the script (if there is any). /// Returns the first opcode of the script (if there is any).
pub fn first_opcode(&self) -> Option<opcodes::All> { pub fn first_opcode(&self) -> Option<opcodes::All> {
@ -467,31 +457,21 @@ impl Iterator for Bytes<'_> {
type Item = u8; type Item = u8;
#[inline] #[inline]
fn next(&mut self) -> Option<Self::Item> { fn next(&mut self) -> Option<Self::Item> { self.0.next() }
self.0.next()
}
#[inline] #[inline]
fn size_hint(&self) -> (usize, Option<usize>) { fn size_hint(&self) -> (usize, Option<usize>) { self.0.size_hint() }
self.0.size_hint()
}
#[inline] #[inline]
fn nth(&mut self, n: usize) -> Option<Self::Item> { fn nth(&mut self, n: usize) -> Option<Self::Item> { self.0.nth(n) }
self.0.nth(n)
}
} }
impl DoubleEndedIterator for Bytes<'_> { impl DoubleEndedIterator for Bytes<'_> {
#[inline] #[inline]
fn next_back(&mut self) -> Option<Self::Item> { fn next_back(&mut self) -> Option<Self::Item> { self.0.next_back() }
self.0.next_back()
}
#[inline] #[inline]
fn nth_back(&mut self, n: usize) -> Option<Self::Item> { fn nth_back(&mut self, n: usize) -> Option<Self::Item> { self.0.nth_back(n) }
self.0.nth_back(n)
}
} }
impl ExactSizeIterator for Bytes<'_> {} impl ExactSizeIterator for Bytes<'_> {}
@ -513,7 +493,14 @@ macro_rules! delegate_index {
} }
} }
delegate_index!(Range<usize>, RangeFrom<usize>, RangeTo<usize>, RangeFull, RangeInclusive<usize>, RangeToInclusive<usize>); delegate_index!(
Range<usize>,
RangeFrom<usize>,
RangeTo<usize>,
RangeFull,
RangeInclusive<usize>,
RangeToInclusive<usize>
);
#[cfg(rust_v_1_53)] #[cfg(rust_v_1_53)]
#[cfg_attr(docsrs, doc(cfg(rust_v_1_53)))] #[cfg_attr(docsrs, doc(cfg(rust_v_1_53)))]
delegate_index!((Bound<usize>, Bound<usize>)); delegate_index!((Bound<usize>, Bound<usize>));

View File

@ -1,15 +1,17 @@
// Written in 2014 by Andrew Poelstra <apoelstra@wpsoftware.net> // Written in 2014 by Andrew Poelstra <apoelstra@wpsoftware.net>
// SPDX-License-Identifier: CC0-1.0 // SPDX-License-Identifier: CC0-1.0
#[cfg(feature="bitcoinconsensus")] use core::convert::From; #[cfg(feature = "bitcoinconsensus")]
use core::convert::From;
use core::default::Default; use core::default::Default;
use core::fmt; use core::fmt;
use secp256k1::XOnlyPublicKey; use secp256k1::XOnlyPublicKey;
use crate::blockdata::locktime::absolute; use crate::blockdata::locktime::absolute;
use crate::blockdata::opcodes::{self, all::*}; use crate::blockdata::opcodes::all::*;
use crate::blockdata::script::{write_scriptint, opcode_to_verify, Script, ScriptBuf, PushBytes}; use crate::blockdata::opcodes::{self};
use crate::blockdata::script::{opcode_to_verify, write_scriptint, PushBytes, Script, ScriptBuf};
use crate::blockdata::transaction::Sequence; use crate::blockdata::transaction::Sequence;
use crate::key::PublicKey; use crate::key::PublicKey;
use crate::prelude::*; use crate::prelude::*;
@ -20,9 +22,7 @@ pub struct Builder(ScriptBuf, Option<opcodes::All>);
impl Builder { impl Builder {
/// Creates a new empty script. /// Creates a new empty script.
pub fn new() -> Self { pub fn new() -> Self { Builder(ScriptBuf::new(), None) }
Builder(ScriptBuf::new(), None)
}
/// Returns the length in bytes of the script. /// Returns the length in bytes of the script.
pub fn len(&self) -> usize { self.0.len() } pub fn len(&self) -> usize { self.0.len() }
@ -37,9 +37,7 @@ impl Builder {
pub fn push_int(self, data: i64) -> Builder { pub fn push_int(self, data: i64) -> Builder {
// We can special-case -1, 1-16 // We can special-case -1, 1-16
if data == -1 || (1..=16).contains(&data) { if data == -1 || (1..=16).contains(&data) {
let opcode = opcodes::All::from( let opcode = opcodes::All::from((data - 1 + opcodes::OP_TRUE.to_u8() as i64) as u8);
(data - 1 + opcodes::OP_TRUE.to_u8() as i64) as u8
);
self.push_opcode(opcode) self.push_opcode(opcode)
} }
// We can also special-case zero // We can also special-case zero
@ -47,7 +45,9 @@ impl Builder {
self.push_opcode(opcodes::OP_0) self.push_opcode(opcodes::OP_0)
} }
// Otherwise encode it as data // Otherwise encode it as data
else { self.push_int_non_minimal(data) } else {
self.push_int_non_minimal(data)
}
} }
/// Adds instructions to push an integer onto the stack without optimization. /// Adds instructions to push an integer onto the stack without optimization.
@ -103,7 +103,7 @@ impl Builder {
Some(opcode) => { Some(opcode) => {
(self.0).0.pop(); (self.0).0.pop();
self.push_opcode(opcode) self.push_opcode(opcode)
}, }
None => self.push_opcode(OP_VERIFY), None => self.push_opcode(OP_VERIFY),
} }
} }
@ -119,24 +119,16 @@ impl Builder {
} }
/// Converts the `Builder` into `ScriptBuf`. /// Converts the `Builder` into `ScriptBuf`.
pub fn into_script(self) -> ScriptBuf { pub fn into_script(self) -> ScriptBuf { self.0 }
self.0
}
/// Converts the `Builder` into script bytes /// Converts the `Builder` into script bytes
pub fn into_bytes(self) -> Vec<u8> { pub fn into_bytes(self) -> Vec<u8> { self.0.into() }
self.0.into()
}
/// Returns the internal script /// Returns the internal script
pub fn as_script(&self) -> &Script { pub fn as_script(&self) -> &Script { &self.0 }
&self.0
}
/// Returns script bytes /// Returns script bytes
pub fn as_bytes(&self) -> &[u8] { pub fn as_bytes(&self) -> &[u8] { self.0.as_bytes() }
self.0.as_bytes()
}
} }
impl Default for Builder { impl Default for Builder {
@ -153,9 +145,7 @@ impl From<Vec<u8>> for Builder {
} }
impl fmt::Display for Builder { impl fmt::Display for Builder {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { self.0.fmt_asm(f) }
self.0.fmt_asm(f)
}
} }
bitcoin_internals::debug_from_display!(Builder); bitcoin_internals::debug_from_display!(Builder);

View File

@ -2,8 +2,9 @@
// SPDX-License-Identifier: CC0-1.0 // SPDX-License-Identifier: CC0-1.0
use core::convert::TryInto; use core::convert::TryInto;
use crate::blockdata::opcodes; use crate::blockdata::opcodes;
use crate::blockdata::script::{read_uint_iter, Error, Script, ScriptBuf, UintError, PushBytes}; use crate::blockdata::script::{read_uint_iter, Error, PushBytes, Script, ScriptBuf, UintError};
/// A "parsed opcode" which allows iterating over a [`Script`] in a more sensible way. /// A "parsed opcode" which allows iterating over a [`Script`] in a more sensible way.
#[derive(Debug, PartialEq, Eq, Copy, Clone)] #[derive(Debug, PartialEq, Eq, Copy, Clone)]
@ -51,9 +52,7 @@ impl<'a> Instructions<'a> {
/// Views the remaining script as a slice. /// Views the remaining script as a slice.
/// ///
/// This is analogous to what [`core::str::Chars::as_str`] does. /// This is analogous to what [`core::str::Chars::as_str`] does.
pub fn as_script(&self) -> &'a Script { pub fn as_script(&self) -> &'a Script { Script::from_bytes(self.data.as_slice()) }
Script::from_bytes(self.data.as_slice())
}
/// Sets the iterator to end so that it won't iterate any longer. /// Sets the iterator to end so that it won't iterate any longer.
pub(super) fn kill(&mut self) { pub(super) fn kill(&mut self) {
@ -80,7 +79,11 @@ impl<'a> Instructions<'a> {
} }
} }
pub(super) fn next_push_data_len(&mut self, len: PushDataLenLen, min_push_len: usize) -> Option<Result<Instruction<'a>, Error>> { pub(super) fn next_push_data_len(
&mut self,
len: PushDataLenLen,
min_push_len: usize,
) -> Option<Result<Instruction<'a>, Error>> {
let n = match read_uint_iter(&mut self.data, len as usize) { let n = match read_uint_iter(&mut self.data, len as usize) {
Ok(n) => n, Ok(n) => n,
// We do exhaustive matching to not forget to handle new variants if we extend // We do exhaustive matching to not forget to handle new variants if we extend
@ -90,7 +93,7 @@ impl<'a> Instructions<'a> {
Err(UintError::EarlyEndOfScript) | Err(UintError::NumericOverflow) => { Err(UintError::EarlyEndOfScript) | Err(UintError::NumericOverflow) => {
self.kill(); self.kill();
return Some(Err(Error::EarlyEndOfScript)); return Some(Err(Error::EarlyEndOfScript));
}, }
}; };
if self.enforce_minimal && n < min_push_len { if self.enforce_minimal && n < min_push_len {
self.kill(); self.kill();
@ -129,33 +132,28 @@ impl<'a> Iterator for Instructions<'a> {
let op_byte = self.data.as_slice().first(); let op_byte = self.data.as_slice().first();
match (self.enforce_minimal, op_byte, n) { match (self.enforce_minimal, op_byte, n) {
(true, Some(&op_byte), 1) if op_byte == 0x81 || (op_byte > 0 && op_byte <= 16) => { (true, Some(&op_byte), 1)
if op_byte == 0x81 || (op_byte > 0 && op_byte <= 16) =>
{
self.kill(); self.kill();
Some(Err(Error::NonMinimalPush)) Some(Err(Error::NonMinimalPush))
}, }
(_, None, 0) => { (_, None, 0) => {
// the iterator is already empty, may as well use this information to avoid // the iterator is already empty, may as well use this information to avoid
// whole take_slice_or_kill function // whole take_slice_or_kill function
Some(Ok(Instruction::PushBytes(PushBytes::empty()))) Some(Ok(Instruction::PushBytes(PushBytes::empty())))
}, }
_ => { _ => Some(self.take_slice_or_kill(n).map(Instruction::PushBytes)),
Some(self.take_slice_or_kill(n).map(Instruction::PushBytes))
} }
} }
} opcodes::Class::Ordinary(opcodes::Ordinary::OP_PUSHDATA1) =>
opcodes::Class::Ordinary(opcodes::Ordinary::OP_PUSHDATA1) => { self.next_push_data_len(PushDataLenLen::One, 76),
self.next_push_data_len(PushDataLenLen::One, 76) opcodes::Class::Ordinary(opcodes::Ordinary::OP_PUSHDATA2) =>
} self.next_push_data_len(PushDataLenLen::Two, 0x100),
opcodes::Class::Ordinary(opcodes::Ordinary::OP_PUSHDATA2) => { opcodes::Class::Ordinary(opcodes::Ordinary::OP_PUSHDATA4) =>
self.next_push_data_len(PushDataLenLen::Two, 0x100) self.next_push_data_len(PushDataLenLen::Four, 0x10000),
}
opcodes::Class::Ordinary(opcodes::Ordinary::OP_PUSHDATA4) => {
self.next_push_data_len(PushDataLenLen::Four, 0x10000)
}
// Everything else we can push right through // Everything else we can push right through
_ => { _ => Some(Ok(Instruction::Op(opcodes::All::from(byte)))),
Some(Ok(Instruction::Op(opcodes::All::from(byte))))
}
} }
} }
@ -188,27 +186,23 @@ impl<'a> InstructionIndices<'a> {
/// ///
/// This is analogous to what [`core::str::Chars::as_str`] does. /// This is analogous to what [`core::str::Chars::as_str`] does.
#[inline] #[inline]
pub fn as_script(&self) -> &'a Script { pub fn as_script(&self) -> &'a Script { self.instructions.as_script() }
self.instructions.as_script()
}
/// Creates `Self` setting `pos` to 0. /// Creates `Self` setting `pos` to 0.
pub(super) fn from_instructions(instructions: Instructions<'a>) -> Self { pub(super) fn from_instructions(instructions: Instructions<'a>) -> Self {
InstructionIndices { InstructionIndices { instructions, pos: 0 }
instructions,
pos: 0,
}
} }
pub(super) fn remaining_bytes(&self) -> usize { pub(super) fn remaining_bytes(&self) -> usize { self.instructions.as_script().len() }
self.instructions.as_script().len()
}
/// Modifies the iterator using `next_fn` returning the next item. /// Modifies the iterator using `next_fn` returning the next item.
/// ///
/// This generically computes the new position and maps the value to be returned from iterator /// This generically computes the new position and maps the value to be returned from iterator
/// method. /// method.
pub(super) fn next_with<F: FnOnce(&mut Self) -> Option<Result<Instruction<'a>, Error>>>(&mut self, next_fn: F) -> Option<<Self as Iterator>::Item> { pub(super) fn next_with<F: FnOnce(&mut Self) -> Option<Result<Instruction<'a>, Error>>>(
&mut self,
next_fn: F,
) -> Option<<Self as Iterator>::Item> {
let prev_remaining = self.remaining_bytes(); let prev_remaining = self.remaining_bytes();
let prev_pos = self.pos; let prev_pos = self.pos;
let instruction = next_fn(self)?; let instruction = next_fn(self)?;
@ -224,14 +218,10 @@ impl<'a> Iterator for InstructionIndices<'a> {
/// The `usize` in the tuple represents index at which the returned `Instruction` is located. /// The `usize` in the tuple represents index at which the returned `Instruction` is located.
type Item = Result<(usize, Instruction<'a>), Error>; type Item = Result<(usize, Instruction<'a>), Error>;
fn next(&mut self) -> Option<Self::Item> { fn next(&mut self) -> Option<Self::Item> { self.next_with(|this| this.instructions.next()) }
self.next_with(|this| this.instructions.next())
}
#[inline] #[inline]
fn size_hint(&self) -> (usize, Option<usize>) { fn size_hint(&self) -> (usize, Option<usize>) { self.instructions.size_hint() }
self.instructions.size_hint()
}
// the override avoids computing pos multiple times // the override avoids computing pos multiple times
fn nth(&mut self, n: usize) -> Option<Self::Item> { fn nth(&mut self, n: usize) -> Option<Self::Item> {

View File

@ -51,28 +51,28 @@
use alloc::rc::Rc; use alloc::rc::Rc;
#[cfg(any(not(rust_v_1_60), target_has_atomic = "ptr"))] #[cfg(any(not(rust_v_1_60), target_has_atomic = "ptr"))]
use alloc::sync::Arc; use alloc::sync::Arc;
use core::cmp::Ordering;
use core::borrow::{Borrow, BorrowMut}; use core::borrow::{Borrow, BorrowMut};
use core::cmp::Ordering;
use core::fmt; use core::fmt;
use core::ops::{Deref, DerefMut}; use core::ops::{Deref, DerefMut};
#[cfg(feature = "serde")] #[cfg(feature = "serde")]
use serde; use serde;
use crate::blockdata::opcodes::{self, all::*}; use crate::blockdata::opcodes::all::*;
use crate::blockdata::opcodes::{self};
use crate::consensus::{encode, Decodable, Encodable}; use crate::consensus::{encode, Decodable, Encodable};
use crate::hash_types::{ScriptHash, WScriptHash}; use crate::hash_types::{ScriptHash, WScriptHash};
use crate::{io, OutPoint};
use crate::prelude::*; use crate::prelude::*;
use crate::{io, OutPoint};
mod borrowed; mod borrowed;
mod builder; mod builder;
mod instruction; mod instruction;
mod owned; mod owned;
mod push_bytes;
#[cfg(test)] #[cfg(test)]
mod tests; mod tests;
mod push_bytes;
pub use self::borrowed::*; pub use self::borrowed::*;
pub use self::builder::*; pub use self::builder::*;
@ -90,7 +90,9 @@ pub use self::push_bytes::*;
/// [`CScriptNum::serialize`]: <https://github.com/bitcoin/bitcoin/blob/8ae2808a4354e8dcc697f76bacc5e2f2befe9220/src/script/script.h#L345> /// [`CScriptNum::serialize`]: <https://github.com/bitcoin/bitcoin/blob/8ae2808a4354e8dcc697f76bacc5e2f2befe9220/src/script/script.h#L345>
pub fn write_scriptint(out: &mut [u8; 8], n: i64) -> usize { pub fn write_scriptint(out: &mut [u8; 8], n: i64) -> usize {
let mut len = 0; let mut len = 0;
if n == 0 { return len; } if n == 0 {
return len;
}
let neg = n < 0; let neg = n < 0;
@ -136,7 +138,9 @@ pub fn write_scriptint(out: &mut [u8; 8], n: i64) -> usize {
/// This code is based on the `CScriptNum` constructor in Bitcoin Core (see `script.h`). /// This code is based on the `CScriptNum` constructor in Bitcoin Core (see `script.h`).
pub fn read_scriptint(v: &[u8]) -> Result<i64, Error> { pub fn read_scriptint(v: &[u8]) -> Result<i64, Error> {
let len = v.len(); let len = v.len();
if len > 4 { return Err(Error::NumericOverflow); } if len > 4 {
return Err(Error::NumericOverflow);
}
let last = match v.last() { let last = match v.last() {
Some(last) => last, Some(last) => last,
None => return Ok(0), None => return Ok(0),
@ -157,8 +161,7 @@ pub fn read_scriptint(v: &[u8]) -> Result<i64, Error> {
} }
} }
let (mut ret, sh) = v.iter() let (mut ret, sh) = v.iter().fold((0, 0), |(acc, sh), n| (acc + ((*n as i64) << sh), sh + 8));
.fold((0, 0), |(acc, sh), n| (acc + ((*n as i64) << sh), sh + 8));
if v[len - 1] & 0x80 != 0 { if v[len - 1] & 0x80 != 0 {
ret &= (1 << (sh - 1)) - 1; ret &= (1 << (sh - 1)) - 1;
ret = -ret; ret = -ret;
@ -219,29 +222,23 @@ fn read_uint_iter(data: &mut core::slice::Iter<'_, u8>, size: usize) -> Result<u
} }
fn opcode_to_verify(opcode: Option<opcodes::All>) -> Option<opcodes::All> { fn opcode_to_verify(opcode: Option<opcodes::All>) -> Option<opcodes::All> {
opcode.and_then(|opcode| { opcode.and_then(|opcode| match opcode {
match opcode {
OP_EQUAL => Some(OP_EQUALVERIFY), OP_EQUAL => Some(OP_EQUALVERIFY),
OP_NUMEQUAL => Some(OP_NUMEQUALVERIFY), OP_NUMEQUAL => Some(OP_NUMEQUALVERIFY),
OP_CHECKSIG => Some(OP_CHECKSIGVERIFY), OP_CHECKSIG => Some(OP_CHECKSIGVERIFY),
OP_CHECKMULTISIG => Some(OP_CHECKMULTISIGVERIFY), OP_CHECKMULTISIG => Some(OP_CHECKMULTISIGVERIFY),
_ => None, _ => None,
}
}) })
} }
// We keep all the `Script` and `ScriptBuf` impls together since its easier to see side-by-side. // We keep all the `Script` and `ScriptBuf` impls together since its easier to see side-by-side.
impl From<ScriptBuf> for Box<Script> { impl From<ScriptBuf> for Box<Script> {
fn from(v: ScriptBuf) -> Self { fn from(v: ScriptBuf) -> Self { v.into_boxed_script() }
v.into_boxed_script()
}
} }
impl From<ScriptBuf> for Cow<'_, Script> { impl From<ScriptBuf> for Cow<'_, Script> {
fn from(value: ScriptBuf) -> Self { fn from(value: ScriptBuf) -> Self { Cow::Owned(value) }
Cow::Owned(value)
}
} }
impl<'a> From<Cow<'a, Script>> for ScriptBuf { impl<'a> From<Cow<'a, Script>> for ScriptBuf {
@ -263,21 +260,15 @@ impl<'a> From<Cow<'a, Script>> for Box<Script> {
} }
impl<'a> From<&'a Script> for Box<Script> { impl<'a> From<&'a Script> for Box<Script> {
fn from(value: &'a Script) -> Self { fn from(value: &'a Script) -> Self { value.to_owned().into() }
value.to_owned().into()
}
} }
impl<'a> From<&'a Script> for ScriptBuf { impl<'a> From<&'a Script> for ScriptBuf {
fn from(value: &'a Script) -> Self { fn from(value: &'a Script) -> Self { value.to_owned() }
value.to_owned()
}
} }
impl<'a> From<&'a Script> for Cow<'a, Script> { impl<'a> From<&'a Script> for Cow<'a, Script> {
fn from(value: &'a Script) -> Self { fn from(value: &'a Script) -> Self { Cow::Borrowed(value) }
Cow::Borrowed(value)
}
} }
/// Note: This will fail to compile on old Rust for targets that don't support atomics /// Note: This will fail to compile on old Rust for targets that don't support atomics
@ -314,90 +305,62 @@ impl From<ScriptBuf> for Vec<u8> {
} }
impl From<ScriptBuf> for ScriptHash { impl From<ScriptBuf> for ScriptHash {
fn from(script: ScriptBuf) -> ScriptHash { fn from(script: ScriptBuf) -> ScriptHash { script.script_hash() }
script.script_hash()
}
} }
impl From<&ScriptBuf> for ScriptHash { impl From<&ScriptBuf> for ScriptHash {
fn from(script: &ScriptBuf) -> ScriptHash { fn from(script: &ScriptBuf) -> ScriptHash { script.script_hash() }
script.script_hash()
}
} }
impl From<&Script> for ScriptHash { impl From<&Script> for ScriptHash {
fn from(script: &Script) -> ScriptHash { fn from(script: &Script) -> ScriptHash { script.script_hash() }
script.script_hash()
}
} }
impl From<ScriptBuf> for WScriptHash { impl From<ScriptBuf> for WScriptHash {
fn from(script: ScriptBuf) -> WScriptHash { fn from(script: ScriptBuf) -> WScriptHash { script.wscript_hash() }
script.wscript_hash()
}
} }
impl From<&ScriptBuf> for WScriptHash { impl From<&ScriptBuf> for WScriptHash {
fn from(script: &ScriptBuf) -> WScriptHash { fn from(script: &ScriptBuf) -> WScriptHash { script.wscript_hash() }
script.wscript_hash()
}
} }
impl From<&Script> for WScriptHash { impl From<&Script> for WScriptHash {
fn from(script: &Script) -> WScriptHash { fn from(script: &Script) -> WScriptHash { script.wscript_hash() }
script.wscript_hash()
}
} }
impl AsRef<Script> for Script { impl AsRef<Script> for Script {
#[inline] #[inline]
fn as_ref(&self) -> &Script { fn as_ref(&self) -> &Script { self }
self
}
} }
impl AsRef<Script> for ScriptBuf { impl AsRef<Script> for ScriptBuf {
fn as_ref(&self) -> &Script { fn as_ref(&self) -> &Script { self }
self
}
} }
impl AsRef<[u8]> for Script { impl AsRef<[u8]> for Script {
#[inline] #[inline]
fn as_ref(&self) -> &[u8] { fn as_ref(&self) -> &[u8] { self.as_bytes() }
self.as_bytes()
}
} }
impl AsRef<[u8]> for ScriptBuf { impl AsRef<[u8]> for ScriptBuf {
fn as_ref(&self) -> &[u8] { fn as_ref(&self) -> &[u8] { self.as_bytes() }
self.as_bytes()
}
} }
impl AsMut<Script> for Script { impl AsMut<Script> for Script {
fn as_mut(&mut self) -> &mut Script { fn as_mut(&mut self) -> &mut Script { self }
self
}
} }
impl AsMut<Script> for ScriptBuf { impl AsMut<Script> for ScriptBuf {
fn as_mut(&mut self) -> &mut Script { fn as_mut(&mut self) -> &mut Script { self }
self
}
} }
impl AsMut<[u8]> for Script { impl AsMut<[u8]> for Script {
#[inline] #[inline]
fn as_mut(&mut self) -> &mut [u8] { fn as_mut(&mut self) -> &mut [u8] { self.as_mut_bytes() }
self.as_mut_bytes()
}
} }
impl AsMut<[u8]> for ScriptBuf { impl AsMut<[u8]> for ScriptBuf {
fn as_mut(&mut self) -> &mut [u8] { fn as_mut(&mut self) -> &mut [u8] { self.as_mut_bytes() }
self.as_mut_bytes()
}
} }
impl fmt::Debug for Script { impl fmt::Debug for Script {
@ -409,23 +372,17 @@ impl fmt::Debug for Script {
} }
impl fmt::Debug for ScriptBuf { impl fmt::Debug for ScriptBuf {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { fmt::Debug::fmt(self.as_script(), f) }
fmt::Debug::fmt(self.as_script(), f)
}
} }
impl fmt::Display for Script { impl fmt::Display for Script {
#[inline] #[inline]
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { self.fmt_asm(f) }
self.fmt_asm(f)
}
} }
impl fmt::Display for ScriptBuf { impl fmt::Display for ScriptBuf {
#[inline] #[inline]
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { fmt::Display::fmt(self.as_script(), f) }
fmt::Display::fmt(self.as_script(), f)
}
} }
impl fmt::LowerHex for Script { impl fmt::LowerHex for Script {
@ -436,9 +393,7 @@ impl fmt::LowerHex for Script {
impl fmt::LowerHex for ScriptBuf { impl fmt::LowerHex for ScriptBuf {
#[inline] #[inline]
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { fmt::LowerHex::fmt(self.as_script(), f) }
fmt::LowerHex::fmt(self.as_script(), f)
}
} }
impl fmt::UpperHex for Script { impl fmt::UpperHex for Script {
@ -449,47 +404,33 @@ impl fmt::UpperHex for Script {
impl fmt::UpperHex for ScriptBuf { impl fmt::UpperHex for ScriptBuf {
#[inline] #[inline]
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { fmt::UpperHex::fmt(self.as_script(), f) }
fmt::UpperHex::fmt(self.as_script(), f)
}
} }
impl Deref for ScriptBuf { impl Deref for ScriptBuf {
type Target = Script; type Target = Script;
fn deref(&self) -> &Self::Target { fn deref(&self) -> &Self::Target { Script::from_bytes(&self.0) }
Script::from_bytes(&self.0)
}
} }
impl DerefMut for ScriptBuf { impl DerefMut for ScriptBuf {
fn deref_mut(&mut self) -> &mut Self::Target { fn deref_mut(&mut self) -> &mut Self::Target { Script::from_bytes_mut(&mut self.0) }
Script::from_bytes_mut(&mut self.0)
}
} }
impl Borrow<Script> for ScriptBuf { impl Borrow<Script> for ScriptBuf {
fn borrow(&self) -> &Script { fn borrow(&self) -> &Script { self }
self
}
} }
impl BorrowMut<Script> for ScriptBuf { impl BorrowMut<Script> for ScriptBuf {
fn borrow_mut(&mut self) -> &mut Script { fn borrow_mut(&mut self) -> &mut Script { self }
self
}
} }
impl PartialEq<ScriptBuf> for Script { impl PartialEq<ScriptBuf> for Script {
fn eq(&self, other: &ScriptBuf) -> bool { fn eq(&self, other: &ScriptBuf) -> bool { self.eq(other.as_script()) }
self.eq(other.as_script())
}
} }
impl PartialEq<Script> for ScriptBuf { impl PartialEq<Script> for ScriptBuf {
fn eq(&self, other: &Script) -> bool { fn eq(&self, other: &Script) -> bool { self.as_script().eq(other) }
self.as_script().eq(other)
}
} }
impl PartialOrd<Script> for ScriptBuf { impl PartialOrd<Script> for ScriptBuf {
@ -531,7 +472,9 @@ impl<'de> serde::Deserialize<'de> for &'de Script {
if deserializer.is_human_readable() { if deserializer.is_human_readable() {
use crate::serde::de::Error; use crate::serde::de::Error;
return Err(D::Error::custom("deserialization of `&Script` from human-readable formats is not possible")); return Err(D::Error::custom(
"deserialization of `&Script` from human-readable formats is not possible",
));
} }
struct Visitor; struct Visitor;
@ -573,10 +516,10 @@ impl<'de> serde::Deserialize<'de> for ScriptBuf {
D: serde::Deserializer<'de>, D: serde::Deserializer<'de>,
{ {
use core::fmt::Formatter; use core::fmt::Formatter;
use crate::hashes::hex::FromHex; use crate::hashes::hex::FromHex;
if deserializer.is_human_readable() { if deserializer.is_human_readable() {
struct Visitor; struct Visitor;
impl<'de> serde::de::Visitor<'de> for Visitor { impl<'de> serde::de::Visitor<'de> for Visitor {
type Value = ScriptBuf; type Value = ScriptBuf;
@ -639,7 +582,9 @@ impl Encodable for ScriptBuf {
impl Decodable for ScriptBuf { impl Decodable for ScriptBuf {
#[inline] #[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> {
Ok(ScriptBuf(Decodable::consensus_decode_from_finite_reader(r)?)) Ok(ScriptBuf(Decodable::consensus_decode_from_finite_reader(r)?))
} }
} }
@ -677,7 +622,9 @@ pub(super) fn bytes_to_asm_fmt(script: &[u8], f: &mut dyn fmt::Write) -> fmt::Re
while let Some(byte) = iter.next() { while let Some(byte) = iter.next() {
let opcode = opcodes::All::from(*byte); let opcode = opcodes::All::from(*byte);
let data_len = if let opcodes::Class::PushBytes(n) = opcode.classify(opcodes::ClassifyContext::Legacy) { let data_len = if let opcodes::Class::PushBytes(n) =
opcode.classify(opcodes::ClassifyContext::Legacy)
{
n as usize n as usize
} else { } else {
match opcode { match opcode {
@ -693,7 +640,7 @@ pub(super) fn bytes_to_asm_fmt(script: &[u8], f: &mut dyn fmt::Write) -> fmt::Re
// side effects: may write and break from the loop // side effects: may write and break from the loop
read_push_data_len!(&mut iter, 4, f) read_push_data_len!(&mut iter, 4, f)
} }
_ => 0 _ => 0,
} }
}; };
@ -744,7 +691,7 @@ pub enum Error {
/// Can not find the spent output. /// Can not find the spent output.
UnknownSpentOutput(OutPoint), UnknownSpentOutput(OutPoint),
/// Can not serialize the spending transaction. /// Can not serialize the spending transaction.
Serialization Serialization,
} }
// If bitcoinonsensus-std is off but bitcoinconsensus is present we patch the error type to // If bitcoinonsensus-std is off but bitcoinconsensus is present we patch the error type to
@ -757,15 +704,11 @@ mod bitcoinconsensus_hack {
pub(crate) struct Error(bitcoinconsensus::Error); pub(crate) struct Error(bitcoinconsensus::Error);
impl fmt::Debug for Error { impl fmt::Debug for Error {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { fmt::Debug::fmt(&self.0, f) }
fmt::Debug::fmt(&self.0, f)
}
} }
impl fmt::Display for Error { impl fmt::Display for Error {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { fmt::Display::fmt(&self.0, f) }
fmt::Display::fmt(&self.0, f)
}
} }
// bitcoinconsensus::Error has no sources at this time // bitcoinconsensus::Error has no sources at this time
@ -775,13 +718,15 @@ mod bitcoinconsensus_hack {
// Unfortunately, we cannot have the reference inside `Error` struct because of the 'static // Unfortunately, we cannot have the reference inside `Error` struct because of the 'static
// bound on `source` return type, so we have to use unsafe to overcome the limitation. // bound on `source` return type, so we have to use unsafe to overcome the limitation.
// SAFETY: the type is repr(transparent) and the lifetimes match // SAFETY: the type is repr(transparent) and the lifetimes match
unsafe { unsafe { &*(error as *const _ as *const Error) }
&*(error as *const _ as *const Error)
}
} }
} }
#[cfg(not(all(feature = "std", feature = "bitcoinconsensus", not(feature = "bitcoinconsensus-std"))))] #[cfg(not(all(
feature = "std",
feature = "bitcoinconsensus",
not(feature = "bitcoinconsensus-std")
)))]
mod bitcoinconsensus_hack { mod bitcoinconsensus_hack {
#[allow(unused_imports)] // conditionally used #[allow(unused_imports)] // conditionally used
pub(crate) use core::convert::identity as wrap_error; pub(crate) use core::convert::identity as wrap_error;
@ -795,11 +740,14 @@ impl fmt::Display for Error {
match *self { match *self {
Error::NonMinimalPush => f.write_str("non-minimal datapush"), Error::NonMinimalPush => f.write_str("non-minimal datapush"),
Error::EarlyEndOfScript => f.write_str("unexpected end of script"), Error::EarlyEndOfScript => f.write_str("unexpected end of script"),
Error::NumericOverflow => f.write_str("numeric overflow (number on stack larger than 4 bytes)"), Error::NumericOverflow =>
f.write_str("numeric overflow (number on stack larger than 4 bytes)"),
#[cfg(feature = "bitcoinconsensus")] #[cfg(feature = "bitcoinconsensus")]
Error::BitcoinConsensus(ref e) => write_err!(f, "bitcoinconsensus verification failed"; bitcoinconsensus_hack::wrap_error(e)), Error::BitcoinConsensus(ref e) =>
write_err!(f, "bitcoinconsensus verification failed"; bitcoinconsensus_hack::wrap_error(e)),
Error::UnknownSpentOutput(ref point) => write!(f, "unknown spent output: {}", point), Error::UnknownSpentOutput(ref point) => write!(f, "unknown spent output: {}", point),
Error::Serialization => f.write_str("can not serialize the spending transaction in Transaction::verify()"), Error::Serialization =>
f.write_str("can not serialize the spending transaction in Transaction::verify()"),
} }
} }
} }
@ -841,7 +789,5 @@ impl From<UintError> for Error {
#[cfg(feature = "bitcoinconsensus")] #[cfg(feature = "bitcoinconsensus")]
#[doc(hidden)] #[doc(hidden)]
impl From<bitcoinconsensus::Error> for Error { impl From<bitcoinconsensus::Error> for Error {
fn from(err: bitcoinconsensus::Error) -> Error { fn from(err: bitcoinconsensus::Error) -> Error { Error::BitcoinConsensus(err) }
Error::BitcoinConsensus(err)
}
} }

View File

@ -6,11 +6,12 @@ use core::ops::Deref;
use secp256k1::{Secp256k1, Verification}; use secp256k1::{Secp256k1, Verification};
use crate::address::{WitnessVersion, WitnessProgram}; use crate::address::{WitnessProgram, WitnessVersion};
use crate::blockdata::opcodes::{self, all::*}; use crate::blockdata::opcodes::all::*;
use crate::blockdata::script::{opcode_to_verify, Builder, Instruction, Script, PushBytes}; use crate::blockdata::opcodes::{self};
use crate::blockdata::script::{opcode_to_verify, Builder, Instruction, PushBytes, Script};
use crate::hash_types::{PubkeyHash, ScriptHash, WPubkeyHash, WScriptHash};
use crate::hashes::hex; use crate::hashes::hex;
use crate::hash_types::{PubkeyHash, WPubkeyHash, ScriptHash, WScriptHash};
use crate::key::{PublicKey, TapTweak, TweakedPublicKey, UntweakedPublicKey}; use crate::key::{PublicKey, TapTweak, TweakedPublicKey, UntweakedPublicKey};
use crate::prelude::*; use crate::prelude::*;
use crate::taproot::TapNodeHash; use crate::taproot::TapNodeHash;
@ -29,14 +30,10 @@ pub struct ScriptBuf(pub(in crate::blockdata::script) Vec<u8>);
impl ScriptBuf { impl ScriptBuf {
/// Creates a new empty script. /// Creates a new empty script.
pub fn new() -> Self { pub fn new() -> Self { ScriptBuf(Vec::new()) }
ScriptBuf(Vec::new())
}
/// Creates a new empty script with pre-allocated capacity. /// Creates a new empty script with pre-allocated capacity.
pub fn with_capacity(capacity: usize) -> Self { pub fn with_capacity(capacity: usize) -> Self { ScriptBuf(Vec::with_capacity(capacity)) }
ScriptBuf(Vec::with_capacity(capacity))
}
/// Pre-allocates at least `additional_len` bytes if needed. /// Pre-allocates at least `additional_len` bytes if needed.
/// ///
@ -48,9 +45,7 @@ impl ScriptBuf {
/// # Panics /// # Panics
/// ///
/// Panics if the new capacity exceeds `isize::MAX bytes`. /// Panics if the new capacity exceeds `isize::MAX bytes`.
pub fn reserve(&mut self, additional_len: usize) { pub fn reserve(&mut self, additional_len: usize) { self.0.reserve(additional_len); }
self.0.reserve(additional_len);
}
/// Pre-allocates exactly `additional_len` bytes if needed. /// Pre-allocates exactly `additional_len` bytes if needed.
/// ///
@ -65,31 +60,20 @@ impl ScriptBuf {
/// # Panics /// # Panics
/// ///
/// Panics if the new capacity exceeds `isize::MAX bytes`. /// Panics if the new capacity exceeds `isize::MAX bytes`.
pub fn reserve_exact(&mut self, additional_len: usize) { pub fn reserve_exact(&mut self, additional_len: usize) { self.0.reserve_exact(additional_len); }
self.0.reserve_exact(additional_len);
}
/// Returns a reference to unsized script. /// Returns a reference to unsized script.
pub fn as_script(&self) -> &Script { pub fn as_script(&self) -> &Script { Script::from_bytes(&self.0) }
Script::from_bytes(&self.0)
}
/// Returns a mutable reference to unsized script. /// Returns a mutable reference to unsized script.
pub fn as_mut_script(&mut self) -> &mut Script { pub fn as_mut_script(&mut self) -> &mut Script { Script::from_bytes_mut(&mut self.0) }
Script::from_bytes_mut(&mut self.0)
}
/// Creates a new script builder /// Creates a new script builder
pub fn builder() -> Builder { pub fn builder() -> Builder { Builder::new() }
Builder::new()
}
/// Generates P2PK-type of scriptPubkey. /// Generates P2PK-type of scriptPubkey.
pub fn new_p2pk(pubkey: &PublicKey) -> Self { pub fn new_p2pk(pubkey: &PublicKey) -> Self {
Builder::new() Builder::new().push_key(pubkey).push_opcode(OP_CHECKSIG).into_script()
.push_key(pubkey)
.push_opcode(OP_CHECKSIG)
.into_script()
} }
/// Generates P2PKH-type of scriptPubkey. /// Generates P2PKH-type of scriptPubkey.
@ -126,7 +110,11 @@ impl ScriptBuf {
/// Generates P2TR for script spending path using an internal public key and some optional /// Generates P2TR for script spending path using an internal public key and some optional
/// script tree merkle root. /// script tree merkle root.
pub fn new_v1_p2tr<C: Verification>(secp: &Secp256k1<C>, internal_key: UntweakedPublicKey, merkle_root: Option<TapNodeHash>) -> Self { pub fn new_v1_p2tr<C: Verification>(
secp: &Secp256k1<C>,
internal_key: UntweakedPublicKey,
merkle_root: Option<TapNodeHash>,
) -> Self {
let (output_key, _) = internal_key.tap_tweak(secp, merkle_root); let (output_key, _) = internal_key.tap_tweak(secp, merkle_root);
// output key is 32 bytes long, so it's safe to use `new_witness_program_unchecked` (Segwitv1) // output key is 32 bytes long, so it's safe to use `new_witness_program_unchecked` (Segwitv1)
ScriptBuf::new_witness_program_unchecked(WitnessVersion::V1, output_key.serialize()) ScriptBuf::new_witness_program_unchecked(WitnessVersion::V1, output_key.serialize())
@ -151,23 +139,20 @@ impl ScriptBuf {
/// ///
/// Convenience method used by `new_v0_p2wpkh`, `new_v0_p2wsh`, `new_v1_p2tr`, and /// Convenience method used by `new_v0_p2wpkh`, `new_v0_p2wsh`, `new_v1_p2tr`, and
/// `new_v1_p2tr_tweaked`. /// `new_v1_p2tr_tweaked`.
fn new_witness_program_unchecked<T: AsRef<PushBytes>>(version: WitnessVersion, program: T) -> Self { fn new_witness_program_unchecked<T: AsRef<PushBytes>>(
version: WitnessVersion,
program: T,
) -> Self {
let program = program.as_ref(); let program = program.as_ref();
debug_assert!(program.len() >= 2 && program.len() <= 40); debug_assert!(program.len() >= 2 && program.len() <= 40);
// In segwit v0, the program must be 20 or 32 bytes long. // In segwit v0, the program must be 20 or 32 bytes long.
debug_assert!(version != WitnessVersion::V0 || program.len() == 20 || program.len() == 32); debug_assert!(version != WitnessVersion::V0 || program.len() == 20 || program.len() == 32);
Builder::new() Builder::new().push_opcode(version.into()).push_slice(program).into_script()
.push_opcode(version.into())
.push_slice(program)
.into_script()
} }
/// Generates OP_RETURN-type of scriptPubkey for the given data. /// Generates OP_RETURN-type of scriptPubkey for the given data.
pub fn new_op_return<T: AsRef<PushBytes>>(data: &T) -> Self { pub fn new_op_return<T: AsRef<PushBytes>>(data: &T) -> Self {
Builder::new() Builder::new().push_opcode(OP_RETURN).push_slice(data).into_script()
.push_opcode(OP_RETURN)
.push_slice(data)
.into_script()
} }
/// Creates a [`ScriptBuf`] from a hex string. /// Creates a [`ScriptBuf`] from a hex string.
@ -181,9 +166,7 @@ impl ScriptBuf {
/// Converts byte vector into script. /// Converts byte vector into script.
/// ///
/// This method doesn't (re)allocate. /// This method doesn't (re)allocate.
pub fn from_bytes(bytes: Vec<u8>) -> Self { pub fn from_bytes(bytes: Vec<u8>) -> Self { ScriptBuf(bytes) }
ScriptBuf(bytes)
}
/// Converts the script into a byte vector. /// Converts the script into a byte vector.
/// ///
@ -191,9 +174,7 @@ impl ScriptBuf {
pub fn into_bytes(self) -> Vec<u8> { self.0 } pub fn into_bytes(self) -> Vec<u8> { self.0 }
/// Computes the P2SH output corresponding to this redeem script. /// Computes the P2SH output corresponding to this redeem script.
pub fn to_p2sh(&self) -> ScriptBuf { pub fn to_p2sh(&self) -> ScriptBuf { ScriptBuf::new_p2sh(&self.script_hash()) }
ScriptBuf::new_p2sh(&self.script_hash())
}
/// Returns the script code used for spending a P2WPKH output if this script is a script pubkey /// Returns the script code used for spending a P2WPKH output if this script is a script pubkey
/// for a P2WPKH output. The `scriptCode` is described in [BIP143]. /// for a P2WPKH output. The `scriptCode` is described in [BIP143].
@ -213,9 +194,7 @@ impl ScriptBuf {
} }
/// Adds a single opcode to the script. /// Adds a single opcode to the script.
pub fn push_opcode(&mut self, data: opcodes::All) { pub fn push_opcode(&mut self, data: opcodes::All) { self.0.push(data.to_u8()); }
self.0.push(data.to_u8());
}
/// Adds instructions to push some arbitrary data onto the stack. /// Adds instructions to push some arbitrary data onto the stack.
pub fn push_slice<T: AsRef<PushBytes>>(&mut self, data: T) { pub fn push_slice<T: AsRef<PushBytes>>(&mut self, data: T) {
@ -228,16 +207,18 @@ impl ScriptBuf {
fn push_slice_no_opt(&mut self, data: &PushBytes) { fn push_slice_no_opt(&mut self, data: &PushBytes) {
// Start with a PUSH opcode // Start with a PUSH opcode
match data.len() as u64 { match data.len() as u64 {
n if n < opcodes::Ordinary::OP_PUSHDATA1 as u64 => { self.0.push(n as u8); }, n if n < opcodes::Ordinary::OP_PUSHDATA1 as u64 => {
self.0.push(n as u8);
}
n if n < 0x100 => { n if n < 0x100 => {
self.0.push(opcodes::Ordinary::OP_PUSHDATA1.to_u8()); self.0.push(opcodes::Ordinary::OP_PUSHDATA1.to_u8());
self.0.push(n as u8); self.0.push(n as u8);
}, }
n if n < 0x10000 => { n if n < 0x10000 => {
self.0.push(opcodes::Ordinary::OP_PUSHDATA2.to_u8()); self.0.push(opcodes::Ordinary::OP_PUSHDATA2.to_u8());
self.0.push((n % 0x100) as u8); self.0.push((n % 0x100) as u8);
self.0.push((n / 0x100) as u8); self.0.push((n / 0x100) as u8);
}, }
n if n < 0x100000000 => { n if n < 0x100000000 => {
self.0.push(opcodes::Ordinary::OP_PUSHDATA4.to_u8()); self.0.push(opcodes::Ordinary::OP_PUSHDATA4.to_u8());
self.0.push((n % 0x100) as u8); self.0.push((n % 0x100) as u8);
@ -245,7 +226,7 @@ impl ScriptBuf {
self.0.push(((n / 0x10000) % 0x100) as u8); self.0.push(((n / 0x10000) % 0x100) as u8);
self.0.push((n / 0x1000000) as u8); self.0.push((n / 0x1000000) as u8);
} }
_ => panic!("tried to put a 4bn+ sized object into a script!") _ => panic!("tried to put a 4bn+ sized object into a script!"),
} }
// Then push the raw bytes // Then push the raw bytes
self.0.extend_from_slice(data.as_bytes()); self.0.extend_from_slice(data.as_bytes());
@ -297,9 +278,7 @@ impl ScriptBuf {
/// This function needs to iterate over the script to find the last instruction. Prefer /// This function needs to iterate over the script to find the last instruction. Prefer
/// `Builder` if you're creating the script from scratch or if you want to push `OP_VERIFY` /// `Builder` if you're creating the script from scratch or if you want to push `OP_VERIFY`
/// multiple times. /// multiple times.
pub fn scan_and_push_verify(&mut self) { pub fn scan_and_push_verify(&mut self) { self.push_verify(self.last_opcode()); }
self.push_verify(self.last_opcode());
}
/// Adds an `OP_VERIFY` to the script or changes the most-recently-added opcode to `VERIFY` /// Adds an `OP_VERIFY` to the script or changes the most-recently-added opcode to `VERIFY`
/// alternative. /// alternative.
@ -310,7 +289,7 @@ impl ScriptBuf {
Some(opcode) => { Some(opcode) => {
self.0.pop(); self.0.pop();
self.push_opcode(opcode); self.push_opcode(opcode);
}, }
None => self.push_opcode(OP_VERIFY), None => self.push_opcode(OP_VERIFY),
} }
} }
@ -331,7 +310,10 @@ impl ScriptBuf {
} }
impl<'a> core::iter::FromIterator<Instruction<'a>> for ScriptBuf { impl<'a> core::iter::FromIterator<Instruction<'a>> for ScriptBuf {
fn from_iter<T>(iter: T) -> Self where T: IntoIterator<Item = Instruction<'a>> { fn from_iter<T>(iter: T) -> Self
where
T: IntoIterator<Item = Instruction<'a>>,
{
let mut script = ScriptBuf::new(); let mut script = ScriptBuf::new();
script.extend(iter); script.extend(iter);
script script
@ -339,7 +321,10 @@ impl<'a> core::iter::FromIterator<Instruction<'a>> for ScriptBuf {
} }
impl<'a> Extend<Instruction<'a>> for ScriptBuf { impl<'a> Extend<Instruction<'a>> for ScriptBuf {
fn extend<T>(&mut self, iter: T) where T: IntoIterator<Item = Instruction<'a>> { fn extend<T>(&mut self, iter: T)
where
T: IntoIterator<Item = Instruction<'a>>,
{
let iter = iter.into_iter(); let iter = iter.into_iter();
// Most of Bitcoin scripts have only a few opcodes, so we can avoid reallocations in many // Most of Bitcoin scripts have only a few opcodes, so we can avoid reallocations in many
// cases. // cases.
@ -354,7 +339,11 @@ impl<'a> Extend<Instruction<'a>> for ScriptBuf {
*head = Some(instr); *head = Some(instr);
} }
// Incorrect impl of `size_hint` breaks `Iterator` contract so we're free to panic. // Incorrect impl of `size_hint` breaks `Iterator` contract so we're free to panic.
assert!(iter.next().is_none(), "Buggy implementation of `Iterator` on {} returns invalid upper bound", core::any::type_name::<T::IntoIter>()); assert!(
iter.next().is_none(),
"Buggy implementation of `Iterator` on {} returns invalid upper bound",
core::any::type_name::<T::IntoIter>()
);
self.reserve(total_size); self.reserve(total_size);
for instr in head.iter().cloned().flatten() { for instr in head.iter().cloned().flatten() {
self.push_instruction_no_opt(instr); self.push_instruction_no_opt(instr);

View File

@ -1,28 +1,29 @@
//! Contains `PushBytes` & co //! Contains `PushBytes` & co
use core::ops::{Deref, DerefMut};
use core::borrow::{Borrow, BorrowMut}; use core::borrow::{Borrow, BorrowMut};
#[allow(unused)] use core::ops::{Deref, DerefMut};
use crate::prelude::*;
pub use primitive::*; pub use primitive::*;
#[allow(unused)]
use crate::prelude::*;
/// This module only contains required operations so that outside functions wouldn't accidentally /// This module only contains required operations so that outside functions wouldn't accidentally
/// break invariants. Therefore auditing this module should be sufficient. /// break invariants. Therefore auditing this module should be sufficient.
mod primitive { mod primitive {
use core::convert::{TryFrom, TryInto};
#[cfg(feature = "rust_v_1_53")]
use core::ops::Bound;
use core::ops::{
Index, Range, RangeFrom, RangeFull, RangeInclusive, RangeTo, RangeToInclusive,
};
use super::PushBytesError;
#[allow(unused)] #[allow(unused)]
use crate::prelude::*; use crate::prelude::*;
use super::PushBytesError;
use core::convert::{TryFrom, TryInto};
use core::ops::{Index, Range, RangeFull, RangeFrom, RangeTo, RangeInclusive, RangeToInclusive};
#[cfg(feature = "rust_v_1_53")]
use core::ops::Bound;
#[cfg(any(target_pointer_width = "16", target_pointer_width = "32"))] #[cfg(any(target_pointer_width = "16", target_pointer_width = "32"))]
fn check_limit(len: usize) -> Result<(), PushBytesError> { fn check_limit(len: usize) -> Result<(), PushBytesError> { Ok(()) }
Ok(())
}
#[cfg(not(any(target_pointer_width = "16", target_pointer_width = "32")))] #[cfg(not(any(target_pointer_width = "16", target_pointer_width = "32")))]
fn check_limit(len: usize) -> Result<(), PushBytesError> { fn check_limit(len: usize) -> Result<(), PushBytesError> {
@ -68,14 +69,10 @@ mod primitive {
} }
/// Returns the underlying bytes. /// Returns the underlying bytes.
pub fn as_bytes(&self) -> &[u8] { pub fn as_bytes(&self) -> &[u8] { &self.0 }
&self.0
}
/// Returns the underlying mutbale bytes. /// Returns the underlying mutbale bytes.
pub fn as_mut_bytes(&mut self) -> &mut [u8] { pub fn as_mut_bytes(&mut self) -> &mut [u8] { &mut self.0 }
&mut self.0
}
} }
macro_rules! delegate_index { macro_rules! delegate_index {
@ -98,7 +95,14 @@ mod primitive {
} }
} }
delegate_index!(Range<usize>, RangeFrom<usize>, RangeTo<usize>, RangeFull, RangeInclusive<usize>, RangeToInclusive<usize>); delegate_index!(
Range<usize>,
RangeFrom<usize>,
RangeTo<usize>,
RangeFull,
RangeInclusive<usize>,
RangeToInclusive<usize>
);
#[cfg(feature = "rust_v_1_53")] #[cfg(feature = "rust_v_1_53")]
#[cfg_attr(docsrs, doc(cfg(feature = "rust_v_1_53")))] #[cfg_attr(docsrs, doc(cfg(feature = "rust_v_1_53")))]
delegate_index!((Bound<usize>, Bound<usize>)); delegate_index!((Bound<usize>, Bound<usize>));
@ -108,9 +112,7 @@ mod primitive {
#[inline] #[inline]
#[cfg_attr(rust_v_1_46, track_caller)] #[cfg_attr(rust_v_1_46, track_caller)]
fn index(&self, index: usize) -> &Self::Output { fn index(&self, index: usize) -> &Self::Output { &self.0[index] }
&self.0[index]
}
} }
impl<'a> TryFrom<&'a [u8]> for &'a PushBytes { impl<'a> TryFrom<&'a [u8]> for &'a PushBytes {
@ -194,14 +196,10 @@ mod primitive {
impl PushBytesBuf { impl PushBytesBuf {
/// Creates a new empty `PushBytesBuf`. /// Creates a new empty `PushBytesBuf`.
pub fn new() -> Self { pub fn new() -> Self { PushBytesBuf(Vec::new()) }
PushBytesBuf(Vec::new())
}
/// Creates a new empty `PushBytesBuf` with reserved capacity. /// Creates a new empty `PushBytesBuf` with reserved capacity.
pub fn with_capacity(capacity: usize) -> Self { pub fn with_capacity(capacity: usize) -> Self { PushBytesBuf(Vec::with_capacity(capacity)) }
PushBytesBuf(Vec::with_capacity(capacity))
}
/// Reserve capacity for `additional_capacity` bytes. /// Reserve capacity for `additional_capacity` bytes.
pub fn reserve(&mut self, additional_capacity: usize) { pub fn reserve(&mut self, additional_capacity: usize) {
@ -234,9 +232,7 @@ mod primitive {
} }
/// Remove the last byte from buffer if any. /// Remove the last byte from buffer if any.
pub fn pop(&mut self) -> Option<u8> { pub fn pop(&mut self) -> Option<u8> { self.0.pop() }
self.0.pop()
}
/// Remove the byte at `index` and return it. /// Remove the byte at `index` and return it.
/// ///
@ -244,19 +240,13 @@ mod primitive {
/// ///
/// This method panics if `index` is out of bounds. /// This method panics if `index` is out of bounds.
#[cfg_attr(rust_v_1_46, track_caller)] #[cfg_attr(rust_v_1_46, track_caller)]
pub fn remove(&mut self, index: usize) -> u8 { pub fn remove(&mut self, index: usize) -> u8 { self.0.remove(index) }
self.0.remove(index)
}
/// Remove all bytes from buffer without affecting capacity. /// Remove all bytes from buffer without affecting capacity.
pub fn clear(&mut self) { pub fn clear(&mut self) { self.0.clear() }
self.0.clear()
}
/// Remove bytes from buffer past `len`. /// Remove bytes from buffer past `len`.
pub fn truncate(&mut self, len: usize) { pub fn truncate(&mut self, len: usize) { self.0.truncate(len) }
self.0.truncate(len)
}
/// Extracts `PushBytes` slice /// Extracts `PushBytes` slice
pub fn as_push_bytes(&self) -> &PushBytes { pub fn as_push_bytes(&self) -> &PushBytes {
@ -271,15 +261,11 @@ mod primitive {
} }
/// Accesses inner `Vec` - provided for `super` to impl other methods. /// Accesses inner `Vec` - provided for `super` to impl other methods.
pub(super) fn inner(&self) -> &Vec<u8> { pub(super) fn inner(&self) -> &Vec<u8> { &self.0 }
&self.0
}
} }
impl From<PushBytesBuf> for Vec<u8> { impl From<PushBytesBuf> for Vec<u8> {
fn from(value: PushBytesBuf) -> Self { fn from(value: PushBytesBuf) -> Self { value.0 }
value.0
}
} }
impl TryFrom<Vec<u8>> for PushBytesBuf { impl TryFrom<Vec<u8>> for PushBytesBuf {
@ -295,101 +281,69 @@ mod primitive {
impl ToOwned for PushBytes { impl ToOwned for PushBytes {
type Owned = PushBytesBuf; type Owned = PushBytesBuf;
fn to_owned(&self) -> Self::Owned { fn to_owned(&self) -> Self::Owned { PushBytesBuf(self.0.to_owned()) }
PushBytesBuf(self.0.to_owned())
}
} }
} }
impl PushBytes { impl PushBytes {
/// Returns the number of bytes in buffer. /// Returns the number of bytes in buffer.
pub fn len(&self) -> usize { pub fn len(&self) -> usize { self.as_bytes().len() }
self.as_bytes().len()
}
/// Returns true if the buffer contains zero bytes. /// Returns true if the buffer contains zero bytes.
pub fn is_empty(&self) -> bool { pub fn is_empty(&self) -> bool { self.as_bytes().is_empty() }
self.as_bytes().is_empty()
}
} }
impl PushBytesBuf { impl PushBytesBuf {
/// Returns the number of bytes in buffer. /// Returns the number of bytes in buffer.
pub fn len(&self) -> usize { pub fn len(&self) -> usize { self.inner().len() }
self.inner().len()
}
/// Returns the number of bytes the buffer can contain without reallocating. /// Returns the number of bytes the buffer can contain without reallocating.
pub fn capacity(&self) -> usize { pub fn capacity(&self) -> usize { self.inner().capacity() }
self.inner().capacity()
}
/// Returns true if the buffer contains zero bytes. /// Returns true if the buffer contains zero bytes.
pub fn is_empty(&self) -> bool { pub fn is_empty(&self) -> bool { self.inner().is_empty() }
self.inner().is_empty()
}
} }
impl AsRef<[u8]> for PushBytes { impl AsRef<[u8]> for PushBytes {
fn as_ref(&self) -> &[u8] { fn as_ref(&self) -> &[u8] { self.as_bytes() }
self.as_bytes()
}
} }
impl AsMut<[u8]> for PushBytes { impl AsMut<[u8]> for PushBytes {
fn as_mut(&mut self) -> &mut [u8] { fn as_mut(&mut self) -> &mut [u8] { self.as_mut_bytes() }
self.as_mut_bytes()
}
} }
impl Deref for PushBytesBuf { impl Deref for PushBytesBuf {
type Target = PushBytes; type Target = PushBytes;
fn deref(&self) -> &Self::Target { fn deref(&self) -> &Self::Target { self.as_push_bytes() }
self.as_push_bytes()
}
} }
impl DerefMut for PushBytesBuf { impl DerefMut for PushBytesBuf {
fn deref_mut(&mut self) -> &mut Self::Target { fn deref_mut(&mut self) -> &mut Self::Target { self.as_mut_push_bytes() }
self.as_mut_push_bytes()
}
} }
impl AsRef<PushBytes> for PushBytes { impl AsRef<PushBytes> for PushBytes {
fn as_ref(&self) -> &PushBytes { fn as_ref(&self) -> &PushBytes { self }
self
}
} }
impl AsMut<PushBytes> for PushBytes { impl AsMut<PushBytes> for PushBytes {
fn as_mut(&mut self) -> &mut PushBytes { fn as_mut(&mut self) -> &mut PushBytes { self }
self
}
} }
impl AsRef<PushBytes> for PushBytesBuf { impl AsRef<PushBytes> for PushBytesBuf {
fn as_ref(&self) -> &PushBytes { fn as_ref(&self) -> &PushBytes { self.as_push_bytes() }
self.as_push_bytes()
}
} }
impl AsMut<PushBytes> for PushBytesBuf { impl AsMut<PushBytes> for PushBytesBuf {
fn as_mut(&mut self) -> &mut PushBytes { fn as_mut(&mut self) -> &mut PushBytes { self.as_mut_push_bytes() }
self.as_mut_push_bytes()
}
} }
impl Borrow<PushBytes> for PushBytesBuf { impl Borrow<PushBytes> for PushBytesBuf {
fn borrow(&self) -> &PushBytes { fn borrow(&self) -> &PushBytes { self.as_push_bytes() }
self.as_push_bytes()
}
} }
impl BorrowMut<PushBytes> for PushBytesBuf { impl BorrowMut<PushBytes> for PushBytesBuf {
fn borrow_mut(&mut self) -> &mut PushBytes { fn borrow_mut(&mut self) -> &mut PushBytes { self.as_mut_push_bytes() }
self.as_mut_push_bytes()
}
} }
/// Reports information about failed conversion into `PushBytes`. /// Reports information about failed conversion into `PushBytes`.
@ -403,9 +357,7 @@ pub trait PushBytesErrorReport {
impl PushBytesErrorReport for core::convert::Infallible { impl PushBytesErrorReport for core::convert::Infallible {
#[inline] #[inline]
fn input_len(&self) -> usize { fn input_len(&self) -> usize { match *self {} }
match *self {}
}
} }
pub use error::*; pub use error::*;
@ -423,15 +375,11 @@ mod error {
impl super::PushBytesErrorReport for PushBytesError { impl super::PushBytesErrorReport for PushBytesError {
#[inline] #[inline]
fn input_len(&self) -> usize { fn input_len(&self) -> usize { match self.never {} }
match self.never {}
}
} }
impl fmt::Display for PushBytesError { impl fmt::Display for PushBytesError {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { match self.never {} }
match self.never {}
}
} }
} }
@ -445,19 +393,21 @@ mod error {
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
pub struct PushBytesError { pub struct PushBytesError {
/// How long the input was. /// How long the input was.
pub(super) len: usize pub(super) len: usize,
} }
impl super::PushBytesErrorReport for PushBytesError { impl super::PushBytesErrorReport for PushBytesError {
#[inline] #[inline]
fn input_len(&self) -> usize { fn input_len(&self) -> usize { self.len }
self.len
}
} }
impl fmt::Display for PushBytesError { impl fmt::Display for PushBytesError {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "attempt to prepare {} bytes to be pushed into script but the limit is 2^32-1", self.len) write!(
f,
"attempt to prepare {} bytes to be pushed into script but the limit is 2^32-1",
self.len
)
} }
} }
} }

View File

@ -1,15 +1,15 @@
use core::str::FromStr; use core::str::FromStr;
use super::*;
use crate::hashes::Hash;
use crate::hash_types::{PubkeyHash, WPubkeyHash, ScriptHash, WScriptHash};
use crate::consensus::encode::{deserialize, serialize};
use crate::blockdata::opcodes;
use crate::crypto::key::{PublicKey, XOnlyPublicKey};
use crate::psbt::serialize::Serialize;
use hex_lit::hex; use hex_lit::hex;
use super::*;
use crate::blockdata::opcodes;
use crate::consensus::encode::{deserialize, serialize};
use crate::crypto::key::{PublicKey, XOnlyPublicKey};
use crate::hash_types::{PubkeyHash, ScriptHash, WPubkeyHash, WScriptHash};
use crate::hashes::Hash;
use crate::psbt::serialize::Serialize;
#[test] #[test]
#[rustfmt::skip] #[rustfmt::skip]
fn script() { fn script() {
@ -89,20 +89,16 @@ fn p2pk_pubkey_bytes_different_op_code_returns_none() {
fn p2pk_pubkey_bytes_incorrect_key_size_returns_none() { fn p2pk_pubkey_bytes_incorrect_key_size_returns_none() {
// 63 byte key // 63 byte key
let malformed_key = b"21032e58afe51f9ed8ad3cc7897f634d881fdbe49816429ded8156bebd2ffd1"; let malformed_key = b"21032e58afe51f9ed8ad3cc7897f634d881fdbe49816429ded8156bebd2ffd1";
let invalid_p2pk_script = Script::builder() let invalid_p2pk_script =
.push_slice(malformed_key) Script::builder().push_slice(malformed_key).push_opcode(OP_CHECKSIG).into_script();
.push_opcode(OP_CHECKSIG)
.into_script();
assert!(invalid_p2pk_script.p2pk_pubkey_bytes().is_none()); assert!(invalid_p2pk_script.p2pk_pubkey_bytes().is_none());
} }
#[test] #[test]
fn p2pk_pubkey_bytes_invalid_key_returns_some() { fn p2pk_pubkey_bytes_invalid_key_returns_some() {
let malformed_key = b"21032e58afe51f9ed8ad3cc7897f634d881fdbe49816429ded8156bebd2ffd1ux"; let malformed_key = b"21032e58afe51f9ed8ad3cc7897f634d881fdbe49816429ded8156bebd2ffd1ux";
let invalid_key_script = Script::builder() let invalid_key_script =
.push_slice(malformed_key) Script::builder().push_slice(malformed_key).push_opcode(OP_CHECKSIG).into_script();
.push_opcode(OP_CHECKSIG)
.into_script();
assert!(invalid_key_script.p2pk_pubkey_bytes().is_some()); assert!(invalid_key_script.p2pk_pubkey_bytes().is_some());
} }
@ -155,21 +151,16 @@ fn p2pk_public_key_different_op_code_returns_none() {
#[test] #[test]
fn p2pk_public_key_incorrect_size_returns_none() { fn p2pk_public_key_incorrect_size_returns_none() {
let malformed_key = b"21032e58afe51f9ed8ad3cc7897f634d881fdbe49816429ded8156bebd2ffd1"; let malformed_key = b"21032e58afe51f9ed8ad3cc7897f634d881fdbe49816429ded8156bebd2ffd1";
let malformed_key_script = Script::builder() let malformed_key_script =
.push_slice(malformed_key) Script::builder().push_slice(malformed_key).push_opcode(OP_CHECKSIG).into_script();
.push_opcode(OP_CHECKSIG)
.into_script();
assert!(malformed_key_script.p2pk_public_key().is_none()); assert!(malformed_key_script.p2pk_public_key().is_none());
} }
#[test] #[test]
fn p2pk_public_key_invalid_key_returns_none() { fn p2pk_public_key_invalid_key_returns_none() {
let malformed_key = b"21032e58afe51f9ed8ad3cc7897f634d881fdbe49816429ded8156bebd2ffd1ux"; let malformed_key = b"21032e58afe51f9ed8ad3cc7897f634d881fdbe49816429ded8156bebd2ffd1ux";
let invalid_key_script = Script::builder() let invalid_key_script =
.push_slice(malformed_key) Script::builder().push_slice(malformed_key).push_opcode(OP_CHECKSIG).into_script();
.push_opcode(OP_CHECKSIG)
.into_script();
assert!(invalid_key_script.p2pk_public_key().is_none()); assert!(invalid_key_script.p2pk_public_key().is_none());
} }
@ -196,7 +187,8 @@ fn script_x_only_key() {
#[test] #[test]
fn script_builder() { fn script_builder() {
// from txid 3bb5e6434c11fb93f64574af5d116736510717f2c595eb45b52c28e31622dfff which was in my mempool when I wrote the test // from txid 3bb5e6434c11fb93f64574af5d116736510717f2c595eb45b52c28e31622dfff which was in my mempool when I wrote the test
let script = Builder::new().push_opcode(OP_DUP) let script = Builder::new()
.push_opcode(OP_DUP)
.push_opcode(OP_HASH160) .push_opcode(OP_HASH160)
.push_slice(hex!("16e1ae70ff0fa102905d4af297f6912bda6cce19")) .push_slice(hex!("16e1ae70ff0fa102905d4af297f6912bda6cce19"))
.push_opcode(OP_EQUALVERIFY) .push_opcode(OP_EQUALVERIFY)
@ -207,7 +199,9 @@ fn script_builder() {
#[test] #[test]
fn script_generators() { fn script_generators() {
let pubkey = PublicKey::from_str("0234e6a79c5359c613762d537e0e19d86c77c1666d8c9ab050f23acd198e97f93e").unwrap(); let pubkey =
PublicKey::from_str("0234e6a79c5359c613762d537e0e19d86c77c1666d8c9ab050f23acd198e97f93e")
.unwrap();
assert!(ScriptBuf::new_p2pk(&pubkey).is_p2pk()); assert!(ScriptBuf::new_p2pk(&pubkey).is_p2pk());
let pubkey_hash = PubkeyHash::hash(&pubkey.inner.serialize()); let pubkey_hash = PubkeyHash::hash(&pubkey.inner.serialize());
@ -216,9 +210,7 @@ fn script_generators() {
let wpubkey_hash = WPubkeyHash::hash(&pubkey.inner.serialize()); let wpubkey_hash = WPubkeyHash::hash(&pubkey.inner.serialize());
assert!(ScriptBuf::new_v0_p2wpkh(&wpubkey_hash).is_v0_p2wpkh()); assert!(ScriptBuf::new_v0_p2wpkh(&wpubkey_hash).is_v0_p2wpkh());
let script = Builder::new().push_opcode(OP_NUMEQUAL) let script = Builder::new().push_opcode(OP_NUMEQUAL).push_verify().into_script();
.push_verify()
.into_script();
let script_hash = ScriptHash::hash(&script.serialize()); let script_hash = ScriptHash::hash(&script.serialize());
let p2sh = ScriptBuf::new_p2sh(&script_hash); let p2sh = ScriptBuf::new_p2sh(&script_hash);
assert!(p2sh.is_p2sh()); assert!(p2sh.is_p2sh());
@ -234,68 +226,42 @@ fn script_generators() {
let data = hex!("aa21a9ed20280f53f2d21663cac89e6bd2ad19edbabb048cda08e73ed19e9268d0afea2a"); let data = hex!("aa21a9ed20280f53f2d21663cac89e6bd2ad19edbabb048cda08e73ed19e9268d0afea2a");
let op_return = ScriptBuf::new_op_return(&data); let op_return = ScriptBuf::new_op_return(&data);
assert!(op_return.is_op_return()); assert!(op_return.is_op_return());
assert_eq!(op_return.to_hex_string(), "6a24aa21a9ed20280f53f2d21663cac89e6bd2ad19edbabb048cda08e73ed19e9268d0afea2a"); assert_eq!(
op_return.to_hex_string(),
"6a24aa21a9ed20280f53f2d21663cac89e6bd2ad19edbabb048cda08e73ed19e9268d0afea2a"
);
} }
#[test] #[test]
fn script_builder_verify() { fn script_builder_verify() {
let simple = Builder::new() let simple = Builder::new().push_verify().into_script();
.push_verify()
.into_script();
assert_eq!(simple.to_hex_string(), "69"); assert_eq!(simple.to_hex_string(), "69");
let simple2 = Builder::from(vec![]) let simple2 = Builder::from(vec![]).push_verify().into_script();
.push_verify()
.into_script();
assert_eq!(simple2.to_hex_string(), "69"); assert_eq!(simple2.to_hex_string(), "69");
let nonverify = Builder::new() let nonverify = Builder::new().push_verify().push_verify().into_script();
.push_verify()
.push_verify()
.into_script();
assert_eq!(nonverify.to_hex_string(), "6969"); assert_eq!(nonverify.to_hex_string(), "6969");
let nonverify2 = Builder::from(vec![0x69]) let nonverify2 = Builder::from(vec![0x69]).push_verify().into_script();
.push_verify()
.into_script();
assert_eq!(nonverify2.to_hex_string(), "6969"); assert_eq!(nonverify2.to_hex_string(), "6969");
let equal = Builder::new() let equal = Builder::new().push_opcode(OP_EQUAL).push_verify().into_script();
.push_opcode(OP_EQUAL)
.push_verify()
.into_script();
assert_eq!(equal.to_hex_string(), "88"); assert_eq!(equal.to_hex_string(), "88");
let equal2 = Builder::from(vec![0x87]) let equal2 = Builder::from(vec![0x87]).push_verify().into_script();
.push_verify()
.into_script();
assert_eq!(equal2.to_hex_string(), "88"); assert_eq!(equal2.to_hex_string(), "88");
let numequal = Builder::new() let numequal = Builder::new().push_opcode(OP_NUMEQUAL).push_verify().into_script();
.push_opcode(OP_NUMEQUAL)
.push_verify()
.into_script();
assert_eq!(numequal.to_hex_string(), "9d"); assert_eq!(numequal.to_hex_string(), "9d");
let numequal2 = Builder::from(vec![0x9c]) let numequal2 = Builder::from(vec![0x9c]).push_verify().into_script();
.push_verify()
.into_script();
assert_eq!(numequal2.to_hex_string(), "9d"); assert_eq!(numequal2.to_hex_string(), "9d");
let checksig = Builder::new() let checksig = Builder::new().push_opcode(OP_CHECKSIG).push_verify().into_script();
.push_opcode(OP_CHECKSIG)
.push_verify()
.into_script();
assert_eq!(checksig.to_hex_string(), "ad"); assert_eq!(checksig.to_hex_string(), "ad");
let checksig2 = Builder::from(vec![0xac]) let checksig2 = Builder::from(vec![0xac]).push_verify().into_script();
.push_verify()
.into_script();
assert_eq!(checksig2.to_hex_string(), "ad"); assert_eq!(checksig2.to_hex_string(), "ad");
let checkmultisig = Builder::new() let checkmultisig = Builder::new().push_opcode(OP_CHECKMULTISIG).push_verify().into_script();
.push_opcode(OP_CHECKMULTISIG)
.push_verify()
.into_script();
assert_eq!(checkmultisig.to_hex_string(), "af"); assert_eq!(checkmultisig.to_hex_string(), "af");
let checkmultisig2 = Builder::from(vec![0xae]) let checkmultisig2 = Builder::from(vec![0xae]).push_verify().into_script();
.push_verify()
.into_script();
assert_eq!(checkmultisig2.to_hex_string(), "af"); assert_eq!(checkmultisig2.to_hex_string(), "af");
let trick_slice = Builder::new() let trick_slice = Builder::new()
@ -303,9 +269,7 @@ fn script_builder_verify() {
.push_verify() .push_verify()
.into_script(); .into_script();
assert_eq!(trick_slice.to_hex_string(), "01ae69"); assert_eq!(trick_slice.to_hex_string(), "01ae69");
let trick_slice2 = Builder::from(vec![0x01, 0xae]) let trick_slice2 = Builder::from(vec![0x01, 0xae]).push_verify().into_script();
.push_verify()
.into_script();
assert_eq!(trick_slice2.to_hex_string(), "01ae69"); assert_eq!(trick_slice2.to_hex_string(), "01ae69");
} }
@ -332,8 +296,18 @@ fn scriptint_round_trip() {
assert_eq!(build_scriptint(257), vec![1, 1]); assert_eq!(build_scriptint(257), vec![1, 1]);
assert_eq!(build_scriptint(511), vec![255, 1]); assert_eq!(build_scriptint(511), vec![255, 1]);
let test_vectors = [ let test_vectors = [
10, 100, 255, 256, 1000, 10000, 25000, 200000, 5000000, 1000000000, 10,
(1 << 31) - 1, -((1 << 31) - 1), 100,
255,
256,
1000,
10000,
25000,
200000,
5000000,
1000000000,
(1 << 31) - 1,
-((1 << 31) - 1),
]; ];
for &i in test_vectors.iter() { for &i in test_vectors.iter() {
assert_eq!(Ok(i), read_scriptint(&build_scriptint(i))); assert_eq!(Ok(i), read_scriptint(&build_scriptint(i)));
@ -355,9 +329,15 @@ fn non_minimal_scriptints() {
fn script_hashes() { fn script_hashes() {
let script = ScriptBuf::from_hex("410446ef0102d1ec5240f0d061a4246c1bdef63fc3dbab7733052fbbf0ecd8f41fc26bf049ebb4f9527f374280259e7cfa99c48b0e3f39c51347a19a5819651503a5ac").unwrap(); let script = ScriptBuf::from_hex("410446ef0102d1ec5240f0d061a4246c1bdef63fc3dbab7733052fbbf0ecd8f41fc26bf049ebb4f9527f374280259e7cfa99c48b0e3f39c51347a19a5819651503a5ac").unwrap();
assert_eq!(script.script_hash().to_string(), "8292bcfbef1884f73c813dfe9c82fd7e814291ea"); assert_eq!(script.script_hash().to_string(), "8292bcfbef1884f73c813dfe9c82fd7e814291ea");
assert_eq!(script.wscript_hash().to_string(), "3e1525eb183ad4f9b3c5fa3175bdca2a52e947b135bbb90383bf9f6408e2c324");
assert_eq!( assert_eq!(
ScriptBuf::from_hex("20d85a959b0290bf19bb89ed43c916be835475d013da4b362117393e25a48229b8ac").unwrap().tapscript_leaf_hash().to_string(), script.wscript_hash().to_string(),
"3e1525eb183ad4f9b3c5fa3175bdca2a52e947b135bbb90383bf9f6408e2c324"
);
assert_eq!(
ScriptBuf::from_hex("20d85a959b0290bf19bb89ed43c916be835475d013da4b362117393e25a48229b8ac")
.unwrap()
.tapscript_leaf_hash()
.to_string(),
"5b75adecf53548f3ec6ad7d78383bf84cc57b55a3127c72b9a2481752dd88b21" "5b75adecf53548f3ec6ad7d78383bf84cc57b55a3127c72b9a2481752dd88b21"
); );
} }
@ -368,14 +348,22 @@ fn provably_unspendable_test() {
assert!(!ScriptBuf::from_hex("410446ef0102d1ec5240f0d061a4246c1bdef63fc3dbab7733052fbbf0ecd8f41fc26bf049ebb4f9527f374280259e7cfa99c48b0e3f39c51347a19a5819651503a5ac").unwrap().is_provably_unspendable()); assert!(!ScriptBuf::from_hex("410446ef0102d1ec5240f0d061a4246c1bdef63fc3dbab7733052fbbf0ecd8f41fc26bf049ebb4f9527f374280259e7cfa99c48b0e3f39c51347a19a5819651503a5ac").unwrap().is_provably_unspendable());
assert!(!ScriptBuf::from_hex("4104ea1feff861b51fe3f5f8a3b12d0f4712db80e919548a80839fc47c6a21e66d957e9c5d8cd108c7a2d2324bad71f9904ac0ae7336507d785b17a2c115e427a32fac").unwrap().is_provably_unspendable()); assert!(!ScriptBuf::from_hex("4104ea1feff861b51fe3f5f8a3b12d0f4712db80e919548a80839fc47c6a21e66d957e9c5d8cd108c7a2d2324bad71f9904ac0ae7336507d785b17a2c115e427a32fac").unwrap().is_provably_unspendable());
// p2pkhash // p2pkhash
assert!(!ScriptBuf::from_hex("76a914ee61d57ab51b9d212335b1dba62794ac20d2bcf988ac").unwrap().is_provably_unspendable()); assert!(!ScriptBuf::from_hex("76a914ee61d57ab51b9d212335b1dba62794ac20d2bcf988ac")
assert!(ScriptBuf::from_hex("6aa9149eb21980dc9d413d8eac27314938b9da920ee53e87").unwrap().is_provably_unspendable()); .unwrap()
.is_provably_unspendable());
assert!(ScriptBuf::from_hex("6aa9149eb21980dc9d413d8eac27314938b9da920ee53e87")
.unwrap()
.is_provably_unspendable());
} }
#[test] #[test]
fn op_return_test() { fn op_return_test() {
assert!(ScriptBuf::from_hex("6aa9149eb21980dc9d413d8eac27314938b9da920ee53e87").unwrap().is_op_return()); assert!(ScriptBuf::from_hex("6aa9149eb21980dc9d413d8eac27314938b9da920ee53e87")
assert!(!ScriptBuf::from_hex("76a914ee61d57ab51b9d212335b1dba62794ac20d2bcf988ac").unwrap().is_op_return()); .unwrap()
.is_op_return());
assert!(!ScriptBuf::from_hex("76a914ee61d57ab51b9d212335b1dba62794ac20d2bcf988ac")
.unwrap()
.is_op_return());
assert!(!ScriptBuf::from_hex("").unwrap().is_op_return()); assert!(!ScriptBuf::from_hex("").unwrap().is_op_return());
} }
@ -393,10 +381,14 @@ fn script_json_serialize() {
#[test] #[test]
fn script_asm() { fn script_asm() {
assert_eq!(ScriptBuf::from_hex("6363636363686868686800").unwrap().to_asm_string(), assert_eq!(
"OP_IF OP_IF OP_IF OP_IF OP_IF OP_ENDIF OP_ENDIF OP_ENDIF OP_ENDIF OP_ENDIF OP_0"); ScriptBuf::from_hex("6363636363686868686800").unwrap().to_asm_string(),
assert_eq!(ScriptBuf::from_hex("6363636363686868686800").unwrap().to_asm_string(), "OP_IF OP_IF OP_IF OP_IF OP_IF OP_ENDIF OP_ENDIF OP_ENDIF OP_ENDIF OP_ENDIF OP_0"
"OP_IF OP_IF OP_IF OP_IF OP_IF OP_ENDIF OP_ENDIF OP_ENDIF OP_ENDIF OP_ENDIF OP_0"); );
assert_eq!(
ScriptBuf::from_hex("6363636363686868686800").unwrap().to_asm_string(),
"OP_IF OP_IF OP_IF OP_IF OP_IF OP_ENDIF OP_ENDIF OP_ENDIF OP_ENDIF OP_ENDIF OP_0"
);
assert_eq!(ScriptBuf::from_hex("2102715e91d37d239dea832f1460e91e368115d8ca6cc23a7da966795abad9e3b699ac").unwrap().to_asm_string(), assert_eq!(ScriptBuf::from_hex("2102715e91d37d239dea832f1460e91e368115d8ca6cc23a7da966795abad9e3b699ac").unwrap().to_asm_string(),
"OP_PUSHBYTES_33 02715e91d37d239dea832f1460e91e368115d8ca6cc23a7da966795abad9e3b699 OP_CHECKSIG"); "OP_PUSHBYTES_33 02715e91d37d239dea832f1460e91e368115d8ca6cc23a7da966795abad9e3b699 OP_CHECKSIG");
// Elements Alpha peg-out transaction with some signatures removed for brevity. Mainly to test PUSHDATA1 // Elements Alpha peg-out transaction with some signatures removed for brevity. Mainly to test PUSHDATA1
@ -404,20 +396,28 @@ fn script_asm() {
"OP_0 OP_PUSHBYTES_71 304402202457e78cc1b7f50d0543863c27de75d07982bde8359b9e3316adec0aec165f2f02200203fd331c4e4a4a02f48cf1c291e2c0d6b2f7078a784b5b3649fca41f8794d401 OP_0 OP_PUSHDATA1 552103244e602b46755f24327142a0517288cebd159eccb6ccf41ea6edf1f601e9af952103bbbacc302d19d29dbfa62d23f37944ae19853cf260c745c2bea739c95328fcb721039227e83246bd51140fe93538b2301c9048be82ef2fb3c7fc5d78426ed6f609ad210229bf310c379b90033e2ecb07f77ecf9b8d59acb623ab7be25a0caed539e2e6472103703e2ed676936f10b3ce9149fa2d4a32060fb86fa9a70a4efe3f21d7ab90611921031e9b7c6022400a6bb0424bbcde14cff6c016b91ee3803926f3440abf5c146d05210334667f975f55a8455d515a2ef1c94fdfa3315f12319a14515d2a13d82831f62f57ae"); "OP_0 OP_PUSHBYTES_71 304402202457e78cc1b7f50d0543863c27de75d07982bde8359b9e3316adec0aec165f2f02200203fd331c4e4a4a02f48cf1c291e2c0d6b2f7078a784b5b3649fca41f8794d401 OP_0 OP_PUSHDATA1 552103244e602b46755f24327142a0517288cebd159eccb6ccf41ea6edf1f601e9af952103bbbacc302d19d29dbfa62d23f37944ae19853cf260c745c2bea739c95328fcb721039227e83246bd51140fe93538b2301c9048be82ef2fb3c7fc5d78426ed6f609ad210229bf310c379b90033e2ecb07f77ecf9b8d59acb623ab7be25a0caed539e2e6472103703e2ed676936f10b3ce9149fa2d4a32060fb86fa9a70a4efe3f21d7ab90611921031e9b7c6022400a6bb0424bbcde14cff6c016b91ee3803926f3440abf5c146d05210334667f975f55a8455d515a2ef1c94fdfa3315f12319a14515d2a13d82831f62f57ae");
// Various weird scripts found in transaction 6d7ed9914625c73c0288694a6819196a27ef6c08f98e1270d975a8e65a3dc09a // Various weird scripts found in transaction 6d7ed9914625c73c0288694a6819196a27ef6c08f98e1270d975a8e65a3dc09a
// which triggerred overflow bugs on 32-bit machines in script formatting in the past. // which triggerred overflow bugs on 32-bit machines in script formatting in the past.
assert_eq!(ScriptBuf::from_hex("01").unwrap().to_asm_string(), assert_eq!(
"OP_PUSHBYTES_1 <push past end>"); ScriptBuf::from_hex("01").unwrap().to_asm_string(),
assert_eq!(ScriptBuf::from_hex("0201").unwrap().to_asm_string(), "OP_PUSHBYTES_1 <push past end>"
"OP_PUSHBYTES_2 <push past end>"); );
assert_eq!(ScriptBuf::from_hex("4c").unwrap().to_asm_string(), assert_eq!(
"<unexpected end>"); ScriptBuf::from_hex("0201").unwrap().to_asm_string(),
assert_eq!(ScriptBuf::from_hex("4c0201").unwrap().to_asm_string(), "OP_PUSHBYTES_2 <push past end>"
"OP_PUSHDATA1 <push past end>"); );
assert_eq!(ScriptBuf::from_hex("4d").unwrap().to_asm_string(), assert_eq!(ScriptBuf::from_hex("4c").unwrap().to_asm_string(), "<unexpected end>");
"<unexpected end>"); assert_eq!(
assert_eq!(ScriptBuf::from_hex("4dffff01").unwrap().to_asm_string(), ScriptBuf::from_hex("4c0201").unwrap().to_asm_string(),
"OP_PUSHDATA2 <push past end>"); "OP_PUSHDATA1 <push past end>"
assert_eq!(ScriptBuf::from_hex("4effffffff01").unwrap().to_asm_string(), );
"OP_PUSHDATA4 <push past end>"); assert_eq!(ScriptBuf::from_hex("4d").unwrap().to_asm_string(), "<unexpected end>");
assert_eq!(
ScriptBuf::from_hex("4dffff01").unwrap().to_asm_string(),
"OP_PUSHDATA2 <push past end>"
);
assert_eq!(
ScriptBuf::from_hex("4effffffff01").unwrap().to_asm_string(),
"OP_PUSHDATA4 <push past end>"
);
} }
#[test] #[test]
@ -430,18 +430,34 @@ fn script_buf_collect() {
#[test] #[test]
fn script_p2sh_p2p2k_template() { fn script_p2sh_p2p2k_template() {
// random outputs I picked out of the mempool // random outputs I picked out of the mempool
assert!(ScriptBuf::from_hex("76a91402306a7c23f3e8010de41e9e591348bb83f11daa88ac").unwrap().is_p2pkh()); assert!(ScriptBuf::from_hex("76a91402306a7c23f3e8010de41e9e591348bb83f11daa88ac")
assert!(!ScriptBuf::from_hex("76a91402306a7c23f3e8010de41e9e591348bb83f11daa88ac").unwrap().is_p2sh()); .unwrap()
assert!(!ScriptBuf::from_hex("76a91402306a7c23f3e8010de41e9e591348bb83f11daa88ad").unwrap().is_p2pkh()); .is_p2pkh());
assert!(!ScriptBuf::from_hex("76a91402306a7c23f3e8010de41e9e591348bb83f11daa88ac")
.unwrap()
.is_p2sh());
assert!(!ScriptBuf::from_hex("76a91402306a7c23f3e8010de41e9e591348bb83f11daa88ad")
.unwrap()
.is_p2pkh());
assert!(!ScriptBuf::from_hex("").unwrap().is_p2pkh()); assert!(!ScriptBuf::from_hex("").unwrap().is_p2pkh());
assert!(ScriptBuf::from_hex("a914acc91e6fef5c7f24e5c8b3f11a664aa8f1352ffd87").unwrap().is_p2sh()); assert!(ScriptBuf::from_hex("a914acc91e6fef5c7f24e5c8b3f11a664aa8f1352ffd87")
assert!(!ScriptBuf::from_hex("a914acc91e6fef5c7f24e5c8b3f11a664aa8f1352ffd87").unwrap().is_p2pkh()); .unwrap()
assert!(!ScriptBuf::from_hex("a314acc91e6fef5c7f24e5c8b3f11a664aa8f1352ffd87").unwrap().is_p2sh()); .is_p2sh());
assert!(!ScriptBuf::from_hex("a914acc91e6fef5c7f24e5c8b3f11a664aa8f1352ffd87")
.unwrap()
.is_p2pkh());
assert!(!ScriptBuf::from_hex("a314acc91e6fef5c7f24e5c8b3f11a664aa8f1352ffd87")
.unwrap()
.is_p2sh());
} }
#[test] #[test]
fn script_p2pk() { fn script_p2pk() {
assert!(ScriptBuf::from_hex("21021aeaf2f8638a129a3156fbe7e5ef635226b0bafd495ff03afe2c843d7e3a4b51ac").unwrap().is_p2pk()); assert!(ScriptBuf::from_hex(
"21021aeaf2f8638a129a3156fbe7e5ef635226b0bafd495ff03afe2c843d7e3a4b51ac"
)
.unwrap()
.is_p2pk());
assert!(ScriptBuf::from_hex("410496b538e853519c726a2c91e61ec11600ae1390813a627c66fb8be7947be63c52da7589379515d4e0a604f8141781e62294721166bf621e73a82cbf2342c858eeac").unwrap().is_p2pk()); assert!(ScriptBuf::from_hex("410496b538e853519c726a2c91e61ec11600ae1390813a627c66fb8be7947be63c52da7589379515d4e0a604f8141781e62294721166bf621e73a82cbf2342c858eeac").unwrap().is_p2pk());
} }
@ -450,20 +466,26 @@ fn p2sh_p2wsh_conversion() {
// Test vectors taken from Core tests/data/script_tests.json // Test vectors taken from Core tests/data/script_tests.json
// bare p2wsh // bare p2wsh
let redeem_script = ScriptBuf::from_hex("410479be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b8ac").unwrap(); let redeem_script = ScriptBuf::from_hex("410479be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b8ac").unwrap();
let expected_witout = ScriptBuf::from_hex("0020b95237b48faaa69eb078e1170be3b5cbb3fddf16d0a991e14ad274f7b33a4f64").unwrap(); let expected_witout =
ScriptBuf::from_hex("0020b95237b48faaa69eb078e1170be3b5cbb3fddf16d0a991e14ad274f7b33a4f64")
.unwrap();
assert!(redeem_script.to_v0_p2wsh().is_v0_p2wsh()); assert!(redeem_script.to_v0_p2wsh().is_v0_p2wsh());
assert_eq!(redeem_script.to_v0_p2wsh(), expected_witout); assert_eq!(redeem_script.to_v0_p2wsh(), expected_witout);
// p2sh // p2sh
let redeem_script = ScriptBuf::from_hex("0479be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b8").unwrap(); let redeem_script = ScriptBuf::from_hex("0479be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b8").unwrap();
let expected_p2shout = ScriptBuf::from_hex("a91491b24bf9f5288532960ac687abb035127b1d28a587").unwrap(); let expected_p2shout =
ScriptBuf::from_hex("a91491b24bf9f5288532960ac687abb035127b1d28a587").unwrap();
assert!(redeem_script.to_p2sh().is_p2sh()); assert!(redeem_script.to_p2sh().is_p2sh());
assert_eq!(redeem_script.to_p2sh(), expected_p2shout); assert_eq!(redeem_script.to_p2sh(), expected_p2shout);
// p2sh-p2wsh // p2sh-p2wsh
let redeem_script = ScriptBuf::from_hex("410479be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b8ac").unwrap(); let redeem_script = ScriptBuf::from_hex("410479be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b8ac").unwrap();
let expected_witout = ScriptBuf::from_hex("0020b95237b48faaa69eb078e1170be3b5cbb3fddf16d0a991e14ad274f7b33a4f64").unwrap(); let expected_witout =
let expected_out = ScriptBuf::from_hex("a914f386c2ba255cc56d20cfa6ea8b062f8b5994551887").unwrap(); ScriptBuf::from_hex("0020b95237b48faaa69eb078e1170be3b5cbb3fddf16d0a991e14ad274f7b33a4f64")
.unwrap();
let expected_out =
ScriptBuf::from_hex("a914f386c2ba255cc56d20cfa6ea8b062f8b5994551887").unwrap();
assert!(redeem_script.to_p2sh().is_p2sh()); assert!(redeem_script.to_p2sh().is_p2sh());
assert!(redeem_script.to_p2sh().to_v0_p2wsh().is_v0_p2wsh()); assert!(redeem_script.to_p2sh().to_v0_p2wsh().is_v0_p2wsh());
assert_eq!(redeem_script.to_v0_p2wsh(), expected_witout); assert_eq!(redeem_script.to_v0_p2wsh(), expected_witout);
@ -492,12 +514,21 @@ fn test_iterator() {
let v_min: Result<Vec<_>, Error> = minimal.instruction_indices_minimal().collect(); let v_min: Result<Vec<_>, Error> = minimal.instruction_indices_minimal().collect();
let v_nonmin: Result<Vec<_>, Error> = nonminimal.instruction_indices_minimal().collect(); let v_nonmin: Result<Vec<_>, Error> = nonminimal.instruction_indices_minimal().collect();
let v_nonmin_alt: Result<Vec<_>, Error> = nonminimal_alt.instruction_indices_minimal().collect(); let v_nonmin_alt: Result<Vec<_>, Error> =
nonminimal_alt.instruction_indices_minimal().collect();
let slop_v_min: Result<Vec<_>, Error> = minimal.instruction_indices().collect(); let slop_v_min: Result<Vec<_>, Error> = minimal.instruction_indices().collect();
let slop_v_nonmin: Result<Vec<_>, Error> = nonminimal.instruction_indices().collect(); let slop_v_nonmin: Result<Vec<_>, Error> = nonminimal.instruction_indices().collect();
let slop_v_nonmin_alt: Result<Vec<_>, Error> = nonminimal_alt.instruction_indices().collect(); let slop_v_nonmin_alt: Result<Vec<_>, Error> = nonminimal_alt.instruction_indices().collect();
unwrap_all!(v_zero, v_zeropush, v_min, v_nonmin_alt, slop_v_min, slop_v_nonmin, slop_v_nonmin_alt); unwrap_all!(
v_zero,
v_zeropush,
v_min,
v_nonmin_alt,
slop_v_min,
slop_v_nonmin,
slop_v_nonmin_alt
);
assert_eq!(v_zero, vec![(0, Instruction::PushBytes(PushBytes::empty()))]); assert_eq!(v_zero, vec![(0, Instruction::PushBytes(PushBytes::empty()))]);
assert_eq!(v_zeropush, vec![(0, Instruction::PushBytes([0].as_ref()))]); assert_eq!(v_zeropush, vec![(0, Instruction::PushBytes([0].as_ref()))]);
@ -511,7 +542,10 @@ fn test_iterator() {
assert_eq!( assert_eq!(
v_nonmin_alt, v_nonmin_alt,
vec![(0, Instruction::PushBytes([105, 0].as_ref())), (3, Instruction::Op(opcodes::OP_NOP3))] vec![
(0, Instruction::PushBytes([105, 0].as_ref())),
(3, Instruction::Op(opcodes::OP_NOP3))
]
); );
assert_eq!(v_min, slop_v_min); assert_eq!(v_min, slop_v_min);

File diff suppressed because it is too large Load Diff

View File

@ -1,7 +1,7 @@
//! Implements `Weight` and associated features. //! Implements `Weight` and associated features.
use core::fmt; use core::fmt;
use core::ops::{Add, AddAssign, Sub, SubAssign, Mul, MulAssign, Div, DivAssign}; use core::ops::{Add, AddAssign, Div, DivAssign, Mul, MulAssign, Sub, SubAssign};
use crate::prelude::*; use crate::prelude::*;
@ -30,28 +30,20 @@ impl Weight {
pub const MAX: Weight = Weight(u64::max_value()); pub const MAX: Weight = Weight(u64::max_value());
/// Directly constructs `Weight` from weight units. /// Directly constructs `Weight` from weight units.
pub const fn from_wu(wu: u64) -> Self { pub const fn from_wu(wu: u64) -> Self { Weight(wu) }
Weight(wu)
}
/// Constructs `Weight` from virtual bytes. /// Constructs `Weight` from virtual bytes.
/// ///
/// # Errors /// # Errors
/// ///
/// Returns `None` on overflow. /// Returns `None` on overflow.
pub fn from_vb(vb: u64) -> Option<Self> { pub fn from_vb(vb: u64) -> Option<Self> { vb.checked_mul(4).map(Weight::from_wu) }
vb.checked_mul(4).map(Weight::from_wu)
}
/// Constructs `Weight` from virtual bytes without overflow check. /// Constructs `Weight` from virtual bytes without overflow check.
pub const fn from_vb_unchecked(vb: u64) -> Self { pub const fn from_vb_unchecked(vb: u64) -> Self { Weight::from_wu(vb * 4) }
Weight::from_wu(vb * 4)
}
/// Constructs `Weight` from witness size. /// Constructs `Weight` from witness size.
pub const fn from_witness_data_size(witness_size: u64) -> Self { pub const fn from_witness_data_size(witness_size: u64) -> Self { Weight(witness_size) }
Weight(witness_size)
}
/// Constructs `Weight` from non-witness size. /// Constructs `Weight` from non-witness size.
pub const fn from_non_witness_data_size(non_witness_size: u64) -> Self { pub const fn from_non_witness_data_size(non_witness_size: u64) -> Self {
@ -61,47 +53,33 @@ impl Weight {
/// Returns raw weight units. /// Returns raw weight units.
/// ///
/// Can be used instead of `into()` to avoid inference issues. /// Can be used instead of `into()` to avoid inference issues.
pub const fn to_wu(self) -> u64 { pub const fn to_wu(self) -> u64 { self.0 }
self.0
}
/// Converts to vB rounding down. /// Converts to vB rounding down.
pub const fn to_vbytes_floor(self) -> u64 { pub const fn to_vbytes_floor(self) -> u64 { self.0 / 4 }
self.0 / 4
}
/// Converts to vB rounding up. /// Converts to vB rounding up.
pub const fn to_vbytes_ceil(self) -> u64 { pub const fn to_vbytes_ceil(self) -> u64 { (self.0 + 3) / 4 }
(self.0 + 3) / 4
}
/// Checked addition. /// Checked addition.
/// ///
/// Computes `self + rhs` returning `None` if overflow occurred. /// Computes `self + rhs` returning `None` if overflow occurred.
pub fn checked_add(self, rhs: Self) -> Option<Self> { pub fn checked_add(self, rhs: Self) -> Option<Self> { self.0.checked_add(rhs.0).map(Self) }
self.0.checked_add(rhs.0).map(Self)
}
/// Checked subtraction. /// Checked subtraction.
/// ///
/// Computes `self - rhs` returning `None` if overflow occurred. /// Computes `self - rhs` returning `None` if overflow occurred.
pub fn checked_sub(self, rhs: Self) -> Option<Self> { pub fn checked_sub(self, rhs: Self) -> Option<Self> { self.0.checked_sub(rhs.0).map(Self) }
self.0.checked_sub(rhs.0).map(Self)
}
/// Checked multiplication. /// Checked multiplication.
/// ///
/// Computes `self * rhs` returning `None` if overflow occurred. /// Computes `self * rhs` returning `None` if overflow occurred.
pub fn checked_mul(self, rhs: u64) -> Option<Self> { pub fn checked_mul(self, rhs: u64) -> Option<Self> { self.0.checked_mul(rhs).map(Self) }
self.0.checked_mul(rhs).map(Self)
}
/// Checked division. /// Checked division.
/// ///
/// Computes `self / rhs` returning `None` if `rhs == 0`. /// Computes `self / rhs` returning `None` if `rhs == 0`.
pub fn checked_div(self, rhs: u64) -> Option<Self> { pub fn checked_div(self, rhs: u64) -> Option<Self> { self.0.checked_div(rhs).map(Self) }
self.0.checked_div(rhs).map(Self)
}
} }
/// Alternative will display the unit. /// Alternative will display the unit.
@ -141,9 +119,7 @@ mod tests {
#[test] #[test]
#[should_panic] #[should_panic]
fn from_vb_unchecked_panic_test() { fn from_vb_unchecked_panic_test() { Weight::from_vb_unchecked(u64::max_value()); }
Weight::from_vb_unchecked(u64::max_value());
}
#[test] #[test]
fn from_witness_data_size_test() { fn from_witness_data_size_test() {
@ -206,83 +182,69 @@ mod tests {
} }
impl From<Weight> for u64 { impl From<Weight> for u64 {
fn from(value: Weight) -> Self { fn from(value: Weight) -> Self { value.to_wu() }
value.to_wu()
}
} }
impl Add for Weight { impl Add for Weight {
type Output = Weight; type Output = Weight;
fn add(self, rhs: Weight) -> Self::Output { fn add(self, rhs: Weight) -> Self::Output { Weight(self.0 + rhs.0) }
Weight(self.0 + rhs.0)
}
} }
impl AddAssign for Weight { impl AddAssign for Weight {
fn add_assign(&mut self, rhs: Self) { fn add_assign(&mut self, rhs: Self) { self.0 += rhs.0 }
self.0 += rhs.0
}
} }
impl Sub for Weight { impl Sub for Weight {
type Output = Weight; type Output = Weight;
fn sub(self, rhs: Weight) -> Self::Output { fn sub(self, rhs: Weight) -> Self::Output { Weight(self.0 - rhs.0) }
Weight(self.0 - rhs.0)
}
} }
impl SubAssign for Weight { impl SubAssign for Weight {
fn sub_assign(&mut self, rhs: Self) { fn sub_assign(&mut self, rhs: Self) { self.0 -= rhs.0 }
self.0 -= rhs.0
}
} }
impl Mul<u64> for Weight { impl Mul<u64> for Weight {
type Output = Weight; type Output = Weight;
fn mul(self, rhs: u64) -> Self::Output { fn mul(self, rhs: u64) -> Self::Output { Weight(self.0 * rhs) }
Weight(self.0 * rhs)
}
} }
impl Mul<Weight> for u64 { impl Mul<Weight> for u64 {
type Output = Weight; type Output = Weight;
fn mul(self, rhs: Weight) -> Self::Output { fn mul(self, rhs: Weight) -> Self::Output { Weight(self * rhs.0) }
Weight(self * rhs.0)
}
} }
impl MulAssign<u64> for Weight { impl MulAssign<u64> for Weight {
fn mul_assign(&mut self, rhs: u64) { fn mul_assign(&mut self, rhs: u64) { self.0 *= rhs }
self.0 *= rhs
}
} }
impl Div<u64> for Weight { impl Div<u64> for Weight {
type Output = Weight; type Output = Weight;
fn div(self, rhs: u64) -> Self::Output { fn div(self, rhs: u64) -> Self::Output { Weight(self.0 / rhs) }
Weight(self.0 / rhs)
}
} }
impl DivAssign<u64> for Weight { impl DivAssign<u64> for Weight {
fn div_assign(&mut self, rhs: u64) { fn div_assign(&mut self, rhs: u64) { self.0 /= rhs }
self.0 /= rhs
}
} }
impl core::iter::Sum for Weight { impl core::iter::Sum for Weight {
fn sum<I>(iter: I) -> Self where I: Iterator<Item = Self> { fn sum<I>(iter: I) -> Self
where
I: Iterator<Item = Self>,
{
Weight(iter.map(Weight::to_wu).sum()) Weight(iter.map(Weight::to_wu).sum())
} }
} }
impl<'a> core::iter::Sum<&'a Weight> for Weight { impl<'a> core::iter::Sum<&'a Weight> for Weight {
fn sum<I>(iter: I) -> Self where I: Iterator<Item = &'a Weight> { fn sum<I>(iter: I) -> Self
where
I: Iterator<Item = &'a Weight>,
{
iter.cloned().sum() iter.cloned().sum()
} }
} }

View File

@ -12,11 +12,11 @@ use secp256k1::ecdsa;
use crate::consensus::encode::{Error, MAX_VEC_SIZE}; use crate::consensus::encode::{Error, MAX_VEC_SIZE};
use crate::consensus::{Decodable, Encodable, WriteExt}; use crate::consensus::{Decodable, Encodable, WriteExt};
use crate::sighash::EcdsaSighashType;
use crate::io::{self, Read, Write}; use crate::io::{self, Read, Write};
use crate::prelude::*; use crate::prelude::*;
use crate::{Script, VarInt}; use crate::sighash::EcdsaSighashType;
use crate::taproot::TAPROOT_ANNEX_PREFIX; use crate::taproot::TAPROOT_ANNEX_PREFIX;
use crate::{Script, VarInt};
/// The Witness is the data used to unlock bitcoin since the [segwit upgrade]. /// The Witness is the data used to unlock bitcoin since the [segwit upgrade].
/// ///
@ -103,8 +103,9 @@ impl Decodable for Witness {
encode_cursor(&mut content, 0, i, cursor - witness_index_space); encode_cursor(&mut content, 0, i, cursor - witness_index_space);
resize_if_needed(&mut content, required_len); resize_if_needed(&mut content, required_len);
element_size_varint element_size_varint.consensus_encode(
.consensus_encode(&mut &mut content[cursor..cursor + element_size_varint_len])?; &mut &mut content[cursor..cursor + element_size_varint_len],
)?;
cursor += element_size_varint_len; cursor += element_size_varint_len;
r.read_exact(&mut content[cursor..cursor + element_size])?; r.read_exact(&mut content[cursor..cursor + element_size])?;
cursor += element_size; cursor += element_size;
@ -112,22 +113,18 @@ impl Decodable for Witness {
content.truncate(cursor); content.truncate(cursor);
// Index space is now at the end of the Vec // Index space is now at the end of the Vec
content.rotate_left(witness_index_space); content.rotate_left(witness_index_space);
Ok(Witness { Ok(Witness { content, witness_elements, indices_start: cursor - witness_index_space })
content,
witness_elements,
indices_start: cursor - witness_index_space,
})
} }
} }
} }
/// Correctness Requirements: value must always fit within u32 /// Correctness Requirements: value must always fit within u32
#[inline] #[inline]
fn encode_cursor(bytes: &mut [u8], start_of_indices: usize, index: usize, value: usize) { fn encode_cursor(bytes: &mut [u8], start_of_indices: usize, index: usize, value: usize) {
let start = start_of_indices + index * 4; let start = start_of_indices + index * 4;
let end = start + 4; let end = start + 4;
bytes[start..end].copy_from_slice(&u32::to_ne_bytes(value.try_into().expect("Larger than u32"))); bytes[start..end]
.copy_from_slice(&u32::to_ne_bytes(value.try_into().expect("Larger than u32")));
} }
#[inline] #[inline]
@ -165,15 +162,11 @@ impl Encodable for Witness {
impl Witness { impl Witness {
/// Creates a new empty [`Witness`]. /// Creates a new empty [`Witness`].
pub fn new() -> Self { pub fn new() -> Self { Witness::default() }
Witness::default()
}
/// Creates [`Witness`] object from an array of byte-arrays /// Creates [`Witness`] object from an array of byte-arrays
#[deprecated(since = "0.30.0", note = "use `Witness::from_slice()` instead")] #[deprecated(since = "0.30.0", note = "use `Witness::from_slice()` instead")]
pub fn from_vec(vec: Vec<Vec<u8>>) -> Self { pub fn from_vec(vec: Vec<Vec<u8>>) -> Self { Witness::from_slice(&vec) }
Witness::from_slice(&vec)
}
/// Creates a [`Witness`] object from a slice of bytes slices where each slice is a witness item. /// Creates a [`Witness`] object from a slice of bytes slices where each slice is a witness item.
pub fn from_slice<T: AsRef<[u8]>>(slice: &[T]) -> Self { pub fn from_slice<T: AsRef<[u8]>>(slice: &[T]) -> Self {
@ -197,42 +190,26 @@ impl Witness {
cursor += elem.as_ref().len(); cursor += elem.as_ref().len();
} }
Witness { Witness { witness_elements, content, indices_start: content_size }
witness_elements,
content,
indices_start: content_size,
}
} }
/// Convenience method to create an array of byte-arrays from this witness. /// Convenience method to create an array of byte-arrays from this witness.
pub fn to_vec(&self) -> Vec<Vec<u8>> { pub fn to_vec(&self) -> Vec<Vec<u8>> { self.iter().map(|s| s.to_vec()).collect() }
self.iter().map(|s| s.to_vec()).collect()
}
/// Returns `true` if the witness contains no element. /// Returns `true` if the witness contains no element.
pub fn is_empty(&self) -> bool { pub fn is_empty(&self) -> bool { self.witness_elements == 0 }
self.witness_elements == 0
}
/// Returns a struct implementing [`Iterator`]. /// Returns a struct implementing [`Iterator`].
pub fn iter(&self) -> Iter { pub fn iter(&self) -> Iter {
Iter { Iter { inner: self.content.as_slice(), indices_start: self.indices_start, current_index: 0 }
inner: self.content.as_slice(),
indices_start: self.indices_start,
current_index: 0,
}
} }
/// Returns the number of elements this witness holds. /// Returns the number of elements this witness holds.
pub fn len(&self) -> usize { pub fn len(&self) -> usize { self.witness_elements }
self.witness_elements
}
/// Returns the bytes required when this Witness is consensus encoded. /// Returns the bytes required when this Witness is consensus encoded.
pub fn serialized_len(&self) -> usize { pub fn serialized_len(&self) -> usize {
self.iter() self.iter().map(|el| VarInt(el.len() as u64).len() + el.len()).sum::<usize>()
.map(|el| VarInt(el.len() as u64).len() + el.len())
.sum::<usize>()
+ VarInt(self.witness_elements as u64).len() + VarInt(self.witness_elements as u64).len()
} }
@ -255,12 +232,16 @@ impl Witness {
let element_len_varint = VarInt(new_element.len() as u64); let element_len_varint = VarInt(new_element.len() as u64);
let current_content_len = self.content.len(); let current_content_len = self.content.len();
let new_item_total_len = element_len_varint.len() + new_element.len(); let new_item_total_len = element_len_varint.len() + new_element.len();
self.content self.content.resize(current_content_len + new_item_total_len + 4, 0);
.resize(current_content_len + new_item_total_len + 4, 0);
self.content[previous_content_end..].rotate_right(new_item_total_len); self.content[previous_content_end..].rotate_right(new_item_total_len);
self.indices_start += new_item_total_len; self.indices_start += new_item_total_len;
encode_cursor(&mut self.content, self.indices_start, self.witness_elements - 1, previous_content_end); encode_cursor(
&mut self.content,
self.indices_start,
self.witness_elements - 1,
previous_content_end,
);
let end_varint = previous_content_end + element_len_varint.len(); let end_varint = previous_content_end + element_len_varint.len();
element_len_varint element_len_varint
@ -271,7 +252,11 @@ impl Witness {
/// Pushes a DER-encoded ECDSA signature with a signature hash type as a new element on the /// Pushes a DER-encoded ECDSA signature with a signature hash type as a new element on the
/// witness, requires an allocation. /// witness, requires an allocation.
pub fn push_bitcoin_signature(&mut self, signature: &ecdsa::SerializedSignature, hash_type: EcdsaSighashType) { pub fn push_bitcoin_signature(
&mut self,
signature: &ecdsa::SerializedSignature,
hash_type: EcdsaSighashType,
) {
// Note that a maximal length ECDSA signature is 72 bytes, plus the sighash type makes 73 // Note that a maximal length ECDSA signature is 72 bytes, plus the sighash type makes 73
let mut sig = [0; 73]; let mut sig = [0; 73];
sig[..signature.len()].copy_from_slice(signature); sig[..signature.len()].copy_from_slice(signature);
@ -279,7 +264,6 @@ impl Witness {
self.push(&sig[..signature.len() + 1]); self.push(&sig[..signature.len() + 1]);
} }
fn element_at(&self, index: usize) -> Option<&[u8]> { fn element_at(&self, index: usize) -> Option<&[u8]> {
let varint = VarInt::consensus_decode(&mut &self.content[index..]).ok()?; let varint = VarInt::consensus_decode(&mut &self.content[index..]).ok()?;
let start = index + varint.len(); let start = index + varint.len();
@ -319,8 +303,7 @@ impl Witness {
/// check whether this is actually a Taproot witness. /// check whether this is actually a Taproot witness.
pub fn tapscript(&self) -> Option<&Script> { pub fn tapscript(&self) -> Option<&Script> {
let len = self.len(); let len = self.len();
self self.last()
.last()
.map(|last_elem| { .map(|last_elem| {
// From BIP341: // From BIP341:
// If there are at least two witness elements, and the first byte of // If there are at least two witness elements, and the first byte of
@ -335,9 +318,7 @@ impl Witness {
} }
}) })
.filter(|&script_pos_from_last| len >= script_pos_from_last) .filter(|&script_pos_from_last| len >= script_pos_from_last)
.and_then(|script_pos_from_last| { .and_then(|script_pos_from_last| self.nth(len - script_pos_from_last))
self.nth(len - script_pos_from_last)
})
.map(Script::from_bytes) .map(Script::from_bytes)
} }
} }
@ -345,9 +326,7 @@ impl Witness {
impl Index<usize> for Witness { impl Index<usize> for Witness {
type Output = [u8]; type Output = [u8];
fn index(&self, index: usize) -> &Self::Output { fn index(&self, index: usize) -> &Self::Output { self.nth(index).expect("Out of Bounds") }
self.nth(index).expect("Out of Bounds")
}
} }
impl<'a> Iterator for Iter<'a> { impl<'a> Iterator for Iter<'a> {
@ -376,9 +355,7 @@ impl<'a> IntoIterator for &'a Witness {
type IntoIter = Iter<'a>; type IntoIter = Iter<'a>;
type Item = &'a [u8]; type Item = &'a [u8];
fn into_iter(self) -> Self::IntoIter { fn into_iter(self) -> Self::IntoIter { self.iter() }
self.iter()
}
} }
// Serde keep backward compatibility with old Vec<Vec<u8>> format // Serde keep backward compatibility with old Vec<Vec<u8>> format
@ -411,40 +388,45 @@ impl<'de> serde::Deserialize<'de> for Witness {
D: serde::Deserializer<'de>, D: serde::Deserializer<'de>,
{ {
struct Visitor; // Human-readable visitor. struct Visitor; // Human-readable visitor.
impl<'de> serde::de::Visitor<'de> for Visitor impl<'de> serde::de::Visitor<'de> for Visitor {
{
type Value = Witness; type Value = Witness;
fn expecting(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result { fn expecting(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
write!(f, "a sequence of hex arrays") write!(f, "a sequence of hex arrays")
} }
fn visit_seq<A: serde::de::SeqAccess<'de>>(self, mut a: A) -> Result<Self::Value, A::Error> fn visit_seq<A: serde::de::SeqAccess<'de>>(
{ self,
use crate::hashes::hex::FromHex; mut a: A,
use crate::hashes::hex::Error::*; ) -> Result<Self::Value, A::Error> {
use serde::de::{self, Unexpected}; use serde::de::{self, Unexpected};
use crate::hashes::hex::Error::*;
use crate::hashes::hex::FromHex;
let mut ret = match a.size_hint() { let mut ret = match a.size_hint() {
Some(len) => Vec::with_capacity(len), Some(len) => Vec::with_capacity(len),
None => Vec::new(), None => Vec::new(),
}; };
while let Some(elem) = a.next_element::<String>()? { while let Some(elem) = a.next_element::<String>()? {
let vec = Vec::<u8>::from_hex(&elem).map_err(|e| { let vec = Vec::<u8>::from_hex(&elem).map_err(|e| match e {
match e { InvalidChar(b) => match core::char::from_u32(b.into()) {
InvalidChar(b) => { Some(c) => de::Error::invalid_value(
match core::char::from_u32(b.into()) { Unexpected::Char(c),
Some(c) => de::Error::invalid_value(Unexpected::Char(c), &"a valid hex character"), &"a valid hex character",
None => de::Error::invalid_value(Unexpected::Unsigned(b.into()), &"a valid hex character") ),
} None => de::Error::invalid_value(
} Unexpected::Unsigned(b.into()),
OddLengthString(len) => de::Error::invalid_length(len, &"an even length string"), &"a valid hex character",
),
},
OddLengthString(len) =>
de::Error::invalid_length(len, &"an even length string"),
InvalidLength(expected, got) => { InvalidLength(expected, got) => {
let exp = format!("expected length: {}", expected); let exp = format!("expected length: {}", expected);
de::Error::invalid_length(got, &exp.as_str()) de::Error::invalid_length(got, &exp.as_str())
} }
}
})?; })?;
ret.push(vec); ret.push(vec);
} }
@ -462,37 +444,28 @@ impl<'de> serde::Deserialize<'de> for Witness {
} }
impl From<Vec<Vec<u8>>> for Witness { impl From<Vec<Vec<u8>>> for Witness {
fn from(vec: Vec<Vec<u8>>) -> Self { fn from(vec: Vec<Vec<u8>>) -> Self { Witness::from_slice(&vec) }
Witness::from_slice(&vec)
}
} }
impl From<&[&[u8]]> for Witness { impl From<&[&[u8]]> for Witness {
fn from(slice: &[&[u8]]) -> Self { fn from(slice: &[&[u8]]) -> Self { Witness::from_slice(slice) }
Witness::from_slice(slice)
}
} }
impl From<&[Vec<u8>]> for Witness { impl From<&[Vec<u8>]> for Witness {
fn from(slice: &[Vec<u8>]) -> Self { fn from(slice: &[Vec<u8>]) -> Self { Witness::from_slice(slice) }
Witness::from_slice(slice)
}
} }
impl From<Vec<&[u8]>> for Witness { impl From<Vec<&[u8]>> for Witness {
fn from(vec: Vec<&[u8]>) -> Self { fn from(vec: Vec<&[u8]>) -> Self { Witness::from_slice(&vec) }
Witness::from_slice(&vec)
}
} }
#[cfg(test)] #[cfg(test)]
mod test { mod test {
use super::*; use super::*;
use crate::consensus::{deserialize, serialize}; use crate::consensus::{deserialize, serialize};
use crate::internal_macros::hex; use crate::internal_macros::hex;
use crate::Transaction;
use crate::secp256k1::ecdsa; use crate::secp256k1::ecdsa;
use crate::Transaction;
fn append_u32_vec(mut v: Vec<u8>, n: &[u32]) -> Vec<u8> { fn append_u32_vec(mut v: Vec<u8>, n: &[u32]) -> Vec<u8> {
for &num in n { for &num in n {
@ -557,7 +530,6 @@ mod test {
assert_eq!(&witness[2], &[4u8, 5u8][..]); assert_eq!(&witness[2], &[4u8, 5u8][..]);
} }
#[test] #[test]
fn test_iter_len() { fn test_iter_len() {
let mut witness = Witness::default(); let mut witness = Witness::default();
@ -588,8 +560,7 @@ mod test {
#[test] #[test]
fn test_witness() { fn test_witness() {
let w0 = let w0 = hex!("03d2e15674941bad4a996372cb87e1856d3652606d98562fe39c5e9e7e413f2105");
hex!("03d2e15674941bad4a996372cb87e1856d3652606d98562fe39c5e9e7e413f2105");
let w1 = hex!("000000"); let w1 = hex!("000000");
let witness_vec = vec![w0.clone(), w1.clone()]; let witness_vec = vec![w0.clone(), w1.clone()];
let witness_serialized: Vec<u8> = serialize(&witness_vec); let witness_serialized: Vec<u8> = serialize(&witness_vec);
@ -655,7 +626,10 @@ mod test {
assert_eq!(expected_wit[i], wit_el.to_lower_hex_string()); assert_eq!(expected_wit[i], wit_el.to_lower_hex_string());
} }
assert_eq!(expected_wit[1], tx.input[0].witness.last().unwrap().to_lower_hex_string()); assert_eq!(expected_wit[1], tx.input[0].witness.last().unwrap().to_lower_hex_string());
assert_eq!(expected_wit[0], tx.input[0].witness.second_to_last().unwrap().to_lower_hex_string()); assert_eq!(
expected_wit[0],
tx.input[0].witness.second_to_last().unwrap().to_lower_hex_string()
);
assert_eq!(expected_wit[0], tx.input[0].witness.nth(0).unwrap().to_lower_hex_string()); assert_eq!(expected_wit[0], tx.input[0].witness.nth(0).unwrap().to_lower_hex_string());
assert_eq!(expected_wit[1], tx.input[0].witness.nth(1).unwrap().to_lower_hex_string()); assert_eq!(expected_wit[1], tx.input[0].witness.nth(1).unwrap().to_lower_hex_string());
assert_eq!(None, tx.input[0].witness.nth(2)); assert_eq!(None, tx.input[0].witness.nth(2));
@ -708,10 +682,10 @@ mod test {
} }
} }
#[cfg(bench)] #[cfg(bench)]
mod benches { mod benches {
use test::{Bencher, black_box}; use test::{black_box, Bencher};
use super::Witness; use super::Witness;
#[bench] #[bench]
@ -733,5 +707,4 @@ mod benches {
black_box(witness.to_vec()); black_box(witness.to_vec());
}); });
} }
} }