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