use core::convert::TryInto;
use core::fmt;
use crate::blockdata::script::witness_version::WitnessVersion;
use crate::blockdata::script::{PushBytes, PushBytesBuf, PushBytesErrorReport};
#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct WitnessProgram {
version: WitnessVersion,
program: PushBytesBuf,
}
impl WitnessProgram {
pub fn new<P>(version: WitnessVersion, program: P) -> Result<Self, Error>
where
P: TryInto<PushBytesBuf>,
<P as TryInto<PushBytesBuf>>::Error: PushBytesErrorReport,
{
use Error::*;
let program = program.try_into().map_err(|error| InvalidLength(error.input_len()))?;
if program.len() < 2 || program.len() > 40 {
return Err(InvalidLength(program.len()));
}
if version == WitnessVersion::V0 && (program.len() != 20 && program.len() != 32) {
return Err(InvalidSegwitV0Length(program.len()));
}
Ok(WitnessProgram { version, program })
}
pub fn version(&self) -> WitnessVersion { self.version }
pub fn program(&self) -> &PushBytes { &self.program }
}
#[derive(Clone, Debug, PartialEq, Eq)]
#[non_exhaustive]
pub enum Error {
InvalidLength(usize),
InvalidSegwitV0Length(usize),
}
impl fmt::Display for Error {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
use Error::*;
match *self {
InvalidLength(len) =>
write!(f, "witness program must be between 2 and 40 bytes: length={}", len),
InvalidSegwitV0Length(len) =>
write!(f, "a v0 witness program must be either 20 or 32 bytes: length={}", len),
}
}
}
#[cfg(feature = "std")]
impl std::error::Error for Error {
fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
use Error::*;
match *self {
InvalidLength(_) | InvalidSegwitV0Length(_) => None,
}
}
}