bitcoin_primitives/script/
mod.rs1mod borrowed;
6mod builder;
7mod owned;
8mod push_bytes;
9mod tag;
10#[cfg(test)]
11mod tests;
12
13pub mod error;
14
15use core::cmp::Ordering;
16use core::fmt;
17#[cfg(feature = "serde")]
18use core::marker::PhantomData;
19
20#[cfg(feature = "hex")]
21use hex::DisplayHex;
22use internals::script::{self, PushDataLenLen};
23
24use crate::prelude::rc::Rc;
25#[cfg(target_has_atomic = "ptr")]
26use crate::prelude::sync::Arc;
27use crate::prelude::{Borrow, BorrowMut, Box, Cow, ToOwned, Vec};
28use crate::witness_version::WitnessVersion;
29
30#[rustfmt::skip] #[doc(inline)]
32pub use self::{
33 borrowed::{Script, ScriptEncoder},
34 builder::Builder,
35 owned::{ScriptBuf, ScriptBufDecoder},
36 push_bytes::{PushBytes, PushBytesBuf, PushBytesErrorReport},
37 tag::{Tag, RedeemScriptTag, ScriptPubKeyTag, ScriptSigTag, SignetBlockScriptTag, TapScriptTag, WitnessScriptTag},
38};
39#[doc(no_inline)]
40pub use self::error::{
41 PushBytesError, RedeemScriptSizeError, ScriptBufDecoderError, WitnessScriptSizeError,
42};
43#[doc(inline)]
44pub use crate::hash_types::{ScriptHash, WScriptHash};
45
46pub type RedeemScriptBuf = ScriptBuf<RedeemScriptTag>;
48
49pub type RedeemScript = Script<RedeemScriptTag>;
51
52pub type ScriptPubKey = Script<ScriptPubKeyTag>;
54
55pub type ScriptSig = Script<ScriptSigTag>;
57
58pub type ScriptPubKeyBuf = ScriptBuf<ScriptPubKeyTag>;
60
61pub type ScriptPubKeyBufDecoder = ScriptBufDecoder<ScriptPubKeyTag>;
63
64pub type ScriptSigBuf = ScriptBuf<ScriptSigTag>;
66
67pub type ScriptSigBufDecoder = ScriptBufDecoder<ScriptSigTag>;
69
70pub type SignetBlockScriptBuf = ScriptBuf<SignetBlockScriptTag>;
72
73pub type SignetBlockScript = Script<SignetBlockScriptTag>;
75
76pub type TapScriptBuf = ScriptBuf<TapScriptTag>;
78
79pub type TapScript = Script<TapScriptTag>;
81
82pub type WitnessScriptBuf = ScriptBuf<WitnessScriptTag>;
84
85pub type WitnessScript = Script<WitnessScriptTag>;
87
88pub const MAX_REDEEM_SCRIPT_SIZE: usize = 520;
90pub const MAX_WITNESS_SCRIPT_SIZE: usize = 10_000;
92
93pub(crate) const P2A_PROGRAM: [u8; 2] = [78, 115];
95
96pub(crate) fn new_witness_program_unchecked<T: AsRef<PushBytes>, Tg>(
103 version: WitnessVersion,
104 program: T,
105) -> ScriptBuf<Tg> {
106 let program = program.as_ref();
107 debug_assert!(program.len() >= 2 && program.len() <= 40);
108 debug_assert!(version != WitnessVersion::V0 || program.len() == 20 || program.len() == 32);
110 Builder::new().push_opcode(version.into()).push_slice(program).into_script()
111}
112
113pub trait ScriptHashableTag: sealed::Sealed {}
124
125impl ScriptHashableTag for RedeemScriptTag {}
126impl ScriptHashableTag for ScriptPubKeyTag {}
127
128mod sealed {
129 pub trait Sealed {}
130 impl Sealed for super::RedeemScriptTag {}
131 impl Sealed for super::ScriptPubKeyTag {}
132}
133
134impl<T: ScriptHashableTag> TryFrom<ScriptBuf<T>> for ScriptHash {
135 type Error = RedeemScriptSizeError;
136
137 #[inline]
138 fn try_from(redeem_script: ScriptBuf<T>) -> Result<Self, Self::Error> {
139 Self::from_script(&redeem_script)
140 }
141}
142
143impl<T: ScriptHashableTag> TryFrom<&ScriptBuf<T>> for ScriptHash {
144 type Error = RedeemScriptSizeError;
145
146 #[inline]
147 fn try_from(redeem_script: &ScriptBuf<T>) -> Result<Self, Self::Error> {
148 Self::from_script(redeem_script)
149 }
150}
151
152impl<T: ScriptHashableTag> TryFrom<&Script<T>> for ScriptHash {
153 type Error = RedeemScriptSizeError;
154
155 #[inline]
156 fn try_from(redeem_script: &Script<T>) -> Result<Self, Self::Error> {
157 Self::from_script(redeem_script)
158 }
159}
160
161impl TryFrom<WitnessScriptBuf> for WScriptHash {
162 type Error = WitnessScriptSizeError;
163
164 #[inline]
165 fn try_from(witness_script: WitnessScriptBuf) -> Result<Self, Self::Error> {
166 Self::from_script(&witness_script)
167 }
168}
169
170impl TryFrom<&WitnessScriptBuf> for WScriptHash {
171 type Error = WitnessScriptSizeError;
172
173 #[inline]
174 fn try_from(witness_script: &WitnessScriptBuf) -> Result<Self, Self::Error> {
175 Self::from_script(witness_script)
176 }
177}
178
179impl TryFrom<&WitnessScript> for WScriptHash {
180 type Error = WitnessScriptSizeError;
181
182 #[inline]
183 fn try_from(witness_script: &WitnessScript) -> Result<Self, Self::Error> {
184 Self::from_script(witness_script)
185 }
186}
187
188impl From<WitnessScriptBuf> for SignetBlockScriptBuf {
189 #[inline]
190 fn from(buf: WitnessScriptBuf) -> Self { Self::from_bytes(buf.into_bytes()) }
191}
192
193impl<T> From<ScriptBuf<T>> for Box<Script<T>> {
196 #[inline]
197 fn from(v: ScriptBuf<T>) -> Self { v.into_boxed_script() }
198}
199
200impl<T> From<ScriptBuf<T>> for Cow<'_, Script<T>> {
201 #[inline]
202 fn from(value: ScriptBuf<T>) -> Self { Cow::Owned(value) }
203}
204
205impl<'a, T> From<Cow<'a, Script<T>>> for ScriptBuf<T> {
206 #[inline]
207 fn from(value: Cow<'a, Script<T>>) -> Self {
208 match value {
209 Cow::Owned(owned) => owned,
210 Cow::Borrowed(borrowed) => borrowed.into(),
211 }
212 }
213}
214
215impl<'a, T> From<Cow<'a, Script<T>>> for Box<Script<T>> {
216 #[inline]
217 fn from(value: Cow<'a, Script<T>>) -> Self {
218 match value {
219 Cow::Owned(owned) => owned.into(),
220 Cow::Borrowed(borrowed) => borrowed.into(),
221 }
222 }
223}
224
225impl<'a, T> From<&'a Script<T>> for Box<Script<T>> {
226 #[inline]
227 fn from(value: &'a Script<T>) -> Self { value.to_owned().into() }
228}
229
230impl<'a, T> From<&'a Script<T>> for ScriptBuf<T> {
231 #[inline]
232 fn from(value: &'a Script<T>) -> Self { value.to_owned() }
233}
234
235impl<'a, T> From<&'a Script<T>> for Cow<'a, Script<T>> {
236 #[inline]
237 fn from(value: &'a Script<T>) -> Self { Cow::Borrowed(value) }
238}
239
240#[cfg(target_has_atomic = "ptr")]
242impl<'a, T> From<&'a Script<T>> for Arc<Script<T>> {
243 #[inline]
244 fn from(value: &'a Script<T>) -> Self { Script::from_arc_bytes(Arc::from(value.as_bytes())) }
245}
246
247impl<'a, T> From<&'a Script<T>> for Rc<Script<T>> {
248 #[inline]
249 fn from(value: &'a Script<T>) -> Self { Script::from_rc_bytes(Rc::from(value.as_bytes())) }
250}
251
252impl<T> From<Vec<u8>> for ScriptBuf<T> {
253 #[inline]
254 fn from(v: Vec<u8>) -> Self { Self::from_bytes(v) }
255}
256
257impl<T> From<ScriptBuf<T>> for Vec<u8> {
258 #[inline]
259 fn from(v: ScriptBuf<T>) -> Self { v.into_bytes() }
260}
261
262impl<T> AsRef<Self> for Script<T> {
263 #[inline]
264 fn as_ref(&self) -> &Self { self }
265}
266
267impl<T> AsRef<Script<T>> for ScriptBuf<T> {
268 #[inline]
269 fn as_ref(&self) -> &Script<T> { self }
270}
271
272impl<T> AsRef<[u8]> for Script<T> {
273 #[inline]
274 fn as_ref(&self) -> &[u8] { self.as_bytes() }
275}
276
277impl<T> AsRef<[u8]> for ScriptBuf<T> {
278 #[inline]
279 fn as_ref(&self) -> &[u8] { self.as_bytes() }
280}
281
282impl<T> AsMut<Self> for Script<T> {
283 #[inline]
284 fn as_mut(&mut self) -> &mut Self { self }
285}
286
287impl<T> AsMut<Script<T>> for ScriptBuf<T> {
288 #[inline]
289 fn as_mut(&mut self) -> &mut Script<T> { self }
290}
291
292impl<T> AsMut<[u8]> for Script<T> {
293 #[inline]
294 fn as_mut(&mut self) -> &mut [u8] { self.as_mut_bytes() }
295}
296
297impl<T> AsMut<[u8]> for ScriptBuf<T> {
298 #[inline]
299 fn as_mut(&mut self) -> &mut [u8] { self.as_mut_bytes() }
300}
301
302impl<T> fmt::Debug for Script<T> {
303 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
304 f.write_str("Script(")?;
305 fmt::Display::fmt(self, f)?;
306 f.write_str(")")
307 }
308}
309
310impl<T> fmt::Debug for ScriptBuf<T> {
311 #[inline]
312 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { fmt::Debug::fmt(self.as_script(), f) }
313}
314
315impl<T> fmt::Display for Script<T> {
316 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
317 macro_rules! read_push_data_len {
319 ($iter:expr, $size:path, $formatter:expr) => {
320 match script::read_push_data_len($iter, $size) {
321 Ok(n) => n,
322 Err(_) => {
323 $formatter.write_str("<unexpected end>")?;
324 break;
325 }
326 }
327 };
328 }
329
330 let mut iter = self.as_bytes().iter();
331 let mut at_least_one = false;
333 while let Some(byte) = iter.next().copied() {
336 use crate::opcodes::{OP_PUSHDATA1, OP_PUSHDATA2, OP_PUSHDATA4};
337
338 let data_len = if byte <= 75 {
339 usize::from(byte)
340 } else {
341 match byte {
342 OP_PUSHDATA1 => {
343 read_push_data_len!(&mut iter, PushDataLenLen::One, f)
345 }
346 OP_PUSHDATA2 => {
347 read_push_data_len!(&mut iter, PushDataLenLen::Two, f)
349 }
350 OP_PUSHDATA4 => {
351 read_push_data_len!(&mut iter, PushDataLenLen::Four, f)
353 }
354 _ => 0,
355 }
356 };
357
358 if at_least_one {
359 f.write_str(" ")?;
360 } else {
361 at_least_one = true;
362 }
363 crate::opcodes::fmt_opcode(byte, f)?;
365 if data_len > 0 {
367 f.write_str(" ")?;
368 if data_len <= iter.len() {
369 for ch in iter.by_ref().take(data_len) {
370 write!(f, "{:02x}", ch)?;
371 }
372 } else {
373 f.write_str("<push past end>")?;
374 break;
375 }
376 }
377 }
378 Ok(())
379 }
380}
381
382impl<T> fmt::Display for ScriptBuf<T> {
383 #[inline]
384 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { fmt::Display::fmt(self.as_script(), f) }
385}
386
387#[cfg(feature = "hex")]
388impl<T> fmt::LowerHex for Script<T> {
389 #[inline]
390 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
391 fmt::LowerHex::fmt(&self.as_bytes().as_hex(), f)
392 }
393}
394
395#[cfg(feature = "hex")]
396impl<T> fmt::LowerHex for ScriptBuf<T> {
397 #[inline]
398 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { fmt::LowerHex::fmt(self.as_script(), f) }
399}
400
401#[cfg(feature = "hex")]
402impl<T> fmt::UpperHex for Script<T> {
403 #[inline]
404 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
405 fmt::UpperHex::fmt(&self.as_bytes().as_hex(), f)
406 }
407}
408
409#[cfg(feature = "hex")]
410impl<T> fmt::UpperHex for ScriptBuf<T> {
411 #[inline]
412 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { fmt::UpperHex::fmt(self.as_script(), f) }
413}
414
415impl<T> Borrow<Script<T>> for ScriptBuf<T> {
416 #[inline]
417 fn borrow(&self) -> &Script<T> { self }
418}
419
420impl<T> BorrowMut<Script<T>> for ScriptBuf<T> {
421 #[inline]
422 fn borrow_mut(&mut self) -> &mut Script<T> { self }
423}
424
425impl<T: PartialEq> PartialEq<ScriptBuf<T>> for Script<T> {
426 #[inline]
427 fn eq(&self, other: &ScriptBuf<T>) -> bool { self.eq(other.as_script()) }
428}
429
430impl<T: PartialEq> PartialEq<Script<T>> for ScriptBuf<T> {
431 #[inline]
432 fn eq(&self, other: &Script<T>) -> bool { self.as_script().eq(other) }
433}
434
435impl<T: PartialOrd> PartialOrd<Script<T>> for ScriptBuf<T> {
436 #[inline]
437 fn partial_cmp(&self, other: &Script<T>) -> Option<Ordering> {
438 self.as_script().partial_cmp(other)
439 }
440}
441
442impl<T: PartialOrd> PartialOrd<ScriptBuf<T>> for Script<T> {
443 #[inline]
444 fn partial_cmp(&self, other: &ScriptBuf<T>) -> Option<Ordering> {
445 self.partial_cmp(other.as_script())
446 }
447}
448
449#[cfg(feature = "serde")]
450impl<T> serde::Serialize for Script<T> {
451 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
453 where
454 S: serde::Serializer,
455 {
456 if serializer.is_human_readable() {
457 serializer.collect_str(&format_args!("{:x}", self))
458 } else {
459 serializer.serialize_bytes(self.as_bytes())
460 }
461 }
462}
463
464#[cfg(feature = "serde")]
466impl<'de, T> serde::Deserialize<'de> for &'de Script<T> {
467 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
468 where
469 D: serde::Deserializer<'de>,
470 {
471 struct Visitor<T>(PhantomData<T>);
472 impl<'de, T: 'de> serde::de::Visitor<'de> for Visitor<T> {
473 type Value = &'de Script<T>;
474
475 fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
476 formatter.write_str("borrowed bytes")
477 }
478
479 fn visit_borrowed_bytes<E>(self, v: &'de [u8]) -> Result<Self::Value, E>
480 where
481 E: serde::de::Error,
482 {
483 Ok(Script::from_bytes(v))
484 }
485 }
486
487 if deserializer.is_human_readable() {
488 use crate::serde::de::Error;
489
490 return Err(D::Error::custom(
491 "deserialization of `&Script` from human-readable formats is not possible",
492 ));
493 }
494
495 deserializer.deserialize_bytes(Visitor(PhantomData))
496 }
497}
498
499#[cfg(feature = "serde")]
500impl<T> serde::Serialize for ScriptBuf<T> {
501 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
503 where
504 S: serde::Serializer,
505 {
506 (**self).serialize(serializer)
507 }
508}
509
510#[cfg(feature = "serde")]
511impl<'de, T> serde::Deserialize<'de> for ScriptBuf<T> {
512 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
513 where
514 D: serde::Deserializer<'de>,
515 {
516 use core::fmt::Formatter;
517
518 if deserializer.is_human_readable() {
519 struct Visitor<T>(PhantomData<T>);
520 impl<T> serde::de::Visitor<'_> for Visitor<T> {
521 type Value = ScriptBuf<T>;
522
523 fn expecting(&self, formatter: &mut Formatter) -> fmt::Result {
524 formatter.write_str("a script hex")
525 }
526
527 fn visit_str<E>(self, v: &str) -> Result<Self::Value, E>
528 where
529 E: serde::de::Error,
530 {
531 let v = hex::decode_to_vec(v).map_err(E::custom)?;
532 Ok(ScriptBuf::from(v))
533 }
534 }
535 deserializer.deserialize_str(Visitor(PhantomData))
536 } else {
537 struct BytesVisitor<T>(PhantomData<T>);
538
539 impl<T> serde::de::Visitor<'_> for BytesVisitor<T> {
540 type Value = ScriptBuf<T>;
541
542 fn expecting(&self, formatter: &mut Formatter) -> fmt::Result {
543 formatter.write_str("a script Vec<u8>")
544 }
545
546 fn visit_bytes<E>(self, v: &[u8]) -> Result<Self::Value, E>
547 where
548 E: serde::de::Error,
549 {
550 Ok(ScriptBuf::from(v.to_vec()))
551 }
552
553 fn visit_byte_buf<E>(self, v: Vec<u8>) -> Result<Self::Value, E>
554 where
555 E: serde::de::Error,
556 {
557 Ok(ScriptBuf::from(v))
558 }
559 }
560 deserializer.deserialize_byte_buf(BytesVisitor(PhantomData))
561 }
562 }
563}