radix_transactions/model/v2/
notarized_transaction_v2.rs

1use super::*;
2use crate::internal_prelude::*;
3
4//=================================================================================
5// NOTE:
6// See versioned.rs for tests and a demonstration for the calculation of hashes etc
7//=================================================================================
8
9#[derive(Debug, Clone, Eq, PartialEq, ManifestSbor, ScryptoDescribe, ScryptoSborAssertion)]
10#[sbor_assert(
11    fixed("FILE:notarized_transaction_v2_schema.bin"),
12    settings(allow_name_changes)
13)]
14/// The transaction format for a V2 user transaction, live at Cuttlefish.
15///
16/// It includes a notary signature and a [`SignedTransactionIntentV2`].
17///
18/// It can be built with a [`TransactionV2Builder`].
19///
20/// For serialization / submission, it should be converted with [`self.to_raw()`][Self::to_raw]
21/// into a [`RawNotarizedTransaction`], which can be coverted to bytes with
22/// [`raw_notarized_transcation.to_vec()`][RawNotarizedTransaction::to_vec].
23pub struct NotarizedTransactionV2 {
24    pub signed_transaction_intent: SignedTransactionIntentV2,
25    pub notary_signature: NotarySignatureV2,
26}
27
28impl NotarizedTransactionV2 {
29    pub fn prepare_and_validate(
30        &self,
31        validator: &TransactionValidator,
32    ) -> Result<ValidatedNotarizedTransactionV2, TransactionValidationError> {
33        self.prepare(validator.preparation_settings())?
34            .validate(validator)
35    }
36
37    pub fn extract_manifest(&self) -> TransactionManifestV2 {
38        TransactionManifestV2::from_intent_core(
39            &self
40                .signed_transaction_intent
41                .transaction_intent
42                .root_intent_core,
43        )
44    }
45
46    pub fn extract_manifests_with_names(
47        &self,
48        names: TransactionObjectNames,
49    ) -> (UserTransactionManifest, Vec<UserSubintentManifest>) {
50        let mut transaction_manifest = TransactionManifestV2::from_intent_core(
51            &self
52                .signed_transaction_intent
53                .transaction_intent
54                .root_intent_core,
55        );
56        transaction_manifest.set_names_if_known(names.root_intent);
57        let subintents = &self
58            .signed_transaction_intent
59            .transaction_intent
60            .non_root_subintents
61            .0;
62        if subintents.len() != names.subintents.len() {
63            panic!(
64                "The transaction object names have names for {} subintents but the transaction has {} subintents",
65                names.subintents.len(),
66                subintents.len(),
67            )
68        }
69        let subintent_manifests = self
70            .signed_transaction_intent
71            .transaction_intent
72            .non_root_subintents
73            .0
74            .iter()
75            .zip(names.subintents.into_iter())
76            .map(|(subintent, names)| {
77                let mut manifest = SubintentManifestV2::from_intent_core(&subintent.intent_core);
78                manifest.set_names_if_known(names);
79                manifest.into()
80            })
81            .collect();
82        (transaction_manifest.into(), subintent_manifests)
83    }
84}
85
86define_transaction_payload!(
87    NotarizedTransactionV2,
88    RawNotarizedTransaction,
89    PreparedNotarizedTransactionV2 {
90        signed_intent: PreparedSignedTransactionIntentV2,
91        notary_signature: PreparedNotarySignatureV2,
92    },
93    TransactionDiscriminator::V2Notarized,
94);
95
96#[derive(Debug, Clone, Eq, PartialEq, ManifestSbor, ScryptoDescribe)]
97#[sbor(transparent)]
98pub struct NotarySignatureV2(pub SignatureV1);
99
100#[allow(deprecated)]
101pub type PreparedNotarySignatureV2 = SummarizedRawValueBody<NotarySignatureV2>;
102
103impl PreparedNotarizedTransactionV2 {
104    pub fn end_epoch_exclusive(&self) -> Epoch {
105        let transaction_intent = &self.signed_intent.transaction_intent;
106
107        let root_intent_expiry_epoch = transaction_intent
108            .root_intent_core
109            .header
110            .inner
111            .end_epoch_exclusive;
112        let non_root_intent_expiry_epochs = transaction_intent
113            .non_root_subintents
114            .subintents
115            .iter()
116            .map(|subintent| subintent.intent_core.header.inner.end_epoch_exclusive);
117
118        // Unwrapping as we know it's non-empty
119        std::iter::once(root_intent_expiry_epoch)
120            .chain(non_root_intent_expiry_epochs)
121            .min()
122            .unwrap()
123    }
124
125    pub fn hashes(&self) -> UserTransactionHashes {
126        UserTransactionHashes {
127            transaction_intent_hash: self.transaction_intent_hash(),
128            signed_transaction_intent_hash: self.signed_transaction_intent_hash(),
129            notarized_transaction_hash: self.notarized_transaction_hash(),
130            // NOTE: If the NotarizedTransactionV2 is invalid, there might be duplicate hashes
131            non_root_subintent_hashes: self.non_root_subintent_hashes(),
132        }
133    }
134
135    pub fn validate(
136        self,
137        validator: &TransactionValidator,
138    ) -> Result<ValidatedNotarizedTransactionV2, TransactionValidationError> {
139        validator.validate_notarized_v2(self)
140    }
141}
142
143impl ResolveAsRawNotarizedTransaction for NotarizedTransactionV2 {
144    type Intermediate = RawNotarizedTransaction;
145
146    fn resolve_raw_notarized_transaction(self) -> Self::Intermediate {
147        self.to_raw().expect("Transaction should be encodable")
148    }
149}
150
151impl<'a> ResolveAsRawNotarizedTransaction for &'a NotarizedTransactionV2 {
152    type Intermediate = RawNotarizedTransaction;
153
154    fn resolve_raw_notarized_transaction(self) -> Self::Intermediate {
155        self.to_raw().expect("Transaction should be encodable")
156    }
157}
158
159impl IntoExecutable for NotarizedTransactionV2 {
160    type Error = TransactionValidationError;
161
162    fn into_executable(
163        self,
164        validator: &TransactionValidator,
165    ) -> Result<ExecutableTransaction, Self::Error> {
166        let executable = self.prepare_and_validate(validator)?.create_executable();
167        Ok(executable)
168    }
169}
170
171impl HasTransactionIntentHash for PreparedNotarizedTransactionV2 {
172    fn transaction_intent_hash(&self) -> TransactionIntentHash {
173        self.signed_intent.transaction_intent_hash()
174    }
175}
176
177impl HasSignedTransactionIntentHash for PreparedNotarizedTransactionV2 {
178    fn signed_transaction_intent_hash(&self) -> SignedTransactionIntentHash {
179        self.signed_intent.signed_transaction_intent_hash()
180    }
181}
182
183impl HasNotarizedTransactionHash for PreparedNotarizedTransactionV2 {
184    fn notarized_transaction_hash(&self) -> NotarizedTransactionHash {
185        NotarizedTransactionHash::from_hash(self.summary.hash)
186    }
187}
188
189impl HasNonRootSubintentHashes for PreparedNotarizedTransactionV2 {
190    fn non_root_subintent_hashes(&self) -> Vec<SubintentHash> {
191        self.signed_intent.non_root_subintent_hashes()
192    }
193}