Skip to main content

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, BlockHeight, 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    DownloadCertificatesByHeights(ChainId, Vec<BlockHeight>),
43    BlobLastUsedBy(Box<BlobId>),
44    MissingBlobIds(Vec<BlobId>),
45    VersionInfoQuery,
46    NetworkDescriptionQuery,
47
48    // Outbound
49    Vote(Box<LiteVote>),
50    ChainInfoResponse(Box<ChainInfoResponse>),
51    Error(Box<NodeError>),
52    VersionInfoResponse(Box<VersionInfo>),
53    NetworkDescriptionResponse(Box<NetworkDescription>),
54    UploadBlobResponse(Box<BlobId>),
55    DownloadBlobResponse(Box<BlobContent>),
56    DownloadPendingBlobResponse(Box<BlobContent>),
57    DownloadConfirmedBlockResponse(Box<ConfirmedBlock>),
58    DownloadCertificatesResponse(Vec<ConfirmedBlockCertificate>),
59    DownloadCertificatesByHeightsResponse(Vec<ConfirmedBlockCertificate>),
60    BlobLastUsedByResponse(Box<CryptoHash>),
61    MissingBlobIdsResponse(Vec<BlobId>),
62
63    // Internal to a validator
64    CrossChainRequest(Box<CrossChainRequest>),
65
66    BlobLastUsedByCertificate(Box<BlobId>),
67    BlobLastUsedByCertificateResponse(Box<ConfirmedBlockCertificate>),
68}
69
70impl RpcMessage {
71    /// Obtains the [`ChainId`] of the chain targeted by this message, if there is one.
72    ///
73    /// Only inbound messages have target chains.
74    pub fn target_chain_id(&self) -> Option<ChainId> {
75        use RpcMessage::*;
76
77        let chain_id = match self {
78            BlockProposal(proposal) => proposal.content.block.chain_id,
79            LiteCertificate(request) => request.certificate.value.chain_id,
80            TimeoutCertificate(request) => request.certificate.inner().chain_id(),
81            ValidatedCertificate(request) => request.certificate.inner().chain_id(),
82            ConfirmedCertificate(request) => request.certificate.inner().chain_id(),
83            ChainInfoQuery(query) => query.chain_id,
84            CrossChainRequest(request) => request.target_chain_id(),
85            DownloadPendingBlob(request) => request.0,
86            DownloadCertificatesByHeights(chain_id, _) => *chain_id,
87            HandlePendingBlob(request) => request.0,
88            Vote(_)
89            | Error(_)
90            | ChainInfoResponse(_)
91            | VersionInfoQuery
92            | VersionInfoResponse(_)
93            | NetworkDescriptionQuery
94            | NetworkDescriptionResponse(_)
95            | UploadBlob(_)
96            | UploadBlobResponse(_)
97            | DownloadBlob(_)
98            | DownloadBlobResponse(_)
99            | DownloadPendingBlobResponse(_)
100            | DownloadConfirmedBlock(_)
101            | DownloadConfirmedBlockResponse(_)
102            | DownloadCertificatesByHeightsResponse(_)
103            | DownloadCertificates(_)
104            | BlobLastUsedBy(_)
105            | BlobLastUsedByResponse(_)
106            | BlobLastUsedByCertificate(_)
107            | BlobLastUsedByCertificateResponse(_)
108            | MissingBlobIds(_)
109            | MissingBlobIdsResponse(_)
110            | DownloadCertificatesResponse(_) => {
111                return None;
112            }
113        };
114
115        Some(chain_id)
116    }
117
118    /// Whether this message is "local" i.e. will be executed locally on the proxy
119    /// or if it'll be proxied to the server.
120    pub fn is_local_message(&self) -> bool {
121        use RpcMessage::*;
122
123        match self {
124            VersionInfoQuery
125            | NetworkDescriptionQuery
126            | UploadBlob(_)
127            | DownloadBlob(_)
128            | DownloadConfirmedBlock(_)
129            | BlobLastUsedBy(_)
130            | BlobLastUsedByCertificate(_)
131            | MissingBlobIds(_)
132            | DownloadCertificates(_)
133            | DownloadCertificatesByHeights(_, _) => true,
134            BlockProposal(_)
135            | LiteCertificate(_)
136            | TimeoutCertificate(_)
137            | ValidatedCertificate(_)
138            | ConfirmedCertificate(_)
139            | ChainInfoQuery(_)
140            | CrossChainRequest(_)
141            | Vote(_)
142            | Error(_)
143            | ChainInfoResponse(_)
144            | VersionInfoResponse(_)
145            | NetworkDescriptionResponse(_)
146            | UploadBlobResponse(_)
147            | DownloadPendingBlob(_)
148            | DownloadPendingBlobResponse(_)
149            | HandlePendingBlob(_)
150            | DownloadBlobResponse(_)
151            | DownloadConfirmedBlockResponse(_)
152            | BlobLastUsedByResponse(_)
153            | BlobLastUsedByCertificateResponse(_)
154            | MissingBlobIdsResponse(_)
155            | DownloadCertificatesResponse(_)
156            | DownloadCertificatesByHeightsResponse(_) => false,
157        }
158    }
159}
160
161impl TryFrom<RpcMessage> for ChainInfoResponse {
162    type Error = NodeError;
163    fn try_from(message: RpcMessage) -> Result<Self, Self::Error> {
164        match message {
165            RpcMessage::ChainInfoResponse(response) => Ok(*response),
166            RpcMessage::Error(error) => Err(*error),
167            _ => Err(NodeError::UnexpectedMessage),
168        }
169    }
170}
171
172impl TryFrom<RpcMessage> for VersionInfo {
173    type Error = NodeError;
174    fn try_from(message: RpcMessage) -> Result<Self, Self::Error> {
175        match message {
176            RpcMessage::VersionInfoResponse(version_info) => Ok(*version_info),
177            RpcMessage::Error(error) => Err(*error),
178            _ => Err(NodeError::UnexpectedMessage),
179        }
180    }
181}
182
183impl TryFrom<RpcMessage> for BlobContent {
184    type Error = NodeError;
185    fn try_from(message: RpcMessage) -> Result<Self, Self::Error> {
186        match message {
187            RpcMessage::DownloadBlobResponse(blob)
188            | RpcMessage::DownloadPendingBlobResponse(blob) => Ok(*blob),
189            RpcMessage::Error(error) => Err(*error),
190            _ => Err(NodeError::UnexpectedMessage),
191        }
192    }
193}
194
195impl TryFrom<RpcMessage> for ConfirmedBlock {
196    type Error = NodeError;
197    fn try_from(message: RpcMessage) -> Result<Self, Self::Error> {
198        match message {
199            RpcMessage::DownloadConfirmedBlockResponse(certificate) => Ok(*certificate),
200            RpcMessage::Error(error) => Err(*error),
201            _ => Err(NodeError::UnexpectedMessage),
202        }
203    }
204}
205
206impl TryFrom<RpcMessage> for ConfirmedBlockCertificate {
207    type Error = NodeError;
208    fn try_from(message: RpcMessage) -> Result<Self, Self::Error> {
209        match message {
210            RpcMessage::BlobLastUsedByCertificateResponse(certificate) => Ok(*certificate),
211            RpcMessage::Error(error) => Err(*error),
212            _ => Err(NodeError::UnexpectedMessage),
213        }
214    }
215}
216
217impl TryFrom<RpcMessage> for Vec<ConfirmedBlockCertificate> {
218    type Error = NodeError;
219    fn try_from(message: RpcMessage) -> Result<Self, Self::Error> {
220        match message {
221            RpcMessage::DownloadCertificatesResponse(certificates) => Ok(certificates),
222            RpcMessage::DownloadCertificatesByHeightsResponse(certificates) => Ok(certificates),
223            RpcMessage::Error(error) => Err(*error),
224            _ => Err(NodeError::UnexpectedMessage),
225        }
226    }
227}
228
229impl TryFrom<RpcMessage> for CryptoHash {
230    type Error = NodeError;
231    fn try_from(message: RpcMessage) -> Result<Self, Self::Error> {
232        match message {
233            RpcMessage::BlobLastUsedByResponse(hash) => Ok(*hash),
234            RpcMessage::Error(error) => Err(*error),
235            _ => Err(NodeError::UnexpectedMessage),
236        }
237    }
238}
239
240impl TryFrom<RpcMessage> for NetworkDescription {
241    type Error = NodeError;
242    fn try_from(message: RpcMessage) -> Result<Self, Self::Error> {
243        match message {
244            RpcMessage::NetworkDescriptionResponse(description) => Ok(*description),
245            _ => Err(NodeError::UnexpectedMessage),
246        }
247    }
248}
249
250impl TryFrom<RpcMessage> for Vec<BlobId> {
251    type Error = NodeError;
252    fn try_from(message: RpcMessage) -> Result<Self, Self::Error> {
253        match message {
254            RpcMessage::MissingBlobIdsResponse(blob_ids) => Ok(blob_ids),
255            RpcMessage::Error(error) => Err(*error),
256            _ => Err(NodeError::UnexpectedMessage),
257        }
258    }
259}
260
261impl TryFrom<RpcMessage> for BlobId {
262    type Error = NodeError;
263    fn try_from(message: RpcMessage) -> Result<Self, Self::Error> {
264        match message {
265            RpcMessage::UploadBlobResponse(blob_id) => Ok(*blob_id),
266            RpcMessage::Error(error) => Err(*error),
267            _ => Err(NodeError::UnexpectedMessage),
268        }
269    }
270}
271
272impl From<NodeError> for RpcMessage {
273    fn from(error: NodeError) -> Self {
274        RpcMessage::Error(Box::new(error))
275    }
276}