Skip to main content

amaru_kernel/cardano/
proposal_id.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 std::{cmp::Ordering, fmt, ops::Deref};
16
17pub use pallas_primitives::conway::GovActionId as ProposalId;
18
19use crate::cbor;
20
21// TODO: This type shouldn't exist, and `Ord` / `PartialOrd` should be derived in Pallas on
22// 'GovActionId' already.
23#[derive(Debug, Eq, PartialEq, Clone)]
24#[repr(transparent)]
25pub struct ComparableProposalId {
26    pub inner: ProposalId,
27}
28
29impl ComparableProposalId {
30    /// Like `Display`, but more compact
31    pub fn to_compact_string(&self) -> String {
32        format!(
33            "{}.{}",
34            self.inner.action_index,
35            self.inner.transaction_id.to_string().chars().take(8).collect::<String>()
36        )
37    }
38}
39
40impl AsRef<ComparableProposalId> for ComparableProposalId {
41    fn as_ref(&self) -> &ComparableProposalId {
42        self
43    }
44}
45
46impl Deref for ComparableProposalId {
47    type Target = ProposalId;
48
49    fn deref(&self) -> &Self::Target {
50        &self.inner
51    }
52}
53
54impl fmt::Display for ComparableProposalId {
55    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
56        write!(f, "{}#{}", self.inner.transaction_id, self.inner.action_index,)
57    }
58}
59
60impl From<ProposalId> for ComparableProposalId {
61    fn from(inner: ProposalId) -> Self {
62        Self { inner }
63    }
64}
65
66impl From<ComparableProposalId> for ProposalId {
67    fn from(comparable: ComparableProposalId) -> ProposalId {
68        comparable.inner
69    }
70}
71
72impl PartialOrd for ComparableProposalId {
73    fn partial_cmp(&self, rhs: &Self) -> Option<Ordering> {
74        Some(self.cmp(rhs))
75    }
76}
77
78impl Ord for ComparableProposalId {
79    fn cmp(&self, rhs: &Self) -> Ordering {
80        match self.inner.transaction_id.cmp(&rhs.inner.transaction_id) {
81            Ordering::Equal => self.inner.action_index.cmp(&rhs.inner.action_index),
82            ordering @ Ordering::Less | ordering @ Ordering::Greater => ordering,
83        }
84    }
85}
86
87impl<C> cbor::encode::Encode<C> for ComparableProposalId {
88    fn encode<W: cbor::encode::Write>(
89        &self,
90        e: &mut cbor::Encoder<W>,
91        ctx: &mut C,
92    ) -> Result<(), cbor::encode::Error<W::Error>> {
93        e.encode_with(&self.inner, ctx)?;
94        Ok(())
95    }
96}
97
98impl<'d, C> cbor::decode::Decode<'d, C> for ComparableProposalId {
99    fn decode(d: &mut cbor::Decoder<'d>, ctx: &mut C) -> Result<Self, cbor::decode::Error> {
100        Ok(Self { inner: d.decode_with(ctx)? })
101    }
102}
103
104#[cfg(any(test, feature = "test-utils"))]
105pub use tests::*;
106
107#[cfg(any(test, feature = "test-utils"))]
108mod tests {
109    use proptest::{prelude::*, prop_compose};
110
111    use super::{ComparableProposalId, ProposalId};
112    use crate::{Hash, prop_cbor_roundtrip};
113
114    prop_cbor_roundtrip!(ComparableProposalId, any_comparable_proposal_id());
115
116    prop_compose! {
117        pub fn any_proposal_id()(
118            transaction_id in any::<[u8; 32]>(),
119            action_index in any::<u32>(),
120        ) -> ProposalId {
121            ProposalId {
122                transaction_id: Hash::new(transaction_id),
123                action_index,
124            }
125        }
126    }
127
128    prop_compose! {
129        pub fn any_comparable_proposal_id()(
130            inner in any_proposal_id()
131        ) -> ComparableProposalId {
132            ComparableProposalId {
133                inner,
134            }
135        }
136    }
137}