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