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
149
150
151
152
153
154
155
156
157
158
159
160
161
// Written in 2014 by Andrew Poelstra <apoelstra@wpsoftware.net>
// SPDX-License-Identifier: CC0-1.0

#[cfg(feature="bitcoinconsensus")] use core::convert::From;
use core::default::Default;
use core::fmt;

use secp256k1::XOnlyPublicKey;

use crate::blockdata::locktime::absolute;
use crate::blockdata::opcodes::{self, all::*};
use crate::blockdata::script::{write_scriptint, opcode_to_verify, Script, ScriptBuf, PushBytes};
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<opcodes::All>);

impl Builder {
    /// Creates a new empty script.
    pub 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 = opcodes::All::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: opcodes::All) -> 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)
    }
}

bitcoin_internals::debug_from_display!(Builder);