sui_types/
message_envelope.rs

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