Skip to main content

amaru_kernel/cardano/memoized/
datum.rs

1// Copyright 2025 PRAGMA
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7//     http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15use serde::ser::SerializeStruct;
16
17use crate::{
18    Hash, Legacy, MemoizedPlutusData,
19    cbor::{self, IanaTag},
20    size::DATUM,
21};
22
23#[derive(Debug, Clone, PartialEq, Eq)]
24pub enum MemoizedDatum {
25    None,
26    Hash(Hash<DATUM>),
27    Inline(MemoizedPlutusData),
28}
29
30impl serde::Serialize for MemoizedDatum {
31    fn serialize<S: serde::ser::Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
32        match self {
33            MemoizedDatum::None => None::<()>.serialize(serializer),
34            MemoizedDatum::Hash(hash) => {
35                let mut s = serializer.serialize_struct("MemoizedDatum::Hash", 1)?;
36                s.serialize_field("Hash", &hash)?;
37                s.end()
38            }
39            MemoizedDatum::Inline(data) => {
40                let mut s = serializer.serialize_struct("MemoizedDatum::Data", 1)?;
41                s.serialize_field("Data", &data)?;
42                s.end()
43            }
44        }
45    }
46}
47
48impl<'de> serde::Deserialize<'de> for MemoizedDatum {
49    fn deserialize<D: serde::de::Deserializer<'de>>(deserializer: D) -> Result<MemoizedDatum, D::Error> {
50        // TODO: rename those fields eventually to something less Rust-tainted.
51        #[derive(serde::Deserialize)]
52        enum PlaceholderDatum {
53            Hash(Hash<DATUM>),
54            Data(MemoizedPlutusData),
55            #[serde(untagged)]
56            Unit(()),
57        }
58
59        match serde::Deserialize::deserialize(deserializer)? {
60            PlaceholderDatum::Unit(()) => Ok(MemoizedDatum::None),
61            PlaceholderDatum::Hash(bytes) => Ok(MemoizedDatum::Hash(bytes)),
62            PlaceholderDatum::Data(data) => Ok(MemoizedDatum::Inline(data)),
63        }
64    }
65}
66
67impl<'b, C> cbor::Decode<'b, C> for MemoizedDatum {
68    fn decode(d: &mut cbor::Decoder<'b>, ctx: &mut C) -> Result<Self, cbor::decode::Error> {
69        cbor::heterogeneous_array(d, |d, assert_len| {
70            assert_len(2)?;
71            let datum_option = d.u8()?;
72            match datum_option {
73                0 => {
74                    let Legacy(datum) = d.decode_with(ctx)?;
75                    Ok(datum)
76                }
77                1 => {
78                    if d.tag()? != IanaTag::Cbor.tag() {
79                        return Err(cbor::decode::Error::message("unknown tag for datum tag"));
80                    }
81                    let plutus_data: pallas_primitives::KeepRaw<'_, pallas_primitives::PlutusData> =
82                        cbor::decode_with(d.bytes()?, ctx)?;
83                    Ok(MemoizedDatum::Inline(MemoizedPlutusData::from(plutus_data)))
84                }
85                _ => Err(cbor::decode::Error::message(format!("unknown datum option: {}", datum_option))),
86            }
87        })
88    }
89}
90
91impl<'b, C> cbor::Decode<'b, C> for Legacy<MemoizedDatum> {
92    fn decode(d: &mut cbor::Decoder<'b>, _ctx: &mut C) -> Result<Self, cbor::decode::Error> {
93        let raw = d.bytes()?;
94        if raw.len() != 32 {
95            return Err(cbor::decode::Error::message(format!("expected datum hash of length 32, got {}", raw.len())));
96        }
97        Ok(Legacy(MemoizedDatum::Hash(Hash::<DATUM>::from(raw))))
98    }
99}
100
101impl<C> cbor::Encode<C> for MemoizedDatum {
102    fn encode<W: cbor::encode::Write>(
103        &self,
104        e: &mut cbor::Encoder<W>,
105        _ctx: &mut C,
106    ) -> Result<(), cbor::encode::Error<W::Error>> {
107        match &self {
108            MemoizedDatum::None => (),
109            MemoizedDatum::Hash(hash) => {
110                e.array(2)?;
111                e.u8(0)?;
112                e.bytes(&hash[..])?;
113            }
114            MemoizedDatum::Inline(data) => {
115                e.array(2)?;
116                e.u8(1)?;
117                e.tag(IanaTag::Cbor)?;
118                e.bytes(data.original_bytes())?;
119            }
120        }
121
122        Ok(())
123    }
124}
125
126impl From<Option<Hash<DATUM>>> for MemoizedDatum {
127    fn from(opt: Option<Hash<DATUM>>) -> Self {
128        opt.map(MemoizedDatum::Hash).unwrap_or(MemoizedDatum::None)
129    }
130}