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::locktime::absolute;
|
||||
use bitcoin::psbt::{self, Input, Psbt, PsbtSighashType};
|
||||
use bitcoin::script::ScriptBufExt as _;
|
||||
use bitcoin::secp256k1::{Secp256k1, Signing, Verification};
|
||||
use bitcoin::{
|
||||
transaction, Address, Amount, CompressedPublicKey, Network, OutPoint, ScriptBuf, Sequence,
|
||||
|
|
|
@ -84,7 +84,7 @@ use bitcoin::consensus::encode;
|
|||
use bitcoin::key::{TapTweak, XOnlyPublicKey};
|
||||
use bitcoin::opcodes::all::{OP_CHECKSIG, OP_CLTV, OP_DROP};
|
||||
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::sighash::{self, SighashCache, TapSighash, TapSighashType};
|
||||
use bitcoin::taproot::{self, LeafVersion, TapLeafHash, TaprootBuilder, TaprootSpendInfo};
|
||||
|
|
|
@ -894,6 +894,7 @@ mod tests {
|
|||
use super::*;
|
||||
use crate::network::params;
|
||||
use crate::network::Network::{Bitcoin, Testnet};
|
||||
use crate::script::ScriptBufExt as _;
|
||||
|
||||
fn roundtrips(addr: &Address, network: Network) {
|
||||
assert_eq!(
|
||||
|
|
|
@ -7,7 +7,7 @@ use crate::locktime::absolute;
|
|||
use crate::opcodes::all::*;
|
||||
use crate::opcodes::{self, Opcode};
|
||||
use crate::prelude::Vec;
|
||||
use crate::script::{ScriptExt as _, ScriptExtPriv as _};
|
||||
use crate::script::{ScriptBufExt as _, ScriptExt as _, ScriptExtPriv as _};
|
||||
use crate::Sequence;
|
||||
|
||||
/// An Object which can be used to construct a script piece by piece.
|
||||
|
|
|
@ -1,6 +1,8 @@
|
|||
// 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};
|
||||
|
||||
/// A "parsed opcode" which allows iterating over a [`Script`] in a more sensible way.
|
||||
|
|
|
@ -89,30 +89,30 @@ impl ScriptBuf {
|
|||
}
|
||||
}
|
||||
|
||||
mod tmp_pub {
|
||||
use super::*;
|
||||
impl ScriptBuf {
|
||||
crate::internal_macros::define_extension_trait! {
|
||||
/// Extension functionality for the [`ScriptBuf`] type.
|
||||
pub trait ScriptBufExt impl for ScriptBuf {
|
||||
/// 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.
|
||||
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()
|
||||
}
|
||||
|
||||
/// 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)?;
|
||||
Ok(ScriptBuf::from_bytes(v))
|
||||
}
|
||||
|
||||
/// 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.
|
||||
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();
|
||||
self.reserve(Self::reserved_len_for_slice(data.len()));
|
||||
self.reserve(ScriptBuf::reserved_len_for_slice(data.len()));
|
||||
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
|
||||
/// 0x100000000.
|
||||
pub fn push_instruction(&mut self, instruction: Instruction<'_>) {
|
||||
fn push_instruction(&mut self, instruction: Instruction<'_>) {
|
||||
match instruction {
|
||||
Instruction::Op(opcode) => self.push_opcode(opcode),
|
||||
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.
|
||||
pub fn push_instruction_no_opt(&mut self, instruction: Instruction<'_>) {
|
||||
fn push_instruction_no_opt(&mut self, instruction: Instruction<'_>) {
|
||||
match instruction {
|
||||
Instruction::Op(opcode) => self.push_opcode(opcode),
|
||||
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
|
||||
/// `Builder` if you're creating the script from scratch or if you want to push `OP_VERIFY`
|
||||
/// 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 {
|
||||
use super::*;
|
||||
impl ScriptBuf {
|
||||
crate::internal_macros::define_extension_trait! {
|
||||
pub(crate) trait ScriptBufExtPriv impl for ScriptBuf {
|
||||
/// 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.
|
||||
pub(crate) fn as_byte_vec(&mut self) -> ScriptBufAsVec<'_> {
|
||||
fn as_byte_vec(&mut self) -> ScriptBufAsVec<'_> {
|
||||
let vec = core::mem::take(self).into_bytes();
|
||||
ScriptBufAsVec(self, vec)
|
||||
}
|
||||
|
||||
/// 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();
|
||||
// Start with a PUSH opcode
|
||||
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.
|
||||
pub(crate) fn reserved_len_for_slice(len: usize) -> usize {
|
||||
fn reserved_len_for_slice(len: usize) -> usize {
|
||||
len + match len {
|
||||
0..=0x4b => 1,
|
||||
0x4c..=0xff => 2,
|
||||
|
@ -211,7 +210,7 @@ mod tmp_priv {
|
|||
/// alternative.
|
||||
///
|
||||
/// 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) {
|
||||
Some(opcode) => {
|
||||
self.as_byte_vec().pop();
|
||||
|
|
|
@ -13,6 +13,8 @@ use io::Write;
|
|||
|
||||
use crate::prelude::{DisplayHex, Vec};
|
||||
use crate::script::PushBytes;
|
||||
#[cfg(doc)]
|
||||
use crate::script::ScriptBufExt as _;
|
||||
use crate::sighash::{EcdsaSighashType, NonStandardSighashTypeError};
|
||||
|
||||
const MAX_SIG_LEN: usize = 73;
|
||||
|
|
|
@ -1470,6 +1470,7 @@ mod tests {
|
|||
use super::*;
|
||||
use crate::consensus::deserialize;
|
||||
use crate::locktime::absolute;
|
||||
use crate::script::ScriptBufExt as _;
|
||||
|
||||
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 {
|
||||
$(
|
||||
$(#[$($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 {
|
||||
|
|
|
@ -1216,7 +1216,7 @@ mod tests {
|
|||
use crate::locktime::absolute;
|
||||
use crate::network::NetworkKind;
|
||||
use crate::psbt::serialize::{Deserialize, Serialize};
|
||||
use crate::script::ScriptBuf;
|
||||
use crate::script::{ScriptBuf, ScriptBufExt as _};
|
||||
use crate::transaction::{self, OutPoint, TxIn};
|
||||
use crate::witness::Witness;
|
||||
use crate::Sequence;
|
||||
|
|
|
@ -383,6 +383,7 @@ fn key_source_len(key_source: &KeySource) -> usize { 4 + 4 * (key_source.1).as_r
|
|||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use crate::script::ScriptBufExt as _;
|
||||
|
||||
// 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
|
||||
|
|
|
@ -1544,6 +1544,7 @@ mod test {
|
|||
use secp256k1::VerifyOnly;
|
||||
|
||||
use super::*;
|
||||
use crate::script::ScriptBufExt as _;
|
||||
use crate::sighash::{TapSighash, TapSighashTag};
|
||||
use crate::{Address, KnownHrp};
|
||||
extern crate serde_json;
|
||||
|
|
|
@ -9,7 +9,7 @@ use bitcoin::consensus::encode::{deserialize, serialize_hex};
|
|||
use bitcoin::hex::FromHex;
|
||||
use bitcoin::opcodes::OP_0;
|
||||
use bitcoin::psbt::{Psbt, PsbtSighashType};
|
||||
use bitcoin::script::PushBytes;
|
||||
use bitcoin::script::{PushBytes, ScriptBufExt as _};
|
||||
use bitcoin::secp256k1::Secp256k1;
|
||||
use bitcoin::{
|
||||
absolute, script, transaction, Amount, Denomination, NetworkKind, OutPoint, PrivateKey,
|
||||
|
|
|
@ -33,6 +33,7 @@ use bitcoin::hex::FromHex;
|
|||
use bitcoin::locktime::{absolute, relative};
|
||||
use bitcoin::psbt::raw::{self, Key, Pair, ProprietaryKey};
|
||||
use bitcoin::psbt::{Input, Output, Psbt, PsbtSighashType};
|
||||
use bitcoin::script::ScriptBufExt as _;
|
||||
use bitcoin::sighash::{EcdsaSighashType, TapSighashType};
|
||||
use bitcoin::taproot::{self, ControlBlock, LeafVersion, TapTree, TaprootBuilder};
|
||||
use bitcoin::witness::Witness;
|
||||
|
|
Loading…
Reference in New Issue