whisky_pallas/wrapper/witness_set/
native_script.rs

1use std::str::FromStr;
2
3use pallas::{
4    crypto::hash::Hash,
5    ledger::{
6        primitives::{conway::NativeScript as PallasNativeScript, Fragment},
7        traverse::ComputeHash,
8    },
9};
10use whisky_common::WError;
11
12pub enum NativeScriptKind {
13    ScriptPubkey(String),
14    ScriptAll(Vec<NativeScriptKind>),
15    ScriptAny(Vec<NativeScriptKind>),
16    ScriptNOfK(u32, Vec<NativeScriptKind>),
17    InvalidBefore(u64),
18    InvalidHereafter(u64),
19}
20
21#[derive(Debug, PartialEq, Eq, Clone)]
22pub struct NativeScript {
23    pub inner: PallasNativeScript,
24}
25
26impl NativeScript {
27    pub fn new(native_script: NativeScriptKind) -> Result<Self, WError> {
28        let inner = Self::convert_native_script_kind_to_pallas(native_script)?;
29        Ok(NativeScript { inner })
30    }
31
32    pub fn new_from_hex(hex_str: &str) -> Result<Self, WError> {
33        let bytes = hex::decode(hex_str).map_err(|e| {
34            WError::new(
35                "WhiskyPallas - Creating native script from hex:",
36                &format!("Hex decode error: {}", e.to_string()),
37            )
38        })?;
39        let inner = PallasNativeScript::decode_fragment(&bytes).map_err(|e| {
40            WError::new(
41                "WhiskyPallas - Creating native script from hex:",
42                &format!("Fragment decode error: {}", e.to_string()),
43            )
44        })?;
45        Ok(NativeScript { inner })
46    }
47
48    fn convert_native_script_kind_to_pallas(
49        kind: NativeScriptKind,
50    ) -> Result<PallasNativeScript, WError> {
51        match kind {
52            NativeScriptKind::ScriptPubkey(key_hash) => {
53                let bytes = Hash::<28>::from_str(&key_hash).map_err(|e| {
54                    WError::new(
55                        "WhiskyPallas - Converting native script:",
56                        &format!("Invalid key hash: {}", e),
57                    )
58                })?;
59                Ok(PallasNativeScript::ScriptPubkey(bytes))
60            }
61            NativeScriptKind::ScriptAll(scripts) => {
62                let converted: Result<Vec<_>, WError> = scripts
63                    .into_iter()
64                    .map(Self::convert_native_script_kind_to_pallas)
65                    .collect();
66                Ok(PallasNativeScript::ScriptAll(converted?))
67            }
68            NativeScriptKind::ScriptAny(scripts) => {
69                let converted: Result<Vec<_>, WError> = scripts
70                    .into_iter()
71                    .map(Self::convert_native_script_kind_to_pallas)
72                    .collect();
73                Ok(PallasNativeScript::ScriptAny(converted?))
74            }
75            NativeScriptKind::ScriptNOfK(n, scripts) => {
76                let converted: Result<Vec<_>, WError> = scripts
77                    .into_iter()
78                    .map(Self::convert_native_script_kind_to_pallas)
79                    .collect();
80                Ok(PallasNativeScript::ScriptNOfK(n, converted?))
81            }
82            NativeScriptKind::InvalidBefore(slot) => Ok(PallasNativeScript::InvalidBefore(slot)),
83            NativeScriptKind::InvalidHereafter(slot) => {
84                Ok(PallasNativeScript::InvalidHereafter(slot))
85            }
86        }
87    }
88
89    pub fn encode(&self) -> Result<String, WError> {
90        self.inner
91            .encode_fragment()
92            .map(|bytes| hex::encode(bytes))
93            .map_err(|_| {
94                WError::new(
95                    "WhiskyPallas - Encoding native script:",
96                    "Failed to encode fragment",
97                )
98            })
99    }
100
101    pub fn decode_bytes(bytes: &[u8]) -> Result<Self, WError> {
102        let inner = PallasNativeScript::decode_fragment(&bytes).map_err(|e| {
103            WError::new(
104                "WhiskyPallas - Decoding native script:",
105                &format!("Fragment decode error: {}", e.to_string()),
106            )
107        })?;
108        Ok(Self { inner })
109    }
110
111    pub fn hash(&self) -> String {
112        self.inner.compute_hash().to_string()
113    }
114}