Skip to main content

amaru_kernel/cardano/
certificate_pointer.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::fmt;
16
17use crate::{Slot, TransactionPointer, cbor};
18
19#[derive(Debug, Copy, Clone, PartialEq, Eq, Default, PartialOrd)]
20pub struct CertificatePointer {
21    pub transaction: TransactionPointer,
22    pub certificate_index: usize,
23}
24
25impl CertificatePointer {
26    pub fn slot(&self) -> Slot {
27        self.transaction.slot
28    }
29}
30
31impl fmt::Display for CertificatePointer {
32    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
33        write!(f, "{},certificate={}", &self.transaction, &self.certificate_index)
34    }
35}
36
37impl<C> cbor::encode::Encode<C> for CertificatePointer {
38    fn encode<W: cbor::encode::Write>(
39        &self,
40        e: &mut cbor::Encoder<W>,
41        ctx: &mut C,
42    ) -> Result<(), cbor::encode::Error<W::Error>> {
43        e.array(2)?;
44        e.encode_with(self.transaction, ctx)?;
45        e.encode_with(self.certificate_index, ctx)?;
46        Ok(())
47    }
48}
49
50impl<'b, C> cbor::decode::Decode<'b, C> for CertificatePointer {
51    fn decode(d: &mut cbor::Decoder<'b>, ctx: &mut C) -> Result<Self, cbor::decode::Error> {
52        cbor::heterogeneous_array(d, |d, assert_len| {
53            assert_len(2)?;
54            Ok(CertificatePointer { transaction: d.decode_with(ctx)?, certificate_index: d.decode_with(ctx)? })
55        })
56    }
57}
58
59#[cfg(any(test, feature = "test-utils"))]
60pub use tests::*;
61
62#[cfg(any(test, feature = "test-utils"))]
63mod tests {
64    use proptest::{prelude::*, prop_compose};
65
66    use super::*;
67    use crate::{any_transaction_pointer, prop_cbor_roundtrip};
68
69    prop_cbor_roundtrip!(CertificatePointer, any_certificate_pointer(u64::MAX));
70
71    prop_compose! {
72        pub fn any_certificate_pointer(max_slot: u64)(
73            transaction in any_transaction_pointer(max_slot),
74            certificate_index in any::<usize>(),
75        ) -> CertificatePointer {
76            CertificatePointer {
77                transaction,
78                certificate_index,
79            }
80        }
81    }
82
83    #[cfg(test)]
84    mod internal {
85        use test_case::test_case;
86
87        use super::*;
88
89        #[test_case((42, 0, 0), (42, 0, 0) => with |(left, right)| assert_eq!(left, right); "reflexivity")]
90        #[test_case((42, 0, 0), (43, 0, 0) => with |(left, right)| assert!(left < right); "across slots")]
91        #[test_case((42, 0, 0), (42, 1, 0) => with |(left, right)| assert!(left < right); "across transactions")]
92        #[test_case((42, 0, 0), (42, 0, 1) => with |(left, right)| assert!(left < right); "across certificates")]
93        #[test_case((42, 0, 5), (42, 1, 0) => with |(left, right)| assert!(left < right); "across transactions and certs")]
94        fn test_pointers(
95            left: (u64, usize, usize),
96            right: (u64, usize, usize),
97        ) -> (CertificatePointer, CertificatePointer) {
98            let new_pointer = |args: (Slot, usize, usize)| CertificatePointer {
99                transaction: TransactionPointer { slot: args.0, transaction_index: args.1 },
100                certificate_index: args.2,
101            };
102
103            (new_pointer((Slot::from(left.0), left.1, left.2)), new_pointer((Slot::from(right.0), right.1, right.2)))
104        }
105    }
106}