use bitcoin::consensus::encode::Error;
use bitcoin::consensus::Decodable;
use bitcoin::hashes::Hash;
use bitcoin::script::ScriptBuf;
use bitcoin::{opcodes, PubkeyHash, PublicKey, ScriptHash};
const NUM_SPECIAL_SCRIPTS: usize = 6;
const MAX_SCRIPT_SIZE: usize = 10_000;
use crate::VarInt;
#[derive(Debug)]
pub struct Script(ScriptBuf);
impl Script {
pub fn into_inner(self) -> ScriptBuf {
self.0
}
}
impl Decodable for Script {
fn consensus_decode<R: bitcoin::io::Read + ?Sized>(reader: &mut R) -> Result<Self, Error> {
let mut size = u64::from(VarInt::consensus_decode(reader)?) as usize;
match size {
0x00 => {
let mut bytes = [0; 20];
reader.read_exact(&mut bytes)?;
let pubkey_hash =
PubkeyHash::from_slice(&bytes).map_err(|_| Error::ParseFailed("HASH-160"))?;
Ok(Script(ScriptBuf::new_p2pkh(&pubkey_hash)))
}
0x01 => {
let mut bytes = [0; 20];
reader.read_exact(&mut bytes)?;
let script_hash =
ScriptHash::from_slice(&bytes).map_err(|_| Error::ParseFailed("HASH-160"))?;
Ok(Script(ScriptBuf::new_p2sh(&script_hash)))
}
0x02 | 0x03 => {
let mut bytes = [0; 32];
reader.read_exact(&mut bytes)?;
let mut script_bytes = Vec::with_capacity(35);
script_bytes.push(opcodes::all::OP_PUSHBYTES_33.to_u8());
script_bytes.push(size as u8);
script_bytes.extend_from_slice(&bytes);
script_bytes.push(opcodes::all::OP_CHECKSIG.to_u8());
Ok(Script(ScriptBuf::from(script_bytes)))
}
0x04 | 0x05 => {
let mut bytes = [0; 32];
reader.read_exact(&mut bytes)?;
let mut compressed_pubkey_bytes = Vec::with_capacity(33);
compressed_pubkey_bytes.push((size - 2) as u8);
compressed_pubkey_bytes.extend_from_slice(&bytes);
let compressed_pubkey = PublicKey::from_slice(&compressed_pubkey_bytes)
.map_err(|_| Error::ParseFailed("parse public key"))?;
let inner_uncompressed = compressed_pubkey.inner.serialize_uncompressed();
let mut script_bytes = Vec::with_capacity(67);
script_bytes.push(opcodes::all::OP_PUSHBYTES_65.to_u8());
script_bytes.extend_from_slice(&inner_uncompressed);
script_bytes.push(opcodes::all::OP_CHECKSIG.to_u8());
Ok(Script(ScriptBuf::from(script_bytes)))
}
_ => {
size = size.saturating_sub(NUM_SPECIAL_SCRIPTS);
if size > MAX_SCRIPT_SIZE {
Err(Error::OversizedVectorAllocation {
requested: size,
max: MAX_SCRIPT_SIZE,
})
} else {
let mut bytes = Vec::with_capacity(size);
bytes.resize_with(size, || 0);
reader.read_exact(&mut bytes)?;
Ok(Script(ScriptBuf::from_bytes(bytes)))
}
}
}
}
}