use crate::script::error::ScriptError;
use crate::script::spend::Spend;
impl Spend {
pub(crate) fn push_stack(&mut self, item: Vec<u8>) -> Result<(), ScriptError> {
self.ensure_stack_mem(item.len())?;
self.stack_mem += item.len();
self.stack.push(item);
Ok(())
}
pub(crate) fn pop_stack(&mut self) -> Result<Vec<u8>, ScriptError> {
match self.stack.pop() {
Some(item) => {
self.stack_mem = self.stack_mem.saturating_sub(item.len());
Ok(item)
}
None => Err(ScriptError::StackUnderflow),
}
}
pub(crate) fn stack_top(&self, offset: isize) -> Result<&Vec<u8>, ScriptError> {
let idx = self.stack.len() as isize - 1 - offset;
if idx < 0 || idx >= self.stack.len() as isize {
return Err(ScriptError::InvalidStackOperation(format!(
"stack_top offset {} out of range (stack size {})",
offset,
self.stack.len()
)));
}
Ok(&self.stack[idx as usize])
}
#[allow(dead_code)]
pub(crate) fn stack_top_mut(&mut self, offset: isize) -> Result<&mut Vec<u8>, ScriptError> {
let len = self.stack.len() as isize;
let idx = len - 1 - offset;
if idx < 0 || idx >= len {
return Err(ScriptError::InvalidStackOperation(format!(
"stack_top_mut offset {} out of range (stack size {})",
offset,
self.stack.len()
)));
}
Ok(&mut self.stack[idx as usize])
}
pub(crate) fn push_alt_stack(&mut self, item: Vec<u8>) -> Result<(), ScriptError> {
self.ensure_stack_mem(item.len())?;
self.alt_stack_mem += item.len();
self.alt_stack.push(item);
Ok(())
}
pub(crate) fn pop_alt_stack(&mut self) -> Result<Vec<u8>, ScriptError> {
match self.alt_stack.pop() {
Some(item) => {
self.alt_stack_mem = self.alt_stack_mem.saturating_sub(item.len());
Ok(item)
}
None => Err(ScriptError::InvalidStackOperation(
"alt stack empty".to_string(),
)),
}
}
pub(crate) fn stack_to_bool(item: &[u8]) -> bool {
if item.is_empty() {
return false;
}
for (i, &byte) in item.iter().enumerate() {
if byte != 0 {
if i == item.len() - 1 && byte == 0x80 {
return false;
}
return true;
}
}
false
}
pub(crate) fn bool_to_stack(b: bool) -> Vec<u8> {
if b {
vec![1]
} else {
vec![]
}
}
pub(crate) fn ensure_stack_mem(&self, additional: usize) -> Result<(), ScriptError> {
let total = self.stack_mem + self.alt_stack_mem + additional;
if total > self.memory_limit {
return Err(ScriptError::MemoryLimitExceeded);
}
Ok(())
}
}