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, EventId},
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    worker::Notification,
18};
19use linera_version::VersionInfo;
20use serde::{Deserialize, Serialize};
21
22use crate::{
23    config::ShardId, HandleConfirmedCertificateRequest, HandleLiteCertRequest,
24    HandleTimeoutCertificateRequest, HandleValidatedCertificateRequest,
25};
26
27/// Information about shard configuration for a specific chain.
28#[derive(Clone, Serialize, Deserialize, Debug)]
29#[cfg_attr(with_testing, derive(Eq, PartialEq))]
30pub struct ShardInfo {
31    /// The ID of the shard assigned to the chain.
32    pub shard_id: ShardId,
33    /// The total number of shards in the validator network.
34    pub total_shards: usize,
35}
36
37#[derive(Clone, Serialize, Deserialize, Debug)]
38#[cfg_attr(with_testing, derive(Eq, PartialEq))]
39pub enum RpcMessage {
40    // Inbound
41    BlockProposal(Box<BlockProposal>),
42    TimeoutCertificate(Box<HandleTimeoutCertificateRequest>),
43    ValidatedCertificate(Box<HandleValidatedCertificateRequest>),
44    ConfirmedCertificate(Box<HandleConfirmedCertificateRequest>),
45    LiteCertificate(Box<HandleLiteCertRequest<'static>>),
46    ChainInfoQuery(Box<ChainInfoQuery>),
47    UploadBlob(Box<BlobContent>),
48    DownloadBlob(Box<BlobId>),
49    DownloadBlobs(Vec<BlobId>),
50    DownloadPendingBlob(Box<(ChainId, BlobId)>),
51    HandlePendingBlob(Box<(ChainId, BlobContent)>),
52    DownloadConfirmedBlock(Box<CryptoHash>),
53    DownloadCertificates(Vec<CryptoHash>),
54    DownloadCertificatesByHeights(ChainId, Vec<BlockHeight>),
55    BlobLastUsedBy(Box<BlobId>),
56    MissingBlobIds(Vec<BlobId>),
57    EventBlockHeights(Vec<EventId>),
58    VersionInfoQuery,
59    NetworkDescriptionQuery,
60
61    // Outbound
62    Vote(Box<LiteVote>),
63    ChainInfoResponse(Box<ChainInfoResponse>),
64    Error(Box<NodeError>),
65    VersionInfoResponse(Box<VersionInfo>),
66    NetworkDescriptionResponse(Box<NetworkDescription>),
67    UploadBlobResponse(Box<BlobId>),
68    DownloadBlobResponse(Box<BlobContent>),
69    DownloadPendingBlobResponse(Box<BlobContent>),
70    DownloadConfirmedBlockResponse(Box<ConfirmedBlock>),
71    DownloadCertificatesResponse(Vec<ConfirmedBlockCertificate>),
72    DownloadCertificatesByHeightsResponse(Vec<ConfirmedBlockCertificate>),
73    BlobLastUsedByResponse(Box<CryptoHash>),
74    MissingBlobIdsResponse(Vec<BlobId>),
75    EventBlockHeightsResponse(Vec<Option<BlockHeight>>),
76
77    // Internal to a validator
78    CrossChainRequest(Box<CrossChainRequest>),
79
80    BlobLastUsedByCertificate(Box<BlobId>),
81    BlobLastUsedByCertificateResponse(Box<ConfirmedBlockCertificate>),
82    ShardInfoQuery(ChainId),
83    ShardInfoResponse(ShardInfo),
84
85    // Notification subscription
86    SubscribeNotifications(Vec<ChainId>),
87    Notification(Box<Notification>),
88}
89
90impl RpcMessage {
91    /// Obtains the [`ChainId`] of the chain targeted by this message, if there is one.
92    ///
93    /// Only inbound messages have target chains.
94    pub fn target_chain_id(&self) -> Option<ChainId> {
95        use RpcMessage::*;
96
97        let chain_id = match self {
98            BlockProposal(proposal) => proposal.content.block.chain_id,
99            LiteCertificate(request) => request.certificate.value.chain_id,
100            TimeoutCertificate(request) => request.certificate.inner().chain_id(),
101            ValidatedCertificate(request) => request.certificate.inner().chain_id(),
102            ConfirmedCertificate(request) => request.certificate.inner().chain_id(),
103            ChainInfoQuery(query) => query.chain_id,
104            CrossChainRequest(request) => request.target_chain_id(),
105            DownloadPendingBlob(request) => request.0,
106            DownloadCertificatesByHeights(chain_id, _) => *chain_id,
107            HandlePendingBlob(request) => request.0,
108            ShardInfoQuery(chain_id) => *chain_id,
109            Vote(_)
110            | Error(_)
111            | ChainInfoResponse(_)
112            | VersionInfoQuery
113            | VersionInfoResponse(_)
114            | NetworkDescriptionQuery
115            | NetworkDescriptionResponse(_)
116            | UploadBlob(_)
117            | UploadBlobResponse(_)
118            | DownloadBlob(_)
119            | DownloadBlobs(_)
120            | DownloadBlobResponse(_)
121            | DownloadPendingBlobResponse(_)
122            | DownloadConfirmedBlock(_)
123            | DownloadConfirmedBlockResponse(_)
124            | DownloadCertificatesByHeightsResponse(_)
125            | DownloadCertificates(_)
126            | BlobLastUsedBy(_)
127            | BlobLastUsedByResponse(_)
128            | BlobLastUsedByCertificate(_)
129            | BlobLastUsedByCertificateResponse(_)
130            | MissingBlobIds(_)
131            | MissingBlobIdsResponse(_)
132            | EventBlockHeights(_)
133            | EventBlockHeightsResponse(_)
134            | ShardInfoResponse(_)
135            | DownloadCertificatesResponse(_)
136            | SubscribeNotifications(_)
137            | Notification(_) => {
138                return None;
139            }
140        };
141
142        Some(chain_id)
143    }
144
145    /// Whether this message is "local" i.e. will be executed locally on the proxy
146    /// or if it'll be proxied to the server.
147    pub fn is_local_message(&self) -> bool {
148        use RpcMessage::*;
149
150        match self {
151            VersionInfoQuery
152            | NetworkDescriptionQuery
153            | ShardInfoQuery(_)
154            | UploadBlob(_)
155            | DownloadBlob(_)
156            | DownloadBlobs(_)
157            | DownloadConfirmedBlock(_)
158            | BlobLastUsedBy(_)
159            | BlobLastUsedByCertificate(_)
160            | MissingBlobIds(_)
161            | EventBlockHeights(_)
162            | DownloadCertificates(_)
163            | DownloadCertificatesByHeights(_, _) => true,
164            BlockProposal(_)
165            | LiteCertificate(_)
166            | TimeoutCertificate(_)
167            | ValidatedCertificate(_)
168            | ConfirmedCertificate(_)
169            | ChainInfoQuery(_)
170            | CrossChainRequest(_)
171            | Vote(_)
172            | Error(_)
173            | ChainInfoResponse(_)
174            | VersionInfoResponse(_)
175            | NetworkDescriptionResponse(_)
176            | ShardInfoResponse(_)
177            | UploadBlobResponse(_)
178            | DownloadPendingBlob(_)
179            | DownloadPendingBlobResponse(_)
180            | HandlePendingBlob(_)
181            | DownloadBlobResponse(_)
182            | DownloadConfirmedBlockResponse(_)
183            | BlobLastUsedByResponse(_)
184            | BlobLastUsedByCertificateResponse(_)
185            | MissingBlobIdsResponse(_)
186            | EventBlockHeightsResponse(_)
187            | DownloadCertificatesResponse(_)
188            | DownloadCertificatesByHeightsResponse(_)
189            | SubscribeNotifications(_)
190            | Notification(_) => false,
191        }
192    }
193}
194
195impl TryFrom<RpcMessage> for ChainInfoResponse {
196    type Error = NodeError;
197    fn try_from(message: RpcMessage) -> Result<Self, Self::Error> {
198        match message {
199            RpcMessage::ChainInfoResponse(response) => Ok(*response),
200            RpcMessage::Error(error) => Err(*error),
201            _ => Err(NodeError::UnexpectedMessage),
202        }
203    }
204}
205
206impl TryFrom<RpcMessage> for VersionInfo {
207    type Error = NodeError;
208    fn try_from(message: RpcMessage) -> Result<Self, Self::Error> {
209        match message {
210            RpcMessage::VersionInfoResponse(version_info) => Ok(*version_info),
211            RpcMessage::Error(error) => Err(*error),
212            _ => Err(NodeError::UnexpectedMessage),
213        }
214    }
215}
216
217impl TryFrom<RpcMessage> for BlobContent {
218    type Error = NodeError;
219    fn try_from(message: RpcMessage) -> Result<Self, Self::Error> {
220        match message {
221            RpcMessage::DownloadBlobResponse(blob)
222            | RpcMessage::DownloadPendingBlobResponse(blob) => Ok(*blob),
223            RpcMessage::Error(error) => Err(*error),
224            _ => Err(NodeError::UnexpectedMessage),
225        }
226    }
227}
228
229impl TryFrom<RpcMessage> for ConfirmedBlock {
230    type Error = NodeError;
231    fn try_from(message: RpcMessage) -> Result<Self, Self::Error> {
232        match message {
233            RpcMessage::DownloadConfirmedBlockResponse(certificate) => Ok(*certificate),
234            RpcMessage::Error(error) => Err(*error),
235            _ => Err(NodeError::UnexpectedMessage),
236        }
237    }
238}
239
240impl TryFrom<RpcMessage> for ConfirmedBlockCertificate {
241    type Error = NodeError;
242    fn try_from(message: RpcMessage) -> Result<Self, Self::Error> {
243        match message {
244            RpcMessage::BlobLastUsedByCertificateResponse(certificate) => Ok(*certificate),
245            RpcMessage::Error(error) => Err(*error),
246            _ => Err(NodeError::UnexpectedMessage),
247        }
248    }
249}
250
251impl TryFrom<RpcMessage> for Vec<ConfirmedBlockCertificate> {
252    type Error = NodeError;
253    fn try_from(message: RpcMessage) -> Result<Self, Self::Error> {
254        match message {
255            RpcMessage::DownloadCertificatesResponse(certificates) => Ok(certificates),
256            RpcMessage::DownloadCertificatesByHeightsResponse(certificates) => Ok(certificates),
257            RpcMessage::Error(error) => Err(*error),
258            _ => Err(NodeError::UnexpectedMessage),
259        }
260    }
261}
262
263impl TryFrom<RpcMessage> for CryptoHash {
264    type Error = NodeError;
265    fn try_from(message: RpcMessage) -> Result<Self, Self::Error> {
266        match message {
267            RpcMessage::BlobLastUsedByResponse(hash) => Ok(*hash),
268            RpcMessage::Error(error) => Err(*error),
269            _ => Err(NodeError::UnexpectedMessage),
270        }
271    }
272}
273
274impl TryFrom<RpcMessage> for NetworkDescription {
275    type Error = NodeError;
276    fn try_from(message: RpcMessage) -> Result<Self, Self::Error> {
277        match message {
278            RpcMessage::NetworkDescriptionResponse(description) => Ok(*description),
279            _ => Err(NodeError::UnexpectedMessage),
280        }
281    }
282}
283
284impl TryFrom<RpcMessage> for Vec<Option<BlockHeight>> {
285    type Error = NodeError;
286    fn try_from(message: RpcMessage) -> Result<Self, Self::Error> {
287        match message {
288            RpcMessage::EventBlockHeightsResponse(heights) => Ok(heights),
289            RpcMessage::Error(error) => Err(*error),
290            _ => Err(NodeError::UnexpectedMessage),
291        }
292    }
293}
294
295impl TryFrom<RpcMessage> for Vec<BlobId> {
296    type Error = NodeError;
297    fn try_from(message: RpcMessage) -> Result<Self, Self::Error> {
298        match message {
299            RpcMessage::MissingBlobIdsResponse(blob_ids) => Ok(blob_ids),
300            RpcMessage::Error(error) => Err(*error),
301            _ => Err(NodeError::UnexpectedMessage),
302        }
303    }
304}
305
306impl TryFrom<RpcMessage> for BlobId {
307    type Error = NodeError;
308    fn try_from(message: RpcMessage) -> Result<Self, Self::Error> {
309        match message {
310            RpcMessage::UploadBlobResponse(blob_id) => Ok(*blob_id),
311            RpcMessage::Error(error) => Err(*error),
312            _ => Err(NodeError::UnexpectedMessage),
313        }
314    }
315}
316
317impl TryFrom<RpcMessage> for ShardInfo {
318    type Error = NodeError;
319    fn try_from(message: RpcMessage) -> Result<Self, Self::Error> {
320        match message {
321            RpcMessage::ShardInfoResponse(shard_info) => Ok(shard_info),
322            RpcMessage::Error(error) => Err(*error),
323            _ => Err(NodeError::UnexpectedMessage),
324        }
325    }
326}
327
328impl From<NodeError> for RpcMessage {
329    fn from(error: NodeError) -> Self {
330        RpcMessage::Error(Box::new(error))
331    }
332}