1use std::collections::{HashSet, VecDeque};
5
6use custom_debug_derive::Debug;
7use futures::future::try_join_all;
8use linera_base::{
9 crypto::ValidatorPublicKey,
10 data_types::{Blob, BlockHeight},
11 ensure,
12 identifiers::{BlobId, ChainId},
13};
14use linera_cache::Arc as CacheArc;
15use linera_chain::{
16 data_types::BlockProposal,
17 types::{
18 CertificateValue, Certified, ConfirmedBlockCertificate, LiteCertificate,
19 TimeoutCertificate, ValidatedBlockCertificate,
20 },
21};
22use tracing::{debug, info, instrument};
23
24use crate::{
25 data_types::{ChainInfo, ChainInfoQuery, ChainInfoResponse},
26 node::{CrossChainMessageDelivery, NodeError, ValidatorNode},
27};
28
29#[derive(Clone, Debug)]
31pub struct RemoteNode<N> {
32 pub public_key: ValidatorPublicKey,
34 #[debug(skip)]
36 pub node: N,
37}
38
39impl<N: ValidatorNode> RemoteNode<N> {
40 pub(crate) async fn handle_chain_info_query(
41 &self,
42 query: ChainInfoQuery,
43 ) -> Result<Box<ChainInfo>, NodeError> {
44 let chain_id = query.chain_id;
45 let response = self.node.handle_chain_info_query(query).await?;
46 self.check_and_return_info(response, chain_id)
47 }
48
49 #[instrument(level = "trace")]
50 pub(crate) async fn handle_block_proposal(
51 &self,
52 proposal: Box<BlockProposal>,
53 ) -> Result<Box<ChainInfo>, NodeError> {
54 let chain_id = proposal.content.block.chain_id;
55 let response = self.node.handle_block_proposal(*proposal).await?;
56 self.check_and_return_info(response, chain_id)
57 }
58
59 pub(crate) async fn handle_timeout_certificate(
60 &self,
61 certificate: TimeoutCertificate,
62 ) -> Result<Box<ChainInfo>, NodeError> {
63 let chain_id = certificate.inner().chain_id();
64 let response = self.node.handle_timeout_certificate(certificate).await?;
65 self.check_and_return_info(response, chain_id)
66 }
67
68 pub(crate) async fn handle_confirmed_certificate(
69 &self,
70 certificate: CacheArc<ConfirmedBlockCertificate>,
71 delivery: CrossChainMessageDelivery,
72 ) -> Result<Box<ChainInfo>, NodeError> {
73 let chain_id = certificate.inner().chain_id();
74 let response = self
75 .node
76 .handle_confirmed_certificate(certificate, delivery)
77 .await?;
78 self.check_and_return_info(response, chain_id)
79 }
80
81 pub(crate) async fn handle_validated_certificate(
82 &self,
83 certificate: ValidatedBlockCertificate,
84 ) -> Result<Box<ChainInfo>, NodeError> {
85 let chain_id = certificate.inner().chain_id();
86 let response = self.node.handle_validated_certificate(certificate).await?;
87 self.check_and_return_info(response, chain_id)
88 }
89
90 #[instrument(level = "trace")]
91 pub(crate) async fn handle_lite_certificate(
92 &self,
93 certificate: LiteCertificate<'_>,
94 delivery: CrossChainMessageDelivery,
95 ) -> Result<Box<ChainInfo>, NodeError> {
96 let chain_id = certificate.value.chain_id;
97 let response = self
98 .node
99 .handle_lite_certificate(certificate, delivery)
100 .await?;
101 self.check_and_return_info(response, chain_id)
102 }
103
104 pub(crate) async fn handle_optimized_validated_certificate(
105 &self,
106 certificate: &ValidatedBlockCertificate,
107 delivery: CrossChainMessageDelivery,
108 ) -> Result<Box<ChainInfo>, NodeError> {
109 if let Some(result) = self.try_lite_certificate(certificate, delivery).await {
110 return result;
111 }
112 self.handle_validated_certificate(certificate.clone()).await
113 }
114
115 pub async fn handle_optimized_confirmed_certificate(
118 &self,
119 certificate: &CacheArc<ConfirmedBlockCertificate>,
120 delivery: CrossChainMessageDelivery,
121 ) -> Result<Box<ChainInfo>, NodeError> {
122 let cert: &ConfirmedBlockCertificate = certificate;
123 if let Some(result) = self.try_lite_certificate(cert, delivery).await {
124 return result;
125 }
126 self.handle_confirmed_certificate(certificate.clone(), delivery)
127 .await
128 }
129
130 async fn try_lite_certificate<C: Certified>(
133 &self,
134 certificate: &C,
135 delivery: CrossChainMessageDelivery,
136 ) -> Option<Result<Box<ChainInfo>, NodeError>> {
137 if !certificate.is_signed_by(&self.public_key) {
138 return None;
139 }
140 let result = self
141 .handle_lite_certificate(certificate.lite_certificate(), delivery)
142 .await;
143 match result {
144 Err(NodeError::MissingCertificateValue) => {
145 debug!(
146 address = self.address(),
147 certificate_hash = %certificate.hash(),
148 kind = ?C::Value::KIND,
149 "validator forgot a certificate value that they signed before",
150 );
151 None
152 }
153 other => Some(other),
154 }
155 }
156
157 fn check_and_return_info(
158 &self,
159 response: ChainInfoResponse,
160 chain_id: ChainId,
161 ) -> Result<Box<ChainInfo>, NodeError> {
162 let manager = &response.info.manager;
163 let proposed = manager.requested_proposed.as_ref();
164 let locking = manager.requested_locking.as_ref();
165 ensure!(
166 proposed.is_none_or(|proposal| proposal.content.block.chain_id == chain_id)
167 && locking.is_none_or(|cert| cert.chain_id() == chain_id)
168 && response.check(self.public_key).is_ok(),
169 NodeError::InvalidChainInfoResponse
170 );
171 Ok(response.info)
172 }
173
174 #[instrument(level = "trace")]
175 pub(crate) async fn download_certificate_for_blob(
176 &self,
177 blob_id: BlobId,
178 ) -> Result<ConfirmedBlockCertificate, NodeError> {
179 let certificate = self.node.blob_last_used_by_certificate(blob_id).await?;
180 if !certificate.block().requires_or_creates_blob(&blob_id) {
181 info!(
182 address = self.address(),
183 %blob_id,
184 "got invalid last used by certificate for blob from validator",
185 );
186 return Err(NodeError::InvalidCertificateForBlob(blob_id));
187 }
188 Ok(certificate)
189 }
190
191 #[instrument(level = "trace")]
193 pub(crate) async fn send_pending_blobs(
194 &self,
195 chain_id: ChainId,
196 blobs: Vec<Blob>,
197 ) -> Result<(), NodeError> {
198 let tasks = blobs
199 .into_iter()
200 .map(|blob| self.node.handle_pending_blob(chain_id, blob.into_content()));
201 try_join_all(tasks).await?;
202 Ok(())
203 }
204
205 #[instrument(level = "trace")]
209 pub async fn download_blob(&self, blob_id: BlobId) -> Result<Option<Blob>, NodeError> {
210 match self.node.download_blob(blob_id).await {
211 Ok(blob) => {
212 let blob = Blob::new(blob);
213 if blob.id() != blob_id {
214 tracing::info!(
215 address = self.address(),
216 %blob_id,
217 "validator sent an invalid blob.",
218 );
219 Ok(None)
220 } else {
221 Ok(Some(blob))
222 }
223 }
224 Err(NodeError::BlobsNotFound(_error)) => {
225 tracing::debug!(
226 ?blob_id,
227 address = self.address(),
228 "validator is missing the blob",
229 );
230 Ok(None)
231 }
232 Err(error) => Err(error),
233 }
234 }
235
236 #[instrument(level = "trace")]
240 pub async fn download_blobs(
241 &self,
242 blob_ids: Vec<BlobId>,
243 ) -> Result<crate::node::BlobStream, NodeError> {
244 self.node.download_blobs(blob_ids).await
245 }
246
247 #[instrument(level = "trace")]
249 pub async fn download_certificates_by_heights(
250 &self,
251 chain_id: ChainId,
252 heights: Vec<BlockHeight>,
253 ) -> Result<Vec<ConfirmedBlockCertificate>, NodeError> {
254 let mut expected_heights = VecDeque::from(heights.clone());
255 let certificates = self
256 .node
257 .download_certificates_by_heights(chain_id, heights)
258 .await?;
259
260 if certificates.len() > expected_heights.len() {
261 return Err(NodeError::TooManyCertificatesReturned {
262 chain_id,
263 remote_node: Box::new(self.public_key),
264 });
265 }
266
267 for certificate in &certificates {
268 ensure!(
269 certificate.inner().chain_id() == chain_id,
270 NodeError::UnexpectedCertificateValue
271 );
272 if let Some(expected_height) = expected_heights.pop_front() {
273 ensure!(
274 expected_height == certificate.inner().height(),
275 NodeError::UnexpectedCertificateValue
276 );
277 } else {
278 return Err(NodeError::UnexpectedCertificateValue);
279 }
280 }
281
282 ensure!(
283 expected_heights.is_empty(),
284 NodeError::MissingCertificatesByHeights {
285 chain_id,
286 heights: expected_heights.into_iter().collect(),
287 }
288 );
289 Ok(certificates)
290 }
291
292 pub fn check_blobs_not_found<C: Certified>(
295 &self,
296 certificate: &C,
297 blob_ids: &[BlobId],
298 ) -> Result<(), NodeError> {
299 ensure!(!blob_ids.is_empty(), NodeError::EmptyBlobsNotFound);
300 let required = certificate.value().required_blob_ids();
301 for blob_id in blob_ids {
302 if !required.contains(blob_id) {
303 info!(
304 address = self.address(),
305 %blob_id,
306 "validator requested blob but it is not required",
307 );
308 return Err(NodeError::UnexpectedEntriesInBlobsNotFound);
309 }
310 }
311 let unique_missing_blob_ids = blob_ids.iter().copied().collect::<HashSet<_>>();
312 if blob_ids.len() > unique_missing_blob_ids.len() {
313 info!(
314 address = self.address(),
315 "blobs requested by validator contain duplicates",
316 );
317 return Err(NodeError::DuplicatesInBlobsNotFound);
318 }
319 Ok(())
320 }
321
322 pub fn address(&self) -> String {
324 self.node.address()
325 }
326}
327
328impl<N: ValidatorNode> PartialEq for RemoteNode<N> {
329 fn eq(&self, other: &Self) -> bool {
330 self.public_key == other.public_key
331 }
332}
333
334impl<N: ValidatorNode> Eq for RemoteNode<N> {}