primitives: split ScriptSig and ScriptSigBuf from Script and ScriptBuf
What changed, and why it matters
This commit is a routine internal refactoring in the rust-bitcoin library. It introduces separate types for transaction input scripts (scriptSig) and other scripts, moving some helper methods between extension traits. There is no indication it fixes a security bug or changes behavior in a way that would create a vulnerability.
No security action required. Treat as a normal API refactoring; downstream users should update type imports if they construct `TxIn` or PSBT `Input` objects directly.
Security signals we found
No security-relevant keywords in commit title or message
No bug-fix language or CVE references
Refactoring-only: type aliases and trait reorganization
Serialization/deserialization paths unchanged (same byte representation)
No new unsafe code, no new dependencies, no consensus-critical algorithm changes
Evidence from the diff
The change splits Script/ScriptBuf into ScriptSig/ScriptSigBuf using a type-tag (ScriptSigTag) on the existing generic script types. It moves redeem_script to a new ScriptSigExt trait, relocates count_sigops, count_sigops_legacy, is_push_only, and internal helpers into generic or private extension traits, and updates all call sites (examples, tests, PSBT input map, transaction primitives) to use ScriptSigBuf for TxIn.script_sig and Input.final_script_sig. The serialization format is unchanged because the underlying byte representation is identical; only the Rust type system distinguishes scriptSigs now.
Changed components
primitives/src/script/mod.rsprimitives/src/script/tag.rsprimitives/src/transaction.rsbitcoin/src/blockdata/script/borrowed.rsbitcoin/src/blockdata/script/mod.rsbitcoin/src/psbt/map/input.rsbitcoin/src/lib.rsprimitives/src/lib.rsInspect captured patch +232 / −198
diff --git a/bitcoin/examples/ecdsa-psbt-simple.rs b/bitcoin/examples/ecdsa-psbt-simple.rs
index 94076b46..a2160c03 100644
--- a/bitcoin/examples/ecdsa-psbt-simple.rs
+++ b/bitcoin/examples/ecdsa-psbt-simple.rs
@@ -32,7 +32,7 @@ use bitcoin::psbt::Input;
use bitcoin::secp256k1::{Secp256k1, Signing};
use bitcoin::{
consensus, transaction, Address, Amount, EcdsaSighashType, Network, OutPoint, Psbt, ScriptBuf,
- Sequence, Transaction, TxIn, TxOut, Txid, Witness,
+ ScriptSigBuf, Sequence, Transaction, TxIn, TxOut, Txid, Witness,
};
// The master xpriv, from which we derive the keys we control.
@@ -157,7 +157,7 @@ fn main() {
.into_iter()
.map(|(outpoint, _)| TxIn {
previous_output: outpoint,
- script_sig: ScriptBuf::default(),
+ script_sig: ScriptSigBuf::default(),
sequence: Sequence::ENABLE_LOCKTIME_AND_RBF,
witness: Witness::default(),
})
diff --git a/bitcoin/examples/ecdsa-psbt.rs b/bitcoin/examples/ecdsa-psbt.rs
index 4d3e2a01..50948d1d 100644
--- a/bitcoin/examples/ecdsa-psbt.rs
+++ b/bitcoin/examples/ecdsa-psbt.rs
@@ -38,8 +38,8 @@ use bitcoin::locktime::absolute;
use bitcoin::psbt::{self, Input, Psbt, PsbtSighashType};
use bitcoin::secp256k1::{Secp256k1, Signing, Verification};
use bitcoin::{
- transaction, Address, Amount, CompressedPublicKey, Network, OutPoint, ScriptBuf, Sequence,
- Transaction, TxIn, TxOut, Witness,
+ transaction, Address, Amount, CompressedPublicKey, Network, OutPoint, ScriptBuf, ScriptSigBuf,
+ Sequence, Transaction, TxIn, TxOut, Witness,
};
type Result<T> = std::result::Result<T, Error>;
@@ -186,7 +186,7 @@ impl WatchOnly {
lock_time: absolute::LockTime::ZERO,
inputs: vec![TxIn {
previous_output: OutPoint { txid: INPUT_UTXO_TXID.parse()?, vout: INPUT_UTXO_VOUT },
- script_sig: ScriptBuf::new(),
+ script_sig: ScriptSigBuf::new(),
sequence: Sequence::MAX, // Disable LockTime and RBF.
witness: Witness::default(),
}],
diff --git a/bitcoin/examples/sign-tx-segwit-v0.rs b/bitcoin/examples/sign-tx-segwit-v0.rs
index de41c91c..5e514b12 100644
--- a/bitcoin/examples/sign-tx-segwit-v0.rs
+++ b/bitcoin/examples/sign-tx-segwit-v0.rs
@@ -8,8 +8,8 @@ use bitcoin::locktime::absolute;
use bitcoin::secp256k1::{rand, Message, Secp256k1, SecretKey, Signing};
use bitcoin::sighash::{EcdsaSighashType, SighashCache};
use bitcoin::{
- transaction, Address, Amount, Network, OutPoint, ScriptBuf, Sequence, Transaction, TxIn, TxOut,
- Txid, Witness,
+ transaction, Address, Amount, Network, OutPoint, ScriptBuf, ScriptSigBuf, Sequence,
+ Transaction, TxIn, TxOut, Txid, Witness,
};
const DUMMY_UTXO_AMOUNT: Amount = Amount::from_sat_u32(20_000_000);
@@ -33,7 +33,7 @@ fn main() {
// The input for the transaction we are constructing.
let input = TxIn {
previous_output: dummy_out_point, // The dummy output we are spending.
- script_sig: ScriptBuf::default(), // For a p2wpkh script_sig is empty.
+ script_sig: ScriptSigBuf::default(), // For a p2wpkh script_sig is empty.
sequence: Sequence::ENABLE_LOCKTIME_AND_RBF,
witness: Witness::default(), // Filled in after signing.
};
diff --git a/bitcoin/examples/sign-tx-taproot.rs b/bitcoin/examples/sign-tx-taproot.rs
index eaac84c7..883aa353 100644
--- a/bitcoin/examples/sign-tx-taproot.rs
+++ b/bitcoin/examples/sign-tx-taproot.rs
@@ -8,8 +8,8 @@ use bitcoin::locktime::absolute;
use bitcoin::secp256k1::{rand, Secp256k1, SecretKey, Signing, Verification};
use bitcoin::sighash::{Prevouts, SighashCache, TapSighashType};
use bitcoin::{
- transaction, Address, Amount, Network, OutPoint, ScriptBuf, Sequence, Transaction, TxIn, TxOut,
- Txid, Witness,
+ transaction, Address, Amount, Network, OutPoint, ScriptBuf, ScriptSigBuf, Sequence,
+ Transaction, TxIn, TxOut, Txid, Witness,
};
const DUMMY_UTXO_AMOUNT: Amount = Amount::from_sat_u32(20_000_000);
@@ -33,7 +33,7 @@ fn main() {
// The input for the transaction we are constructing.
let input = TxIn {
previous_output: dummy_out_point, // The dummy output we are spending.
- script_sig: ScriptBuf::default(), // For a p2tr script_sig is empty.
+ script_sig: ScriptSigBuf::default(), // For a p2tr script_sig is empty.
sequence: Sequence::ENABLE_LOCKTIME_AND_RBF,
witness: Witness::default(), // Filled in after signing.
};
diff --git a/bitcoin/examples/taproot-psbt-simple.rs b/bitcoin/examples/taproot-psbt-simple.rs
index 8ba75a05..e252af60 100644
--- a/bitcoin/examples/taproot-psbt-simple.rs
+++ b/bitcoin/examples/taproot-psbt-simple.rs
@@ -29,8 +29,8 @@ use bitcoin::locktime::absolute;
use bitcoin::psbt::Input;
use bitcoin::secp256k1::{Secp256k1, Signing};
use bitcoin::{
- consensus, transaction, Address, Amount, Network, OutPoint, Psbt, ScriptBuf, Sequence,
- TapLeafHash, TapSighashType, Transaction, TxIn, TxOut, Txid, Witness, XOnlyPublicKey,
+ consensus, transaction, Address, Amount, Network, OutPoint, Psbt, ScriptBuf, ScriptSigBuf,
+ Sequence, TapLeafHash, TapSighashType, Transaction, TxIn, TxOut, Txid, Witness, XOnlyPublicKey,
};
// The master xpriv, from which we derive the keys we control.
@@ -177,7 +177,7 @@ fn main() {
.into_iter()
.map(|(outpoint, _)| TxIn {
previous_output: outpoint,
- script_sig: ScriptBuf::default(),
+ script_sig: ScriptSigBuf::default(),
sequence: Sequence::ENABLE_LOCKTIME_AND_RBF,
witness: Witness::default(),
})
diff --git a/bitcoin/examples/taproot-psbt.rs b/bitcoin/examples/taproot-psbt.rs
index 918eab67..a5e34d97 100644
--- a/bitcoin/examples/taproot-psbt.rs
+++ b/bitcoin/examples/taproot-psbt.rs
@@ -87,8 +87,8 @@ use bitcoin::secp256k1::Secp256k1;
use bitcoin::sighash::{self, SighashCache, TapSighash, TapSighashType};
use bitcoin::taproot::{self, LeafVersion, TapLeafHash, TaprootBuilder, TaprootSpendInfo};
use bitcoin::{
- absolute, script, transaction, Address, Amount, Network, OutPoint, ScriptBuf, Transaction,
- TxIn, TxOut, Witness,
+ absolute, script, transaction, Address, Amount, Network, OutPoint, ScriptBuf, ScriptSigBuf,
+ Transaction, TxIn, TxOut, Witness,
};
fn main() -> Result<(), Box<dyn std::error::Error>> {
@@ -232,7 +232,7 @@ fn generate_bip86_key_spend_tx(
lock_time: absolute::LockTime::ZERO,
inputs: vec![TxIn {
previous_output: OutPoint { txid: input_utxo.txid.parse()?, vout: input_utxo.vout },
- script_sig: ScriptBuf::new(),
+ script_sig: ScriptSigBuf::new(),
sequence: bitcoin::Sequence(0xFFFFFFFF), // Ignore nSequence.
witness: Witness::default(),
}],
@@ -429,7 +429,7 @@ impl BenefactorWallet {
lock_time,
inputs: vec![TxIn {
previous_output: OutPoint { txid: tx.compute_txid(), vout: 0 },
- script_sig: ScriptBuf::new(),
+ script_sig: ScriptSigBuf::new(),
sequence: bitcoin::Sequence(0xFFFFFFFD), // enable locktime and opt-in RBF
witness: Witness::default(),
}],
@@ -579,7 +579,7 @@ impl BenefactorWallet {
lock_time,
inputs: vec![TxIn {
previous_output: OutPoint { txid: tx.compute_txid(), vout: 0 },
- script_sig: ScriptBuf::new(),
+ script_sig: ScriptSigBuf::new(),
sequence: bitcoin::Sequence(0xFFFFFFFD), // enable locktime and opt-in RBF
witness: Witness::default(),
}],
diff --git a/bitcoin/src/bip152.rs b/bitcoin/src/bip152.rs
index 8d1a09fb..fd969eef 100644
--- a/bitcoin/src/bip152.rs
+++ b/bitcoin/src/bip152.rs
@@ -460,8 +460,8 @@ mod test {
use crate::merkle_tree::TxMerkleNode;
use crate::transaction::OutPointExt;
use crate::{
- transaction, Amount, BlockChecked, BlockTime, CompactTarget, OutPoint, ScriptBuf, Sequence,
- TxIn, TxOut, Txid, Witness,
+ transaction, Amount, BlockChecked, BlockTime, CompactTarget, OutPoint, ScriptBuf,
+ ScriptSigBuf, Sequence, TxIn, TxOut, Txid, Witness,
};
fn dummy_tx(nonce: &[u8]) -> Transaction {
@@ -471,7 +471,7 @@ mod test {
lock_time: absolute::LockTime::from_consensus(2),
inputs: vec![TxIn {
previous_output: OutPoint::new(dummy_txid, 0),
- script_sig: ScriptBuf::new(),
+ script_sig: ScriptSigBuf::new(),
sequence: Sequence(1),
witness: Witness::new(),
}],
diff --git a/bitcoin/src/blockdata/block.rs b/bitcoin/src/blockdata/block.rs
index ff59bfc1..60087d35 100644
--- a/bitcoin/src/blockdata/block.rs
+++ b/bitcoin/src/blockdata/block.rs
@@ -535,7 +535,7 @@ mod tests {
use super::*;
use crate::consensus::encode::{deserialize, serialize};
use crate::pow::test_utils::{u128_to_work, u64_to_work};
- use crate::script::ScriptBuf;
+ use crate::script::{ScriptBuf, ScriptSigBuf};
use crate::transaction::{OutPoint, Transaction, TxIn, TxOut, Txid};
use crate::{block, Amount, CompactTarget, Network, Sequence, TestnetVersion, Witness};
@@ -811,7 +811,7 @@ mod tests {
txid: Txid::from_byte_array([1; 32]), // Not all zeros
vout: 0,
},
- script_sig: ScriptBuf::new(),
+ script_sig: ScriptSigBuf::new(),
sequence: Sequence::ENABLE_LOCKTIME_AND_RBF,
witness: Witness::new(),
}],
@@ -887,7 +887,7 @@ mod tests {
txid: Txid::from_byte_array([1; 32]), // Not all zeros
vout: 0,
},
- script_sig: ScriptBuf::new(),
+ script_sig: ScriptSigBuf::new(),
sequence: Sequence::ENABLE_LOCKTIME_AND_RBF,
witness: Witness::new(),
}],
diff --git a/bitcoin/src/blockdata/script/borrowed.rs b/bitcoin/src/blockdata/script/borrowed.rs
index 8151e10c..f460d698 100644
--- a/bitcoin/src/blockdata/script/borrowed.rs
+++ b/bitcoin/src/blockdata/script/borrowed.rs
@@ -10,7 +10,7 @@ use secp256k1::{Secp256k1, Verification};
use super::witness_version::WitnessVersion;
use super::{
Builder, GenericScript, Instruction, InstructionIndices, Instructions, PushBytes,
- RedeemScriptSizeError, Script, ScriptHash, WScriptHash, WitnessScriptSizeError,
+ RedeemScriptSizeError, Script, ScriptHash, ScriptSig, WScriptHash, WitnessScriptSizeError,
};
use crate::consensus::{self, Encodable};
use crate::key::{PublicKey, UntweakedPublicKey, WPubkeyHash};
@@ -28,6 +28,55 @@ internal_macros::define_extension_trait! {
/// Constructs a new script builder
fn builder() -> Builder<T> { Builder::new() }
+ /// Counts the sigops for this Script using accurate counting.
+ ///
+ /// In Bitcoin Core, there are two ways to count sigops, "accurate" and "legacy".
+ /// This method uses "accurate" counting. This means that OP_CHECKMULTISIG and its
+ /// verify variant count for N sigops where N is the number of pubkeys used in the
+ /// multisig. However, it will count for 20 sigops if CHECKMULTISIG is not preceded by an
+ /// OP_PUSHNUM from 1 - 16 (this would be an invalid script)
+ ///
+ /// Bitcoin Core uses accurate counting for sigops contained within redeemScripts (P2SH)
+ /// and witnessScripts (P2WSH) only. It uses legacy for sigops in scriptSigs and scriptPubkeys.
+ ///
+ /// (Note: Taproot scripts don't count toward the sigop count of the block,
+ /// nor do they have CHECKMULTISIG operations. This function does not count OP_CHECKSIGADD,
+ /// so do not use this to try and estimate if a Taproot script goes over the sigop budget.)
+ fn count_sigops(&self) -> usize { self.count_sigops_internal(true) }
+
+ /// Counts the sigops for this Script using legacy counting.
+ ///
+ /// In Bitcoin Core, there are two ways to count sigops, "accurate" and "legacy".
+ /// This method uses "legacy" counting. This means that OP_CHECKMULTISIG and its
+ /// verify variant count for 20 sigops.
+ ///
+ /// Bitcoin Core uses legacy counting for sigops contained within scriptSigs and
+ /// scriptPubkeys. It uses accurate for redeemScripts (P2SH) and witnessScripts (P2WSH).
+ ///
+ /// (Note: Taproot scripts don't count toward the sigop count of the block,
+ /// nor do they have CHECKMULTISIG operations. This function does not count OP_CHECKSIGADD,
+ /// so do not use this to try and estimate if a Taproot script goes over the sigop budget.)
+ fn count_sigops_legacy(&self) -> usize { self.count_sigops_internal(false) }
+
+ /// Checks whether a script is push only.
+ ///
+ /// Note: `OP_RESERVED` (`0x50`) and all the OP_PUSHNUM operations
+ /// are considered push operations.
+ #[inline]
+ fn is_push_only(&self) -> bool {
+ for inst in self.instructions() {
+ match inst {
+ Err(_) => return false,
+ Ok(Instruction::PushBytes(_)) => {}
+ Ok(Instruction::Op(op)) if op.to_u8() <= 0x60 => {}
+ // From Bitcoin Core
+ // if (opcode > OP_PUSHNUM_16 (0x60)) return false
+ Ok(Instruction::Op(_)) => return false,
+ }
+ }
+ true
+ }
+
/// Returns an iterator over script bytes.
#[inline]
fn bytes(&self) -> Bytes<'_> { Bytes(self.as_bytes().iter().copied()) }
@@ -203,25 +252,6 @@ crate::internal_macros::define_extension_trait! {
&& self.as_bytes()[24] == OP_CHECKSIG.to_u8()
}
- /// Checks whether a script is push only.
- ///
- /// Note: `OP_RESERVED` (`0x50`) and all the OP_PUSHNUM operations
- /// are considered push operations.
- #[inline]
- fn is_push_only(&self) -> bool {
- for inst in self.instructions() {
- match inst {
- Err(_) => return false,
- Ok(Instruction::PushBytes(_)) => {}
- Ok(Instruction::Op(op)) if op.to_u8() <= 0x60 => {}
- // From Bitcoin Core
- // if (opcode > OP_PUSHNUM_16 (0x60)) return false
- Ok(Instruction::Op(_)) => return false,
- }
- }
- true
- }
-
/// Checks whether a script pubkey is a bare multisig output.
///
/// In a bare multisig pubkey script the keys are not hashed, the script
@@ -342,25 +372,6 @@ crate::internal_macros::define_extension_trait! {
}
}
- /// Get redeemScript following BIP-0016 rules regarding P2SH spending.
- ///
- /// This does not guarantee that this represents a P2SH input [`Script`].
- /// It merely gets the last push of the script.
- ///
- /// Use [`Script::is_p2sh`] on the scriptPubKey to check whether it is actually a P2SH script.
- fn redeem_script(&self) -> Option<&Script> {
- // Script must consist entirely of pushes.
- if self.instructions().any(|i| i.is_err() || i.unwrap().push_bytes().is_none()) {
- return None;
- }
-
- if let Some(Ok(Instruction::PushBytes(b))) = self.instructions().last() {
- Some(Script::from_bytes(b.as_bytes()))
- } else {
- None
- }
- }
-
/// Returns the minimum value an output with this script should have in order to be
/// broadcastable on today’s Bitcoin network.
#[deprecated(since = "0.32.0", note = "use `minimal_non_dust` etc. instead")]
@@ -395,36 +406,6 @@ crate::internal_macros::define_extension_trait! {
self.minimal_non_dust_internal(dust_relay.to_sat_per_kvb_ceil())
}
- /// Counts the sigops for this Script using accurate counting.
- ///
- /// In Bitcoin Core, there are two ways to count sigops, "accurate" and "legacy".
- /// This method uses "accurate" counting. This means that OP_CHECKMULTISIG and its
- /// verify variant count for N sigops where N is the number of pubkeys used in the
- /// multisig. However, it will count for 20 sigops if CHECKMULTISIG is not preceded by an
- /// OP_PUSHNUM from 1 - 16 (this would be an invalid script)
- ///
- /// Bitcoin Core uses accurate counting for sigops contained within redeemScripts (P2SH)
- /// and witnessScripts (P2WSH) only. It uses legacy for sigops in scriptSigs and scriptPubkeys.
- ///
- /// (Note: Taproot scripts don't count toward the sigop count of the block,
- /// nor do they have CHECKMULTISIG operations. This function does not count OP_CHECKSIGADD,
- /// so do not use this to try and estimate if a Taproot script goes over the sigop budget.)
- fn count_sigops(&self) -> usize { self.count_sigops_internal(true) }
-
- /// Counts the sigops for this Script using legacy counting.
- ///
- /// In Bitcoin Core, there are two ways to count sigops, "accurate" and "legacy".
- /// This method uses "legacy" counting. This means that OP_CHECKMULTISIG and its
- /// verify variant count for 20 sigops.
- ///
- /// Bitcoin Core uses legacy counting for sigops contained within scriptSigs and
- /// scriptPubkeys. It uses accurate for redeemScripts (P2SH) and witnessScripts (P2WSH).
- ///
- /// (Note: Taproot scripts don't count toward the sigop count of the block,
- /// nor do they have CHECKMULTISIG operations. This function does not count OP_CHECKSIGADD,
- /// so do not use this to try and estimate if a Taproot script goes over the sigop budget.)
- fn count_sigops_legacy(&self) -> usize { self.count_sigops_internal(false) }
-
/// Writes the human-readable assembly representation of the script to the formatter.
#[deprecated(since = "TBD", note = "use the script's `Display` impl instead")]
fn fmt_asm(&self, f: &mut dyn fmt::Write) -> fmt::Result {
@@ -465,8 +446,48 @@ mod sealed {
impl<T> Sealed for super::GenericScript<T> {}
}
-crate::internal_macros::define_extension_trait! {
+internal_macros::define_extension_trait! {
pub(crate) trait GenericScriptExtPriv<T> impl<T> for GenericScript<T> {
+ fn count_sigops_internal(&self, accurate: bool) -> usize {
+ let mut n = 0;
+ let mut pushnum_cache = None;
+ for inst in self.instructions() {
+ match inst {
+ Ok(Instruction::Op(opcode)) => {
+ match opcode {
+ // p2pk, p2pkh
+ OP_CHECKSIG | OP_CHECKSIGVERIFY => {
+ n += 1;
+ }
+ OP_CHECKMULTISIG | OP_CHECKMULTISIGVERIFY => {
+ match (accurate, pushnum_cache) {
+ (true, Some(pushnum)) => {
+ // Add the number of pubkeys in the multisig as sigop count
+ n += usize::from(pushnum);
+ }
+ _ => {
+ // MAX_PUBKEYS_PER_MULTISIG from Bitcoin Core
+ // https://github.com/bitcoin/bitcoin/blob/v25.0/src/script/script.h#L29-L30
+ n += 20;
+ }
+ }
+ }
+ _ => {
+ pushnum_cache = opcode.decode_pushnum();
+ }
+ }
+ }
+ Ok(Instruction::PushBytes(_)) => {
+ pushnum_cache = None;
+ }
+ // In Bitcoin Core it does `if (!GetOp(pc, opcode)) break;`
+ Err(_) => break,
+ }
+ }
+
+ n
+ }
+
/// Iterates the script to find the last opcode.
///
/// Returns `None` is the instruction is data push or if the script is empty.
@@ -476,6 +497,19 @@ crate::internal_macros::define_extension_trait! {
_ => None,
}
}
+
+ /// Iterates the script to find the last pushdata.
+ ///
+ /// Returns `None` if the instruction is an opcode or if the script is empty.
+ fn last_pushdata(&self) -> Option<&PushBytes> {
+ match self.instructions().last() {
+ // Handles op codes up to (but excluding) OP_PUSHNUM_NEG.
+ Some(Ok(Instruction::PushBytes(bytes))) => Some(bytes),
+ // OP_16 (0x60) and lower are considered "pushes" by Bitcoin Core (excl. OP_RESERVED).
+ // However we are only interested in the pushdata so we can ignore them.
+ _ => None,
+ }
+ }
}
}
@@ -517,57 +551,28 @@ internal_macros::define_extension_trait! {
Amount::from_sat(sats).ok()
}
+ }
+}
- fn count_sigops_internal(&self, accurate: bool) -> usize {
- let mut n = 0;
- let mut pushnum_cache = None;
- for inst in self.instructions() {
- match inst {
- Ok(Instruction::Op(opcode)) => {
- match opcode {
- // p2pk, p2pkh
- OP_CHECKSIG | OP_CHECKSIGVERIFY => {
- n += 1;
- }
- OP_CHECKMULTISIG | OP_CHECKMULTISIGVERIFY => {
- match (accurate, pushnum_cache) {
- (true, Some(pushnum)) => {
- // Add the number of pubkeys in the multisig as sigop count
- n += usize::from(pushnum);
- }
- _ => {
- // MAX_PUBKEYS_PER_MULTISIG from Bitcoin Core
- // https://github.com/bitcoin/bitcoin/blob/v25.0/src/script/script.h#L29-L30
- n += 20;
- }
- }
- }
- _ => {
- pushnum_cache = opcode.decode_pushnum();
- }
- }
- }
- Ok(Instruction::PushBytes(_)) => {
- pushnum_cache = None;
- }
- // In Bitcoin Core it does `if (!GetOp(pc, opcode)) break;`
- Err(_) => break,
- }
+internal_macros::define_extension_trait! {
+ /// Extension functionality for the [`ScriptSig`] type.
+ pub trait ScriptSigExt impl for ScriptSig {
+ /// Get redeemScript following BIP-0016 rules regarding P2SH spending.
+ ///
+ /// This does not guarantee that this represents a P2SH input [`Script`].
+ /// It merely gets the last push of the script.
+ ///
+ /// Use [`Script::is_p2sh`] on the scriptPubKey to check whether it is actually a P2SH script.
+ fn redeem_script(&self) -> Option<&Script> {
+ // Script must consist entirely of pushes.
+ if self.instructions().any(|i| i.is_err() || i.unwrap().push_bytes().is_none()) {
+ return None;
}
- n
- }
-
- /// Iterates the script to find the last pushdata.
- ///
- /// Returns `None` if the instruction is an opcode or if the script is empty.
- fn last_pushdata(&self) -> Option<&PushBytes> {
- match self.instructions().last() {
- // Handles op codes up to (but excluding) OP_PUSHNUM_NEG.
- Some(Ok(Instruction::PushBytes(bytes))) => Some(bytes),
- // OP_16 (0x60) and lower are considered "pushes" by Bitcoin Core (excl. OP_RESERVED).
- // However we are only interested in the pushdata so we can ignore them.
- _ => None,
+ if let Some(Ok(Instruction::PushBytes(b))) = self.instructions().last() {
+ Some(Script::from_bytes(b.as_bytes()))
+ } else {
+ None
}
}
}
diff --git a/bitcoin/src/blockdata/script/instruction.rs b/bitcoin/src/blockdata/script/instruction.rs
index 5cdfae7e..66566967 100644
--- a/bitcoin/src/blockdata/script/instruction.rs
+++ b/bitcoin/src/blockdata/script/instruction.rs
@@ -56,9 +56,10 @@ impl Instruction<'_> {
pub(super) fn script_serialized_len(&self) -> usize {
match self {
Instruction::Op(_) => 1,
- // In a later commit this `super::ScriptBuf` will become a specific tagged
- // script. It doesn't matter which one. But Rust insists that we pick one.
- Instruction::PushBytes(bytes) => super::ScriptBuf::reserved_len_for_slice(bytes.len()),
+ // The use of `ScriptSigBuf` here is arbitrary. Rust insists that we pick
+ // a specific tagged script type.
+ Instruction::PushBytes(bytes) =>
+ super::ScriptSigBuf::reserved_len_for_slice(bytes.len()),
}
}
diff --git a/bitcoin/src/blockdata/script/mod.rs b/bitcoin/src/blockdata/script/mod.rs
index 2e4319df..e530223f 100644
--- a/bitcoin/src/blockdata/script/mod.rs
+++ b/bitcoin/src/blockdata/script/mod.rs
@@ -74,7 +74,7 @@ use crate::OutPoint;
#[rustfmt::skip] // Keep public re-exports separate.
#[doc(inline)]
pub use self::{
- borrowed::{GenericScriptExt, ScriptExt},
+ borrowed::{GenericScriptExt, ScriptExt, ScriptSigExt},
builder::Builder,
instruction::{Instruction, Instructions, InstructionIndices},
owned::{GenericScriptBufExt, ScriptBufExt},
@@ -82,11 +82,11 @@ pub use self::{
};
#[doc(inline)]
pub use primitives::script::{
- GenericScript, GenericScriptBuf, RedeemScriptSizeError, Script, ScriptBuf, ScriptHash, Tag,
- WScriptHash, Whatever, WitnessScriptSizeError,
+ GenericScript, GenericScriptBuf, RedeemScriptSizeError, Script, ScriptBuf, ScriptHash,
+ ScriptSig, ScriptSigBuf, ScriptSigTag, Tag, WScriptHash, Whatever, WitnessScriptSizeError,
};
-pub(crate) use self::borrowed::{GenericScriptExtPriv, ScriptExtPriv};
+pub(crate) use self::borrowed::GenericScriptExtPriv;
pub(crate) use self::owned::GenericScriptBufExtPriv;
impl_asref_push_bytes!(ScriptHash, WScriptHash);
diff --git a/bitcoin/src/blockdata/script/tests.rs b/bitcoin/src/blockdata/script/tests.rs
index 99d31519..cfb52d16 100644
--- a/bitcoin/src/blockdata/script/tests.rs
+++ b/bitcoin/src/blockdata/script/tests.rs
@@ -5,6 +5,7 @@ use hex_lit::hex;
use super::*;
use crate::consensus::encode::{deserialize, serialize};
use crate::crypto::key::{PublicKey, XOnlyPublicKey};
+use crate::script::borrowed::ScriptExtPriv as _;
use crate::script::witness_program::WitnessProgram;
use crate::script::witness_version::WitnessVersion;
use crate::{opcodes, Amount, FeeRate};
@@ -206,7 +207,7 @@ fn script_x_only_key() {
#[test]
fn script_builder() {
// from txid 3bb5e6434c11fb93f64574af5d116736510717f2c595eb45b52c28e31622dfff which was in my mempool when I wrote the test
- let script = Builder::new()
+ let script = Script::builder()
.push_opcode(OP_DUP)
.push_opcode(OP_HASH160)
.push_slice(hex!("16e1ae70ff0fa102905d4af297f6912bda6cce19"))
@@ -774,7 +775,7 @@ fn default_dust_value() {
#[test]
fn script_get_sigop_count() {
assert_eq!(
- Builder::new()
+ Script::builder()
.push_opcode(OP_DUP)
.push_opcode(OP_HASH160)
.push_slice([42; 20])
@@ -784,7 +785,7 @@ fn script_get_sigop_count() {
0
);
assert_eq!(
- Builder::new()
+ Script::builder()
.push_opcode(OP_DUP)
.push_opcode(OP_HASH160)
.push_slice([42; 20])
@@ -795,7 +796,7 @@ fn script_get_sigop_count() {
1
);
assert_eq!(
- Builder::new()
+ Script::builder()
.push_opcode(OP_DUP)
.push_opcode(OP_HASH160)
.push_slice([42; 20])
@@ -806,7 +807,7 @@ fn script_get_sigop_count() {
.count_sigops(),
1
);
- let multi = Builder::new()
+ let multi = Script::builder()
.push_opcode(OP_PUSHNUM_1)
.push_slice([3; 33])
.push_slice([3; 33])
@@ -816,7 +817,7 @@ fn script_get_sigop_count() {
.into_script();
assert_eq!(multi.count_sigops(), 3);
assert_eq!(multi.count_sigops_legacy(), 20);
- let multi_verify = Builder::new()
+ let multi_verify = Script::builder()
.push_opcode(OP_PUSHNUM_1)
.push_slice([3; 33])
.push_slice([3; 33])
@@ -827,7 +828,7 @@ fn script_get_sigop_count() {
.into_script();
assert_eq!(multi_verify.count_sigops(), 3);
assert_eq!(multi_verify.count_sigops_legacy(), 20);
- let multi_nopushnum_pushdata = Builder::new()
+ let multi_nopushnum_pushdata = Script::builder()
.push_opcode(OP_PUSHNUM_1)
.push_slice([3; 33])
.push_slice([3; 33])
@@ -836,7 +837,7 @@ fn script_get_sigop_count() {
.into_script();
assert_eq!(multi_nopushnum_pushdata.count_sigops(), 20);
assert_eq!(multi_nopushnum_pushdata.count_sigops_legacy(), 20);
- let multi_nopushnum_op = Builder::new()
+ let multi_nopushnum_op = Script::builder()
.push_opcode(OP_PUSHNUM_1)
.push_slice([3; 33])
.push_slice([3; 33])
diff --git a/bitcoin/src/blockdata/transaction.rs b/bitcoin/src/blockdata/transaction.rs
index 01c03309..b61b7ac9 100644
--- a/bitcoin/src/blockdata/transaction.rs
+++ b/bitcoin/src/blockdata/transaction.rs
@@ -21,7 +21,9 @@ use super::Weight;
use crate::consensus::{self, encode, Decodable, Encodable};
use crate::locktime::absolute::{self, Height, MedianTimePast};
use crate::prelude::{Borrow, Vec};
-use crate::script::{Script, ScriptBuf, ScriptExt as _, ScriptExtPriv as _};
+use crate::script::{
+ GenericScriptExt as _, GenericScriptExtPriv as _, Script, ScriptBuf, ScriptExt as _,
+};
#[cfg(doc)]
use crate::sighash::{EcdsaSighashType, TapSighashType};
use crate::witness::Witness;
@@ -1243,6 +1245,7 @@ mod tests {
use super::*;
use crate::consensus::encode::{deserialize, serialize};
use crate::constants::WITNESS_SCALE_FACTOR;
+ use crate::script::ScriptSigBuf;
use crate::sighash::EcdsaSighashType;
const SOME_TX: &str = "0100000001a15d57094aa7a21a28cb20b59aab8fc7d1149a3bdbcddba9c622e4f5f6a99ece010000006c493046022100f93bb0e7d8db7bd46e40132d1f8242026e045f03a0efe71bbb8e3f475e970d790221009337cd7f1f929f00cc6ff01f03729b069a7c21b59b1736ddfee5db5946c5da8c0121033b9b137ee87d5a812d6f506efdd37f0affa7ffc310711c06c7f3e097c9447c52ffffffff0100e1f505000000001976a9140389035a9225b3839e2bbf32d826a1e222031fd888ac00000000";
@@ -1488,7 +1491,7 @@ mod tests {
"c3573dbea28ce24425c59a189391937e00d255150fa973d59d61caf3a06b601d"
);
// changing sigs does not affect it
- tx.inputs[0].script_sig = ScriptBuf::new();
+ tx.inputs[0].script_sig = ScriptSigBuf::new();
assert_eq!(old_ntxid, tx.compute_ntxid());
// changing pks does
tx.outputs[0].script_pubkey = ScriptBuf::new();
diff --git a/bitcoin/src/lib.rs b/bitcoin/src/lib.rs
index 828ca1dc..e8d5afd7 100644
--- a/bitcoin/src/lib.rs
+++ b/bitcoin/src/lib.rs
@@ -114,7 +114,7 @@ pub mod ext {
pub use crate::{
block::{BlockUncheckedExt as _, BlockCheckedExt as _, HeaderExt as _},
pow::CompactTargetExt as _,
- script::{GenericScriptExt as _, GenericScriptBufExt as _, ScriptExt as _, ScriptBufExt as _},
+ script::{GenericScriptExt as _, GenericScriptBufExt as _, ScriptExt as _, ScriptBufExt as _, ScriptSigExt as _},
transaction::{TxidExt as _, WtxidExt as _, OutPointExt as _, TxInExt as _, TxOutExt as _, TransactionExt as _},
witness::WitnessExt as _,
};
@@ -152,7 +152,7 @@ pub use primitives::{
},
merkle_tree::{TxMerkleNode, WitnessMerkleNode},
pow::CompactTarget, // No `pow` module outside of `primitives`.
- script::{Script, ScriptBuf},
+ script::{Script, ScriptBuf, ScriptSig, ScriptSigBuf},
sequence::{self, Sequence}, // No `sequence` module outside of `primitives`.
transaction::{OutPoint, Transaction, TxIn, TxOut, Txid, Version as TransactionVersion, Wtxid},
witness::Witness,
diff --git a/bitcoin/src/psbt/map/input.rs b/bitcoin/src/psbt/map/input.rs
index 3a6a066e..bf8679c8 100644
--- a/bitcoin/src/psbt/map/input.rs
+++ b/bitcoin/src/psbt/map/input.rs
@@ -12,7 +12,7 @@ use crate::prelude::{btree_map, BTreeMap, Borrow, Box, ToOwned, Vec};
use crate::psbt::map::Map;
use crate::psbt::serialize::Deserialize;
use crate::psbt::{error, raw, Error};
-use crate::script::ScriptBuf;
+use crate::script::{ScriptBuf, ScriptSigBuf};
use crate::sighash::{
EcdsaSighashType, InvalidSighashTypeError, NonStandardSighashTypeError, SighashTypeParseError,
TapSighashType,
@@ -91,7 +91,7 @@ pub struct Input {
pub bip32_derivation: BTreeMap<secp256k1::PublicKey, KeySource>,
/// The finalized, fully-constructed scriptSig with signatures and any other
/// scripts necessary for this input to pass validation.
- pub final_script_sig: Option<ScriptBuf>,
+ pub final_script_sig: Option<ScriptSigBuf>,
/// The finalized, fully-constructed scriptWitness with signatures and any
/// other scripts necessary for this input to pass validation.
pub final_script_witness: Option<Witness>,
@@ -298,7 +298,7 @@ impl Input {
}
PSBT_IN_FINAL_SCRIPTSIG => {
impl_psbt_insert_pair! {
- self.final_script_sig <= <raw_key: _>|<raw_value: ScriptBuf>
+ self.final_script_sig <= <raw_key: _>|<raw_value: ScriptSigBuf>
}
}
PSBT_IN_FINAL_SCRIPTWITNESS => {
diff --git a/bitcoin/src/psbt/mod.rs b/bitcoin/src/psbt/mod.rs
index b67803ab..a0daffe9 100644
--- a/bitcoin/src/psbt/mod.rs
+++ b/bitcoin/src/psbt/mod.rs
@@ -1343,7 +1343,7 @@ mod tests {
use crate::locktime::absolute;
use crate::network::NetworkKind;
use crate::psbt::serialize::{Deserialize, Serialize};
- use crate::script::{GenericScriptBufExt as _, ScriptBuf};
+ use crate::script::{GenericScriptBufExt as _, ScriptBuf, ScriptSigBuf};
use crate::transaction::{self, OutPoint, TxIn};
use crate::witness::Witness;
use crate::Sequence;
@@ -1370,7 +1370,7 @@ mod tests {
.unwrap(),
vout: 0,
},
- script_sig: ScriptBuf::new(),
+ script_sig: ScriptSigBuf::new(),
sequence: Sequence::ENABLE_LOCKTIME_NO_RBF,
witness: Witness::default(),
}],
@@ -1546,7 +1546,7 @@ mod tests {
.unwrap(),
vout: 0,
},
- script_sig: ScriptBuf::new(),
+ script_sig: ScriptSigBuf::new(),
sequence: Sequence::ENABLE_LOCKTIME_NO_RBF,
witness: Witness::default(),
}],
@@ -1617,7 +1617,7 @@ mod tests {
.unwrap(),
vout: 1,
},
- script_sig: ScriptBuf::from_hex_no_length_prefix(
+ script_sig: ScriptSigBuf::from_hex_no_length_prefix(
"160014be18d152a9b012039daf3da7de4f53349eecb985",
)
.unwrap(),
@@ -1668,7 +1668,7 @@ mod tests {
unsigned_tx: {
let mut unsigned = tx.clone();
unsigned.inputs[0].previous_output.txid = tx.compute_txid();
- unsigned.inputs[0].script_sig = ScriptBuf::new();
+ unsigned.inputs[0].script_sig = ScriptSigBuf::new();
unsigned.inputs[0].witness = Witness::default();
unsigned
},
@@ -1797,7 +1797,7 @@ mod tests {
txid: "f61b1742ca13176464adb3cb66050c00787bb3a4eead37e985f2df1e37718126".parse().unwrap(),
vout: 0,
},
- script_sig: ScriptBuf::new(),
+ script_sig: ScriptSigBuf::new(),
sequence: Sequence::ENABLE_LOCKTIME_NO_RBF,
witness: Witness::default(),
}
@@ -1829,7 +1829,7 @@ mod tests {
txid: "e567952fb6cc33857f392efa3a46c995a28f69cca4bb1b37e0204dab1ec7a389".parse().unwrap(),
vout: 1,
},
- script_sig: ScriptBuf::from_hex_no_length_prefix("160014be18d152a9b012039daf3da7de4f53349eecb985").unwrap(),
+ script_sig: ScriptSigBuf::from_hex_no_length_prefix("160014be18d152a9b012039daf3da7de4f53349eecb985").unwrap(),
sequence: Sequence::MAX,
witness: Witness::from_slice(&[
hex!("304402202712be22e0270f394f568311dc7ca9a68970b8025fdd3b240229f07f8a5f3a240220018b38d7dcd314e734c9276bd6fb40f673325bc4baa144c800d2f2f02db2765c01").as_slice(),
@@ -1841,7 +1841,7 @@ mod tests {
txid: "b490486aec3ae671012dddb2bb08466bef37720a533a894814ff1da743aaf886".parse().unwrap(),
vout: 1,
},
- script_sig: ScriptBuf::from_hex_no_length_prefix("160014fe3e9ef1a745e974d902c4355943abcb34bd5353").unwrap(),
+ script_sig: ScriptSigBuf::from_hex_no_length_prefix("160014fe3e9ef1a745e974d902c4355943abcb34bd5353").unwrap(),
sequence: Sequence::MAX,
witness: Witness::from_slice(&[
hex!("3045022100d12b852d85dcd961d2f5f4ab660654df6eedcc794c0c33ce5cc309ffb5fce58d022067338a8e0e1725c197fb1a88af59f51e44e4255b20167c8684031c05d1f2592a01").as_slice(),
@@ -2158,7 +2158,7 @@ mod tests {
txid: "f61b1742ca13176464adb3cb66050c00787bb3a4eead37e985f2df1e37718126".parse().unwrap(),
vout: 0,
},
- script_sig: ScriptBuf::new(),
+ script_sig: ScriptSigBuf::new(),
sequence: Sequence::ENABLE_LOCKTIME_NO_RBF,
witness: Witness::default(),
}
@@ -2190,7 +2190,7 @@ mod tests {
txid: "e567952fb6cc33857f392efa3a46c995a28f69cca4bb1b37e0204dab1ec7a389".parse().unwrap(),
vout: 1,
},
- script_sig: ScriptBuf::from_hex_no_length_prefix("160014be18d152a9b012039daf3da7de4f53349eecb985").unwrap(),
+ script_sig: ScriptSigBuf::from_hex_no_length_prefix("160014be18d152a9b012039daf3da7de4f53349eecb985").unwrap(),
sequence: Sequence::MAX,
witness: Witness::from_slice(&[
hex!("304402202712be22e0270f394f568311dc7ca9a68970b8025fdd3b240229f07f8a5f3a240220018b38d7dcd314e734c9276bd6fb40f673325bc4baa144c800d2f2f02db2765c01").as_slice(),
@@ -2202,7 +2202,7 @@ mod tests {
txid: "b490486aec3ae671012dddb2bb08466bef37720a533a894814ff1da743aaf886".parse().unwrap(),
vout: 1,
},
- script_sig: ScriptBuf::from_hex_no_length_prefix("160014fe3e9ef1a745e974d902c4355943abcb34bd5353").unwrap(),
+ script_sig: ScriptSigBuf::from_hex_no_length_prefix("160014fe3e9ef1a745e974d902c4355943abcb34bd5353").unwrap(),
sequence: Sequence::MAX,
witness: Witness::from_slice(&[
hex!("3045022100d12b852d85dcd961d2f5f4ab660654df6eedcc794c0c33ce5cc309ffb5fce58d022067338a8e0e1725c197fb1a88af59f51e44e4255b20167c8684031c05d1f2592a01").as_slice(),
diff --git a/bitcoin/tests/bip_174.rs b/bitcoin/tests/bip_174.rs
index 5f3ae395..730140db 100644
--- a/bitcoin/tests/bip_174.rs
+++ b/bitcoin/tests/bip_174.rs
@@ -13,7 +13,7 @@ use bitcoin::script::{GenericScriptBufExt as _, PushBytes};
use bitcoin::secp256k1::Secp256k1;
use bitcoin::{
absolute, script, transaction, NetworkKind, OutPoint, PrivateKey, PublicKey, ScriptBuf,
- Sequence, Transaction, TxIn, TxOut, Witness,
+ ScriptSigBuf, Sequence, Transaction, TxIn, TxOut, Witness,
};
#[track_caller]
@@ -166,7 +166,7 @@ fn create_transaction() -> Transaction {
txid: input_0.txid.parse().expect("failed to parse txid"),
vout: input_0.index,
},
- script_sig: ScriptBuf::new(),
+ script_sig: ScriptSigBuf::new(),
sequence: Sequence::MAX, // Disable nSequence.
witness: Witness::default(),
},
@@ -175,7 +175,7 @@ fn create_transaction() -> Transaction {
txid: input_1.txid.parse().expect("failed to parse txid"),
vout: input_1.index,
},
- script_sig: ScriptBuf::new(),
+ script_sig: ScriptSigBuf::new(),
sequence: Sequence::MAX,
witness: Witness::default(),
},
diff --git a/bitcoin/tests/psbt-sign-taproot.rs b/bitcoin/tests/psbt-sign-taproot.rs
index be650285..6cf1ec05 100644
--- a/bitcoin/tests/psbt-sign-taproot.rs
+++ b/bitcoin/tests/psbt-sign-taproot.rs
@@ -10,8 +10,8 @@ use bitcoin::script::ScriptExt as _;
use bitcoin::taproot::{LeafVersion, TaprootBuilder, TaprootSpendInfo};
use bitcoin::transaction::Version;
use bitcoin::{
- absolute, script, Address, Amount, Network, OutPoint, PrivateKey, Psbt, ScriptBuf, Sequence,
- Transaction, TxIn, TxOut, Witness, XOnlyPublicKey,
+ absolute, script, Address, Amount, Network, OutPoint, PrivateKey, Psbt, ScriptBuf,
+ ScriptSigBuf, Sequence, Transaction, TxIn, TxOut, Witness, XOnlyPublicKey,
};
use secp256k1::{Keypair, Secp256k1, Signing};
@@ -212,7 +212,7 @@ fn create_psbt_for_taproot_key_path_spend(
lock_time: absolute::LockTime::ZERO,
inputs: vec![TxIn {
previous_output: OutPoint { txid: prev_tx_id.parse().unwrap(), vout: 0 },
- script_sig: ScriptBuf::new(),
+ script_sig: ScriptSigBuf::new(),
sequence: Sequence(0xFFFFFFFF), // Ignore nSequence.
witness: Witness::default(),
}],
@@ -290,7 +290,7 @@ fn create_psbt_for_taproot_script_path_spend<K: Into<XOnlyPublicKey>>(
lock_time: absolute::LockTime::ZERO,
inputs: vec![TxIn {
previous_output: OutPoint { txid: prev_tx_id.parse().unwrap(), vout: 0 },
- script_sig: ScriptBuf::new(),
+ script_sig: ScriptSigBuf::new(),
sequence: Sequence(0xFFFFFFFF), // Ignore nSequence.
witness: Witness::default(),
}],
diff --git a/bitcoin/tests/serde.rs b/bitcoin/tests/serde.rs
index 1ad44ae9..efa6ab00 100644
--- a/bitcoin/tests/serde.rs
+++ b/bitcoin/tests/serde.rs
@@ -33,7 +33,7 @@ use bitcoin::taproot::{self, ControlBlock, LeafVersion, TapTree, TaprootBuilder}
use bitcoin::witness::Witness;
use bitcoin::{
ecdsa, transaction, Address, Amount, NetworkKind, OutPoint, PrivateKey, PublicKey, ScriptBuf,
- Sequence, Target, Transaction, TxIn, TxOut, Txid, Work,
+ ScriptSigBuf, Sequence, Target, Transaction, TxIn, TxOut, Txid, Work,
};
#[test]
@@ -203,7 +203,7 @@ fn serde_regression_psbt() {
.unwrap(),
vout: 1,
},
- script_sig: ScriptBuf::from_hex_no_length_prefix(
+ script_sig: ScriptSigBuf::from_hex_no_length_prefix(
"160014be18d152a9b012039daf3da7de4f53349eecb985",
)
.unwrap(),
@@ -254,7 +254,7 @@ fn serde_regression_psbt() {
unsigned_tx: {
let mut unsigned = tx.clone();
unsigned.inputs[0].previous_output.txid = tx.compute_txid();
- unsigned.inputs[0].script_sig = ScriptBuf::new();
+ unsigned.inputs[0].script_sig = ScriptSigBuf::new();
unsigned.inputs[0].witness = Witness::default();
unsigned
},
diff --git a/primitives/src/lib.rs b/primitives/src/lib.rs
index c0a60c78..1f4a31ba 100644
--- a/primitives/src/lib.rs
+++ b/primitives/src/lib.rs
@@ -74,7 +74,7 @@ pub use self::{
block::{
Block, Checked as BlockChecked, Unchecked as BlockUnchecked, Validation as BlockValidation,
},
- script::{Script, ScriptBuf},
+ script::{Script, ScriptBuf, ScriptSig, ScriptSigBuf},
transaction::{Transaction, TxIn, TxOut},
witness::Witness,
};
diff --git a/primitives/src/script/mod.rs b/primitives/src/script/mod.rs
index 1e2110b0..80c16861 100644
--- a/primitives/src/script/mod.rs
+++ b/primitives/src/script/mod.rs
@@ -30,7 +30,7 @@ use crate::prelude::{Borrow, BorrowMut, Box, Cow, ToOwned, Vec};
pub use self::{
borrowed::GenericScript,
owned::GenericScriptBuf,
- tag::{Tag, Whatever},
+ tag::{Tag, ScriptSigTag, Whatever},
};
/// Placeholder doc (will be replaced in later commit)
@@ -39,6 +39,12 @@ pub type Script = GenericScript<Whatever>;
/// Placeholder doc (will be replaced in later commit)
pub type ScriptBuf = GenericScriptBuf<Whatever>;
+/// A reference to a script signature (scriptSig).
+pub type ScriptSig = GenericScript<ScriptSigTag>;
+
+/// A script signature (scriptSig).
+pub type ScriptSigBuf = GenericScriptBuf<ScriptSigTag>;
+
/// 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.
diff --git a/primitives/src/script/tag.rs b/primitives/src/script/tag.rs
index 6383c026..94eadec3 100644
--- a/primitives/src/script/tag.rs
+++ b/primitives/src/script/tag.rs
@@ -13,3 +13,8 @@ pub trait Tag {}
pub enum Whatever {}
impl Tag for Whatever {}
+
+/// A script signature (scriptSig).
+#[derive(Clone, PartialOrd, Ord, PartialEq, Eq, Hash)]
+pub enum ScriptSigTag {}
+impl Tag for ScriptSigTag {}
diff --git a/primitives/src/transaction.rs b/primitives/src/transaction.rs
index b4693046..621bd449 100644
--- a/primitives/src/transaction.rs
+++ b/primitives/src/transaction.rs
@@ -36,7 +36,7 @@ use units::{Amount, Weight};
#[cfg(feature = "alloc")]
use crate::prelude::Vec;
#[cfg(feature = "alloc")]
-use crate::script::ScriptBuf;
+use crate::script::{ScriptBuf, ScriptSigBuf};
#[cfg(feature = "alloc")]
use crate::witness::Witness;
@@ -137,7 +137,7 @@ impl Transaction {
.inputs
.iter()
.map(|txin| TxIn {
- script_sig: ScriptBuf::new(),
+ script_sig: ScriptSigBuf::new(),
witness: Witness::default(),
..*txin
})
@@ -308,7 +308,7 @@ pub struct TxIn {
pub previous_output: OutPoint,
/// The script which pushes values on the stack which will cause
/// the referenced output's script to be accepted.
- pub script_sig: ScriptBuf,
+ pub script_sig: ScriptSigBuf,
/// The sequence number, which suggests to miners which of two
/// conflicting transactions should be preferred, or 0xFFFFFFFF
/// to ignore this feature. This is generally never used since
@@ -327,7 +327,7 @@ impl TxIn {
/// An empty transaction input with the previous output as for a coinbase transaction.
pub const EMPTY_COINBASE: TxIn = TxIn {
previous_output: OutPoint::COINBASE_PREVOUT,
- script_sig: ScriptBuf::new(),
+ script_sig: ScriptSigBuf::new(),
sequence: Sequence::MAX,
witness: Witness::new(),
};
@@ -605,7 +605,7 @@ impl<'a> Arbitrary<'a> for TxIn {
fn arbitrary(u: &mut Unstructured<'a>) -> arbitrary::Result<Self> {
Ok(TxIn {
previous_output: OutPoint::arbitrary(u)?,
- script_sig: ScriptBuf::arbitrary(u)?,
+ script_sig: ScriptSigBuf::arbitrary(u)?,
sequence: Sequence::arbitrary(u)?,
witness: Witness::arbitrary(u)?,
})
@@ -684,7 +684,7 @@ mod tests {
txid: Txid::from_byte_array([0xAA; 32]), // Arbitrary invalid dummy value.
vout: 0,
},
- script_sig: ScriptBuf::new(),
+ script_sig: ScriptSigBuf::new(),
sequence: Sequence::MAX,
witness: Witness::new(),
};
diff --git a/primitives/tests/api.rs b/primitives/tests/api.rs
index 47646f9f..2bb22e36 100644
--- a/primitives/tests/api.rs
+++ b/primitives/tests/api.rs
@@ -18,7 +18,7 @@ use bitcoin_primitives::block::{Checked, Unchecked};
use bitcoin_primitives::script::{self, ScriptHash, WScriptHash};
use bitcoin_primitives::{
absolute, block, merkle_tree, pow, relative, transaction, witness, OutPoint, Script, ScriptBuf,
- Sequence, Transaction, TxIn, TxOut, Txid, Witness, Wtxid,
+ ScriptSig, ScriptSigBuf, Sequence, Transaction, TxIn, TxOut, Txid, Witness, Wtxid,
};
use hashes::sha256t;
@@ -44,9 +44,11 @@ struct Structs<'a> {
h: merkle_tree::WitnessMerkleNode,
i: pow::CompactTarget,
j: &'a Script,
+ j3: &'a ScriptSig,
k: ScriptHash,
l: WScriptHash,
m: ScriptBuf,
+ m3: ScriptSigBuf,
n: Sequence,
o: Transaction,
p: TxIn,
@@ -60,6 +62,7 @@ struct Structs<'a> {
}
static SCRIPT: ScriptBuf = ScriptBuf::new();
+static SCRIPT_SIG: ScriptSigBuf = ScriptSigBuf::new();
static BYTES: [u8; 32] = [0x00; 32];
/// Public structs that derive common traits.
@@ -79,6 +82,7 @@ struct CommonTraits {
k: ScriptHash,
l: WScriptHash,
m: ScriptBuf,
+ m3: ScriptSigBuf,
n: Sequence,
o: Transaction,
p: TxIn,
@@ -107,6 +111,7 @@ struct Clone<'a> {
k: ScriptHash,
l: WScriptHash,
m: ScriptBuf,
+ m3: ScriptSigBuf,
n: Sequence,
o: Transaction,
p: TxIn,
@@ -136,6 +141,7 @@ struct Ord {
k: ScriptHash,
l: WScriptHash,
m: ScriptBuf,
+ m3: ScriptSigBuf,
n: Sequence,
o: Transaction,
p: TxIn,
@@ -153,7 +159,9 @@ struct Ord {
struct Default {
a: block::Version,
b: &'static Script,
+ b3: &'static ScriptSig,
c: ScriptBuf,
+ c3: ScriptSigBuf,
d: Sequence,
e: Witness,
}
@@ -209,8 +217,8 @@ fn api_can_use_modules_from_crate_root() {
fn api_can_use_types_from_crate_root() {
use bitcoin_primitives::{
Block, BlockHash, BlockHeader, BlockVersion, CompactTarget, OutPoint, Script, ScriptBuf,
- Sequence, Transaction, TransactionVersion, TxIn, TxMerkleNode, TxOut, Txid, Witness,
- WitnessCommitment, WitnessMerkleNode, Wtxid,
+ ScriptSig, ScriptSigBuf, Sequence, Transaction, TransactionVersion, TxIn, TxMerkleNode,
+ TxOut, Txid, Witness, WitnessCommitment, WitnessMerkleNode, Wtxid,
};
}
@@ -226,7 +234,8 @@ fn api_can_use_all_types_from_module_locktime() {
#[test]
fn api_can_use_all_types_from_module_script() {
use bitcoin_primitives::script::{
- RedeemScriptSizeError, Script, ScriptBuf, ScriptHash, WScriptHash, WitnessScriptSizeError,
+ RedeemScriptSizeError, Script, ScriptBuf, ScriptHash, ScriptSig, ScriptSigBuf, WScriptHash,
+ WitnessScriptSizeError,
};
}
@@ -265,9 +274,11 @@ fn api_all_non_error_types_have_non_empty_debug() {
merkle_tree::WitnessMerkleNode::from_byte_array(BYTES);
pow::CompactTarget::from_consensus(0x1d00_ffff);
SCRIPT.as_script();
+ SCRIPT_SIG.as_script();
ScriptHash::from_script(&SCRIPT).unwrap();
WScriptHash::from_script(&SCRIPT).unwrap();
SCRIPT.clone();
+ SCRIPT_SIG.clone();
Sequence::arbitrary(&mut u).unwrap();
Transaction::arbitrary(&mut u).unwrap();
TxIn::arbitrary(&mut u).unwrap();
@@ -303,7 +314,9 @@ fn regression_default() {
let want = Default {
a: block::Version::NO_SOFT_FORK_SIGNALLING,
b: Script::from_bytes(&[]),
+ b3: ScriptSig::from_bytes(&[]),
c: ScriptBuf::from_bytes(Vec::new()),
+ c3: ScriptSigBuf::from_bytes(Vec::new()),
d: Sequence::MAX,
e: Witness::new(),
};
Why this scored 18/100
Community notes
Notes can correct, qualify, or add evidence to the AI analysis. Every note shown here has been validated by a human moderator.
The AI analysis stands alone for now. Submit a note if you can add evidence or important context.