1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148
// SPDX-License-Identifier: CC0-1.0
use core::fmt;
use secp256k1::XOnlyPublicKey;
use crate::blockdata::locktime::absolute;
use crate::blockdata::opcodes::all::*;
use crate::blockdata::opcodes::{self, Opcode};
use crate::blockdata::script::{opcode_to_verify, write_scriptint, PushBytes, Script, ScriptBuf};
use crate::blockdata::transaction::Sequence;
use crate::key::PublicKey;
use crate::prelude::*;
/// An Object which can be used to construct a script piece by piece.
#[derive(PartialEq, Eq, Clone)]
pub struct Builder(ScriptBuf, Option<Opcode>);
impl Builder {
/// Creates a new empty script.
#[inline]
pub const fn new() -> Self { Builder(ScriptBuf::new(), None) }
/// Returns the length in bytes of the script.
pub fn len(&self) -> usize { self.0.len() }
/// Checks whether the script is the empty script.
pub fn is_empty(&self) -> bool { self.0.is_empty() }
/// Adds instructions to push an integer onto the stack.
///
/// Integers are encoded as little-endian signed-magnitude numbers, but there are dedicated
/// opcodes to push some small integers.
pub fn push_int(self, data: i64) -> Builder {
// We can special-case -1, 1-16
if data == -1 || (1..=16).contains(&data) {
let opcode = Opcode::from((data - 1 + opcodes::OP_TRUE.to_u8() as i64) as u8);
self.push_opcode(opcode)
}
// We can also special-case zero
else if data == 0 {
self.push_opcode(opcodes::OP_0)
}
// Otherwise encode it as data
else {
self.push_int_non_minimal(data)
}
}
/// Adds instructions to push an integer onto the stack without optimization.
///
/// This uses the explicit encoding regardless of the availability of dedicated opcodes.
pub(in crate::blockdata) fn push_int_non_minimal(self, data: i64) -> Builder {
let mut buf = [0u8; 8];
let len = write_scriptint(&mut buf, data);
self.push_slice(&<&PushBytes>::from(&buf)[..len])
}
/// Adds instructions to push some arbitrary data onto the stack.
pub fn push_slice<T: AsRef<PushBytes>>(mut self, data: T) -> Builder {
self.0.push_slice(data);
self.1 = None;
self
}
/// Adds instructions to push a public key onto the stack.
pub fn push_key(self, key: &PublicKey) -> Builder {
if key.compressed {
self.push_slice(key.inner.serialize())
} else {
self.push_slice(key.inner.serialize_uncompressed())
}
}
/// Adds instructions to push an XOnly public key onto the stack.
pub fn push_x_only_key(self, x_only_key: &XOnlyPublicKey) -> Builder {
self.push_slice(x_only_key.serialize())
}
/// Adds a single opcode to the script.
pub fn push_opcode(mut self, data: Opcode) -> Builder {
self.0.push_opcode(data);
self.1 = Some(data);
self
}
/// Adds an `OP_VERIFY` to the script or replaces the last opcode with VERIFY form.
///
/// Some opcodes such as `OP_CHECKSIG` have a verify variant that works as if `VERIFY` was
/// in the script right after. To save space this function appends `VERIFY` only if
/// the most-recently-added opcode *does not* have an alternate `VERIFY` form. If it does
/// the last opcode is replaced. E.g., `OP_CHECKSIG` will become `OP_CHECKSIGVERIFY`.
///
/// Note that existing `OP_*VERIFY` opcodes do not lead to the instruction being ignored
/// because `OP_VERIFY` consumes an item from the stack so ignoring them would change the
/// semantics.
pub fn push_verify(mut self) -> Builder {
// "duplicated code" because we need to update `1` field
match opcode_to_verify(self.1) {
Some(opcode) => {
(self.0).0.pop();
self.push_opcode(opcode)
}
None => self.push_opcode(OP_VERIFY),
}
}
/// Adds instructions to push an absolute lock time onto the stack.
pub fn push_lock_time(self, lock_time: absolute::LockTime) -> Builder {
self.push_int(lock_time.to_consensus_u32().into())
}
/// Adds instructions to push a sequence number onto the stack.
pub fn push_sequence(self, sequence: Sequence) -> Builder {
self.push_int(sequence.to_consensus_u32().into())
}
/// Converts the `Builder` into `ScriptBuf`.
pub fn into_script(self) -> ScriptBuf { self.0 }
/// Converts the `Builder` into script bytes
pub fn into_bytes(self) -> Vec<u8> { self.0.into() }
/// Returns the internal script
pub fn as_script(&self) -> &Script { &self.0 }
/// Returns script bytes
pub fn as_bytes(&self) -> &[u8] { self.0.as_bytes() }
}
impl Default for Builder {
fn default() -> Builder { Builder::new() }
}
/// Creates a new builder from an existing vector.
impl From<Vec<u8>> for Builder {
fn from(v: Vec<u8>) -> Builder {
let script = ScriptBuf::from(v);
let last_op = script.last_opcode();
Builder(script, last_op)
}
}
impl fmt::Display for Builder {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { self.0.fmt_asm(f) }
}
internals::debug_from_display!(Builder);