partner_chains_plutus_data/
lib.rs1#![deny(missing_docs)]
3use cardano_serialization_lib::{PlutusData, PlutusList};
4
5pub mod candidate_keys;
6pub mod d_param;
7pub mod governed_map;
8pub mod permissioned_candidates;
9pub mod registered_candidates;
10pub mod reserve;
11pub mod version_oracle;
12
13#[derive(Debug, PartialEq, thiserror::Error)]
14#[error("Could not decode {datum:?} to {to}: {msg}")]
15pub struct DataDecodingError {
17 datum: PlutusData,
18 to: String,
19 msg: String,
20}
21
22type DecodingResult<T> = std::result::Result<T, DataDecodingError>;
23
24pub trait PlutusDataExtensions {
26 fn as_u64(&self) -> Option<u64>;
28 fn as_u32(&self) -> Option<u32>;
30 fn as_u16(&self) -> Option<u16>;
32}
33
34impl PlutusDataExtensions for PlutusData {
35 fn as_u64(&self) -> Option<u64> {
36 self.as_integer()?.as_u64().map(u64::from)
37 }
38 fn as_u32(&self) -> Option<u32> {
39 u32::try_from(self.as_integer()?.as_u64()?).ok()
40 }
41 fn as_u16(&self) -> Option<u16> {
42 u16::try_from(self.as_u32()?).ok()
43 }
44}
45
46pub(crate) trait VersionedDatum: Sized {
61 fn decode(data: &PlutusData) -> DecodingResult<Self>;
63}
64
65pub(crate) trait VersionedDatumWithLegacy: Sized {
69 const NAME: &str;
70
71 fn decode_legacy(data: &PlutusData) -> Result<Self, String>;
73
74 fn decode_versioned(
81 version: u64,
82 datum: &PlutusData,
83 appendix: &PlutusData,
84 ) -> Result<Self, String>;
85}
86
87impl<T: VersionedDatumWithLegacy> VersionedDatum for T {
88 fn decode(data: &PlutusData) -> DecodingResult<Self> {
89 (match plutus_data_version_and_payload(data) {
90 None => Self::decode_legacy(data),
91 Some(VersionedGenericDatum { datum, appendix, version }) => {
92 Self::decode_versioned(version, &datum, &appendix)
93 },
94 })
95 .map_err(|msg| decoding_error_and_log(data, Self::NAME, &msg))
96 }
97}
98
99fn plutus_data_version_and_payload(data: &PlutusData) -> Option<VersionedGenericDatum> {
100 let fields = data.as_list().filter(|outer_list| outer_list.len() == 3)?;
101
102 Some(VersionedGenericDatum {
103 datum: fields.get(0),
104 appendix: fields.get(1),
105 version: fields.get(2).as_u64()?,
106 })
107}
108
109fn decoding_error_and_log(data: &PlutusData, to: &str, msg: &str) -> DataDecodingError {
110 log::error!("Could not decode {data:?} to {to}: {msg}");
111 DataDecodingError { datum: data.clone(), to: to.to_string(), msg: msg.to_string() }
112}
113
114pub struct VersionedGenericDatum {
118 pub datum: PlutusData,
120 pub appendix: PlutusData,
122 pub version: u64,
124}
125
126impl From<VersionedGenericDatum> for PlutusData {
127 fn from(value: VersionedGenericDatum) -> Self {
128 let mut list = PlutusList::new();
129 list.add(&value.datum);
130 list.add(&value.appendix);
131 list.add(&PlutusData::new_integer(&value.version.into()));
132 PlutusData::new_list(&list)
133 }
134}
135
136#[cfg(test)]
137pub(crate) mod test_helpers {
138 use cardano_serialization_lib::PlutusData;
139 macro_rules! test_plutus_data {
140 ($json:tt) => {
141 cardano_serialization_lib::encode_json_value_to_plutus_datum(
142 serde_json::json!($json),
143 cardano_serialization_lib::PlutusDatumSchema::DetailedSchema,
144 )
145 .expect("test data is valid")
146 };
147 }
148 pub(crate) use test_plutus_data;
149
150 pub(crate) fn json_to_plutus_data(json: serde_json::Value) -> PlutusData {
151 cardano_serialization_lib::encode_json_value_to_plutus_datum(
152 json,
153 cardano_serialization_lib::PlutusDatumSchema::DetailedSchema,
154 )
155 .expect("test data is valid")
156 }
157
158 pub(crate) fn plutus_data_to_json(data: PlutusData) -> serde_json::Value {
159 cardano_serialization_lib::decode_plutus_datum_to_json_value(
160 &data,
161 cardano_serialization_lib::PlutusDatumSchema::DetailedSchema,
162 )
163 .expect("test data is valid")
164 }
165}