cardano_serialization_lib/serialization/
metadata.rs

1use hashlink::LinkedHashMap;
2use crate::*;
3use crate::serialization::utils::{is_break_tag, merge_option_plutus_list};
4
5impl cbor_event::se::Serialize for MetadataMap {
6    fn serialize<'se, W: Write>(
7        &self,
8        serializer: &'se mut Serializer<W>,
9    ) -> cbor_event::Result<&'se mut Serializer<W>> {
10        serializer.write_map(cbor_event::Len::Len(self.0.len() as u64))?;
11        for (key, value) in &self.0 {
12            key.serialize(serializer)?;
13            value.serialize(serializer)?;
14        }
15        Ok(serializer)
16    }
17}
18
19impl Deserialize for MetadataMap {
20    fn deserialize<R: BufRead + Seek>(raw: &mut Deserializer<R>) -> Result<Self, DeserializeError> {
21        let mut table = LinkedHashMap::new();
22        let mut entries: Vec<(TransactionMetadatum, TransactionMetadatum)> = Vec::new();
23        (|| -> Result<_, DeserializeError> {
24            let len = raw.map()?;
25            while match len {
26                cbor_event::Len::Len(n) => entries.len() < n as usize,
27                cbor_event::Len::Indefinite => true,
28            } {
29                if is_break_tag(raw, "MetadataMap")? {
30                    break;
31                }
32                let key = TransactionMetadatum::deserialize(raw)?;
33                let value = TransactionMetadatum::deserialize(raw)?;
34                entries.push((key.clone(), value));
35            }
36            Ok(())
37        })()
38            .map_err(|e| e.annotate("MetadataMap"))?;
39        entries.iter().for_each(|(k, v)| {
40            if table.insert(k.clone(), v.clone()).is_some() {
41                // Turns out this is totally possible on the actual blockchain
42                // return Err(DeserializeFailure::DuplicateKey(Key::Str(String::from("some complicated/unsupported type"))).into());
43            }
44        });
45        Ok(Self(table))
46    }
47}
48
49impl cbor_event::se::Serialize for MetadataList {
50    fn serialize<'se, W: Write>(
51        &self,
52        serializer: &'se mut Serializer<W>,
53    ) -> cbor_event::Result<&'se mut Serializer<W>> {
54        serializer.write_array(cbor_event::Len::Len(self.0.len() as u64))?;
55        for element in &self.0 {
56            element.serialize(serializer)?;
57        }
58        Ok(serializer)
59    }
60}
61
62impl Deserialize for MetadataList {
63    fn deserialize<R: BufRead + Seek>(raw: &mut Deserializer<R>) -> Result<Self, DeserializeError> {
64        let mut arr = Vec::new();
65        (|| -> Result<_, DeserializeError> {
66            let len = raw.array()?;
67            while match len {
68                cbor_event::Len::Len(n) => arr.len() < n as usize,
69                cbor_event::Len::Indefinite => true,
70            } {
71                if is_break_tag(raw, "MetadataList")? {
72                    break;
73                }
74                arr.push(TransactionMetadatum::deserialize(raw)?);
75            }
76            Ok(())
77        })()
78            .map_err(|e| e.annotate("MetadataList"))?;
79        Ok(Self(arr))
80    }
81}
82
83impl cbor_event::se::Serialize for TransactionMetadatumEnum {
84    fn serialize<'se, W: Write>(
85        &self,
86        serializer: &'se mut Serializer<W>,
87    ) -> cbor_event::Result<&'se mut Serializer<W>> {
88        match self {
89            TransactionMetadatumEnum::MetadataMap(x) => x.serialize(serializer),
90            TransactionMetadatumEnum::MetadataList(x) => x.serialize(serializer),
91            TransactionMetadatumEnum::Int(x) => x.serialize(serializer),
92            TransactionMetadatumEnum::Bytes(x) => serializer.write_bytes(&x),
93            TransactionMetadatumEnum::Text(x) => serializer.write_text(&x),
94        }
95    }
96}
97
98impl Deserialize for TransactionMetadatumEnum {
99    fn deserialize<R: BufRead + Seek>(raw: &mut Deserializer<R>) -> Result<Self, DeserializeError> {
100        match raw.cbor_type()? {
101            CBORType::Array => {
102                MetadataList::deserialize(raw).map(TransactionMetadatumEnum::MetadataList)
103            }
104            CBORType::Map => {
105                MetadataMap::deserialize(raw).map(TransactionMetadatumEnum::MetadataMap)
106            }
107            CBORType::Bytes => TransactionMetadatum::new_bytes(raw.bytes()?)
108                .map(|m| m.0)
109                .map_err(|e| DeserializeFailure::Metadata(e).into()),
110            CBORType::Text => TransactionMetadatum::new_text(raw.text()?)
111                .map(|m| m.0)
112                .map_err(|e| DeserializeFailure::Metadata(e).into()),
113            CBORType::UnsignedInteger | CBORType::NegativeInteger => {
114                Int::deserialize(raw).map(TransactionMetadatumEnum::Int)
115            }
116            _ => Err(DeserializeError::new(
117                "TransactionMetadatumEnum",
118                DeserializeFailure::NoVariantMatched.into(),
119            )),
120        }
121    }
122}
123
124impl cbor_event::se::Serialize for TransactionMetadatum {
125    fn serialize<'se, W: Write>(
126        &self,
127        serializer: &'se mut Serializer<W>,
128    ) -> cbor_event::Result<&'se mut Serializer<W>> {
129        self.0.serialize(serializer)
130    }
131}
132
133impl Deserialize for TransactionMetadatum {
134    fn deserialize<R: BufRead + Seek>(raw: &mut Deserializer<R>) -> Result<Self, DeserializeError> {
135        Ok(Self(TransactionMetadatumEnum::deserialize(raw)?))
136    }
137}
138
139impl cbor_event::se::Serialize for TransactionMetadatumLabels {
140    fn serialize<'se, W: Write>(
141        &self,
142        serializer: &'se mut Serializer<W>,
143    ) -> cbor_event::Result<&'se mut Serializer<W>> {
144        serializer.write_array(cbor_event::Len::Len(self.0.len() as u64))?;
145        for element in &self.0 {
146            element.serialize(serializer)?;
147        }
148        Ok(serializer)
149    }
150}
151
152impl Deserialize for TransactionMetadatumLabels {
153    fn deserialize<R: BufRead + Seek>(raw: &mut Deserializer<R>) -> Result<Self, DeserializeError> {
154        let mut arr = Vec::new();
155        (|| -> Result<_, DeserializeError> {
156            let len = raw.array()?;
157            while match len {
158                cbor_event::Len::Len(n) => arr.len() < n as usize,
159                cbor_event::Len::Indefinite => true,
160            } {
161                if is_break_tag(raw, "TransactionMetadatumLabels")? {
162                    break;
163                }
164                arr.push(TransactionMetadatumLabel::deserialize(raw)?);
165            }
166            Ok(())
167        })()
168            .map_err(|e| e.annotate("TransactionMetadatumLabels"))?;
169        Ok(Self(arr))
170    }
171}
172
173impl cbor_event::se::Serialize for GeneralTransactionMetadata {
174    fn serialize<'se, W: Write>(
175        &self,
176        serializer: &'se mut Serializer<W>,
177    ) -> cbor_event::Result<&'se mut Serializer<W>> {
178        serializer.write_map(cbor_event::Len::Len(self.0.len() as u64))?;
179        for (key, value) in &self.0 {
180            key.serialize(serializer)?;
181            value.serialize(serializer)?;
182        }
183        Ok(serializer)
184    }
185}
186
187impl Deserialize for GeneralTransactionMetadata {
188    fn deserialize<R: BufRead + Seek>(raw: &mut Deserializer<R>) -> Result<Self, DeserializeError> {
189        let mut table = LinkedHashMap::new();
190        (|| -> Result<_, DeserializeError> {
191            let len = raw.map()?;
192            while match len {
193                cbor_event::Len::Len(n) => table.len() < n as usize,
194                cbor_event::Len::Indefinite => true,
195            } {
196                if is_break_tag(raw, "GeneralTransactionMetadata")? {
197                    break;
198                }
199                let key = TransactionMetadatumLabel::deserialize(raw)?;
200                let value = TransactionMetadatum::deserialize(raw)?;
201                if table.insert(key.clone(), value).is_some() {
202                    return Err(DeserializeFailure::DuplicateKey(Key::Str(String::from(
203                        "some complicated/unsupported type",
204                    )))
205                        .into());
206                }
207            }
208            Ok(())
209        })()
210            .map_err(|e| e.annotate("GeneralTransactionMetadata"))?;
211        Ok(Self(table))
212    }
213}
214
215impl cbor_event::se::Serialize for AuxiliaryData {
216    fn serialize<'se, W: Write>(
217        &self,
218        serializer: &'se mut Serializer<W>,
219    ) -> cbor_event::Result<&'se mut Serializer<W>> {
220        // we still serialize using the shelley-mary era format as it is still supported
221        // and it takes up less space on-chain so this should be better for scaling.
222        // Plus the code was already written for shelley-mary anyway
223        if !self.prefer_alonzo_format && self.metadata.is_some() && self.plutus_scripts.is_none() {
224            match &self.native_scripts() {
225                Some(native_scripts) => {
226                    serializer.write_array(cbor_event::Len::Len(2))?;
227                    self.metadata.as_ref().unwrap().serialize(serializer)?;
228                    native_scripts.serialize(serializer)
229                }
230                None => self.metadata.as_ref().unwrap().serialize(serializer),
231            }
232        } else {
233            let mut has_plutus_v2 = false;
234            let mut has_plutus_v3 = false;
235            let plutus_added_length = match &self.plutus_scripts {
236                Some(scripts) => {
237                    has_plutus_v2 = scripts.has_version(&Language::new_plutus_v2());
238                    has_plutus_v3 = scripts.has_version(&Language::new_plutus_v3());
239                    1 + (has_plutus_v2 as u64) + (has_plutus_v3 as u64)
240                },
241                _ => 0,
242            };
243
244            // new format with plutus support
245            serializer.write_tag(259u64)?;
246            serializer.write_map(cbor_event::Len::Len(
247                opt64(&self.metadata) + opt64(&self.native_scripts) + plutus_added_length,
248            ))?;
249            if let Some(metadata) = &self.metadata {
250                serializer.write_unsigned_integer(0)?;
251                metadata.serialize(serializer)?;
252            }
253            if let Some(native_scripts) = &self.native_scripts {
254                serializer.write_unsigned_integer(1)?;
255                native_scripts.serialize(serializer)?;
256            }
257            if let Some(plutus_scripts) = &self.plutus_scripts {
258                serializer.write_unsigned_integer(2)?;
259                plutus_scripts.serialize_by_version(&Language::new_plutus_v1(), serializer)?;
260                if has_plutus_v2 {
261                    serializer.write_unsigned_integer(3)?;
262                    plutus_scripts.serialize_by_version(&Language::new_plutus_v2(), serializer)?;
263                }
264                if has_plutus_v3 {
265                    serializer.write_unsigned_integer(4)?;
266                    plutus_scripts.serialize_by_version(&Language::new_plutus_v3(), serializer)?;
267                }
268            }
269            Ok(serializer)
270        }
271    }
272}
273
274impl Deserialize for AuxiliaryData {
275    fn deserialize<R: BufRead + Seek>(raw: &mut Deserializer<R>) -> Result<Self, DeserializeError> {
276        (|| -> Result<_, DeserializeError> {
277            match raw.cbor_type()? {
278                // alonzo format
279                CBORType::Tag => {
280                    let tag = raw.tag()?;
281                    if tag != 259 {
282                        return Err(DeserializeError::new(
283                            "AuxiliaryData",
284                            DeserializeFailure::TagMismatch {
285                                found: tag,
286                                expected: 259,
287                            },
288                        ));
289                    }
290                    let len = raw.map()?;
291                    let mut read_len = CBORReadLen::new(len);
292                    let mut metadata = None;
293                    let mut native_scripts = None;
294                    let mut plutus_scripts_v1 = None;
295                    let mut plutus_scripts_v2 = None;
296                    let mut plutus_scripts_v3 = None;
297                    let mut read = 0;
298                    while match len {
299                        cbor_event::Len::Len(n) => read < n as usize,
300                        cbor_event::Len::Indefinite => true,
301                    } {
302                        match raw.cbor_type()? {
303                            CBORType::UnsignedInteger => match raw.unsigned_integer()? {
304                                0 => {
305                                    if metadata.is_some() {
306                                        return Err(
307                                            DeserializeFailure::DuplicateKey(Key::Uint(0)).into()
308                                        );
309                                    }
310                                    metadata = Some(
311                                        (|| -> Result<_, DeserializeError> {
312                                            read_len.read_elems(1)?;
313                                            Ok(GeneralTransactionMetadata::deserialize(raw)?)
314                                        })()
315                                            .map_err(|e| e.annotate("metadata"))?,
316                                    );
317                                }
318                                1 => {
319                                    if native_scripts.is_some() {
320                                        return Err(
321                                            DeserializeFailure::DuplicateKey(Key::Uint(1)).into()
322                                        );
323                                    }
324                                    native_scripts = Some(
325                                        (|| -> Result<_, DeserializeError> {
326                                            read_len.read_elems(1)?;
327                                            Ok(NativeScripts::deserialize(raw)?)
328                                        })()
329                                            .map_err(|e| e.annotate("native_scripts"))?,
330                                    );
331                                }
332                                2 => {
333                                    if plutus_scripts_v1.is_some() {
334                                        return Err(
335                                            DeserializeFailure::DuplicateKey(Key::Uint(2)).into()
336                                        );
337                                    }
338                                    plutus_scripts_v1 = Some(
339                                        (|| -> Result<_, DeserializeError> {
340                                            read_len.read_elems(1)?;
341                                            Ok(PlutusScripts::deserialize(raw)?)
342                                        })()
343                                            .map_err(|e| e.annotate("plutus_scripts_v1"))?,
344                                    );
345                                }
346                                3 => {
347                                    if plutus_scripts_v2.is_some() {
348                                        return Err(
349                                            DeserializeFailure::DuplicateKey(Key::Uint(3)).into()
350                                        );
351                                    }
352                                    plutus_scripts_v2 = Some(
353                                        (|| -> Result<_, DeserializeError> {
354                                            read_len.read_elems(1)?;
355                                            Ok(PlutusScripts::deserialize_with_version(raw, &Language::new_plutus_v2())?)
356                                        })()
357                                            .map_err(|e| e.annotate("plutus_scripts_v2"))?,
358                                    );
359                                }
360                                4 => {
361                                    if plutus_scripts_v3.is_some() {
362                                        return Err(
363                                            DeserializeFailure::DuplicateKey(Key::Uint(3)).into()
364                                        );
365                                    }
366                                    plutus_scripts_v3 = Some(
367                                        (|| -> Result<_, DeserializeError> {
368                                            read_len.read_elems(1)?;
369                                            Ok(PlutusScripts::deserialize_with_version(raw, &Language::new_plutus_v3())?)
370                                        })()
371                                            .map_err(|e| e.annotate("plutus_scripts_v3"))?,
372                                    );
373                                }
374                                unknown_key => {
375                                    return Err(DeserializeFailure::UnknownKey(Key::Uint(
376                                        unknown_key,
377                                    ))
378                                        .into())
379                                }
380                            },
381                            CBORType::Text => match raw.text()?.as_str() {
382                                unknown_key => {
383                                    return Err(DeserializeFailure::UnknownKey(Key::Str(
384                                        unknown_key.to_owned(),
385                                    ))
386                                        .into())
387                                }
388                            },
389                            CBORType::Special => match len {
390                                cbor_event::Len::Len(_) => {
391                                    return Err(DeserializeFailure::BreakInDefiniteLen.into())
392                                }
393                                cbor_event::Len::Indefinite => match raw.special()? {
394                                    CBORSpecial::Break => break,
395                                    _ => return Err(DeserializeFailure::EndingBreakMissing.into()),
396                                },
397                            },
398                            other_type => {
399                                return Err(DeserializeFailure::UnexpectedKeyType(other_type).into())
400                            }
401                        }
402                        read += 1;
403                    }
404                    read_len.finish()?;
405                    let mut  plutus_scripts = None;
406                    plutus_scripts = merge_option_plutus_list(plutus_scripts, plutus_scripts_v1, &Language::new_plutus_v1());
407                    plutus_scripts = merge_option_plutus_list(plutus_scripts, plutus_scripts_v2, &Language::new_plutus_v2());
408                    plutus_scripts = merge_option_plutus_list(plutus_scripts, plutus_scripts_v3, &Language::new_plutus_v3());
409
410                    Ok(Self {
411                        metadata,
412                        native_scripts,
413                        plutus_scripts,
414                        prefer_alonzo_format: true,
415                    })
416                }
417                // shelley mary format (still valid for alonzo)
418                CBORType::Array => {
419                    let len = raw.array()?;
420                    let mut read_len = CBORReadLen::new(len);
421                    read_len.read_elems(2)?;
422                    let metadata = (|| -> Result<_, DeserializeError> {
423                        Ok(GeneralTransactionMetadata::deserialize(raw)?)
424                    })()
425                        .map_err(|e| e.annotate("metadata"))?;
426                    let native_scripts = (|| -> Result<_, DeserializeError> {
427                        Ok(NativeScripts::deserialize(raw)?)
428                    })()
429                        .map_err(|e| e.annotate("native_scripts"))?;
430                    match len {
431                        cbor_event::Len::Len(_) => (),
432                        cbor_event::Len::Indefinite => match raw.special()? {
433                            CBORSpecial::Break => (),
434                            _ => return Err(DeserializeFailure::EndingBreakMissing.into()),
435                        },
436                    }
437                    Ok(Self {
438                        metadata: Some(metadata),
439                        native_scripts: Some(native_scripts),
440                        plutus_scripts: None,
441                        prefer_alonzo_format: false,
442                    })
443                }
444                // shelley pre-mary format (still valid for alonzo + mary)
445                CBORType::Map => Ok(Self {
446                    metadata: Some(
447                        GeneralTransactionMetadata::deserialize(raw)
448                            .map_err(|e| e.annotate("metadata"))?,
449                    ),
450                    native_scripts: None,
451                    plutus_scripts: None,
452                    prefer_alonzo_format: false,
453                }),
454                _ => return Err(DeserializeFailure::NoVariantMatched)?,
455            }
456        })()
457            .map_err(|e| e.annotate("AuxiliaryData"))
458    }
459}