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)
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
100impl TransactionPartialPrepare for NotarySignatureV2 {
101    type Prepared = PreparedNotarySignatureV2;
102}
103
104#[allow(deprecated)]
105pub type PreparedNotarySignatureV2 = SummarizedRawValueBody<NotarySignatureV2>;
106
107impl PreparedNotarizedTransactionV2 {
108    pub fn end_epoch_exclusive(&self) -> Epoch {
109        let transaction_intent = &self.signed_intent.transaction_intent;
110
111        let root_intent_expiry_epoch = transaction_intent
112            .root_intent_core
113            .header
114            .inner
115            .end_epoch_exclusive;
116        let non_root_intent_expiry_epochs = transaction_intent
117            .non_root_subintents
118            .subintents
119            .iter()
120            .map(|subintent| subintent.intent_core.header.inner.end_epoch_exclusive);
121
122        // Unwrapping as we know it's non-empty
123        std::iter::once(root_intent_expiry_epoch)
124            .chain(non_root_intent_expiry_epochs)
125            .min()
126            .unwrap()
127    }
128
129    pub fn hashes(&self) -> UserTransactionHashes {
130        UserTransactionHashes {
131            transaction_intent_hash: self.transaction_intent_hash(),
132            signed_transaction_intent_hash: self.signed_transaction_intent_hash(),
133            notarized_transaction_hash: self.notarized_transaction_hash(),
134            // NOTE: If the NotarizedTransactionV2 is invalid, there might be duplicate hashes
135            non_root_subintent_hashes: self.non_root_subintent_hashes(),
136        }
137    }
138
139    pub fn validate(
140        self,
141        validator: &TransactionValidator,
142    ) -> Result<ValidatedNotarizedTransactionV2, TransactionValidationError> {
143        validator.validate_notarized_v2(self)
144    }
145}
146
147impl ResolveAsRawNotarizedTransaction for NotarizedTransactionV2 {
148    type Intermediate = RawNotarizedTransaction;
149
150    fn resolve_raw_notarized_transaction(self) -> Self::Intermediate {
151        self.to_raw().expect("Transaction should be encodable")
152    }
153}
154
155impl ResolveAsRawNotarizedTransaction for &NotarizedTransactionV2 {
156    type Intermediate = RawNotarizedTransaction;
157
158    fn resolve_raw_notarized_transaction(self) -> Self::Intermediate {
159        self.to_raw().expect("Transaction should be encodable")
160    }
161}
162
163impl IntoExecutable for NotarizedTransactionV2 {
164    type Error = TransactionValidationError;
165
166    fn into_executable(
167        self,
168        validator: &TransactionValidator,
169    ) -> Result<ExecutableTransaction, Self::Error> {
170        let executable = self.prepare_and_validate(validator)?.create_executable();
171        Ok(executable)
172    }
173}
174
175impl HasTransactionIntentHash for PreparedNotarizedTransactionV2 {
176    fn transaction_intent_hash(&self) -> TransactionIntentHash {
177        self.signed_intent.transaction_intent_hash()
178    }
179}
180
181impl HasSignedTransactionIntentHash for PreparedNotarizedTransactionV2 {
182    fn signed_transaction_intent_hash(&self) -> SignedTransactionIntentHash {
183        self.signed_intent.signed_transaction_intent_hash()
184    }
185}
186
187impl HasNotarizedTransactionHash for PreparedNotarizedTransactionV2 {
188    fn notarized_transaction_hash(&self) -> NotarizedTransactionHash {
189        NotarizedTransactionHash::from_hash(self.summary.hash)
190    }
191}
192
193impl HasNonRootSubintentHashes for PreparedNotarizedTransactionV2 {
194    fn non_root_subintent_hashes(&self) -> Vec<SubintentHash> {
195        self.signed_intent.non_root_subintent_hashes()
196    }
197}