Move script hashes to primitives
Woops, this should have been done before v0.101.0 was released. Move the `ScriptHash` and `WScriptHash` types to `primitives`. Requires moving constants and error types as well. We re-export the errors because they are in the `mod.rs` file so they should appear in both `primitives::script::FooError` and `bitcoin::script::FooError`.
This commit is contained in:
parent
d1dd63d6d4
commit
3855d3cc83
|
@ -38,9 +38,9 @@ pub const PUBKEY_ADDRESS_PREFIX_TEST: u8 = 111; // 0x6f
|
|||
/// Test (tesnet, signet, regtest) script address prefix.
|
||||
pub const SCRIPT_ADDRESS_PREFIX_TEST: u8 = 196; // 0xc4
|
||||
/// The maximum allowed redeem script size for a P2SH output.
|
||||
pub const MAX_REDEEM_SCRIPT_SIZE: usize = 520;
|
||||
pub const MAX_REDEEM_SCRIPT_SIZE: usize = primitives::script::MAX_REDEEM_SCRIPT_SIZE; // 520
|
||||
/// The maximum allowed redeem script size of the witness script.
|
||||
pub const MAX_WITNESS_SCRIPT_SIZE: usize = 10_000;
|
||||
pub const MAX_WITNESS_SCRIPT_SIZE: usize = primitives::script::MAX_WITNESS_SCRIPT_SIZE; // 10_000
|
||||
/// The maximum allowed size of any single witness stack element.
|
||||
pub const MAX_STACK_ELEMENT_SIZE: usize = 520;
|
||||
/// How may blocks between halvings.
|
||||
|
|
|
@ -59,13 +59,11 @@ pub mod witness_version;
|
|||
|
||||
use core::fmt;
|
||||
|
||||
use hashes::{hash160, sha256};
|
||||
use io::{BufRead, Write};
|
||||
use primitives::opcodes::all::*;
|
||||
use primitives::opcodes::Opcode;
|
||||
|
||||
use crate::consensus::{encode, Decodable, Encodable};
|
||||
use crate::constants::{MAX_REDEEM_SCRIPT_SIZE, MAX_WITNESS_SCRIPT_SIZE};
|
||||
use crate::internal_macros::impl_asref_push_bytes;
|
||||
use crate::key::WPubkeyHash;
|
||||
use crate::prelude::Vec;
|
||||
|
@ -81,130 +79,15 @@ pub use self::{
|
|||
push_bytes::{PushBytes, PushBytesBuf, PushBytesError, PushBytesErrorReport},
|
||||
};
|
||||
#[doc(inline)]
|
||||
pub use primitives::script::{Script, ScriptBuf};
|
||||
pub use primitives::script::{
|
||||
RedeemScriptSizeError, Script, ScriptBuf, ScriptHash, WScriptHash, WitnessScriptSizeError,
|
||||
};
|
||||
|
||||
pub(crate) use self::borrowed::ScriptExtPriv;
|
||||
pub(crate) use self::owned::ScriptBufExtPriv;
|
||||
|
||||
hashes::hash_newtype! {
|
||||
/// A hash of Bitcoin Script bytecode.
|
||||
pub struct ScriptHash(hash160::Hash);
|
||||
/// SegWit version of a Bitcoin Script bytecode hash.
|
||||
pub struct WScriptHash(sha256::Hash);
|
||||
}
|
||||
|
||||
hashes::impl_hex_for_newtype!(ScriptHash, WScriptHash);
|
||||
#[cfg(feature = "serde")]
|
||||
hashes::impl_serde_for_newtype!(ScriptHash, WScriptHash);
|
||||
|
||||
impl_asref_push_bytes!(ScriptHash, WScriptHash);
|
||||
|
||||
impl ScriptHash {
|
||||
/// Constructs a new `ScriptHash` after first checking the script size.
|
||||
///
|
||||
/// # 520-byte limitation on serialized script size
|
||||
///
|
||||
/// > As a consequence of the requirement for backwards compatibility the serialized script is
|
||||
/// > itself subject to the same rules as any other PUSHDATA operation, including the rule that
|
||||
/// > no data greater than 520 bytes may be pushed to the stack. Thus it is not possible to
|
||||
/// > spend a P2SH output if the redemption script it refers to is >520 bytes in length.
|
||||
///
|
||||
/// ref: [BIP-16](https://github.com/bitcoin/bips/blob/master/bip-0016.mediawiki#user-content-520byte_limitation_on_serialized_script_size)
|
||||
pub fn from_script(redeem_script: &Script) -> Result<Self, RedeemScriptSizeError> {
|
||||
if redeem_script.len() > MAX_REDEEM_SCRIPT_SIZE {
|
||||
return Err(RedeemScriptSizeError { size: redeem_script.len() });
|
||||
}
|
||||
|
||||
Ok(ScriptHash(hash160::Hash::hash(redeem_script.as_bytes())))
|
||||
}
|
||||
|
||||
/// Constructs a new `ScriptHash` from any script irrespective of script size.
|
||||
///
|
||||
/// If you hash a script that exceeds 520 bytes in size and use it to create a P2SH output
|
||||
/// then the output will be unspendable (see [BIP-16]).
|
||||
///
|
||||
/// [BIP-16]: <https://github.com/bitcoin/bips/blob/master/bip-0016.mediawiki#user-content-520byte_limitation_on_serialized_script_size>
|
||||
pub fn from_script_unchecked(script: &Script) -> Self {
|
||||
ScriptHash(hash160::Hash::hash(script.as_bytes()))
|
||||
}
|
||||
}
|
||||
|
||||
impl WScriptHash {
|
||||
/// Constructs a new `WScriptHash` after first checking the script size.
|
||||
///
|
||||
/// # 10,000-byte limit on the witness script
|
||||
///
|
||||
/// > The witnessScript (≤ 10,000 bytes) is popped off the initial witness stack. SHA256 of the
|
||||
/// > witnessScript must match the 32-byte witness program.
|
||||
///
|
||||
/// ref: [BIP-141](https://github.com/bitcoin/bips/blob/master/bip-0141.mediawiki)
|
||||
pub fn from_script(witness_script: &Script) -> Result<Self, WitnessScriptSizeError> {
|
||||
if witness_script.len() > MAX_WITNESS_SCRIPT_SIZE {
|
||||
return Err(WitnessScriptSizeError { size: witness_script.len() });
|
||||
}
|
||||
|
||||
Ok(WScriptHash(sha256::Hash::hash(witness_script.as_bytes())))
|
||||
}
|
||||
|
||||
/// Constructs a new `WScriptHash` from any script irrespective of script size.
|
||||
///
|
||||
/// If you hash a script that exceeds 10,000 bytes in size and use it to create a Segwit
|
||||
/// output then the output will be unspendable (see [BIP-141]).
|
||||
///
|
||||
/// ref: [BIP-141](https://github.com/bitcoin/bips/blob/master/bip-0141.mediawiki)
|
||||
pub fn from_script_unchecked(script: &Script) -> Self {
|
||||
WScriptHash(sha256::Hash::hash(script.as_bytes()))
|
||||
}
|
||||
}
|
||||
|
||||
impl TryFrom<ScriptBuf> for ScriptHash {
|
||||
type Error = RedeemScriptSizeError;
|
||||
|
||||
fn try_from(redeem_script: ScriptBuf) -> Result<Self, Self::Error> {
|
||||
Self::from_script(&redeem_script)
|
||||
}
|
||||
}
|
||||
|
||||
impl TryFrom<&ScriptBuf> for ScriptHash {
|
||||
type Error = RedeemScriptSizeError;
|
||||
|
||||
fn try_from(redeem_script: &ScriptBuf) -> Result<Self, Self::Error> {
|
||||
Self::from_script(redeem_script)
|
||||
}
|
||||
}
|
||||
|
||||
impl TryFrom<&Script> for ScriptHash {
|
||||
type Error = RedeemScriptSizeError;
|
||||
|
||||
fn try_from(redeem_script: &Script) -> Result<Self, Self::Error> {
|
||||
Self::from_script(redeem_script)
|
||||
}
|
||||
}
|
||||
|
||||
impl TryFrom<ScriptBuf> for WScriptHash {
|
||||
type Error = WitnessScriptSizeError;
|
||||
|
||||
fn try_from(witness_script: ScriptBuf) -> Result<Self, Self::Error> {
|
||||
Self::from_script(&witness_script)
|
||||
}
|
||||
}
|
||||
|
||||
impl TryFrom<&ScriptBuf> for WScriptHash {
|
||||
type Error = WitnessScriptSizeError;
|
||||
|
||||
fn try_from(witness_script: &ScriptBuf) -> Result<Self, Self::Error> {
|
||||
Self::from_script(witness_script)
|
||||
}
|
||||
}
|
||||
|
||||
impl TryFrom<&Script> for WScriptHash {
|
||||
type Error = WitnessScriptSizeError;
|
||||
|
||||
fn try_from(witness_script: &Script) -> Result<Self, Self::Error> {
|
||||
Self::from_script(witness_script)
|
||||
}
|
||||
}
|
||||
|
||||
/// Constructs a new [`ScriptBuf`] containing the script code used for spending a P2WPKH output.
|
||||
///
|
||||
/// The `scriptCode` is described in [BIP143].
|
||||
|
@ -383,39 +266,3 @@ impl std::error::Error for Error {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Error while hashing a redeem script.
|
||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||
pub struct RedeemScriptSizeError {
|
||||
/// Invalid redeem script size (cannot exceed 520 bytes).
|
||||
pub size: usize,
|
||||
}
|
||||
|
||||
internals::impl_from_infallible!(RedeemScriptSizeError);
|
||||
|
||||
impl fmt::Display for RedeemScriptSizeError {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
write!(f, "redeem script size exceeds {} bytes: {}", MAX_REDEEM_SCRIPT_SIZE, self.size)
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "std")]
|
||||
impl std::error::Error for RedeemScriptSizeError {}
|
||||
|
||||
/// Error while hashing a witness script.
|
||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||
pub struct WitnessScriptSizeError {
|
||||
/// Invalid witness script size (cannot exceed 10,000 bytes).
|
||||
pub size: usize,
|
||||
}
|
||||
|
||||
internals::impl_from_infallible!(WitnessScriptSizeError);
|
||||
|
||||
impl fmt::Display for WitnessScriptSizeError {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
write!(f, "witness script size exceeds {} bytes: {}", MAX_WITNESS_SCRIPT_SIZE, self.size)
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "std")]
|
||||
impl std::error::Error for WitnessScriptSizeError {}
|
||||
|
|
|
@ -11,6 +11,7 @@ use core::cmp::Ordering;
|
|||
use core::fmt;
|
||||
use core::ops::{Deref, DerefMut};
|
||||
|
||||
use hashes::{hash160, sha256};
|
||||
use hex::DisplayHex;
|
||||
use internals::script::{self, PushDataLenLen};
|
||||
|
||||
|
@ -28,6 +29,164 @@ pub use self::{
|
|||
owned::ScriptBuf,
|
||||
};
|
||||
|
||||
/// The maximum allowed redeem script size for a P2SH output.
|
||||
pub const MAX_REDEEM_SCRIPT_SIZE: usize = 520;
|
||||
/// The maximum allowed redeem script size of the witness script.
|
||||
pub const MAX_WITNESS_SCRIPT_SIZE: usize = 10_000;
|
||||
|
||||
hashes::hash_newtype! {
|
||||
/// A hash of Bitcoin Script bytecode.
|
||||
pub struct ScriptHash(hash160::Hash);
|
||||
/// SegWit version of a Bitcoin Script bytecode hash.
|
||||
pub struct WScriptHash(sha256::Hash);
|
||||
}
|
||||
|
||||
hashes::impl_hex_for_newtype!(ScriptHash, WScriptHash);
|
||||
#[cfg(feature = "serde")]
|
||||
hashes::impl_serde_for_newtype!(ScriptHash, WScriptHash);
|
||||
|
||||
impl ScriptHash {
|
||||
/// Constructs a new `ScriptHash` after first checking the script size.
|
||||
///
|
||||
/// # 520-byte limitation on serialized script size
|
||||
///
|
||||
/// > As a consequence of the requirement for backwards compatibility the serialized script is
|
||||
/// > itself subject to the same rules as any other PUSHDATA operation, including the rule that
|
||||
/// > no data greater than 520 bytes may be pushed to the stack. Thus it is not possible to
|
||||
/// > spend a P2SH output if the redemption script it refers to is >520 bytes in length.
|
||||
///
|
||||
/// ref: [BIP-16](https://github.com/bitcoin/bips/blob/master/bip-0016.mediawiki#user-content-520byte_limitation_on_serialized_script_size)
|
||||
pub fn from_script(redeem_script: &Script) -> Result<Self, RedeemScriptSizeError> {
|
||||
if redeem_script.len() > MAX_REDEEM_SCRIPT_SIZE {
|
||||
return Err(RedeemScriptSizeError { size: redeem_script.len() });
|
||||
}
|
||||
|
||||
Ok(ScriptHash(hash160::Hash::hash(redeem_script.as_bytes())))
|
||||
}
|
||||
|
||||
/// Constructs a new `ScriptHash` from any script irrespective of script size.
|
||||
///
|
||||
/// If you hash a script that exceeds 520 bytes in size and use it to create a P2SH output
|
||||
/// then the output will be unspendable (see [BIP-16]).
|
||||
///
|
||||
/// [BIP-16]: <https://github.com/bitcoin/bips/blob/master/bip-0016.mediawiki#user-content-520byte_limitation_on_serialized_script_size>
|
||||
pub fn from_script_unchecked(script: &Script) -> Self {
|
||||
ScriptHash(hash160::Hash::hash(script.as_bytes()))
|
||||
}
|
||||
}
|
||||
|
||||
impl WScriptHash {
|
||||
/// Constructs a new `WScriptHash` after first checking the script size.
|
||||
///
|
||||
/// # 10,000-byte limit on the witness script
|
||||
///
|
||||
/// > The witnessScript (≤ 10,000 bytes) is popped off the initial witness stack. SHA256 of the
|
||||
/// > witnessScript must match the 32-byte witness program.
|
||||
///
|
||||
/// ref: [BIP-141](https://github.com/bitcoin/bips/blob/master/bip-0141.mediawiki)
|
||||
pub fn from_script(witness_script: &Script) -> Result<Self, WitnessScriptSizeError> {
|
||||
if witness_script.len() > MAX_WITNESS_SCRIPT_SIZE {
|
||||
return Err(WitnessScriptSizeError { size: witness_script.len() });
|
||||
}
|
||||
|
||||
Ok(WScriptHash(sha256::Hash::hash(witness_script.as_bytes())))
|
||||
}
|
||||
|
||||
/// Constructs a new `WScriptHash` from any script irrespective of script size.
|
||||
///
|
||||
/// If you hash a script that exceeds 10,000 bytes in size and use it to create a Segwit
|
||||
/// output then the output will be unspendable (see [BIP-141]).
|
||||
///
|
||||
/// ref: [BIP-141](https://github.com/bitcoin/bips/blob/master/bip-0141.mediawiki)
|
||||
pub fn from_script_unchecked(script: &Script) -> Self {
|
||||
WScriptHash(sha256::Hash::hash(script.as_bytes()))
|
||||
}
|
||||
}
|
||||
|
||||
impl TryFrom<ScriptBuf> for ScriptHash {
|
||||
type Error = RedeemScriptSizeError;
|
||||
|
||||
fn try_from(redeem_script: ScriptBuf) -> Result<Self, Self::Error> {
|
||||
Self::from_script(&redeem_script)
|
||||
}
|
||||
}
|
||||
|
||||
impl TryFrom<&ScriptBuf> for ScriptHash {
|
||||
type Error = RedeemScriptSizeError;
|
||||
|
||||
fn try_from(redeem_script: &ScriptBuf) -> Result<Self, Self::Error> {
|
||||
Self::from_script(redeem_script)
|
||||
}
|
||||
}
|
||||
|
||||
impl TryFrom<&Script> for ScriptHash {
|
||||
type Error = RedeemScriptSizeError;
|
||||
|
||||
fn try_from(redeem_script: &Script) -> Result<Self, Self::Error> {
|
||||
Self::from_script(redeem_script)
|
||||
}
|
||||
}
|
||||
|
||||
impl TryFrom<ScriptBuf> for WScriptHash {
|
||||
type Error = WitnessScriptSizeError;
|
||||
|
||||
fn try_from(witness_script: ScriptBuf) -> Result<Self, Self::Error> {
|
||||
Self::from_script(&witness_script)
|
||||
}
|
||||
}
|
||||
|
||||
impl TryFrom<&ScriptBuf> for WScriptHash {
|
||||
type Error = WitnessScriptSizeError;
|
||||
|
||||
fn try_from(witness_script: &ScriptBuf) -> Result<Self, Self::Error> {
|
||||
Self::from_script(witness_script)
|
||||
}
|
||||
}
|
||||
|
||||
impl TryFrom<&Script> for WScriptHash {
|
||||
type Error = WitnessScriptSizeError;
|
||||
|
||||
fn try_from(witness_script: &Script) -> Result<Self, Self::Error> {
|
||||
Self::from_script(witness_script)
|
||||
}
|
||||
}
|
||||
|
||||
/// Error while hashing a redeem script.
|
||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||
pub struct RedeemScriptSizeError {
|
||||
/// Invalid redeem script size (cannot exceed 520 bytes).
|
||||
pub size: usize,
|
||||
}
|
||||
|
||||
internals::impl_from_infallible!(RedeemScriptSizeError);
|
||||
|
||||
impl fmt::Display for RedeemScriptSizeError {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
write!(f, "redeem script size exceeds {} bytes: {}", MAX_REDEEM_SCRIPT_SIZE, self.size)
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "std")]
|
||||
impl std::error::Error for RedeemScriptSizeError {}
|
||||
|
||||
/// Error while hashing a witness script.
|
||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||
pub struct WitnessScriptSizeError {
|
||||
/// Invalid witness script size (cannot exceed 10,000 bytes).
|
||||
pub size: usize,
|
||||
}
|
||||
|
||||
internals::impl_from_infallible!(WitnessScriptSizeError);
|
||||
|
||||
impl fmt::Display for WitnessScriptSizeError {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
write!(f, "witness script size exceeds {} bytes: {}", MAX_WITNESS_SCRIPT_SIZE, self.size)
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "std")]
|
||||
impl std::error::Error for WitnessScriptSizeError {}
|
||||
|
||||
// We keep all the `Script` and `ScriptBuf` impls together since its easier to see side-by-side.
|
||||
|
||||
impl From<ScriptBuf> for Box<Script> {
|
||||
|
|
Loading…
Reference in New Issue