#[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::*;
#[derive(PartialEq, Eq, Clone)]
pub struct Builder(ScriptBuf, Option<opcodes::All>);
impl Builder {
pub fn new() -> Self {
Builder(ScriptBuf::new(), None)
}
pub fn len(&self) -> usize { self.0.len() }
pub fn is_empty(&self) -> bool { self.0.is_empty() }
pub fn push_int(self, data: i64) -> Builder {
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)
}
else if data == 0 {
self.push_opcode(opcodes::OP_0)
}
else { self.push_int_non_minimal(data) }
}
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])
}
pub fn push_slice<T: AsRef<PushBytes>>(mut self, data: T) -> Builder {
self.0.push_slice(data);
self.1 = None;
self
}
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())
}
}
pub fn push_x_only_key(self, x_only_key: &XOnlyPublicKey) -> Builder {
self.push_slice(x_only_key.serialize())
}
pub fn push_opcode(mut self, data: opcodes::All) -> Builder {
self.0.push_opcode(data);
self.1 = Some(data);
self
}
pub fn push_verify(mut self) -> Builder {
match opcode_to_verify(self.1) {
Some(opcode) => {
(self.0).0.pop();
self.push_opcode(opcode)
},
None => self.push_opcode(OP_VERIFY),
}
}
pub fn push_lock_time(self, lock_time: absolute::LockTime) -> Builder {
self.push_int(lock_time.to_consensus_u32().into())
}
pub fn push_sequence(self, sequence: Sequence) -> Builder {
self.push_int(sequence.to_consensus_u32().into())
}
pub fn into_script(self) -> ScriptBuf {
self.0
}
pub fn into_bytes(self) -> Vec<u8> {
self.0.into()
}
pub fn as_script(&self) -> &Script {
&self.0
}
pub fn as_bytes(&self) -> &[u8] {
self.0.as_bytes()
}
}
impl Default for Builder {
fn default() -> Builder { Builder::new() }
}
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);