Skip to main content

mithril_common/messages/proof_v2/
cardano_transactions_proof.rs

1use serde::{Deserialize, Serialize};
2
3use crate::entities::{BlockNumber, BlockNumberOffset, CardanoTransaction, TransactionHash};
4use crate::messages::proof_v2::ProofMessageVerifier;
5use crate::messages::{CardanoTransactionMessagePart, MkSetProofMessagePart, VerifyProofsV2Error};
6
7#[cfg(target_family = "wasm")]
8use wasm_bindgen::prelude::*;
9
10/// A cryptographic proof for a set of Cardano transactions
11#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
12#[cfg_attr(
13    target_family = "wasm",
14    wasm_bindgen(getter_with_clone, js_name = "CardanoTransactionsProofsV2")
15)]
16pub struct CardanoTransactionsProofsV2Message {
17    /// Hash of the certificate that validates this proof Merkle root
18    pub certificate_hash: String,
19
20    /// Transactions that have been certified
21    // Note: Skip in wasm as `wasm_bindgen` doesn't support generics
22    #[cfg_attr(target_family = "wasm", wasm_bindgen(skip))]
23    pub certified_transactions: Option<MkSetProofMessagePart<CardanoTransactionMessagePart>>,
24
25    /// Hashes of the transactions that could not be certified
26    pub non_certified_transactions: Vec<String>,
27
28    /// Latest block number that has been certified by the associated Mithril certificate
29    #[cfg_attr(target_family = "wasm", wasm_bindgen(skip))]
30    pub latest_block_number: BlockNumber,
31
32    /// Security parameter that has been certified by the associated Mithril certificate
33    #[cfg_attr(target_family = "wasm", wasm_bindgen(skip))]
34    pub security_parameter: BlockNumberOffset,
35}
36
37#[cfg_attr(
38    target_family = "wasm",
39    wasm_bindgen(js_class = "CardanoTransactionsProofsV2")
40)]
41impl CardanoTransactionsProofsV2Message {
42    /// Hashes of the Cardano transactions that have been certified
43    #[cfg_attr(target_family = "wasm", wasm_bindgen(getter))]
44    pub fn transactions_hashes(&self) -> Vec<TransactionHash> {
45        self.certified_transactions
46            .as_ref()
47            .map(|ctxs| ctxs.items.iter().map(|t| t.transaction_hash.clone()).collect())
48            .unwrap_or_default()
49    }
50}
51
52#[cfg(target_family = "wasm")]
53#[wasm_bindgen(js_class = "CardanoTransactionsProofsV2")]
54impl CardanoTransactionsProofsV2Message {
55    /// Cardano transactions that have been certified
56    #[wasm_bindgen(getter)]
57    pub fn certified_transactions(&self) -> Vec<CardanoTransactionMessagePart> {
58        self.certified_transactions
59            .as_ref()
60            .map(|ctxs| ctxs.items.clone())
61            .unwrap_or_default()
62    }
63
64    /// Latest block number that has been certified by the associated Mithril certificate
65    #[wasm_bindgen(getter)]
66    pub fn latest_block_number(&self) -> u64 {
67        *self.latest_block_number
68    }
69
70    /// Security parameter that has been certified by the associated Mithril certificate
71    #[wasm_bindgen(getter)]
72    pub fn security_parameter(&self) -> u64 {
73        *self.latest_block_number
74    }
75}
76
77/// Transactions successfully verified by [`CardanoTransactionsProofsV2Message::verify`].
78///
79/// Can be used to reconstruct a [`ProtocolMessage`][crate::entities::ProtocolMessage]
80/// and confirm it was signed by a certificate.
81#[derive(Debug, Clone, PartialEq)]
82pub struct VerifiedCardanoTransactionsV2 {
83    certificate_hash: String,
84    merkle_root: String,
85    certified_transactions: Vec<CardanoTransactionMessagePart>,
86    latest_block_number: BlockNumber,
87    security_parameter: BlockNumberOffset,
88}
89
90impl VerifiedCardanoTransactionsV2 {
91    /// Hash of the certificate that signs this struct Merkle root.
92    pub fn certificate_hash(&self) -> &str {
93        &self.certificate_hash
94    }
95
96    /// Hex encoded Merkle root of the certified transactions
97    pub fn certified_merkle_root(&self) -> &str {
98        &self.merkle_root
99    }
100
101    /// Certified transactions
102    pub fn certified_transactions(&self) -> &[CardanoTransactionMessagePart] {
103        &self.certified_transactions
104    }
105
106    /// Hashes of the certified transactions
107    pub fn certified_transactions_hashes(&self) -> Vec<TransactionHash> {
108        self.certified_transactions
109            .iter()
110            .map(|t| t.transaction_hash.clone())
111            .collect()
112    }
113
114    /// Latest block number that has been certified by the associated Mithril certificate
115    pub fn latest_certified_block_number(&self) -> BlockNumber {
116        self.latest_block_number
117    }
118
119    /// Security parameter that has been certified by the associated Mithril certificate
120    pub fn security_parameter(&self) -> BlockNumberOffset {
121        self.security_parameter
122    }
123}
124
125impl CardanoTransactionsProofsV2Message {
126    /// Create a new `ProofsV2CardanoTransactionsMessage`
127    pub fn new(
128        certificate_hash: &str,
129        certified_transactions: Option<MkSetProofMessagePart<CardanoTransactionMessagePart>>,
130        non_certified_transactions: Vec<String>,
131        latest_block_number: BlockNumber,
132        security_parameter: BlockNumberOffset,
133    ) -> Self {
134        Self {
135            certificate_hash: certificate_hash.to_string(),
136            certified_transactions,
137            non_certified_transactions,
138            latest_block_number,
139            security_parameter,
140        }
141    }
142
143    /// Verify that all the certified transactions proofs are valid
144    ///
145    /// The following checks will be executed:
146    ///
147    /// 1 - Check that each Merkle proof is valid
148    ///
149    /// 2 - Check that all proofs share the same Merkle root
150    ///
151    /// 3 - Assert that there's at least one certified transaction
152    ///
153    /// If every check is okay, the hex encoded Merkle root of the proof will be returned.
154    pub fn verify(&self) -> Result<VerifiedCardanoTransactionsV2, VerifyProofsV2Error> {
155        const SUBJECT: &str = "Cardano transactions";
156        let certified_transactions = self
157            .certified_transactions
158            .as_ref()
159            .ok_or(VerifyProofsV2Error::NoCertifiedItem(SUBJECT))?;
160        let merkle_root = ProofMessageVerifier::<_, CardanoTransaction>::new(SUBJECT, |tx| {
161            tx.transaction_hash.clone()
162        })
163        .verify(certified_transactions)?;
164
165        Ok(VerifiedCardanoTransactionsV2 {
166            certificate_hash: self.certificate_hash.clone(),
167            merkle_root,
168            certified_transactions: certified_transactions.items.clone(),
169            latest_block_number: self.latest_block_number,
170            security_parameter: self.security_parameter,
171        })
172    }
173}