linera_rpc/
message.rs

1// Copyright (c) Facebook, Inc. and its affiliates.
2// Copyright (c) Zefchain Labs, Inc.
3// SPDX-License-Identifier: Apache-2.0
4
5use linera_base::{
6    crypto::CryptoHash,
7    data_types::{BlobContent, NetworkDescription},
8    identifiers::{BlobId, ChainId},
9};
10use linera_chain::{
11    data_types::{BlockProposal, LiteVote},
12    types::{ConfirmedBlock, ConfirmedBlockCertificate},
13};
14use linera_core::{
15    data_types::{ChainInfoQuery, ChainInfoResponse, CrossChainRequest},
16    node::NodeError,
17};
18use linera_version::VersionInfo;
19use serde::{Deserialize, Serialize};
20
21use crate::{
22    HandleConfirmedCertificateRequest, HandleLiteCertRequest, HandleTimeoutCertificateRequest,
23    HandleValidatedCertificateRequest,
24};
25
26#[derive(Clone, Serialize, Deserialize, Debug)]
27#[cfg_attr(with_testing, derive(Eq, PartialEq))]
28pub enum RpcMessage {
29    // Inbound
30    BlockProposal(Box<BlockProposal>),
31    TimeoutCertificate(Box<HandleTimeoutCertificateRequest>),
32    ValidatedCertificate(Box<HandleValidatedCertificateRequest>),
33    ConfirmedCertificate(Box<HandleConfirmedCertificateRequest>),
34    LiteCertificate(Box<HandleLiteCertRequest<'static>>),
35    ChainInfoQuery(Box<ChainInfoQuery>),
36    UploadBlob(Box<BlobContent>),
37    DownloadBlob(Box<BlobId>),
38    DownloadPendingBlob(Box<(ChainId, BlobId)>),
39    HandlePendingBlob(Box<(ChainId, BlobContent)>),
40    DownloadConfirmedBlock(Box<CryptoHash>),
41    DownloadCertificates(Vec<CryptoHash>),
42    BlobLastUsedBy(Box<BlobId>),
43    MissingBlobIds(Vec<BlobId>),
44    VersionInfoQuery,
45    NetworkDescriptionQuery,
46
47    // Outbound
48    Vote(Box<LiteVote>),
49    ChainInfoResponse(Box<ChainInfoResponse>),
50    Error(Box<NodeError>),
51    VersionInfoResponse(Box<VersionInfo>),
52    NetworkDescriptionResponse(Box<NetworkDescription>),
53    UploadBlobResponse(Box<BlobId>),
54    DownloadBlobResponse(Box<BlobContent>),
55    DownloadPendingBlobResponse(Box<BlobContent>),
56    DownloadConfirmedBlockResponse(Box<ConfirmedBlock>),
57    DownloadCertificatesResponse(Vec<ConfirmedBlockCertificate>),
58    BlobLastUsedByResponse(Box<CryptoHash>),
59    MissingBlobIdsResponse(Vec<BlobId>),
60
61    // Internal to a validator
62    CrossChainRequest(Box<CrossChainRequest>),
63}
64
65impl RpcMessage {
66    /// Obtains the [`ChainId`] of the chain targeted by this message, if there is one.
67    ///
68    /// Only inbound messages have target chains.
69    pub fn target_chain_id(&self) -> Option<ChainId> {
70        use RpcMessage::*;
71
72        let chain_id = match self {
73            BlockProposal(proposal) => proposal.content.block.chain_id,
74            LiteCertificate(request) => request.certificate.value.chain_id,
75            TimeoutCertificate(request) => request.certificate.inner().chain_id(),
76            ValidatedCertificate(request) => request.certificate.inner().chain_id(),
77            ConfirmedCertificate(request) => request.certificate.inner().chain_id(),
78            ChainInfoQuery(query) => query.chain_id,
79            CrossChainRequest(request) => request.target_chain_id(),
80            DownloadPendingBlob(request) => request.0,
81            HandlePendingBlob(request) => request.0,
82            Vote(_)
83            | Error(_)
84            | ChainInfoResponse(_)
85            | VersionInfoQuery
86            | VersionInfoResponse(_)
87            | NetworkDescriptionQuery
88            | NetworkDescriptionResponse(_)
89            | UploadBlob(_)
90            | UploadBlobResponse(_)
91            | DownloadBlob(_)
92            | DownloadBlobResponse(_)
93            | DownloadPendingBlobResponse(_)
94            | DownloadConfirmedBlock(_)
95            | DownloadConfirmedBlockResponse(_)
96            | DownloadCertificates(_)
97            | BlobLastUsedBy(_)
98            | BlobLastUsedByResponse(_)
99            | MissingBlobIds(_)
100            | MissingBlobIdsResponse(_)
101            | DownloadCertificatesResponse(_) => {
102                return None;
103            }
104        };
105
106        Some(chain_id)
107    }
108
109    /// Whether this message is "local" i.e. will be executed locally on the proxy
110    /// or if it'll be proxied to the server.
111    pub fn is_local_message(&self) -> bool {
112        use RpcMessage::*;
113
114        match self {
115            VersionInfoQuery
116            | NetworkDescriptionQuery
117            | UploadBlob(_)
118            | DownloadBlob(_)
119            | DownloadConfirmedBlock(_)
120            | BlobLastUsedBy(_)
121            | MissingBlobIds(_)
122            | DownloadCertificates(_) => true,
123            BlockProposal(_)
124            | LiteCertificate(_)
125            | TimeoutCertificate(_)
126            | ValidatedCertificate(_)
127            | ConfirmedCertificate(_)
128            | ChainInfoQuery(_)
129            | CrossChainRequest(_)
130            | Vote(_)
131            | Error(_)
132            | ChainInfoResponse(_)
133            | VersionInfoResponse(_)
134            | NetworkDescriptionResponse(_)
135            | UploadBlobResponse(_)
136            | DownloadPendingBlob(_)
137            | DownloadPendingBlobResponse(_)
138            | HandlePendingBlob(_)
139            | DownloadBlobResponse(_)
140            | DownloadConfirmedBlockResponse(_)
141            | BlobLastUsedByResponse(_)
142            | MissingBlobIdsResponse(_)
143            | DownloadCertificatesResponse(_) => false,
144        }
145    }
146}
147
148impl TryFrom<RpcMessage> for ChainInfoResponse {
149    type Error = NodeError;
150    fn try_from(message: RpcMessage) -> Result<Self, Self::Error> {
151        match message {
152            RpcMessage::ChainInfoResponse(response) => Ok(*response),
153            RpcMessage::Error(error) => Err(*error),
154            _ => Err(NodeError::UnexpectedMessage),
155        }
156    }
157}
158
159impl TryFrom<RpcMessage> for VersionInfo {
160    type Error = NodeError;
161    fn try_from(message: RpcMessage) -> Result<Self, Self::Error> {
162        match message {
163            RpcMessage::VersionInfoResponse(version_info) => Ok(*version_info),
164            RpcMessage::Error(error) => Err(*error),
165            _ => Err(NodeError::UnexpectedMessage),
166        }
167    }
168}
169
170impl TryFrom<RpcMessage> for BlobContent {
171    type Error = NodeError;
172    fn try_from(message: RpcMessage) -> Result<Self, Self::Error> {
173        match message {
174            RpcMessage::DownloadBlobResponse(blob)
175            | RpcMessage::DownloadPendingBlobResponse(blob) => Ok(*blob),
176            RpcMessage::Error(error) => Err(*error),
177            _ => Err(NodeError::UnexpectedMessage),
178        }
179    }
180}
181
182impl TryFrom<RpcMessage> for ConfirmedBlock {
183    type Error = NodeError;
184    fn try_from(message: RpcMessage) -> Result<Self, Self::Error> {
185        match message {
186            RpcMessage::DownloadConfirmedBlockResponse(certificate) => Ok(*certificate),
187            RpcMessage::Error(error) => Err(*error),
188            _ => Err(NodeError::UnexpectedMessage),
189        }
190    }
191}
192
193impl TryFrom<RpcMessage> for Vec<ConfirmedBlockCertificate> {
194    type Error = NodeError;
195    fn try_from(message: RpcMessage) -> Result<Self, Self::Error> {
196        match message {
197            RpcMessage::DownloadCertificatesResponse(certificates) => Ok(certificates),
198            RpcMessage::Error(error) => Err(*error),
199            _ => Err(NodeError::UnexpectedMessage),
200        }
201    }
202}
203
204impl TryFrom<RpcMessage> for CryptoHash {
205    type Error = NodeError;
206    fn try_from(message: RpcMessage) -> Result<Self, Self::Error> {
207        match message {
208            RpcMessage::BlobLastUsedByResponse(hash) => Ok(*hash),
209            RpcMessage::Error(error) => Err(*error),
210            _ => Err(NodeError::UnexpectedMessage),
211        }
212    }
213}
214
215impl TryFrom<RpcMessage> for NetworkDescription {
216    type Error = NodeError;
217    fn try_from(message: RpcMessage) -> Result<Self, Self::Error> {
218        match message {
219            RpcMessage::NetworkDescriptionResponse(description) => Ok(*description),
220            _ => Err(NodeError::UnexpectedMessage),
221        }
222    }
223}
224
225impl TryFrom<RpcMessage> for Vec<BlobId> {
226    type Error = NodeError;
227    fn try_from(message: RpcMessage) -> Result<Self, Self::Error> {
228        match message {
229            RpcMessage::MissingBlobIdsResponse(blob_ids) => Ok(blob_ids),
230            RpcMessage::Error(error) => Err(*error),
231            _ => Err(NodeError::UnexpectedMessage),
232        }
233    }
234}
235
236impl TryFrom<RpcMessage> for BlobId {
237    type Error = NodeError;
238    fn try_from(message: RpcMessage) -> Result<Self, Self::Error> {
239        match message {
240            RpcMessage::UploadBlobResponse(blob_id) => Ok(*blob_id),
241            RpcMessage::Error(error) => Err(*error),
242            _ => Err(NodeError::UnexpectedMessage),
243        }
244    }
245}
246
247impl From<NodeError> for RpcMessage {
248    fn from(error: NodeError) -> Self {
249        RpcMessage::Error(Box::new(error))
250    }
251}