whisky_pallas/wrapper/auxiliary_data/
auxiliary_data.rs

1use std::{collections::BTreeMap, str::FromStr};
2
3use crate::wrapper::witness_set::{native_script::NativeScript, plutus_script::PlutusScript};
4
5use pallas::{
6    codec::utils::{Bytes, Int},
7    ledger::primitives::{
8        alonzo::{
9            PostAlonzoAuxiliaryData as PallasPostAlonzoAuxiliaryData,
10            ShelleyMaAuxiliaryData as PallasShelleyMaAuxiliaryData,
11        },
12        conway::{
13            AuxiliaryData as PallasAuxiliaryData, Metadata as PallasMetadata,
14            Metadatum as PallasMetadum,
15        },
16        Fragment, KeyValuePairs,
17    },
18};
19
20pub type MetadatumLabel = u64;
21
22pub type Metadata = BTreeMap<MetadatumLabel, Metadatum>;
23
24#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Clone)]
25pub enum Metadatum {
26    Int(i64),
27    Bytes(String),
28    Text(String),
29    Array(Vec<Metadatum>),
30    Map(Vec<(Metadatum, Metadatum)>),
31}
32
33#[derive(Debug, PartialEq, Clone, Eq)]
34pub struct PostAlonzoAuxiliaryData {
35    pub metadata: Option<Metadata>,
36    pub native_scripts: Option<Vec<NativeScript>>,
37    pub plutus_scripts: Option<Vec<PlutusScript<1>>>,
38}
39
40#[derive(Debug, PartialEq, Clone, Eq)]
41pub struct ShelleyMaAuxiliaryData {
42    pub transaction_metadata: Metadata,
43    pub auxiliary_scripts: Option<Vec<NativeScript>>,
44}
45
46#[derive(Debug, PartialEq, Clone, Eq)]
47pub enum AuxiliaryDataKind {
48    Shelley(Metadata),
49    ShelleyMa(ShelleyMaAuxiliaryData),
50    PostAlonzo(PostAlonzoAuxiliaryData),
51}
52
53#[derive(Debug, PartialEq, Clone, Eq)]
54pub struct AuxiliaryData {
55    pub inner: PallasAuxiliaryData,
56}
57
58impl AuxiliaryData {
59    pub fn new(kind: AuxiliaryDataKind) -> Result<Self, String> {
60        let inner: PallasAuxiliaryData = match kind {
61            AuxiliaryDataKind::Shelley(metadata) => {
62                PallasAuxiliaryData::Shelley(Self::to_pallas_metadatum_map(metadata)?)
63            }
64            AuxiliaryDataKind::ShelleyMa(shelley_ma_aux_data) => {
65                PallasAuxiliaryData::ShelleyMa(PallasShelleyMaAuxiliaryData {
66                    transaction_metadata: Self::to_pallas_metadatum_map(
67                        shelley_ma_aux_data.transaction_metadata,
68                    )?,
69                    auxiliary_scripts: match shelley_ma_aux_data.auxiliary_scripts {
70                        Some(scripts) => Some(scripts.into_iter().map(|s| s.inner).collect()),
71                        None => None,
72                    },
73                })
74            }
75            AuxiliaryDataKind::PostAlonzo(post_alonzo_aux_data) => {
76                PallasAuxiliaryData::PostAlonzo(PallasPostAlonzoAuxiliaryData {
77                    metadata: match post_alonzo_aux_data.metadata {
78                        Some(meta) => Some(Self::to_pallas_metadatum_map(meta)?),
79                        None => None,
80                    },
81                    native_scripts: match post_alonzo_aux_data.native_scripts {
82                        Some(scripts) => Some(scripts.into_iter().map(|s| s.inner).collect()),
83                        None => None,
84                    },
85                    plutus_scripts: match post_alonzo_aux_data.plutus_scripts {
86                        Some(scripts) => Some(scripts.into_iter().map(|s| s.inner).collect()),
87                        None => None,
88                    },
89                })
90            }
91        };
92
93        Ok(Self { inner })
94    }
95
96    fn to_pallas_metadatum_map(metadata: Metadata) -> Result<PallasMetadata, String> {
97        let mut pallas_metadata_map: BTreeMap<u64, PallasMetadum> = BTreeMap::new();
98        for (key, value) in metadata {
99            let pallas_value = Self::to_pallas_metadatum(value)
100                .map_err(|e| format!("Invalid metadatum during serialization: {}", e))?;
101            pallas_metadata_map.insert(key, pallas_value);
102        }
103        Ok(PallasMetadata::from(pallas_metadata_map))
104    }
105
106    fn to_pallas_metadatum(metadatum: Metadatum) -> Result<PallasMetadum, String> {
107        match metadatum {
108            Metadatum::Int(i) => Ok(PallasMetadum::Int(Int::from(i))),
109            Metadatum::Bytes(b) => {
110                Ok(PallasMetadum::Bytes(Bytes::from_str(&b).map_err(|e| {
111                    format!("Invalid bytes in metadatum: {}", e)
112                })?))
113            }
114            Metadatum::Text(t) => Ok(PallasMetadum::Text(t)),
115            Metadatum::Array(arr) => {
116                let mut pallas_array = Vec::new();
117                for item in arr {
118                    pallas_array.push(Self::to_pallas_metadatum(item)?);
119                }
120                Ok(PallasMetadum::Array(pallas_array))
121            }
122            Metadatum::Map(map) => {
123                let mut pallas_key_values = Vec::new();
124                for (key, value) in map {
125                    let pallas_key = Self::to_pallas_metadatum(key)?;
126                    let pallas_value = Self::to_pallas_metadatum(value)?;
127                    pallas_key_values.push((pallas_key, pallas_value));
128                }
129                Ok(PallasMetadum::Map(KeyValuePairs::from(pallas_key_values)))
130            }
131        }
132    }
133
134    pub fn encode(&self) -> String {
135        hex::encode(
136            self.inner
137                .encode_fragment()
138                .expect("encoding failed at AuxiliaryData"),
139        )
140    }
141
142    pub fn decode_bytes(bytes: &[u8]) -> Result<Self, String> {
143        let inner = PallasAuxiliaryData::decode_fragment(&bytes)
144            .map_err(|e| format!("Fragment decode error: {}", e.to_string()))?;
145        Ok(Self { inner })
146    }
147}