use anyhow::{Context, Result};
use bitcoincash::blockdata::opcodes;
use bitcoincash::blockdata::script::read_uint;
use core::slice::Iter;
pub fn read_push_from_script(mut iter: Iter<u8>) -> Result<(Iter<u8>, Option<Vec<u8>>)> {
macro_rules! take_stack_item {
($iter:expr, $len:expr) => {{
let p = $iter.by_ref().take($len).cloned().collect::<Vec<u8>>();
if p.len() < $len {
return Err(anyhow!(
"Item on stack is smaller than expected ({} > {})",
p.len(),
$len
));
}
p
}};
}
let opcode = if let Some(o) = iter.next() {
opcodes::All::from(*o)
} else {
return Ok((iter, None));
};
if let opcodes::Class::PushBytes(n) = opcode.classify(opcodes::ClassifyContext::Legacy) {
let item = Some(take_stack_item!(iter, n as usize));
return Ok((iter, item));
}
let n = match opcode {
opcodes::all::OP_PUSHDATA1 => {
let n = read_uint(iter.as_slice(), 1).context("Invalid PUSHDATA1")?;
iter.next().unwrap();
n
}
opcodes::all::OP_PUSHDATA2 => {
let n = read_uint(iter.as_slice(), 2).context("Invalid PUSHDATA2")?;
iter.next().unwrap();
iter.next().unwrap();
n
}
opcodes::all::OP_PUSHDATA4 => {
let n = read_uint(iter.as_slice(), 4).context("Invalid PUSHDATA4")?;
iter.next().unwrap();
iter.next().unwrap();
iter.next().unwrap();
iter.next().unwrap();
n
}
_ => bail!("Not a push operation"),
};
let item = take_stack_item!(iter, n);
Ok((iter, Some(item)))
}