Skip to main content

iota_types/
message_envelope.rs

1// Copyright (c) Mysten Labs, Inc.
2// Modifications Copyright (c) 2024 IOTA Stiftung
3// SPDX-License-Identifier: Apache-2.0
4
5use std::{
6    fmt::{Debug, Display, Formatter},
7    ops::{Deref, DerefMut},
8};
9
10use fastcrypto::traits::KeyPair;
11use iota_sdk_types::{
12    SenderSignedTransaction,
13    crypto::{Intent, IntentScope},
14};
15use once_cell::sync::OnceCell;
16use serde::{Deserialize, Serialize, de::DeserializeOwned};
17use serde_name::{DeserializeNameAdapter, SerializeNameAdapter};
18use tracing::instrument;
19
20use crate::{
21    base_types::AuthorityName,
22    committee::{Committee, EpochId},
23    crypto::{
24        AuthorityKeyPair, AuthorityQuorumSignInfo, AuthoritySignInfo, AuthoritySignInfoTrait,
25        AuthoritySignature, AuthorityStrongQuorumSignInfo, EmptySignInfo, Signer,
26    },
27    error::IotaResult,
28    executable_transaction::CertificateProof,
29    messages_checkpoint::CheckpointSequenceNumber,
30};
31
32pub trait Message {
33    type DigestType: Clone + Debug;
34    const SCOPE: IntentScope;
35
36    fn scope(&self) -> IntentScope {
37        Self::SCOPE
38    }
39
40    fn digest(&self) -> Self::DigestType;
41}
42
43#[derive(Clone, Debug, Eq, Serialize, Deserialize)]
44#[serde(remote = "Envelope")]
45pub struct Envelope<T: Message, S> {
46    #[serde(skip)]
47    digest: OnceCell<T::DigestType>,
48
49    data: T,
50    auth_signature: S,
51}
52
53impl<'de, T, S> Deserialize<'de> for Envelope<T, S>
54where
55    T: Message + Deserialize<'de>,
56    S: Deserialize<'de>,
57{
58    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
59    where
60        D: serde::de::Deserializer<'de>,
61    {
62        Envelope::deserialize(DeserializeNameAdapter::new(
63            deserializer,
64            std::any::type_name::<Self>(),
65        ))
66    }
67}
68
69impl<T, Sig> Serialize for Envelope<T, Sig>
70where
71    T: Message + Serialize,
72    Sig: Serialize,
73{
74    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
75    where
76        S: serde::ser::Serializer,
77    {
78        Envelope::serialize(
79            self,
80            SerializeNameAdapter::new(serializer, std::any::type_name::<Self>()),
81        )
82    }
83}
84
85impl<T: Message, S> Envelope<T, S> {
86    pub fn new_from_data_and_sig(data: T, sig: S) -> Self {
87        Self {
88            digest: Default::default(),
89            data,
90            auth_signature: sig,
91        }
92    }
93
94    pub fn data(&self) -> &T {
95        &self.data
96    }
97
98    pub fn into_data(self) -> T {
99        self.data
100    }
101
102    pub fn into_sig(self) -> S {
103        self.auth_signature
104    }
105
106    pub fn into_data_and_sig(self) -> (T, S) {
107        let Self {
108            data,
109            auth_signature,
110            ..
111        } = self;
112        (data, auth_signature)
113    }
114
115    /// Remove the authority signatures `S` from this envelope.
116    pub fn into_unsigned(self) -> Envelope<T, EmptySignInfo> {
117        Envelope::<T, EmptySignInfo>::new(self.into_data())
118    }
119
120    pub fn auth_sig(&self) -> &S {
121        &self.auth_signature
122    }
123
124    pub fn auth_sig_mut_for_testing(&mut self) -> &mut S {
125        &mut self.auth_signature
126    }
127
128    pub fn digest(&self) -> &T::DigestType {
129        self.digest.get_or_init(|| self.data.digest())
130    }
131
132    pub fn data_mut_for_testing(&mut self) -> &mut T {
133        &mut self.data
134    }
135}
136
137impl<T: Message + PartialEq, S: PartialEq> PartialEq for Envelope<T, S> {
138    fn eq(&self, other: &Self) -> bool {
139        self.data == other.data && self.auth_signature == other.auth_signature
140    }
141}
142
143impl<T: Message> Envelope<T, EmptySignInfo> {
144    pub fn new(data: T) -> Self {
145        Self {
146            digest: OnceCell::new(),
147            data,
148            auth_signature: EmptySignInfo {},
149        }
150    }
151}
152
153impl<T> Envelope<T, AuthoritySignInfo>
154where
155    T: Message + Serialize,
156{
157    pub fn new(
158        epoch: EpochId,
159        data: T,
160        secret: &dyn Signer<AuthoritySignature>,
161        authority: AuthorityName,
162    ) -> Self {
163        let auth_signature = Self::sign(epoch, &data, secret, authority);
164        Self {
165            digest: OnceCell::new(),
166            data,
167            auth_signature,
168        }
169    }
170
171    pub fn sign(
172        epoch: EpochId,
173        data: &T,
174        secret: &dyn Signer<AuthoritySignature>,
175        authority: AuthorityName,
176    ) -> AuthoritySignInfo {
177        AuthoritySignInfo::new(epoch, &data, Intent::iota_app(T::SCOPE), authority, secret)
178    }
179
180    pub fn epoch(&self) -> EpochId {
181        self.auth_signature.epoch
182    }
183}
184
185impl Envelope<SenderSignedTransaction, AuthoritySignInfo> {
186    #[instrument(level = "trace", skip_all)]
187    pub fn verify_committee_sigs_only(&self, committee: &Committee) -> IotaResult {
188        self.auth_signature.verify_secure(
189            self.data(),
190            Intent::iota_app(IntentScope::SenderSignedTransaction),
191            committee,
192        )
193    }
194}
195
196impl<T, const S: bool> Envelope<T, AuthorityQuorumSignInfo<S>>
197where
198    T: Message + Serialize,
199{
200    pub fn new(
201        data: T,
202        signatures: Vec<AuthoritySignInfo>,
203        committee: &Committee,
204    ) -> IotaResult<Self> {
205        let cert = Self {
206            digest: OnceCell::new(),
207            data,
208            auth_signature: AuthorityQuorumSignInfo::<S>::new_from_auth_sign_infos(
209                signatures, committee,
210            )?,
211        };
212
213        Ok(cert)
214    }
215
216    pub fn new_from_keypairs_for_testing(
217        data: T,
218        keypairs: &[AuthorityKeyPair],
219        committee: &Committee,
220    ) -> Self {
221        let signatures = keypairs
222            .iter()
223            .map(|keypair| {
224                AuthoritySignInfo::new(
225                    committee.epoch(),
226                    &data,
227                    Intent::iota_app(T::SCOPE),
228                    keypair.public().into(),
229                    keypair,
230                )
231            })
232            .collect();
233        Self::new(data, signatures, committee).unwrap()
234    }
235
236    pub fn epoch(&self) -> EpochId {
237        self.auth_signature.epoch
238    }
239}
240
241/// TrustedEnvelope is a serializable wrapper around Envelope which is
242/// `Into<VerifiedEnvelope>` - in other words it models a verified message which
243/// has been written to the db (or some other trusted store), and may be read
244/// back from the db without further signature verification.
245///
246/// TrustedEnvelope should *only* appear in database interfaces.
247///
248/// DO NOT USE in networked APIs.
249///
250/// Because it is used very sparingly, it can be audited easily: Use
251/// rust-analyzer, or run: git grep -E 'TrustedEnvelope'
252///
253/// And verify that none of the uses appear in any network APIs.
254#[derive(Clone, Serialize, Deserialize)]
255pub struct TrustedEnvelope<T: Message, S>(Envelope<T, S>);
256
257impl<T, S: Debug> Debug for TrustedEnvelope<T, S>
258where
259    T: Message + Debug,
260{
261    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
262        write!(f, "{:?}", self.0)
263    }
264}
265
266impl<T: Message, S> TrustedEnvelope<T, S> {
267    pub fn into_inner(self) -> Envelope<T, S> {
268        self.0
269    }
270
271    pub fn inner(&self) -> &Envelope<T, S> {
272        &self.0
273    }
274}
275
276// An empty marker struct that can't be serialized.
277#[derive(Clone)]
278struct NoSer;
279// Never remove this assert!
280static_assertions::assert_not_impl_any!(NoSer: Serialize, DeserializeOwned);
281
282#[derive(Clone)]
283pub struct VerifiedEnvelope<T: Message, S>(TrustedEnvelope<T, S>, NoSer);
284
285impl<T, S: Debug> Debug for VerifiedEnvelope<T, S>
286where
287    T: Message + Debug,
288{
289    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
290        write!(f, "{:?}", self.0.0)
291    }
292}
293
294impl<T: Message, S> VerifiedEnvelope<T, S> {
295    /// This API should only be called when the input is already verified.
296    pub fn new_from_verified(inner: Envelope<T, S>) -> Self {
297        Self(TrustedEnvelope(inner), NoSer)
298    }
299
300    /// There are some situations (e.g. fragment verification) where its very
301    /// awkward and/or inefficient to obtain verified certificates from
302    /// calling CertifiedTransaction::verify() Use this carefully.
303    pub fn new_unchecked(inner: Envelope<T, S>) -> Self {
304        Self(TrustedEnvelope(inner), NoSer)
305    }
306
307    pub fn into_inner(self) -> Envelope<T, S> {
308        self.0.0
309    }
310
311    pub fn inner(&self) -> &Envelope<T, S> {
312        &self.0.0
313    }
314
315    pub fn into_message(self) -> T {
316        self.into_inner().into_data()
317    }
318
319    /// Use this when you need to serialize a verified envelope.
320    /// This should generally only be used for database writes.
321    /// ***never use over the network!***
322    pub fn serializable_ref(&self) -> &TrustedEnvelope<T, S> {
323        &self.0
324    }
325
326    /// Use this when you need to serialize a verified envelope.
327    /// This should generally only be used for database writes.
328    /// ***never use over the network!***
329    pub fn serializable(self) -> TrustedEnvelope<T, S> {
330        self.0
331    }
332
333    /// Remove the authority signatures `S` from this envelope.
334    pub fn into_unsigned(self) -> VerifiedEnvelope<T, EmptySignInfo> {
335        VerifiedEnvelope::<T, EmptySignInfo>::new_from_verified(self.into_inner().into_unsigned())
336    }
337}
338
339/// After deserialization, a TrustedTransactionEnvelope can be turned back into
340/// a VerifiedTransactionEnvelope.
341impl<T: Message, S> From<TrustedEnvelope<T, S>> for VerifiedEnvelope<T, S> {
342    fn from(e: TrustedEnvelope<T, S>) -> Self {
343        Self::new_unchecked(e.0)
344    }
345}
346
347impl<T: Message, S> Deref for VerifiedEnvelope<T, S> {
348    type Target = Envelope<T, S>;
349    fn deref(&self) -> &Self::Target {
350        &self.0.0
351    }
352}
353
354impl<T: Message, S> Deref for Envelope<T, S> {
355    type Target = T;
356    fn deref(&self) -> &Self::Target {
357        &self.data
358    }
359}
360
361impl<T: Message, S> DerefMut for Envelope<T, S> {
362    fn deref_mut(&mut self) -> &mut Self::Target {
363        &mut self.data
364    }
365}
366
367impl<T: Message, S> From<VerifiedEnvelope<T, S>> for Envelope<T, S> {
368    fn from(v: VerifiedEnvelope<T, S>) -> Self {
369        v.0.0
370    }
371}
372
373impl<T: Message, S> PartialEq for VerifiedEnvelope<T, S>
374where
375    Envelope<T, S>: PartialEq,
376{
377    fn eq(&self, other: &Self) -> bool {
378        self.0.0 == other.0.0
379    }
380}
381
382impl<T: Message, S> Eq for VerifiedEnvelope<T, S> where Envelope<T, S>: Eq {}
383
384impl<T, S> Display for VerifiedEnvelope<T, S>
385where
386    T: Message,
387    Envelope<T, S>: Display,
388{
389    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
390        write!(f, "{}", self.0.0)
391    }
392}
393
394/// The following implementation provides two ways to construct a
395/// VerifiedEnvelope with CertificateProof. It is implemented in this file such
396/// that we could reuse the digest without having to recompute it.
397/// We allow converting a VerifiedCertificate into a VerifiedEnvelope with
398/// CertificateProof::Certificate; and converting a VerifiedTransaction along
399/// with checkpoint information into a VerifiedEnvelope
400/// with CertificateProof::Checkpoint.
401impl<T: Message> VerifiedEnvelope<T, CertificateProof> {
402    pub fn new_from_certificate(
403        certificate: VerifiedEnvelope<T, AuthorityStrongQuorumSignInfo>,
404    ) -> Self {
405        let inner = certificate.into_inner();
406        let Envelope {
407            digest,
408            data,
409            auth_signature,
410        } = inner;
411        VerifiedEnvelope::new_unchecked(Envelope {
412            digest,
413            data,
414            auth_signature: CertificateProof::new_from_cert_sig(auth_signature),
415        })
416    }
417
418    pub fn new_from_checkpoint(
419        transaction: VerifiedEnvelope<T, EmptySignInfo>,
420        epoch: EpochId,
421        checkpoint: CheckpointSequenceNumber,
422    ) -> Self {
423        let inner = transaction.into_inner();
424        let Envelope {
425            digest,
426            data,
427            auth_signature: _,
428        } = inner;
429        VerifiedEnvelope::new_unchecked(Envelope {
430            digest,
431            data,
432            auth_signature: CertificateProof::new_from_checkpoint(epoch, checkpoint),
433        })
434    }
435
436    pub fn new_system(transaction: VerifiedEnvelope<T, EmptySignInfo>, epoch: EpochId) -> Self {
437        let inner = transaction.into_inner();
438        let Envelope {
439            digest,
440            data,
441            auth_signature: _,
442        } = inner;
443        VerifiedEnvelope::new_unchecked(Envelope {
444            digest,
445            data,
446            auth_signature: CertificateProof::new_system(epoch),
447        })
448    }
449
450    pub fn new_from_quorum_execution(
451        transaction: VerifiedEnvelope<T, EmptySignInfo>,
452        epoch: EpochId,
453    ) -> Self {
454        let inner = transaction.into_inner();
455        let Envelope {
456            digest,
457            data,
458            auth_signature: _,
459        } = inner;
460        VerifiedEnvelope::new_unchecked(Envelope {
461            digest,
462            data,
463            auth_signature: CertificateProof::QuorumExecuted(epoch),
464        })
465    }
466
467    pub fn epoch(&self) -> EpochId {
468        self.auth_signature.epoch()
469    }
470}