Introduce two extensions traits for ScriptBuf
In preparation for moving the `ScritpBuf` type to `primitives` add a public and private extension trait for the functions we want to leave here in `bitcoin`. Note, includes a change to the `difine_extension_trait` metavariable used on `$gent` from `ident` to `path` to support the generic `AsRef<PushBytes>`.
This commit is contained in:
parent
ae0a5bd64a
commit
2bb90b8203
|
@ -37,6 +37,7 @@ use bitcoin::bip32::{ChildNumber, DerivationPath, Fingerprint, IntoDerivationPat
|
||||||
use bitcoin::consensus::encode;
|
use bitcoin::consensus::encode;
|
||||||
use bitcoin::locktime::absolute;
|
use bitcoin::locktime::absolute;
|
||||||
use bitcoin::psbt::{self, Input, Psbt, PsbtSighashType};
|
use bitcoin::psbt::{self, Input, Psbt, PsbtSighashType};
|
||||||
|
use bitcoin::script::ScriptBufExt as _;
|
||||||
use bitcoin::secp256k1::{Secp256k1, Signing, Verification};
|
use bitcoin::secp256k1::{Secp256k1, Signing, Verification};
|
||||||
use bitcoin::{
|
use bitcoin::{
|
||||||
transaction, Address, Amount, CompressedPublicKey, Network, OutPoint, ScriptBuf, Sequence,
|
transaction, Address, Amount, CompressedPublicKey, Network, OutPoint, ScriptBuf, Sequence,
|
||||||
|
|
|
@ -84,7 +84,7 @@ use bitcoin::consensus::encode;
|
||||||
use bitcoin::key::{TapTweak, XOnlyPublicKey};
|
use bitcoin::key::{TapTweak, XOnlyPublicKey};
|
||||||
use bitcoin::opcodes::all::{OP_CHECKSIG, OP_CLTV, OP_DROP};
|
use bitcoin::opcodes::all::{OP_CHECKSIG, OP_CLTV, OP_DROP};
|
||||||
use bitcoin::psbt::{self, Input, Output, Psbt, PsbtSighashType};
|
use bitcoin::psbt::{self, Input, Output, Psbt, PsbtSighashType};
|
||||||
use bitcoin::script::ScriptExt as _;
|
use bitcoin::script::{ScriptBufExt as _, ScriptExt as _};
|
||||||
use bitcoin::secp256k1::Secp256k1;
|
use bitcoin::secp256k1::Secp256k1;
|
||||||
use bitcoin::sighash::{self, SighashCache, TapSighash, TapSighashType};
|
use bitcoin::sighash::{self, SighashCache, TapSighash, TapSighashType};
|
||||||
use bitcoin::taproot::{self, LeafVersion, TapLeafHash, TaprootBuilder, TaprootSpendInfo};
|
use bitcoin::taproot::{self, LeafVersion, TapLeafHash, TaprootBuilder, TaprootSpendInfo};
|
||||||
|
|
|
@ -894,6 +894,7 @@ mod tests {
|
||||||
use super::*;
|
use super::*;
|
||||||
use crate::network::params;
|
use crate::network::params;
|
||||||
use crate::network::Network::{Bitcoin, Testnet};
|
use crate::network::Network::{Bitcoin, Testnet};
|
||||||
|
use crate::script::ScriptBufExt as _;
|
||||||
|
|
||||||
fn roundtrips(addr: &Address, network: Network) {
|
fn roundtrips(addr: &Address, network: Network) {
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
|
|
|
@ -7,7 +7,7 @@ use crate::locktime::absolute;
|
||||||
use crate::opcodes::all::*;
|
use crate::opcodes::all::*;
|
||||||
use crate::opcodes::{self, Opcode};
|
use crate::opcodes::{self, Opcode};
|
||||||
use crate::prelude::Vec;
|
use crate::prelude::Vec;
|
||||||
use crate::script::{ScriptExt as _, ScriptExtPriv as _};
|
use crate::script::{ScriptBufExt as _, ScriptExt as _, ScriptExtPriv as _};
|
||||||
use crate::Sequence;
|
use crate::Sequence;
|
||||||
|
|
||||||
/// An Object which can be used to construct a script piece by piece.
|
/// An Object which can be used to construct a script piece by piece.
|
||||||
|
|
|
@ -1,6 +1,8 @@
|
||||||
// SPDX-License-Identifier: CC0-1.0
|
// SPDX-License-Identifier: CC0-1.0
|
||||||
|
|
||||||
use super::{read_uint_iter, Error, PushBytes, Script, ScriptBuf, UintError};
|
use super::{
|
||||||
|
read_uint_iter, Error, PushBytes, Script, ScriptBuf, ScriptBufExtPriv as _, UintError,
|
||||||
|
};
|
||||||
use crate::opcodes::{self, Opcode};
|
use crate::opcodes::{self, Opcode};
|
||||||
|
|
||||||
/// 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.
|
||||||
|
|
|
@ -89,30 +89,30 @@ impl ScriptBuf {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
mod tmp_pub {
|
crate::internal_macros::define_extension_trait! {
|
||||||
use super::*;
|
/// Extension functionality for the [`ScriptBuf`] type.
|
||||||
impl ScriptBuf {
|
pub trait ScriptBufExt impl for ScriptBuf {
|
||||||
/// Creates a new script builder
|
/// Creates a new script builder
|
||||||
pub fn builder() -> Builder { Builder::new() }
|
fn builder() -> Builder { Builder::new() }
|
||||||
|
|
||||||
/// 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 {
|
fn new_op_return<T: AsRef<PushBytes>>(data: T) -> Self {
|
||||||
Builder::new().push_opcode(OP_RETURN).push_slice(data).into_script()
|
Builder::new().push_opcode(OP_RETURN).push_slice(data).into_script()
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Creates a [`ScriptBuf`] from a hex string.
|
/// Creates a [`ScriptBuf`] from a hex string.
|
||||||
pub fn from_hex(s: &str) -> Result<Self, hex::HexToBytesError> {
|
fn from_hex(s: &str) -> Result<ScriptBuf, hex::HexToBytesError> {
|
||||||
let v = Vec::from_hex(s)?;
|
let v = Vec::from_hex(s)?;
|
||||||
Ok(ScriptBuf::from_bytes(v))
|
Ok(ScriptBuf::from_bytes(v))
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Adds a single opcode to the script.
|
/// Adds a single opcode to the script.
|
||||||
pub fn push_opcode(&mut self, data: Opcode) { self.as_byte_vec().push(data.to_u8()); }
|
fn push_opcode(&mut self, data: Opcode) { self.as_byte_vec().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) {
|
fn push_slice<T: AsRef<PushBytes>>(&mut self, data: T) {
|
||||||
let data = data.as_ref();
|
let data = data.as_ref();
|
||||||
self.reserve(Self::reserved_len_for_slice(data.len()));
|
self.reserve(ScriptBuf::reserved_len_for_slice(data.len()));
|
||||||
self.push_slice_no_opt(data);
|
self.push_slice_no_opt(data);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -122,7 +122,7 @@ mod tmp_pub {
|
||||||
///
|
///
|
||||||
/// The method panics if the instruction is a data push with length greater or equal to
|
/// The method panics if the instruction is a data push with length greater or equal to
|
||||||
/// 0x100000000.
|
/// 0x100000000.
|
||||||
pub fn push_instruction(&mut self, instruction: Instruction<'_>) {
|
fn push_instruction(&mut self, instruction: Instruction<'_>) {
|
||||||
match instruction {
|
match instruction {
|
||||||
Instruction::Op(opcode) => self.push_opcode(opcode),
|
Instruction::Op(opcode) => self.push_opcode(opcode),
|
||||||
Instruction::PushBytes(bytes) => self.push_slice(bytes),
|
Instruction::PushBytes(bytes) => self.push_slice(bytes),
|
||||||
|
@ -130,7 +130,7 @@ mod tmp_pub {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Like push_instruction, but avoids calling `reserve` to not re-check the length.
|
/// Like push_instruction, but avoids calling `reserve` to not re-check the length.
|
||||||
pub fn push_instruction_no_opt(&mut self, instruction: Instruction<'_>) {
|
fn push_instruction_no_opt(&mut self, instruction: Instruction<'_>) {
|
||||||
match instruction {
|
match instruction {
|
||||||
Instruction::Op(opcode) => self.push_opcode(opcode),
|
Instruction::Op(opcode) => self.push_opcode(opcode),
|
||||||
Instruction::PushBytes(bytes) => self.push_slice_no_opt(bytes),
|
Instruction::PushBytes(bytes) => self.push_slice_no_opt(bytes),
|
||||||
|
@ -151,23 +151,22 @@ mod tmp_pub {
|
||||||
/// 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) { self.push_verify(self.last_opcode()); }
|
fn scan_and_push_verify(&mut self) { self.push_verify(self.last_opcode()); }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
mod tmp_priv {
|
crate::internal_macros::define_extension_trait! {
|
||||||
use super::*;
|
pub(crate) trait ScriptBufExtPriv impl for ScriptBuf {
|
||||||
impl ScriptBuf {
|
|
||||||
/// Pretends to convert `&mut ScriptBuf` to `&mut Vec<u8>` so that it can be modified.
|
/// Pretends to convert `&mut ScriptBuf` to `&mut Vec<u8>` so that it can be modified.
|
||||||
///
|
///
|
||||||
/// Note: if the returned value leaks the original `ScriptBuf` will become empty.
|
/// Note: if the returned value leaks the original `ScriptBuf` will become empty.
|
||||||
pub(crate) fn as_byte_vec(&mut self) -> ScriptBufAsVec<'_> {
|
fn as_byte_vec(&mut self) -> ScriptBufAsVec<'_> {
|
||||||
let vec = core::mem::take(self).into_bytes();
|
let vec = core::mem::take(self).into_bytes();
|
||||||
ScriptBufAsVec(self, vec)
|
ScriptBufAsVec(self, vec)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Pushes the slice without reserving
|
/// Pushes the slice without reserving
|
||||||
pub(crate) fn push_slice_no_opt(&mut self, data: &PushBytes) {
|
fn push_slice_no_opt(&mut self, data: &PushBytes) {
|
||||||
let mut this = self.as_byte_vec();
|
let mut this = self.as_byte_vec();
|
||||||
// Start with a PUSH opcode
|
// Start with a PUSH opcode
|
||||||
match data.len().to_u64() {
|
match data.len().to_u64() {
|
||||||
|
@ -197,7 +196,7 @@ mod tmp_priv {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Computes the sum of `len` and the length of an appropriate push opcode.
|
/// Computes the sum of `len` and the length of an appropriate push opcode.
|
||||||
pub(crate) fn reserved_len_for_slice(len: usize) -> usize {
|
fn reserved_len_for_slice(len: usize) -> usize {
|
||||||
len + match len {
|
len + match len {
|
||||||
0..=0x4b => 1,
|
0..=0x4b => 1,
|
||||||
0x4c..=0xff => 2,
|
0x4c..=0xff => 2,
|
||||||
|
@ -211,7 +210,7 @@ mod tmp_priv {
|
||||||
/// alternative.
|
/// alternative.
|
||||||
///
|
///
|
||||||
/// See the public fn [`Self::scan_and_push_verify`] to learn more.
|
/// See the public fn [`Self::scan_and_push_verify`] to learn more.
|
||||||
pub(crate) fn push_verify(&mut self, last_opcode: Option<Opcode>) {
|
fn push_verify(&mut self, last_opcode: Option<Opcode>) {
|
||||||
match opcode_to_verify(last_opcode) {
|
match opcode_to_verify(last_opcode) {
|
||||||
Some(opcode) => {
|
Some(opcode) => {
|
||||||
self.as_byte_vec().pop();
|
self.as_byte_vec().pop();
|
||||||
|
|
|
@ -13,6 +13,8 @@ use io::Write;
|
||||||
|
|
||||||
use crate::prelude::{DisplayHex, Vec};
|
use crate::prelude::{DisplayHex, Vec};
|
||||||
use crate::script::PushBytes;
|
use crate::script::PushBytes;
|
||||||
|
#[cfg(doc)]
|
||||||
|
use crate::script::ScriptBufExt as _;
|
||||||
use crate::sighash::{EcdsaSighashType, NonStandardSighashTypeError};
|
use crate::sighash::{EcdsaSighashType, NonStandardSighashTypeError};
|
||||||
|
|
||||||
const MAX_SIG_LEN: usize = 73;
|
const MAX_SIG_LEN: usize = 73;
|
||||||
|
|
|
@ -1470,6 +1470,7 @@ mod tests {
|
||||||
use super::*;
|
use super::*;
|
||||||
use crate::consensus::deserialize;
|
use crate::consensus::deserialize;
|
||||||
use crate::locktime::absolute;
|
use crate::locktime::absolute;
|
||||||
|
use crate::script::ScriptBufExt as _;
|
||||||
|
|
||||||
extern crate serde_json;
|
extern crate serde_json;
|
||||||
|
|
||||||
|
|
|
@ -251,7 +251,7 @@ macro_rules! define_extension_trait {
|
||||||
($(#[$($trait_attrs:tt)*])* $trait_vis:vis trait $trait_name:ident impl for $ty:ident {
|
($(#[$($trait_attrs:tt)*])* $trait_vis:vis trait $trait_name:ident impl for $ty:ident {
|
||||||
$(
|
$(
|
||||||
$(#[$($fn_attrs:tt)*])*
|
$(#[$($fn_attrs:tt)*])*
|
||||||
fn $fn:ident$(<$($gen:ident: $gent:ident),*>)?($($params:tt)*) $( -> $ret:ty )? $body:block
|
fn $fn:ident$(<$($gen:ident: $gent:path),*>)?($($params:tt)*) $( -> $ret:ty )? $body:block
|
||||||
)*
|
)*
|
||||||
}) => {
|
}) => {
|
||||||
$(#[$($trait_attrs)*])* $trait_vis trait $trait_name {
|
$(#[$($trait_attrs)*])* $trait_vis trait $trait_name {
|
||||||
|
|
|
@ -1216,7 +1216,7 @@ mod tests {
|
||||||
use crate::locktime::absolute;
|
use crate::locktime::absolute;
|
||||||
use crate::network::NetworkKind;
|
use crate::network::NetworkKind;
|
||||||
use crate::psbt::serialize::{Deserialize, Serialize};
|
use crate::psbt::serialize::{Deserialize, Serialize};
|
||||||
use crate::script::ScriptBuf;
|
use crate::script::{ScriptBuf, ScriptBufExt as _};
|
||||||
use crate::transaction::{self, OutPoint, TxIn};
|
use crate::transaction::{self, OutPoint, TxIn};
|
||||||
use crate::witness::Witness;
|
use crate::witness::Witness;
|
||||||
use crate::Sequence;
|
use crate::Sequence;
|
||||||
|
|
|
@ -383,6 +383,7 @@ fn key_source_len(key_source: &KeySource) -> usize { 4 + 4 * (key_source.1).as_r
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use super::*;
|
use super::*;
|
||||||
|
use crate::script::ScriptBufExt as _;
|
||||||
|
|
||||||
// Composes tree matching a given depth map, filled with dumb script leafs,
|
// Composes tree matching a given depth map, filled with dumb script leafs,
|
||||||
// each of which consists of a single push-int op code, with int value
|
// each of which consists of a single push-int op code, with int value
|
||||||
|
|
|
@ -1544,6 +1544,7 @@ mod test {
|
||||||
use secp256k1::VerifyOnly;
|
use secp256k1::VerifyOnly;
|
||||||
|
|
||||||
use super::*;
|
use super::*;
|
||||||
|
use crate::script::ScriptBufExt as _;
|
||||||
use crate::sighash::{TapSighash, TapSighashTag};
|
use crate::sighash::{TapSighash, TapSighashTag};
|
||||||
use crate::{Address, KnownHrp};
|
use crate::{Address, KnownHrp};
|
||||||
extern crate serde_json;
|
extern crate serde_json;
|
||||||
|
|
|
@ -9,7 +9,7 @@ use bitcoin::consensus::encode::{deserialize, serialize_hex};
|
||||||
use bitcoin::hex::FromHex;
|
use bitcoin::hex::FromHex;
|
||||||
use bitcoin::opcodes::OP_0;
|
use bitcoin::opcodes::OP_0;
|
||||||
use bitcoin::psbt::{Psbt, PsbtSighashType};
|
use bitcoin::psbt::{Psbt, PsbtSighashType};
|
||||||
use bitcoin::script::PushBytes;
|
use bitcoin::script::{PushBytes, ScriptBufExt as _};
|
||||||
use bitcoin::secp256k1::Secp256k1;
|
use bitcoin::secp256k1::Secp256k1;
|
||||||
use bitcoin::{
|
use bitcoin::{
|
||||||
absolute, script, transaction, Amount, Denomination, NetworkKind, OutPoint, PrivateKey,
|
absolute, script, transaction, Amount, Denomination, NetworkKind, OutPoint, PrivateKey,
|
||||||
|
|
|
@ -33,6 +33,7 @@ use bitcoin::hex::FromHex;
|
||||||
use bitcoin::locktime::{absolute, relative};
|
use bitcoin::locktime::{absolute, relative};
|
||||||
use bitcoin::psbt::raw::{self, Key, Pair, ProprietaryKey};
|
use bitcoin::psbt::raw::{self, Key, Pair, ProprietaryKey};
|
||||||
use bitcoin::psbt::{Input, Output, Psbt, PsbtSighashType};
|
use bitcoin::psbt::{Input, Output, Psbt, PsbtSighashType};
|
||||||
|
use bitcoin::script::ScriptBufExt as _;
|
||||||
use bitcoin::sighash::{EcdsaSighashType, TapSighashType};
|
use bitcoin::sighash::{EcdsaSighashType, TapSighashType};
|
||||||
use bitcoin::taproot::{self, ControlBlock, LeafVersion, TapTree, TaprootBuilder};
|
use bitcoin::taproot::{self, ControlBlock, LeafVersion, TapTree, TaprootBuilder};
|
||||||
use bitcoin::witness::Witness;
|
use bitcoin::witness::Witness;
|
||||||
|
|
Loading…
Reference in New Issue