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