Skip to main content

bsv_script/interpreter/
stack.rs

1//! Script execution stack.
2
3use super::error::{InterpreterError, InterpreterErrorCode};
4use super::scriptnum::ScriptNumber;
5
6/// Convert byte array to boolean (Bitcoin consensus rules).
7pub fn as_bool(t: &[u8]) -> bool {
8    for i in 0..t.len() {
9        if t[i] != 0 {
10            // Negative 0 is also considered false
11            if i == t.len() - 1 && t[i] == 0x80 {
12                return false;
13            }
14            return true;
15        }
16    }
17    false
18}
19
20/// Convert boolean to byte array.
21pub fn from_bool(v: bool) -> Vec<u8> {
22    if v {
23        vec![1]
24    } else {
25        vec![]
26    }
27}
28
29/// The main data/alt stack used by the script interpreter.
30pub struct Stack {
31    /// The underlying stack storage, where the last element is the top.
32    pub stk: Vec<Vec<u8>>,
33    /// Maximum allowed byte length for numeric values on this stack.
34    pub max_num_length: usize,
35    /// Whether post-genesis rules are active (relaxed limits).
36    pub after_genesis: bool,
37    /// Whether to enforce minimal data encoding for numeric conversions.
38    pub verify_minimal_data: bool,
39}
40
41impl Stack {
42    /// Create a new empty stack with the given numeric limits and flags.
43    pub fn new(max_num_length: usize, after_genesis: bool, verify_minimal_data: bool) -> Self {
44        Stack {
45            stk: Vec::new(),
46            max_num_length,
47            after_genesis,
48            verify_minimal_data,
49        }
50    }
51
52    /// Return the number of elements on the stack.
53    pub fn depth(&self) -> i32 {
54        self.stk.len() as i32
55    }
56
57    /// Push a raw byte array onto the top of the stack.
58    pub fn push_byte_array(&mut self, data: Vec<u8>) {
59        self.stk.push(data);
60    }
61
62    /// Push a script number onto the stack, serialized to bytes.
63    pub fn push_int(&mut self, n: &ScriptNumber) {
64        self.push_byte_array(n.to_bytes());
65    }
66
67    /// Push a boolean value onto the stack.
68    pub fn push_bool(&mut self, val: bool) {
69        self.push_byte_array(from_bool(val));
70    }
71
72    /// Pop and return the top byte array from the stack.
73    pub fn pop_byte_array(&mut self) -> Result<Vec<u8>, InterpreterError> {
74        self.nip_n(0)
75    }
76
77    /// Pop the top element and decode it as a script number.
78    pub fn pop_int(&mut self) -> Result<ScriptNumber, InterpreterError> {
79        let data = self.pop_byte_array()?;
80        ScriptNumber::from_bytes(
81            &data,
82            self.max_num_length,
83            self.verify_minimal_data,
84            self.after_genesis,
85        )
86    }
87
88    /// Pop the top element and interpret it as a boolean.
89    pub fn pop_bool(&mut self) -> Result<bool, InterpreterError> {
90        let data = self.pop_byte_array()?;
91        Ok(as_bool(&data))
92    }
93
94    /// Peek at a byte array at the given depth index (0 = top) without removing it.
95    pub fn peek_byte_array(&self, idx: i32) -> Result<Vec<u8>, InterpreterError> {
96        let sz = self.stk.len() as i32;
97        if idx < 0 || idx >= sz {
98            return Err(InterpreterError::new(
99                InterpreterErrorCode::InvalidStackOperation,
100                format!("index {} is invalid for stack size {}", idx, sz),
101            ));
102        }
103        Ok(self.stk[(sz - idx - 1) as usize].clone())
104    }
105
106    /// Peek at a script number at the given depth index without removing it.
107    pub fn peek_int(&self, idx: i32) -> Result<ScriptNumber, InterpreterError> {
108        let data = self.peek_byte_array(idx)?;
109        ScriptNumber::from_bytes(
110            &data,
111            self.max_num_length,
112            self.verify_minimal_data,
113            self.after_genesis,
114        )
115    }
116
117    /// Peek at a boolean at the given depth index without removing it.
118    pub fn peek_bool(&self, idx: i32) -> Result<bool, InterpreterError> {
119        let data = self.peek_byte_array(idx)?;
120        Ok(as_bool(&data))
121    }
122
123    fn nip_n(&mut self, idx: i32) -> Result<Vec<u8>, InterpreterError> {
124        let sz = self.stk.len() as i32;
125        if idx < 0 || idx > sz - 1 {
126            return Err(InterpreterError::new(
127                InterpreterErrorCode::InvalidStackOperation,
128                format!("index {} is invalid for stack size {}", idx, sz),
129            ));
130        }
131        let pos = (sz - idx - 1) as usize;
132        Ok(self.stk.remove(pos))
133    }
134
135    /// Remove and discard the element at the given depth index (0 = top).
136    pub fn nip_n_discard(&mut self, idx: i32) -> Result<(), InterpreterError> {
137        self.nip_n(idx)?;
138        Ok(())
139    }
140
141    /// Copy the top element and insert it before the second-to-top element (OP_TUCK).
142    pub fn tuck(&mut self) -> Result<(), InterpreterError> {
143        let so2 = self.pop_byte_array()?;
144        let so1 = self.pop_byte_array()?;
145        self.push_byte_array(so2.clone());
146        self.push_byte_array(so1);
147        self.push_byte_array(so2);
148        Ok(())
149    }
150
151    /// Remove the top `n` elements from the stack.
152    pub fn drop_n(&mut self, n: i32) -> Result<(), InterpreterError> {
153        if n < 1 {
154            return Err(InterpreterError::new(
155                InterpreterErrorCode::InvalidStackOperation,
156                format!("attempt to drop {} items from stack", n),
157            ));
158        }
159        for _ in 0..n {
160            self.pop_byte_array()?;
161        }
162        Ok(())
163    }
164
165    /// Duplicate the top `n` elements on the stack.
166    pub fn dup_n(&mut self, n: i32) -> Result<(), InterpreterError> {
167        if n < 1 {
168            return Err(InterpreterError::new(
169                InterpreterErrorCode::InvalidStackOperation,
170                format!("attempt to dup {} stack items", n),
171            ));
172        }
173        for _ in (0..n).rev() {
174            let so = self.peek_byte_array(n - 1)?;
175            self.push_byte_array(so);
176        }
177        Ok(())
178    }
179
180    /// Rotate the top `3*n` elements: move the bottom `n` of that group to the top.
181    pub fn rot_n(&mut self, n: i32) -> Result<(), InterpreterError> {
182        if n < 1 {
183            return Err(InterpreterError::new(
184                InterpreterErrorCode::InvalidStackOperation,
185                format!("attempt to rotate {} stack items", n),
186            ));
187        }
188        let entry = 3 * n - 1;
189        for _ in (0..n).rev() {
190            let so = self.nip_n(entry)?;
191            self.push_byte_array(so);
192        }
193        Ok(())
194    }
195
196    /// Swap the top `n` elements with the `n` elements below them.
197    pub fn swap_n(&mut self, n: i32) -> Result<(), InterpreterError> {
198        if n < 1 {
199            return Err(InterpreterError::new(
200                InterpreterErrorCode::InvalidStackOperation,
201                format!("attempt to swap {} stack items", n),
202            ));
203        }
204        let entry = 2 * n - 1;
205        for _ in (0..n).rev() {
206            let so = self.nip_n(entry)?;
207            self.push_byte_array(so);
208        }
209        Ok(())
210    }
211
212    /// Copy `n` elements from below the top `n` elements and push them on top.
213    pub fn over_n(&mut self, n: i32) -> Result<(), InterpreterError> {
214        if n < 1 {
215            return Err(InterpreterError::new(
216                InterpreterErrorCode::InvalidStackOperation,
217                format!("attempt to perform over on {} stack items", n),
218            ));
219        }
220        let entry = 2 * n - 1;
221        for _ in (0..n).rev() {
222            let so = self.peek_byte_array(entry)?;
223            self.push_byte_array(so);
224        }
225        Ok(())
226    }
227
228    /// Copy the element at depth `n` and push it on top (OP_PICK).
229    pub fn pick_n(&mut self, n: i32) -> Result<(), InterpreterError> {
230        let so = self.peek_byte_array(n)?;
231        self.push_byte_array(so);
232        Ok(())
233    }
234
235    /// Remove the element at depth `n` and push it on top (OP_ROLL).
236    pub fn roll_n(&mut self, n: i32) -> Result<(), InterpreterError> {
237        let so = self.nip_n(n)?;
238        self.push_byte_array(so);
239        Ok(())
240    }
241
242    /// Get stack contents as array (bottom to top).
243    pub fn get_stack(&self) -> Vec<Vec<u8>> {
244        self.stk.clone()
245    }
246
247    /// Set stack contents from array (last = top).
248    pub fn set_stack(&mut self, data: Vec<Vec<u8>>) {
249        self.stk = data;
250    }
251
252    /// Clear all items.
253    pub fn clear(&mut self) {
254        self.stk.clear();
255    }
256}
257
258/// A simple boolean stack for tracking if/else state.
259pub struct BoolStack {
260    stk: Vec<bool>,
261}
262
263impl BoolStack {
264    /// Create a new empty boolean stack.
265    pub fn new() -> Self {
266        BoolStack { stk: Vec::new() }
267    }
268
269    /// Push a boolean value onto the stack.
270    pub fn push_bool(&mut self, b: bool) {
271        self.stk.push(b);
272    }
273
274    /// Pop and return the top boolean value from the stack.
275    pub fn pop_bool(&mut self) -> Result<bool, InterpreterError> {
276        self.stk.pop().ok_or_else(|| {
277            InterpreterError::new(
278                InterpreterErrorCode::InvalidStackOperation,
279                "bool stack empty".to_string(),
280            )
281        })
282    }
283
284    /// Return the number of elements on the boolean stack.
285    pub fn depth(&self) -> i32 {
286        self.stk.len() as i32
287    }
288}
289
290#[cfg(test)]
291mod tests {
292    use super::*;
293
294    #[test]
295    fn test_as_bool() {
296        assert!(!as_bool(&[]));
297        assert!(!as_bool(&[0x00]));
298        assert!(!as_bool(&[0x80])); // negative zero
299        assert!(as_bool(&[0x01]));
300        assert!(as_bool(&[0x00, 0x01]));
301        assert!(!as_bool(&[0x00, 0x00]));
302        assert!(!as_bool(&[0x00, 0x80])); // negative zero
303    }
304
305    #[test]
306    fn test_stack_basic_ops() {
307        let mut s = Stack::new(4, false, false);
308        s.push_byte_array(vec![1, 2, 3]);
309        s.push_byte_array(vec![4, 5]);
310        assert_eq!(s.depth(), 2);
311        let top = s.pop_byte_array().unwrap();
312        assert_eq!(top, vec![4, 5]);
313        assert_eq!(s.depth(), 1);
314    }
315
316    #[test]
317    fn test_stack_dup() {
318        let mut s = Stack::new(4, false, false);
319        s.push_byte_array(vec![1]);
320        s.push_byte_array(vec![2]);
321        s.dup_n(2).unwrap();
322        assert_eq!(s.depth(), 4);
323        assert_eq!(s.pop_byte_array().unwrap(), vec![2]);
324        assert_eq!(s.pop_byte_array().unwrap(), vec![1]);
325    }
326
327    #[test]
328    fn test_stack_swap() {
329        let mut s = Stack::new(4, false, false);
330        s.push_byte_array(vec![1]);
331        s.push_byte_array(vec![2]);
332        s.swap_n(1).unwrap();
333        assert_eq!(s.pop_byte_array().unwrap(), vec![1]);
334        assert_eq!(s.pop_byte_array().unwrap(), vec![2]);
335    }
336}