cardano_sdk/cardano/
plutus_script.rs

1//  This Source Code Form is subject to the terms of the Mozilla Public
2//  License, v. 2.0. If a copy of the MPL was not distributed with this
3//  file, You can obtain one at http://mozilla.org/MPL/2.0/.
4
5use crate::{Hash, PlutusVersion, pallas};
6use std::fmt;
7
8/// A flat-encoded Plutus program, alongside its [`PlutusVersion`](crate::PlutusVersion).
9///
10/// Note that a hash of the script can be obtained using [`Hash::from`](crate::Hash::from):
11///
12/// ```rust
13/// # use cardano_sdk::{Hash, PlutusVersion, hash, plutus_script};
14/// assert_eq!(
15///     Hash::from(&plutus_script!(PlutusVersion::V3, "5101010023259800a518a4d136564004ae69")),
16///     hash!("bd3ae991b5aafccafe5ca70758bd36a9b2f872f57f6d3a1ffa0eb777"),
17/// )
18/// ```
19#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord)]
20pub struct PlutusScript(PlutusVersion, Vec<u8>);
21
22impl fmt::Display for PlutusScript {
23    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
24        write!(f, "{}({})", self.0, <Hash<28>>::from(self))
25    }
26}
27
28// --------------------------------------------------------------------- Building
29
30impl PlutusScript {
31    /// Instantiate a script from its language and serialised (flat) form
32    ///
33    /// See also [`plutus_script!`](crate::plutus_script!).
34    pub fn new(version: PlutusVersion, script: Vec<u8>) -> Self {
35        Self(version, script)
36    }
37}
38
39// ------------------------------------------------------------------- Inspecting
40
41impl PlutusScript {
42    pub fn version(&self) -> PlutusVersion {
43        self.0
44    }
45
46    pub fn script(&self) -> &[u8] {
47        &self.1
48    }
49
50    /// The size of the flat-serialized script, without any CBOR wrapper.
51    pub fn size(&self) -> u64 {
52        self.1.len() as u64
53    }
54}
55
56// ------------------------------------------------------------ Converting (from)
57
58impl From<pallas::PlutusScript<1>> for PlutusScript {
59    fn from(plutus_script: pallas::PlutusScript<1>) -> Self {
60        Self(PlutusVersion::V1, plutus_script.0.to_vec())
61    }
62}
63
64impl From<pallas::PlutusScript<2>> for PlutusScript {
65    fn from(plutus_script: pallas::PlutusScript<2>) -> Self {
66        Self(PlutusVersion::V2, plutus_script.0.to_vec())
67    }
68}
69
70impl From<pallas::PlutusScript<3>> for PlutusScript {
71    fn from(plutus_script: pallas::PlutusScript<3>) -> Self {
72        Self(PlutusVersion::V3, plutus_script.0.to_vec())
73    }
74}
75
76// -------------------------------------------------------------- Converting (to)
77
78impl From<&PlutusScript> for Hash<28> {
79    fn from(PlutusScript(version, script): &PlutusScript) -> Self {
80        let mut buffer: Vec<u8> = vec![u8::from(*version)];
81        buffer.extend_from_slice(script.as_slice());
82        Hash::from(pallas::Hasher::<224>::hash(&buffer))
83    }
84}
85
86pub struct PlutusVersionMismatch {
87    pub expected: PlutusVersion,
88    pub found: PlutusVersion,
89}
90
91impl From<PlutusScript> for pallas::ScriptRef {
92    fn from(PlutusScript(version, script): PlutusScript) -> Self {
93        match version {
94            PlutusVersion::V1 => pallas::ScriptRef::PlutusV1Script(pallas::PlutusScript::<1>(
95                pallas::Bytes::from(script),
96            )),
97            PlutusVersion::V2 => pallas::ScriptRef::PlutusV2Script(pallas::PlutusScript::<2>(
98                pallas::Bytes::from(script),
99            )),
100            PlutusVersion::V3 => pallas::ScriptRef::PlutusV3Script(pallas::PlutusScript::<3>(
101                pallas::Bytes::from(script),
102            )),
103        }
104    }
105}
106
107impl TryFrom<PlutusScript> for pallas::PlutusScript<1> {
108    type Error = PlutusVersionMismatch;
109
110    fn try_from(PlutusScript(version, script): PlutusScript) -> Result<Self, Self::Error> {
111        match version {
112            PlutusVersion::V1 => Ok(pallas::PlutusScript(pallas::Bytes::from(script))),
113            PlutusVersion::V2 | PlutusVersion::V3 => Err(PlutusVersionMismatch {
114                expected: PlutusVersion::V1,
115                found: version,
116            }),
117        }
118    }
119}
120
121impl TryFrom<PlutusScript> for pallas::PlutusScript<2> {
122    type Error = PlutusVersionMismatch;
123
124    fn try_from(PlutusScript(version, script): PlutusScript) -> Result<Self, Self::Error> {
125        match version {
126            PlutusVersion::V2 => Ok(pallas::PlutusScript(pallas::Bytes::from(script))),
127            PlutusVersion::V1 | PlutusVersion::V3 => Err(PlutusVersionMismatch {
128                expected: PlutusVersion::V2,
129                found: version,
130            }),
131        }
132    }
133}
134
135impl TryFrom<PlutusScript> for pallas::PlutusScript<3> {
136    type Error = PlutusVersionMismatch;
137
138    fn try_from(PlutusScript(version, script): PlutusScript) -> Result<Self, Self::Error> {
139        match version {
140            PlutusVersion::V3 => Ok(pallas::PlutusScript(pallas::Bytes::from(script))),
141            PlutusVersion::V1 | PlutusVersion::V2 => Err(PlutusVersionMismatch {
142                expected: PlutusVersion::V3,
143                found: version,
144            }),
145        }
146    }
147}