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(&data, self.max_num_length, self.verify_minimal_data, self.after_genesis)
81    }
82
83    /// Pop the top element and interpret it as a boolean.
84    pub fn pop_bool(&mut self) -> Result<bool, InterpreterError> {
85        let data = self.pop_byte_array()?;
86        Ok(as_bool(&data))
87    }
88
89    /// Peek at a byte array at the given depth index (0 = top) without removing it.
90    pub fn peek_byte_array(&self, idx: i32) -> Result<Vec<u8>, InterpreterError> {
91        let sz = self.stk.len() as i32;
92        if idx < 0 || idx >= sz {
93            return Err(InterpreterError::new(
94                InterpreterErrorCode::InvalidStackOperation,
95                format!("index {} is invalid for stack size {}", idx, sz),
96            ));
97        }
98        Ok(self.stk[(sz - idx - 1) as usize].clone())
99    }
100
101    /// Peek at a script number at the given depth index without removing it.
102    pub fn peek_int(&self, idx: i32) -> Result<ScriptNumber, InterpreterError> {
103        let data = self.peek_byte_array(idx)?;
104        ScriptNumber::from_bytes(&data, self.max_num_length, self.verify_minimal_data, self.after_genesis)
105    }
106
107    /// Peek at a boolean at the given depth index without removing it.
108    pub fn peek_bool(&self, idx: i32) -> Result<bool, InterpreterError> {
109        let data = self.peek_byte_array(idx)?;
110        Ok(as_bool(&data))
111    }
112
113    fn nip_n(&mut self, idx: i32) -> Result<Vec<u8>, InterpreterError> {
114        let sz = self.stk.len() as i32;
115        if idx < 0 || idx > sz - 1 {
116            return Err(InterpreterError::new(
117                InterpreterErrorCode::InvalidStackOperation,
118                format!("index {} is invalid for stack size {}", idx, sz),
119            ));
120        }
121        let pos = (sz - idx - 1) as usize;
122        Ok(self.stk.remove(pos))
123    }
124
125    /// Remove and discard the element at the given depth index (0 = top).
126    pub fn nip_n_discard(&mut self, idx: i32) -> Result<(), InterpreterError> {
127        self.nip_n(idx)?;
128        Ok(())
129    }
130
131    /// Copy the top element and insert it before the second-to-top element (OP_TUCK).
132    pub fn tuck(&mut self) -> Result<(), InterpreterError> {
133        let so2 = self.pop_byte_array()?;
134        let so1 = self.pop_byte_array()?;
135        self.push_byte_array(so2.clone());
136        self.push_byte_array(so1);
137        self.push_byte_array(so2);
138        Ok(())
139    }
140
141    /// Remove the top `n` elements from the stack.
142    pub fn drop_n(&mut self, n: i32) -> Result<(), InterpreterError> {
143        if n < 1 {
144            return Err(InterpreterError::new(
145                InterpreterErrorCode::InvalidStackOperation,
146                format!("attempt to drop {} items from stack", n),
147            ));
148        }
149        for _ in 0..n {
150            self.pop_byte_array()?;
151        }
152        Ok(())
153    }
154
155    /// Duplicate the top `n` elements on the stack.
156    pub fn dup_n(&mut self, n: i32) -> Result<(), InterpreterError> {
157        if n < 1 {
158            return Err(InterpreterError::new(
159                InterpreterErrorCode::InvalidStackOperation,
160                format!("attempt to dup {} stack items", n),
161            ));
162        }
163        for _ in (0..n).rev() {
164            let so = self.peek_byte_array(n - 1)?;
165            self.push_byte_array(so);
166        }
167        Ok(())
168    }
169
170    /// Rotate the top `3*n` elements: move the bottom `n` of that group to the top.
171    pub fn rot_n(&mut self, n: i32) -> Result<(), InterpreterError> {
172        if n < 1 {
173            return Err(InterpreterError::new(
174                InterpreterErrorCode::InvalidStackOperation,
175                format!("attempt to rotate {} stack items", n),
176            ));
177        }
178        let entry = 3 * n - 1;
179        for _ in (0..n).rev() {
180            let so = self.nip_n(entry)?;
181            self.push_byte_array(so);
182        }
183        Ok(())
184    }
185
186    /// Swap the top `n` elements with the `n` elements below them.
187    pub fn swap_n(&mut self, n: i32) -> Result<(), InterpreterError> {
188        if n < 1 {
189            return Err(InterpreterError::new(
190                InterpreterErrorCode::InvalidStackOperation,
191                format!("attempt to swap {} stack items", n),
192            ));
193        }
194        let entry = 2 * n - 1;
195        for _ in (0..n).rev() {
196            let so = self.nip_n(entry)?;
197            self.push_byte_array(so);
198        }
199        Ok(())
200    }
201
202    /// Copy `n` elements from below the top `n` elements and push them on top.
203    pub fn over_n(&mut self, n: i32) -> Result<(), InterpreterError> {
204        if n < 1 {
205            return Err(InterpreterError::new(
206                InterpreterErrorCode::InvalidStackOperation,
207                format!("attempt to perform over on {} stack items", n),
208            ));
209        }
210        let entry = 2 * n - 1;
211        for _ in (0..n).rev() {
212            let so = self.peek_byte_array(entry)?;
213            self.push_byte_array(so);
214        }
215        Ok(())
216    }
217
218    /// Copy the element at depth `n` and push it on top (OP_PICK).
219    pub fn pick_n(&mut self, n: i32) -> Result<(), InterpreterError> {
220        let so = self.peek_byte_array(n)?;
221        self.push_byte_array(so);
222        Ok(())
223    }
224
225    /// Remove the element at depth `n` and push it on top (OP_ROLL).
226    pub fn roll_n(&mut self, n: i32) -> Result<(), InterpreterError> {
227        let so = self.nip_n(n)?;
228        self.push_byte_array(so);
229        Ok(())
230    }
231
232    /// Get stack contents as array (bottom to top).
233    pub fn get_stack(&self) -> Vec<Vec<u8>> {
234        self.stk.clone()
235    }
236
237    /// Set stack contents from array (last = top).
238    pub fn set_stack(&mut self, data: Vec<Vec<u8>>) {
239        self.stk = data;
240    }
241
242    /// Clear all items.
243    pub fn clear(&mut self) {
244        self.stk.clear();
245    }
246}
247
248/// A simple boolean stack for tracking if/else state.
249pub struct BoolStack {
250    stk: Vec<bool>,
251}
252
253impl BoolStack {
254    /// Create a new empty boolean stack.
255    pub fn new() -> Self {
256        BoolStack { stk: Vec::new() }
257    }
258
259    /// Push a boolean value onto the stack.
260    pub fn push_bool(&mut self, b: bool) {
261        self.stk.push(b);
262    }
263
264    /// Pop and return the top boolean value from the stack.
265    pub fn pop_bool(&mut self) -> Result<bool, InterpreterError> {
266        self.stk.pop().ok_or_else(|| {
267            InterpreterError::new(
268                InterpreterErrorCode::InvalidStackOperation,
269                "bool stack empty".to_string(),
270            )
271        })
272    }
273
274    /// Return the number of elements on the boolean stack.
275    pub fn depth(&self) -> i32 {
276        self.stk.len() as i32
277    }
278}
279
280#[cfg(test)]
281mod tests {
282    use super::*;
283
284    #[test]
285    fn test_as_bool() {
286        assert!(!as_bool(&[]));
287        assert!(!as_bool(&[0x00]));
288        assert!(!as_bool(&[0x80])); // negative zero
289        assert!(as_bool(&[0x01]));
290        assert!(as_bool(&[0x00, 0x01]));
291        assert!(!as_bool(&[0x00, 0x00]));
292        assert!(!as_bool(&[0x00, 0x80])); // negative zero
293    }
294
295    #[test]
296    fn test_stack_basic_ops() {
297        let mut s = Stack::new(4, false, false);
298        s.push_byte_array(vec![1, 2, 3]);
299        s.push_byte_array(vec![4, 5]);
300        assert_eq!(s.depth(), 2);
301        let top = s.pop_byte_array().unwrap();
302        assert_eq!(top, vec![4, 5]);
303        assert_eq!(s.depth(), 1);
304    }
305
306    #[test]
307    fn test_stack_dup() {
308        let mut s = Stack::new(4, false, false);
309        s.push_byte_array(vec![1]);
310        s.push_byte_array(vec![2]);
311        s.dup_n(2).unwrap();
312        assert_eq!(s.depth(), 4);
313        assert_eq!(s.pop_byte_array().unwrap(), vec![2]);
314        assert_eq!(s.pop_byte_array().unwrap(), vec![1]);
315    }
316
317    #[test]
318    fn test_stack_swap() {
319        let mut s = Stack::new(4, false, false);
320        s.push_byte_array(vec![1]);
321        s.push_byte_array(vec![2]);
322        s.swap_n(1).unwrap();
323        assert_eq!(s.pop_byte_array().unwrap(), vec![1]);
324        assert_eq!(s.pop_byte_array().unwrap(), vec![2]);
325    }
326}