pallas_primitives/
lib.rs

1//! Ledger primitives and cbor codec for the Cardano eras
2
3mod framework;
4mod plutus_data;
5
6pub mod alonzo;
7pub mod babbage;
8pub mod byron;
9pub mod conway;
10pub use plutus_data::*;
11
12pub use framework::*;
13
14pub use pallas_codec::utils::{
15    Bytes, Int, KeepRaw, KeyValuePairs, MaybeIndefArray, NonEmptyKeyValuePairs, NonEmptySet,
16    NonZeroInt, Nullable, PositiveCoin, Set,
17};
18pub use pallas_crypto::hash::Hash;
19
20use pallas_codec::minicbor::{self, data::Tag, Decode, Encode};
21use serde::{Deserialize, Serialize};
22
23// ----- Common type definitions
24
25pub type AddrKeyhash = Hash<28>;
26
27pub type AssetName = Bytes;
28
29pub type Coin = u64;
30
31pub type CostModel = Vec<i64>;
32
33pub type DatumHash = Hash<32>;
34
35pub type DnsName = String;
36
37pub type Epoch = u64;
38
39#[derive(Serialize, Deserialize, Encode, Decode, Debug, PartialEq, Eq, Clone, Copy)]
40pub struct ExUnits {
41    #[n(0)]
42    pub mem: u64,
43    #[n(1)]
44    pub steps: u64,
45}
46
47#[derive(Serialize, Deserialize, Encode, Decode, Debug, PartialEq, Eq, Clone)]
48pub struct ExUnitPrices {
49    #[n(0)]
50    pub mem_price: PositiveInterval,
51
52    #[n(1)]
53    pub step_price: PositiveInterval,
54}
55
56pub type Genesishash = Bytes;
57
58pub type GenesisDelegateHash = Bytes;
59
60pub type IPv4 = Bytes;
61
62pub type IPv6 = Bytes;
63
64pub type Metadata = KeyValuePairs<MetadatumLabel, Metadatum>;
65
66#[derive(Serialize, Deserialize, Debug, PartialEq, Eq, PartialOrd, Ord, Clone)]
67pub enum Metadatum {
68    Int(Int),
69    Bytes(Bytes),
70    Text(String),
71    Array(Vec<Metadatum>),
72    Map(KeyValuePairs<Metadatum, Metadatum>),
73}
74
75impl<'b, C> minicbor::Decode<'b, C> for Metadatum {
76    fn decode(d: &mut minicbor::Decoder<'b>, ctx: &mut C) -> Result<Self, minicbor::decode::Error> {
77        match d.datatype()? {
78            minicbor::data::Type::U8
79            | minicbor::data::Type::U16
80            | minicbor::data::Type::U32
81            | minicbor::data::Type::U64
82            | minicbor::data::Type::I8
83            | minicbor::data::Type::I16
84            | minicbor::data::Type::I32
85            | minicbor::data::Type::I64
86            | minicbor::data::Type::Int => {
87                let i = d.decode()?;
88                Ok(Metadatum::Int(i))
89            }
90            minicbor::data::Type::Bytes => Ok(Metadatum::Bytes(d.decode_with(ctx)?)),
91            minicbor::data::Type::String => Ok(Metadatum::Text(d.decode_with(ctx)?)),
92            minicbor::data::Type::Array | minicbor::data::Type::ArrayIndef => {
93                Ok(Metadatum::Array(d.decode_with(ctx)?))
94            }
95            minicbor::data::Type::Map | minicbor::data::Type::MapIndef => {
96                Ok(Metadatum::Map(d.decode_with(ctx)?))
97            }
98            _ => Err(minicbor::decode::Error::message(
99                "Can't turn data type into metadatum",
100            )),
101        }
102    }
103}
104
105impl<C> minicbor::Encode<C> for Metadatum {
106    fn encode<W: minicbor::encode::Write>(
107        &self,
108        e: &mut minicbor::Encoder<W>,
109        ctx: &mut C,
110    ) -> Result<(), minicbor::encode::Error<W::Error>> {
111        match self {
112            Metadatum::Int(a) => {
113                e.encode_with(a, ctx)?;
114            }
115            Metadatum::Bytes(a) => {
116                e.encode_with(a, ctx)?;
117            }
118            Metadatum::Text(a) => {
119                e.encode_with(a, ctx)?;
120            }
121            Metadatum::Array(a) => {
122                e.encode_with(a, ctx)?;
123            }
124            Metadatum::Map(a) => {
125                e.encode_with(a, ctx)?;
126            }
127        };
128
129        Ok(())
130    }
131}
132
133pub type MetadatumLabel = u64;
134
135#[derive(
136    Serialize, Deserialize, Encode, Decode, Debug, PartialEq, Eq, PartialOrd, Ord, Clone, Copy,
137)]
138#[cbor(index_only)]
139pub enum NetworkId {
140    #[n(0)]
141    Testnet,
142    #[n(1)]
143    Mainnet,
144}
145
146impl From<NetworkId> for u8 {
147    fn from(network_id: NetworkId) -> u8 {
148        match network_id {
149            NetworkId::Testnet => 0,
150            NetworkId::Mainnet => 1,
151        }
152    }
153}
154
155impl TryFrom<u8> for NetworkId {
156    type Error = ();
157
158    fn try_from(i: u8) -> Result<Self, Self::Error> {
159        match i {
160            0 => Ok(Self::Testnet),
161            1 => Ok(Self::Mainnet),
162            _ => Err(()),
163        }
164    }
165}
166
167#[derive(Serialize, Deserialize, Encode, Decode, Debug, PartialEq, Eq, Clone)]
168pub struct Nonce {
169    #[n(0)]
170    pub variant: NonceVariant,
171
172    #[n(1)]
173    pub hash: Option<Hash<32>>,
174}
175
176#[derive(Serialize, Deserialize, Encode, Decode, Debug, PartialEq, Eq, Clone)]
177#[cbor(index_only)]
178pub enum NonceVariant {
179    #[n(0)]
180    NeutralNonce,
181
182    #[n(1)]
183    Nonce,
184}
185
186#[derive(Serialize, Deserialize, Encode, Decode, Debug, PartialEq, Eq, Clone)]
187#[cbor(transparent)]
188pub struct PlutusScript<const VERSION: usize>(#[n(0)] pub Bytes);
189
190impl<const VERSION: usize> AsRef<[u8]> for PlutusScript<VERSION> {
191    fn as_ref(&self) -> &[u8] {
192        self.0.as_slice()
193    }
194}
195
196pub type PolicyId = Hash<28>;
197
198pub type PoolKeyhash = Hash<28>;
199
200#[derive(Serialize, Deserialize, Encode, Decode, Debug, PartialEq, Eq, Clone)]
201pub struct PoolMetadata {
202    #[n(0)]
203    pub url: String,
204
205    #[n(1)]
206    pub hash: PoolMetadataHash,
207}
208
209pub type PoolMetadataHash = Hash<32>;
210
211pub type Port = u32;
212
213pub type PositiveInterval = RationalNumber;
214
215pub type ProtocolVersion = (u64, u64);
216
217#[derive(Serialize, Deserialize, Debug, PartialEq, Eq, Clone)]
218pub struct RationalNumber {
219    pub numerator: u64,
220    pub denominator: u64,
221}
222
223impl<'b, C> minicbor::decode::Decode<'b, C> for RationalNumber {
224    fn decode(d: &mut minicbor::Decoder<'b>, ctx: &mut C) -> Result<Self, minicbor::decode::Error> {
225        // TODO: Enforce tag == 30 & array of size 2
226        d.tag()?;
227        d.array()?;
228        Ok(RationalNumber {
229            numerator: d.decode_with(ctx)?,
230            denominator: d.decode_with(ctx)?,
231        })
232    }
233}
234
235impl<C> minicbor::encode::Encode<C> for RationalNumber {
236    fn encode<W: minicbor::encode::Write>(
237        &self,
238        e: &mut minicbor::Encoder<W>,
239        ctx: &mut C,
240    ) -> Result<(), minicbor::encode::Error<W::Error>> {
241        e.tag(Tag::new(30))?;
242        e.array(2)?;
243        e.encode_with(self.numerator, ctx)?;
244        e.encode_with(self.denominator, ctx)?;
245        Ok(())
246    }
247}
248
249#[derive(Serialize, Deserialize, Debug, PartialEq, Eq, Clone)]
250pub enum Relay {
251    SingleHostAddr(Nullable<Port>, Nullable<IPv4>, Nullable<IPv6>),
252    SingleHostName(Nullable<Port>, DnsName),
253    MultiHostName(DnsName),
254}
255
256impl<'b, C> minicbor::decode::Decode<'b, C> for Relay {
257    fn decode(d: &mut minicbor::Decoder<'b>, ctx: &mut C) -> Result<Self, minicbor::decode::Error> {
258        d.array()?;
259        let variant = d.u16()?;
260
261        match variant {
262            0 => Ok(Relay::SingleHostAddr(
263                d.decode_with(ctx)?,
264                d.decode_with(ctx)?,
265                d.decode_with(ctx)?,
266            )),
267            1 => Ok(Relay::SingleHostName(
268                d.decode_with(ctx)?,
269                d.decode_with(ctx)?,
270            )),
271            2 => Ok(Relay::MultiHostName(d.decode_with(ctx)?)),
272            _ => Err(minicbor::decode::Error::message(
273                "invalid variant id for Relay",
274            )),
275        }
276    }
277}
278
279impl<C> minicbor::encode::Encode<C> for Relay {
280    fn encode<W: minicbor::encode::Write>(
281        &self,
282        e: &mut minicbor::Encoder<W>,
283        ctx: &mut C,
284    ) -> Result<(), minicbor::encode::Error<W::Error>> {
285        match self {
286            Relay::SingleHostAddr(a, b, c) => {
287                e.array(4)?;
288                e.encode_with(0, ctx)?;
289                e.encode_with(a, ctx)?;
290                e.encode_with(b, ctx)?;
291                e.encode_with(c, ctx)?;
292
293                Ok(())
294            }
295            Relay::SingleHostName(a, b) => {
296                e.array(3)?;
297                e.encode_with(1, ctx)?;
298                e.encode_with(a, ctx)?;
299                e.encode_with(b, ctx)?;
300
301                Ok(())
302            }
303            Relay::MultiHostName(a) => {
304                e.array(2)?;
305                e.encode_with(2, ctx)?;
306                e.encode_with(a, ctx)?;
307
308                Ok(())
309            }
310        }
311    }
312}
313
314pub type RewardAccount = Bytes;
315
316pub type ScriptHash = Hash<28>;
317
318#[derive(Serialize, Deserialize, Debug, PartialEq, PartialOrd, Eq, Ord, Clone, Hash)]
319// !! NOTE / IMPORTANT !!
320// It is tempting to swap the order of the two constructors so that AddrKeyHash
321// comes first. This indeed nicely maps the binary representation which
322// associates 0 to AddrKeyHash and 1 to ScriptHash.
323//
324// However, for historical reasons, the ScriptHash variant comes first in the
325// Haskell reference codebase. From this ordering is derived the `PartialOrd`
326// and `Ord` instances; which impacts how Maps/Dictionnaries indexed by
327// StakeCredential will be ordered. So, it is crucial to preserve this quirks to
328// avoid hard to troubleshoot issues down the line.
329pub enum StakeCredential {
330    ScriptHash(ScriptHash),
331    AddrKeyhash(AddrKeyhash),
332}
333
334impl<'b, C> minicbor::decode::Decode<'b, C> for StakeCredential {
335    fn decode(d: &mut minicbor::Decoder<'b>, ctx: &mut C) -> Result<Self, minicbor::decode::Error> {
336        d.array()?;
337        let variant = d.u16()?;
338
339        match variant {
340            0 => Ok(StakeCredential::AddrKeyhash(d.decode_with(ctx)?)),
341            1 => Ok(StakeCredential::ScriptHash(d.decode_with(ctx)?)),
342            _ => Err(minicbor::decode::Error::message(
343                "invalid variant id for StakeCredential",
344            )),
345        }
346    }
347}
348
349impl<C> minicbor::encode::Encode<C> for StakeCredential {
350    fn encode<W: minicbor::encode::Write>(
351        &self,
352        e: &mut minicbor::Encoder<W>,
353        ctx: &mut C,
354    ) -> Result<(), minicbor::encode::Error<W::Error>> {
355        match self {
356            StakeCredential::AddrKeyhash(a) => {
357                e.array(2)?;
358                e.encode_with(0, ctx)?;
359                e.encode_with(a, ctx)?;
360
361                Ok(())
362            }
363            StakeCredential::ScriptHash(a) => {
364                e.array(2)?;
365                e.encode_with(1, ctx)?;
366                e.encode_with(a, ctx)?;
367
368                Ok(())
369            }
370        }
371    }
372}
373
374pub type TransactionIndex = u32;
375
376#[derive(
377    Serialize,
378    Deserialize,
379    Encode,
380    Decode,
381    Debug,
382    PartialEq,
383    Eq,
384    PartialOrd,
385    Ord,
386    Clone,
387    std::hash::Hash,
388)]
389pub struct TransactionInput {
390    #[n(0)]
391    pub transaction_id: Hash<32>,
392
393    #[n(1)]
394    pub index: u64,
395}
396
397pub type UnitInterval = RationalNumber;
398
399#[derive(Serialize, Deserialize, Encode, Decode, Debug, PartialEq, Eq, Clone)]
400pub struct VrfCert(#[n(0)] pub Bytes, #[n(1)] pub Bytes);
401
402pub type VrfKeyhash = Hash<32>;