1use linera_base::{
5 crypto::{
6 AccountPublicKey, AccountSignature, CryptoError, CryptoHash, ValidatorPublicKey,
7 ValidatorSignature,
8 },
9 data_types::{BlobContent, BlockHeight, NetworkDescription},
10 ensure,
11 identifiers::{AccountOwner, BlobId, ChainId},
12};
13use linera_chain::{
14 data_types::{BlockProposal, LiteValue, ProposalContent},
15 types::{
16 Certificate, CertificateKind, ConfirmedBlock, ConfirmedBlockCertificate, LiteCertificate,
17 Timeout, TimeoutCertificate, ValidatedBlock, ValidatedBlockCertificate,
18 },
19};
20use linera_core::{
21 data_types::{
22 CertificatesByHeightRequest, ChainInfoQuery, ChainInfoResponse, CrossChainRequest,
23 },
24 node::NodeError,
25 worker::Notification,
26};
27use thiserror::Error;
28use tonic::{Code, Status};
29
30use super::api::{self, PendingBlobRequest};
31use crate::{
32 HandleConfirmedCertificateRequest, HandleLiteCertRequest, HandleTimeoutCertificateRequest,
33 HandleValidatedCertificateRequest,
34};
35
36#[derive(Error, Debug)]
37pub enum GrpcProtoConversionError {
38 #[error(transparent)]
39 BincodeError(#[from] bincode::Error),
40 #[error("Conversion failed due to missing field")]
41 MissingField,
42 #[error("Signature error: {0}")]
43 SignatureError(ed25519_dalek::SignatureError),
44 #[error("Cryptographic error: {0}")]
45 CryptoError(#[from] CryptoError),
46 #[error("Inconsistent outer/inner chain IDs")]
47 InconsistentChainId,
48 #[error("Unrecognized certificate type")]
49 InvalidCertificateType,
50}
51
52impl From<ed25519_dalek::SignatureError> for GrpcProtoConversionError {
53 fn from(signature_error: ed25519_dalek::SignatureError) -> Self {
54 GrpcProtoConversionError::SignatureError(signature_error)
55 }
56}
57
58fn try_proto_convert<S, T>(t: Option<T>) -> Result<S, GrpcProtoConversionError>
60where
61 T: TryInto<S, Error = GrpcProtoConversionError>,
62{
63 t.ok_or(GrpcProtoConversionError::MissingField)?.try_into()
64}
65
66impl From<GrpcProtoConversionError> for Status {
67 fn from(error: GrpcProtoConversionError) -> Self {
68 Status::new(Code::InvalidArgument, error.to_string())
69 }
70}
71
72impl From<GrpcProtoConversionError> for NodeError {
73 fn from(error: GrpcProtoConversionError) -> Self {
74 NodeError::GrpcError {
75 error: error.to_string(),
76 }
77 }
78}
79
80impl From<linera_version::CrateVersion> for api::CrateVersion {
81 fn from(
82 linera_version::CrateVersion {
83 major,
84 minor,
85 patch,
86 }: linera_version::CrateVersion,
87 ) -> Self {
88 Self {
89 major,
90 minor,
91 patch,
92 }
93 }
94}
95
96impl From<api::CrateVersion> for linera_version::CrateVersion {
97 fn from(
98 api::CrateVersion {
99 major,
100 minor,
101 patch,
102 }: api::CrateVersion,
103 ) -> Self {
104 Self {
105 major,
106 minor,
107 patch,
108 }
109 }
110}
111
112impl From<linera_version::VersionInfo> for api::VersionInfo {
113 fn from(version_info: linera_version::VersionInfo) -> api::VersionInfo {
114 api::VersionInfo {
115 crate_version: Some(version_info.crate_version.value.into()),
116 git_commit: version_info.git_commit.into(),
117 git_dirty: version_info.git_dirty,
118 rpc_hash: version_info.rpc_hash.into(),
119 graphql_hash: version_info.graphql_hash.into(),
120 wit_hash: version_info.wit_hash.into(),
121 }
122 }
123}
124
125impl From<api::VersionInfo> for linera_version::VersionInfo {
126 fn from(version_info: api::VersionInfo) -> linera_version::VersionInfo {
127 linera_version::VersionInfo {
128 crate_version: linera_version::Pretty::new(
129 version_info
130 .crate_version
131 .unwrap_or(api::CrateVersion {
132 major: 0,
133 minor: 0,
134 patch: 0,
135 })
136 .into(),
137 ),
138 git_commit: version_info.git_commit.into(),
139 git_dirty: version_info.git_dirty,
140 rpc_hash: version_info.rpc_hash.into(),
141 graphql_hash: version_info.graphql_hash.into(),
142 wit_hash: version_info.wit_hash.into(),
143 }
144 }
145}
146
147impl From<NetworkDescription> for api::NetworkDescription {
148 fn from(
149 NetworkDescription {
150 name,
151 genesis_config_hash,
152 genesis_timestamp,
153 genesis_committee_blob_hash,
154 admin_chain_id,
155 }: NetworkDescription,
156 ) -> Self {
157 Self {
158 name,
159 genesis_config_hash: Some(genesis_config_hash.into()),
160 genesis_timestamp: genesis_timestamp.micros(),
161 admin_chain_id: Some(admin_chain_id.into()),
162 genesis_committee_blob_hash: Some(genesis_committee_blob_hash.into()),
163 }
164 }
165}
166
167impl TryFrom<api::NetworkDescription> for NetworkDescription {
168 type Error = GrpcProtoConversionError;
169
170 fn try_from(
171 api::NetworkDescription {
172 name,
173 genesis_config_hash,
174 genesis_timestamp,
175 genesis_committee_blob_hash,
176 admin_chain_id,
177 }: api::NetworkDescription,
178 ) -> Result<Self, Self::Error> {
179 Ok(Self {
180 name,
181 genesis_config_hash: try_proto_convert(genesis_config_hash)?,
182 genesis_timestamp: genesis_timestamp.into(),
183 admin_chain_id: try_proto_convert(admin_chain_id)?,
184 genesis_committee_blob_hash: try_proto_convert(genesis_committee_blob_hash)?,
185 })
186 }
187}
188
189impl TryFrom<Notification> for api::Notification {
190 type Error = GrpcProtoConversionError;
191
192 fn try_from(notification: Notification) -> Result<Self, Self::Error> {
193 Ok(Self {
194 chain_id: Some(notification.chain_id.into()),
195 reason: bincode::serialize(¬ification.reason)?,
196 })
197 }
198}
199
200impl TryFrom<api::Notification> for Option<Notification> {
201 type Error = GrpcProtoConversionError;
202
203 fn try_from(notification: api::Notification) -> Result<Self, Self::Error> {
204 if notification.chain_id.is_none() && notification.reason.is_empty() {
205 Ok(None)
206 } else {
207 Ok(Some(Notification {
208 chain_id: try_proto_convert(notification.chain_id)?,
209 reason: bincode::deserialize(¬ification.reason)?,
210 }))
211 }
212 }
213}
214
215impl TryFrom<ChainInfoResponse> for api::ChainInfoResult {
216 type Error = GrpcProtoConversionError;
217
218 fn try_from(chain_info_response: ChainInfoResponse) -> Result<Self, Self::Error> {
219 let response = chain_info_response.try_into()?;
220 Ok(api::ChainInfoResult {
221 inner: Some(api::chain_info_result::Inner::ChainInfoResponse(response)),
222 })
223 }
224}
225
226impl TryFrom<NodeError> for api::ChainInfoResult {
227 type Error = GrpcProtoConversionError;
228
229 fn try_from(node_error: NodeError) -> Result<Self, Self::Error> {
230 let error = bincode::serialize(&node_error)?;
231 Ok(api::ChainInfoResult {
232 inner: Some(api::chain_info_result::Inner::Error(error)),
233 })
234 }
235}
236
237impl TryFrom<BlockProposal> for api::BlockProposal {
238 type Error = GrpcProtoConversionError;
239
240 fn try_from(block_proposal: BlockProposal) -> Result<Self, Self::Error> {
241 Ok(Self {
242 chain_id: Some(block_proposal.content.block.chain_id.into()),
243 content: bincode::serialize(&block_proposal.content)?,
244 owner: Some(block_proposal.owner().try_into()?),
245 signature: Some(block_proposal.signature.into()),
246 original_proposal: block_proposal
247 .original_proposal
248 .map(|cert| bincode::serialize(&cert))
249 .transpose()?,
250 })
251 }
252}
253
254impl TryFrom<api::BlockProposal> for BlockProposal {
255 type Error = GrpcProtoConversionError;
256
257 fn try_from(block_proposal: api::BlockProposal) -> Result<Self, Self::Error> {
258 let content: ProposalContent = bincode::deserialize(&block_proposal.content)?;
259 ensure!(
260 Some(content.block.chain_id.into()) == block_proposal.chain_id,
261 GrpcProtoConversionError::InconsistentChainId
262 );
263 Ok(Self {
264 content,
265 signature: try_proto_convert(block_proposal.signature)?,
266 original_proposal: block_proposal
267 .original_proposal
268 .map(|bytes| bincode::deserialize(&bytes))
269 .transpose()?,
270 })
271 }
272}
273
274impl TryFrom<api::CrossChainRequest> for CrossChainRequest {
275 type Error = GrpcProtoConversionError;
276
277 fn try_from(cross_chain_request: api::CrossChainRequest) -> Result<Self, Self::Error> {
278 use api::cross_chain_request::Inner;
279
280 let ccr = match cross_chain_request
281 .inner
282 .ok_or(GrpcProtoConversionError::MissingField)?
283 {
284 Inner::UpdateRecipient(api::UpdateRecipient {
285 sender,
286 recipient,
287 bundles,
288 }) => CrossChainRequest::UpdateRecipient {
289 sender: try_proto_convert(sender)?,
290 recipient: try_proto_convert(recipient)?,
291 bundles: bincode::deserialize(&bundles)?,
292 },
293 Inner::ConfirmUpdatedRecipient(api::ConfirmUpdatedRecipient {
294 sender,
295 recipient,
296 latest_height,
297 }) => CrossChainRequest::ConfirmUpdatedRecipient {
298 sender: try_proto_convert(sender)?,
299 recipient: try_proto_convert(recipient)?,
300 latest_height: latest_height
301 .ok_or(GrpcProtoConversionError::MissingField)?
302 .into(),
303 },
304 };
305 Ok(ccr)
306 }
307}
308
309impl TryFrom<CrossChainRequest> for api::CrossChainRequest {
310 type Error = GrpcProtoConversionError;
311
312 fn try_from(cross_chain_request: CrossChainRequest) -> Result<Self, Self::Error> {
313 use api::cross_chain_request::Inner;
314
315 let inner = match cross_chain_request {
316 CrossChainRequest::UpdateRecipient {
317 sender,
318 recipient,
319 bundles,
320 } => Inner::UpdateRecipient(api::UpdateRecipient {
321 sender: Some(sender.into()),
322 recipient: Some(recipient.into()),
323 bundles: bincode::serialize(&bundles)?,
324 }),
325 CrossChainRequest::ConfirmUpdatedRecipient {
326 sender,
327 recipient,
328 latest_height,
329 } => Inner::ConfirmUpdatedRecipient(api::ConfirmUpdatedRecipient {
330 sender: Some(sender.into()),
331 recipient: Some(recipient.into()),
332 latest_height: Some(latest_height.into()),
333 }),
334 };
335 Ok(Self { inner: Some(inner) })
336 }
337}
338
339impl TryFrom<api::LiteCertificate> for HandleLiteCertRequest<'_> {
340 type Error = GrpcProtoConversionError;
341
342 fn try_from(certificate: api::LiteCertificate) -> Result<Self, Self::Error> {
343 let kind = if certificate.kind == api::CertificateKind::Validated as i32 {
344 CertificateKind::Validated
345 } else if certificate.kind == api::CertificateKind::Confirmed as i32 {
346 CertificateKind::Confirmed
347 } else if certificate.kind == api::CertificateKind::Timeout as i32 {
348 CertificateKind::Timeout
349 } else {
350 return Err(GrpcProtoConversionError::InvalidCertificateType);
351 };
352
353 let value = LiteValue {
354 value_hash: CryptoHash::try_from(certificate.hash.as_slice())?,
355 chain_id: try_proto_convert(certificate.chain_id)?,
356 kind,
357 };
358 let signatures = bincode::deserialize(&certificate.signatures)?;
359 let round = bincode::deserialize(&certificate.round)?;
360 Ok(Self {
361 certificate: LiteCertificate::new(value, round, signatures),
362 wait_for_outgoing_messages: certificate.wait_for_outgoing_messages,
363 })
364 }
365}
366
367impl TryFrom<HandleLiteCertRequest<'_>> for api::LiteCertificate {
368 type Error = GrpcProtoConversionError;
369
370 fn try_from(request: HandleLiteCertRequest) -> Result<Self, Self::Error> {
371 Ok(Self {
372 hash: request.certificate.value.value_hash.as_bytes().to_vec(),
373 round: bincode::serialize(&request.certificate.round)?,
374 chain_id: Some(request.certificate.value.chain_id.into()),
375 signatures: bincode::serialize(&request.certificate.signatures)?,
376 wait_for_outgoing_messages: request.wait_for_outgoing_messages,
377 kind: request.certificate.value.kind as i32,
378 })
379 }
380}
381
382impl TryFrom<api::HandleTimeoutCertificateRequest> for HandleTimeoutCertificateRequest {
383 type Error = GrpcProtoConversionError;
384
385 fn try_from(cert_request: api::HandleTimeoutCertificateRequest) -> Result<Self, Self::Error> {
386 let certificate: TimeoutCertificate = cert_request
387 .certificate
388 .ok_or(GrpcProtoConversionError::MissingField)?
389 .try_into()?;
390
391 let req_chain_id: ChainId = cert_request
392 .chain_id
393 .ok_or(GrpcProtoConversionError::MissingField)?
394 .try_into()?;
395
396 ensure!(
397 certificate.inner().chain_id() == req_chain_id,
398 GrpcProtoConversionError::InconsistentChainId
399 );
400 Ok(HandleTimeoutCertificateRequest { certificate })
401 }
402}
403
404impl TryFrom<api::HandleValidatedCertificateRequest> for HandleValidatedCertificateRequest {
405 type Error = GrpcProtoConversionError;
406
407 fn try_from(cert_request: api::HandleValidatedCertificateRequest) -> Result<Self, Self::Error> {
408 let certificate: ValidatedBlockCertificate = cert_request
409 .certificate
410 .ok_or(GrpcProtoConversionError::MissingField)?
411 .try_into()?;
412
413 let req_chain_id: ChainId = cert_request
414 .chain_id
415 .ok_or(GrpcProtoConversionError::MissingField)?
416 .try_into()?;
417
418 ensure!(
419 certificate.inner().chain_id() == req_chain_id,
420 GrpcProtoConversionError::InconsistentChainId
421 );
422 Ok(HandleValidatedCertificateRequest { certificate })
423 }
424}
425
426impl TryFrom<api::HandleConfirmedCertificateRequest> for HandleConfirmedCertificateRequest {
427 type Error = GrpcProtoConversionError;
428
429 fn try_from(cert_request: api::HandleConfirmedCertificateRequest) -> Result<Self, Self::Error> {
430 let certificate: ConfirmedBlockCertificate = cert_request
431 .certificate
432 .ok_or(GrpcProtoConversionError::MissingField)?
433 .try_into()?;
434
435 let req_chain_id: ChainId = cert_request
436 .chain_id
437 .ok_or(GrpcProtoConversionError::MissingField)?
438 .try_into()?;
439
440 ensure!(
441 certificate.inner().chain_id() == req_chain_id,
442 GrpcProtoConversionError::InconsistentChainId
443 );
444 Ok(HandleConfirmedCertificateRequest {
445 certificate,
446 wait_for_outgoing_messages: cert_request.wait_for_outgoing_messages,
447 })
448 }
449}
450
451impl TryFrom<HandleConfirmedCertificateRequest> for api::HandleConfirmedCertificateRequest {
452 type Error = GrpcProtoConversionError;
453
454 fn try_from(request: HandleConfirmedCertificateRequest) -> Result<Self, Self::Error> {
455 Ok(Self {
456 chain_id: Some(request.certificate.inner().chain_id().into()),
457 certificate: Some(request.certificate.try_into()?),
458 wait_for_outgoing_messages: request.wait_for_outgoing_messages,
459 })
460 }
461}
462
463impl TryFrom<HandleValidatedCertificateRequest> for api::HandleValidatedCertificateRequest {
464 type Error = GrpcProtoConversionError;
465
466 fn try_from(request: HandleValidatedCertificateRequest) -> Result<Self, Self::Error> {
467 Ok(Self {
468 chain_id: Some(request.certificate.inner().chain_id().into()),
469 certificate: Some(request.certificate.try_into()?),
470 })
471 }
472}
473
474impl TryFrom<HandleTimeoutCertificateRequest> for api::HandleTimeoutCertificateRequest {
475 type Error = GrpcProtoConversionError;
476
477 fn try_from(request: HandleTimeoutCertificateRequest) -> Result<Self, Self::Error> {
478 Ok(Self {
479 chain_id: Some(request.certificate.inner().chain_id().into()),
480 certificate: Some(request.certificate.try_into()?),
481 })
482 }
483}
484
485impl TryFrom<api::Certificate> for TimeoutCertificate {
486 type Error = GrpcProtoConversionError;
487
488 fn try_from(certificate: api::Certificate) -> Result<Self, Self::Error> {
489 let round = bincode::deserialize(&certificate.round)?;
490 let signatures = bincode::deserialize(&certificate.signatures)?;
491 let cert_type = certificate.kind;
492
493 if cert_type == api::CertificateKind::Timeout as i32 {
494 let value: Timeout = bincode::deserialize(&certificate.value)?;
495 Ok(TimeoutCertificate::new(value, round, signatures))
496 } else {
497 Err(GrpcProtoConversionError::InvalidCertificateType)
498 }
499 }
500}
501
502impl TryFrom<api::Certificate> for ValidatedBlockCertificate {
503 type Error = GrpcProtoConversionError;
504
505 fn try_from(certificate: api::Certificate) -> Result<Self, Self::Error> {
506 let round = bincode::deserialize(&certificate.round)?;
507 let signatures = bincode::deserialize(&certificate.signatures)?;
508 let cert_type = certificate.kind;
509
510 if cert_type == api::CertificateKind::Validated as i32 {
511 let value: ValidatedBlock = bincode::deserialize(&certificate.value)?;
512 Ok(ValidatedBlockCertificate::new(value, round, signatures))
513 } else {
514 Err(GrpcProtoConversionError::InvalidCertificateType)
515 }
516 }
517}
518
519impl TryFrom<api::Certificate> for ConfirmedBlockCertificate {
520 type Error = GrpcProtoConversionError;
521
522 fn try_from(certificate: api::Certificate) -> Result<Self, Self::Error> {
523 let round = bincode::deserialize(&certificate.round)?;
524 let signatures = bincode::deserialize(&certificate.signatures)?;
525 let cert_type = certificate.kind;
526
527 if cert_type == api::CertificateKind::Confirmed as i32 {
528 let value: ConfirmedBlock = bincode::deserialize(&certificate.value)?;
529 Ok(ConfirmedBlockCertificate::new(value, round, signatures))
530 } else {
531 Err(GrpcProtoConversionError::InvalidCertificateType)
532 }
533 }
534}
535
536impl TryFrom<TimeoutCertificate> for api::Certificate {
537 type Error = GrpcProtoConversionError;
538
539 fn try_from(certificate: TimeoutCertificate) -> Result<Self, Self::Error> {
540 let round = bincode::serialize(&certificate.round)?;
541 let signatures = bincode::serialize(certificate.signatures())?;
542
543 let value = bincode::serialize(certificate.value())?;
544
545 Ok(Self {
546 value,
547 round,
548 signatures,
549 kind: api::CertificateKind::Timeout as i32,
550 })
551 }
552}
553
554impl TryFrom<ConfirmedBlockCertificate> for api::Certificate {
555 type Error = GrpcProtoConversionError;
556
557 fn try_from(certificate: ConfirmedBlockCertificate) -> Result<Self, Self::Error> {
558 let round = bincode::serialize(&certificate.round)?;
559 let signatures = bincode::serialize(certificate.signatures())?;
560
561 let value = bincode::serialize(certificate.value())?;
562
563 Ok(Self {
564 value,
565 round,
566 signatures,
567 kind: api::CertificateKind::Confirmed as i32,
568 })
569 }
570}
571
572impl TryFrom<ValidatedBlockCertificate> for api::Certificate {
573 type Error = GrpcProtoConversionError;
574
575 fn try_from(certificate: ValidatedBlockCertificate) -> Result<Self, Self::Error> {
576 let round = bincode::serialize(&certificate.round)?;
577 let signatures = bincode::serialize(certificate.signatures())?;
578
579 let value = bincode::serialize(certificate.value())?;
580
581 Ok(Self {
582 value,
583 round,
584 signatures,
585 kind: api::CertificateKind::Validated as i32,
586 })
587 }
588}
589
590impl TryFrom<api::ChainInfoQuery> for ChainInfoQuery {
591 type Error = GrpcProtoConversionError;
592
593 fn try_from(chain_info_query: api::ChainInfoQuery) -> Result<Self, Self::Error> {
594 let request_sent_certificate_hashes_by_heights = chain_info_query
595 .request_sent_certificate_hashes_by_heights
596 .map(|heights| bincode::deserialize(&heights))
597 .transpose()?
598 .unwrap_or_default();
599 let request_leader_timeout = chain_info_query
600 .request_leader_timeout
601 .map(|height_and_round| bincode::deserialize(&height_and_round))
602 .transpose()?;
603
604 Ok(Self {
605 request_committees: chain_info_query.request_committees,
606 request_owner_balance: try_proto_convert(chain_info_query.request_owner_balance)?,
607 request_pending_message_bundles: chain_info_query.request_pending_message_bundles,
608 chain_id: try_proto_convert(chain_info_query.chain_id)?,
609 request_received_log_excluding_first_n: chain_info_query
610 .request_received_log_excluding_first_n,
611 test_next_block_height: chain_info_query.test_next_block_height.map(Into::into),
612 request_manager_values: chain_info_query.request_manager_values,
613 request_leader_timeout,
614 request_fallback: chain_info_query.request_fallback,
615 request_sent_certificate_hashes_by_heights,
616 request_sent_certificate_hashes_in_range: None,
617 create_network_actions: chain_info_query.create_network_actions.unwrap_or(true),
618 })
619 }
620}
621
622impl TryFrom<ChainInfoQuery> for api::ChainInfoQuery {
623 type Error = GrpcProtoConversionError;
624
625 fn try_from(chain_info_query: ChainInfoQuery) -> Result<Self, Self::Error> {
626 let request_sent_certificate_hashes_by_heights =
627 bincode::serialize(&chain_info_query.request_sent_certificate_hashes_by_heights)?;
628 let request_owner_balance = Some(chain_info_query.request_owner_balance.try_into()?);
629 let request_leader_timeout = chain_info_query
630 .request_leader_timeout
631 .map(|height_and_round| bincode::serialize(&height_and_round))
632 .transpose()?;
633
634 Ok(Self {
635 chain_id: Some(chain_info_query.chain_id.into()),
636 request_committees: chain_info_query.request_committees,
637 request_owner_balance,
638 request_pending_message_bundles: chain_info_query.request_pending_message_bundles,
639 test_next_block_height: chain_info_query.test_next_block_height.map(Into::into),
640 request_sent_certificate_hashes_by_heights: Some(
641 request_sent_certificate_hashes_by_heights,
642 ),
643 request_received_log_excluding_first_n: chain_info_query
644 .request_received_log_excluding_first_n,
645 request_manager_values: chain_info_query.request_manager_values,
646 request_leader_timeout,
647 request_fallback: chain_info_query.request_fallback,
648 create_network_actions: Some(chain_info_query.create_network_actions),
649 })
650 }
651}
652
653impl From<ChainId> for api::ChainId {
654 fn from(chain_id: ChainId) -> Self {
655 Self {
656 bytes: chain_id.0.as_bytes().to_vec(),
657 }
658 }
659}
660
661impl TryFrom<api::ChainId> for ChainId {
662 type Error = GrpcProtoConversionError;
663
664 fn try_from(chain_id: api::ChainId) -> Result<Self, Self::Error> {
665 Ok(ChainId::try_from(chain_id.bytes.as_slice())?)
666 }
667}
668
669impl From<AccountPublicKey> for api::AccountPublicKey {
670 fn from(public_key: AccountPublicKey) -> Self {
671 Self {
672 bytes: public_key.as_bytes(),
673 }
674 }
675}
676
677impl From<ValidatorPublicKey> for api::ValidatorPublicKey {
678 fn from(public_key: ValidatorPublicKey) -> Self {
679 Self {
680 bytes: public_key.as_bytes().to_vec(),
681 }
682 }
683}
684
685impl TryFrom<api::ValidatorPublicKey> for ValidatorPublicKey {
686 type Error = GrpcProtoConversionError;
687
688 fn try_from(public_key: api::ValidatorPublicKey) -> Result<Self, Self::Error> {
689 Ok(Self::from_bytes(public_key.bytes.as_slice())?)
690 }
691}
692
693impl TryFrom<api::AccountPublicKey> for AccountPublicKey {
694 type Error = GrpcProtoConversionError;
695
696 fn try_from(public_key: api::AccountPublicKey) -> Result<Self, Self::Error> {
697 Ok(Self::from_slice(public_key.bytes.as_slice())?)
698 }
699}
700
701impl From<AccountSignature> for api::AccountSignature {
702 fn from(signature: AccountSignature) -> Self {
703 Self {
704 bytes: signature.to_bytes(),
705 }
706 }
707}
708
709impl From<ValidatorSignature> for api::ValidatorSignature {
710 fn from(signature: ValidatorSignature) -> Self {
711 Self {
712 bytes: signature.as_bytes().to_vec(),
713 }
714 }
715}
716
717impl TryFrom<api::ValidatorSignature> for ValidatorSignature {
718 type Error = GrpcProtoConversionError;
719
720 fn try_from(signature: api::ValidatorSignature) -> Result<Self, Self::Error> {
721 Self::from_slice(signature.bytes.as_slice()).map_err(GrpcProtoConversionError::CryptoError)
722 }
723}
724
725impl TryFrom<api::AccountSignature> for AccountSignature {
726 type Error = GrpcProtoConversionError;
727
728 fn try_from(signature: api::AccountSignature) -> Result<Self, Self::Error> {
729 Ok(Self::from_slice(signature.bytes.as_slice())?)
730 }
731}
732
733impl TryFrom<ChainInfoResponse> for api::ChainInfoResponse {
734 type Error = GrpcProtoConversionError;
735
736 fn try_from(chain_info_response: ChainInfoResponse) -> Result<Self, Self::Error> {
737 Ok(Self {
738 chain_info: bincode::serialize(&chain_info_response.info)?,
739 signature: chain_info_response.signature.map(Into::into),
740 })
741 }
742}
743
744impl TryFrom<api::ChainInfoResponse> for ChainInfoResponse {
745 type Error = GrpcProtoConversionError;
746
747 fn try_from(chain_info_response: api::ChainInfoResponse) -> Result<Self, Self::Error> {
748 let signature = chain_info_response
749 .signature
750 .map(TryInto::try_into)
751 .transpose()?;
752 let info = bincode::deserialize(chain_info_response.chain_info.as_slice())?;
753 Ok(Self { info, signature })
754 }
755}
756
757impl TryFrom<(ChainId, BlobId)> for api::PendingBlobRequest {
758 type Error = GrpcProtoConversionError;
759
760 fn try_from((chain_id, blob_id): (ChainId, BlobId)) -> Result<Self, Self::Error> {
761 Ok(Self {
762 chain_id: Some(chain_id.into()),
763 blob_id: Some(blob_id.try_into()?),
764 })
765 }
766}
767
768impl TryFrom<api::PendingBlobRequest> for (ChainId, BlobId) {
769 type Error = GrpcProtoConversionError;
770
771 fn try_from(request: PendingBlobRequest) -> Result<Self, Self::Error> {
772 Ok((
773 try_proto_convert(request.chain_id)?,
774 try_proto_convert(request.blob_id)?,
775 ))
776 }
777}
778
779impl TryFrom<(ChainId, BlobContent)> for api::HandlePendingBlobRequest {
780 type Error = GrpcProtoConversionError;
781
782 fn try_from((chain_id, blob_content): (ChainId, BlobContent)) -> Result<Self, Self::Error> {
783 Ok(Self {
784 chain_id: Some(chain_id.into()),
785 blob: Some(blob_content.try_into()?),
786 })
787 }
788}
789
790impl TryFrom<api::HandlePendingBlobRequest> for (ChainId, BlobContent) {
791 type Error = GrpcProtoConversionError;
792
793 fn try_from(request: api::HandlePendingBlobRequest) -> Result<Self, Self::Error> {
794 Ok((
795 try_proto_convert(request.chain_id)?,
796 try_proto_convert(request.blob)?,
797 ))
798 }
799}
800
801impl TryFrom<BlobContent> for api::PendingBlobResult {
802 type Error = GrpcProtoConversionError;
803
804 fn try_from(blob: BlobContent) -> Result<Self, Self::Error> {
805 Ok(Self {
806 inner: Some(api::pending_blob_result::Inner::Blob(blob.try_into()?)),
807 })
808 }
809}
810
811impl TryFrom<NodeError> for api::PendingBlobResult {
812 type Error = GrpcProtoConversionError;
813
814 fn try_from(node_error: NodeError) -> Result<Self, Self::Error> {
815 let error = bincode::serialize(&node_error)?;
816 Ok(api::PendingBlobResult {
817 inner: Some(api::pending_blob_result::Inner::Error(error)),
818 })
819 }
820}
821
822impl From<BlockHeight> for api::BlockHeight {
823 fn from(block_height: BlockHeight) -> Self {
824 Self {
825 height: block_height.0,
826 }
827 }
828}
829
830impl From<api::BlockHeight> for BlockHeight {
831 fn from(block_height: api::BlockHeight) -> Self {
832 Self(block_height.height)
833 }
834}
835
836impl TryFrom<AccountOwner> for api::AccountOwner {
837 type Error = GrpcProtoConversionError;
838
839 fn try_from(account_owner: AccountOwner) -> Result<Self, Self::Error> {
840 Ok(Self {
841 bytes: bincode::serialize(&account_owner)?,
842 })
843 }
844}
845
846impl TryFrom<api::AccountOwner> for AccountOwner {
847 type Error = GrpcProtoConversionError;
848
849 fn try_from(account_owner: api::AccountOwner) -> Result<Self, Self::Error> {
850 Ok(bincode::deserialize(&account_owner.bytes)?)
851 }
852}
853
854impl TryFrom<api::BlobId> for BlobId {
855 type Error = GrpcProtoConversionError;
856
857 fn try_from(blob_id: api::BlobId) -> Result<Self, Self::Error> {
858 Ok(bincode::deserialize(blob_id.bytes.as_slice())?)
859 }
860}
861
862impl TryFrom<api::BlobIds> for Vec<BlobId> {
863 type Error = GrpcProtoConversionError;
864
865 fn try_from(blob_ids: api::BlobIds) -> Result<Self, Self::Error> {
866 Ok(blob_ids
867 .bytes
868 .into_iter()
869 .map(|x| bincode::deserialize(x.as_slice()))
870 .collect::<Result<_, _>>()?)
871 }
872}
873
874impl TryFrom<BlobId> for api::BlobId {
875 type Error = GrpcProtoConversionError;
876
877 fn try_from(blob_id: BlobId) -> Result<Self, Self::Error> {
878 Ok(Self {
879 bytes: bincode::serialize(&blob_id)?,
880 })
881 }
882}
883
884impl TryFrom<Vec<BlobId>> for api::BlobIds {
885 type Error = GrpcProtoConversionError;
886
887 fn try_from(blob_ids: Vec<BlobId>) -> Result<Self, Self::Error> {
888 let bytes = blob_ids
889 .into_iter()
890 .map(|blob_id| bincode::serialize(&blob_id))
891 .collect::<Result<_, _>>()?;
892 Ok(Self { bytes })
893 }
894}
895
896impl TryFrom<api::CryptoHash> for CryptoHash {
897 type Error = GrpcProtoConversionError;
898
899 fn try_from(hash: api::CryptoHash) -> Result<Self, Self::Error> {
900 Ok(CryptoHash::try_from(hash.bytes.as_slice())?)
901 }
902}
903
904impl TryFrom<BlobContent> for api::BlobContent {
905 type Error = GrpcProtoConversionError;
906
907 fn try_from(blob: BlobContent) -> Result<Self, Self::Error> {
908 Ok(Self {
909 bytes: bincode::serialize(&blob)?,
910 })
911 }
912}
913
914impl TryFrom<api::BlobContent> for BlobContent {
915 type Error = GrpcProtoConversionError;
916
917 fn try_from(blob: api::BlobContent) -> Result<Self, Self::Error> {
918 Ok(bincode::deserialize(blob.bytes.as_slice())?)
919 }
920}
921
922impl From<CryptoHash> for api::CryptoHash {
923 fn from(hash: CryptoHash) -> Self {
924 Self {
925 bytes: hash.as_bytes().to_vec(),
926 }
927 }
928}
929
930impl From<Vec<CryptoHash>> for api::CertificatesBatchRequest {
931 fn from(certs: Vec<CryptoHash>) -> Self {
932 Self {
933 hashes: certs.into_iter().map(Into::into).collect(),
934 }
935 }
936}
937
938impl TryFrom<Certificate> for api::Certificate {
939 type Error = GrpcProtoConversionError;
940
941 fn try_from(certificate: Certificate) -> Result<Self, Self::Error> {
942 let round = bincode::serialize(&certificate.round())?;
943 let signatures = bincode::serialize(certificate.signatures())?;
944
945 let (kind, value) = match certificate {
946 Certificate::Confirmed(confirmed) => (
947 api::CertificateKind::Confirmed,
948 bincode::serialize(confirmed.value())?,
949 ),
950 Certificate::Validated(validated) => (
951 api::CertificateKind::Validated,
952 bincode::serialize(validated.value())?,
953 ),
954 Certificate::Timeout(timeout) => (
955 api::CertificateKind::Timeout,
956 bincode::serialize(timeout.value())?,
957 ),
958 };
959
960 Ok(Self {
961 value,
962 round,
963 signatures,
964 kind: kind as i32,
965 })
966 }
967}
968
969impl TryFrom<api::Certificate> for Certificate {
970 type Error = GrpcProtoConversionError;
971
972 fn try_from(certificate: api::Certificate) -> Result<Self, Self::Error> {
973 let round = bincode::deserialize(&certificate.round)?;
974 let signatures = bincode::deserialize(&certificate.signatures)?;
975
976 let value = if certificate.kind == api::CertificateKind::Confirmed as i32 {
977 let value: ConfirmedBlock = bincode::deserialize(&certificate.value)?;
978 Certificate::Confirmed(ConfirmedBlockCertificate::new(value, round, signatures))
979 } else if certificate.kind == api::CertificateKind::Validated as i32 {
980 let value: ValidatedBlock = bincode::deserialize(&certificate.value)?;
981 Certificate::Validated(ValidatedBlockCertificate::new(value, round, signatures))
982 } else if certificate.kind == api::CertificateKind::Timeout as i32 {
983 let value: Timeout = bincode::deserialize(&certificate.value)?;
984 Certificate::Timeout(TimeoutCertificate::new(value, round, signatures))
985 } else {
986 return Err(GrpcProtoConversionError::InvalidCertificateType);
987 };
988
989 Ok(value)
990 }
991}
992
993impl TryFrom<Vec<Certificate>> for api::CertificatesBatchResponse {
994 type Error = GrpcProtoConversionError;
995
996 fn try_from(certs: Vec<Certificate>) -> Result<Self, Self::Error> {
997 Ok(Self {
998 certificates: certs
999 .into_iter()
1000 .map(TryInto::try_into)
1001 .collect::<Result<_, _>>()?,
1002 })
1003 }
1004}
1005
1006impl TryFrom<api::CertificatesBatchResponse> for Vec<Certificate> {
1007 type Error = GrpcProtoConversionError;
1008
1009 fn try_from(response: api::CertificatesBatchResponse) -> Result<Self, Self::Error> {
1010 response
1011 .certificates
1012 .into_iter()
1013 .map(Certificate::try_from)
1014 .collect()
1015 }
1016}
1017
1018impl From<CertificatesByHeightRequest> for api::DownloadCertificatesByHeightsRequest {
1019 fn from(request: CertificatesByHeightRequest) -> Self {
1020 Self {
1021 chain_id: Some(request.chain_id.into()),
1022 heights: request.heights.into_iter().map(Into::into).collect(),
1023 }
1024 }
1025}
1026
1027impl TryFrom<api::DownloadCertificatesByHeightsRequest> for CertificatesByHeightRequest {
1028 type Error = GrpcProtoConversionError;
1029
1030 fn try_from(request: api::DownloadCertificatesByHeightsRequest) -> Result<Self, Self::Error> {
1031 Ok(Self {
1032 chain_id: try_proto_convert(request.chain_id)?,
1033 heights: request.heights.into_iter().map(Into::into).collect(),
1034 })
1035 }
1036}
1037
1038#[cfg(test)]
1039pub mod tests {
1040 use std::{borrow::Cow, fmt::Debug};
1041
1042 use linera_base::{
1043 crypto::{AccountSecretKey, BcsSignable, CryptoHash, Secp256k1SecretKey, ValidatorKeypair},
1044 data_types::{Amount, Blob, Epoch, Round, Timestamp},
1045 };
1046 use linera_chain::{
1047 data_types::{BlockExecutionOutcome, OriginalProposal, ProposedBlock},
1048 test::make_first_block,
1049 types::CertificateKind,
1050 };
1051 use linera_core::data_types::ChainInfo;
1052 use serde::{Deserialize, Serialize};
1053
1054 use super::*;
1055
1056 #[derive(Debug, Serialize, Deserialize)]
1057 struct Foo(String);
1058
1059 impl BcsSignable<'_> for Foo {}
1060
1061 fn dummy_chain_id(index: u32) -> ChainId {
1062 ChainId(CryptoHash::test_hash(format!("chain{}", index)))
1063 }
1064
1065 fn get_block() -> ProposedBlock {
1066 make_first_block(dummy_chain_id(0))
1067 }
1068
1069 fn round_trip_check<T, M>(value: T)
1072 where
1073 T: TryFrom<M> + Clone + Debug + Eq,
1074 M: TryFrom<T>,
1075 T::Error: Debug,
1076 M::Error: Debug,
1077 {
1078 let message = M::try_from(value.clone()).unwrap();
1079 assert_eq!(value, message.try_into().unwrap());
1080 }
1081
1082 #[test]
1083 pub fn test_public_key() {
1084 let account_key = AccountSecretKey::generate().public();
1085 round_trip_check::<_, api::AccountPublicKey>(account_key);
1086
1087 let validator_key = ValidatorKeypair::generate().public_key;
1088 round_trip_check::<_, api::ValidatorPublicKey>(validator_key);
1089 }
1090
1091 #[test]
1092 pub fn test_signature() {
1093 let validator_key_pair = ValidatorKeypair::generate();
1094 let validator_signature =
1095 ValidatorSignature::new(&Foo("test".into()), &validator_key_pair.secret_key);
1096 round_trip_check::<_, api::ValidatorSignature>(validator_signature);
1097
1098 let account_key_pair = AccountSecretKey::generate();
1099 let account_signature = account_key_pair.sign(&Foo("test".into()));
1100 round_trip_check::<_, api::AccountSignature>(account_signature);
1101 }
1102
1103 #[test]
1104 pub fn test_owner() {
1105 let key_pair = AccountSecretKey::generate();
1106 let owner = AccountOwner::from(key_pair.public());
1107 round_trip_check::<_, api::AccountOwner>(owner);
1108 }
1109
1110 #[test]
1111 pub fn test_block_height() {
1112 let block_height = BlockHeight::from(10);
1113 round_trip_check::<_, api::BlockHeight>(block_height);
1114 }
1115
1116 #[test]
1117 pub fn test_chain_id() {
1118 let chain_id = dummy_chain_id(0);
1119 round_trip_check::<_, api::ChainId>(chain_id);
1120 }
1121
1122 #[test]
1123 pub fn test_chain_info_response() {
1124 let chain_info = Box::new(ChainInfo {
1125 chain_id: dummy_chain_id(0),
1126 epoch: Epoch::ZERO,
1127 description: None,
1128 manager: Box::default(),
1129 chain_balance: Amount::ZERO,
1130 block_hash: None,
1131 timestamp: Timestamp::default(),
1132 next_block_height: BlockHeight::ZERO,
1133 state_hash: None,
1134 requested_committees: None,
1135 requested_owner_balance: None,
1136 requested_pending_message_bundles: vec![],
1137 requested_sent_certificate_hashes: vec![],
1138 count_received_log: 0,
1139 requested_received_log: vec![],
1140 });
1141
1142 let chain_info_response_none = ChainInfoResponse {
1143 info: chain_info.clone(),
1145 signature: None,
1146 };
1147 round_trip_check::<_, api::ChainInfoResponse>(chain_info_response_none);
1148
1149 let chain_info_response_some = ChainInfoResponse {
1150 info: chain_info,
1152 signature: Some(ValidatorSignature::new(
1153 &Foo("test".into()),
1154 &ValidatorKeypair::generate().secret_key,
1155 )),
1156 };
1157 round_trip_check::<_, api::ChainInfoResponse>(chain_info_response_some);
1158 }
1159
1160 #[test]
1161 pub fn test_chain_info_query() {
1162 let chain_info_query_none = ChainInfoQuery::new(dummy_chain_id(0));
1163 round_trip_check::<_, api::ChainInfoQuery>(chain_info_query_none);
1164
1165 let chain_info_query_some = ChainInfoQuery {
1166 chain_id: dummy_chain_id(0),
1167 test_next_block_height: Some(BlockHeight::from(10)),
1168 request_committees: false,
1169 request_owner_balance: AccountOwner::CHAIN,
1170 request_pending_message_bundles: false,
1171 request_received_log_excluding_first_n: None,
1172 request_manager_values: false,
1173 request_leader_timeout: None,
1174 request_fallback: true,
1175 request_sent_certificate_hashes_by_heights: (3..8).map(BlockHeight::from).collect(),
1176 request_sent_certificate_hashes_in_range: None,
1177 create_network_actions: true,
1178 };
1179 round_trip_check::<_, api::ChainInfoQuery>(chain_info_query_some);
1180 }
1181
1182 #[test]
1183 pub fn test_pending_blob_request() {
1184 let chain_id = dummy_chain_id(2);
1185 let blob_id = Blob::new(BlobContent::new_data(*b"foo")).id();
1186 let pending_blob_request = (chain_id, blob_id);
1187 round_trip_check::<_, api::PendingBlobRequest>(pending_blob_request);
1188 }
1189
1190 #[test]
1191 pub fn test_pending_blob_result() {
1192 let blob = BlobContent::new_data(*b"foo");
1193 round_trip_check::<_, api::PendingBlobResult>(blob);
1194 }
1195
1196 #[test]
1197 pub fn test_handle_pending_blob_request() {
1198 let chain_id = dummy_chain_id(2);
1199 let blob_content = BlobContent::new_data(*b"foo");
1200 let pending_blob_request = (chain_id, blob_content);
1201 round_trip_check::<_, api::HandlePendingBlobRequest>(pending_blob_request);
1202 }
1203
1204 #[test]
1205 pub fn test_lite_certificate() {
1206 let key_pair = ValidatorKeypair::generate();
1207 let certificate = LiteCertificate {
1208 value: LiteValue {
1209 value_hash: CryptoHash::new(&Foo("value".into())),
1210 chain_id: dummy_chain_id(0),
1211 kind: CertificateKind::Validated,
1212 },
1213 round: Round::MultiLeader(2),
1214 signatures: Cow::Owned(vec![(
1215 key_pair.public_key,
1216 ValidatorSignature::new(&Foo("test".into()), &key_pair.secret_key),
1217 )]),
1218 };
1219 let request = HandleLiteCertRequest {
1220 certificate,
1221 wait_for_outgoing_messages: true,
1222 };
1223
1224 round_trip_check::<_, api::LiteCertificate>(request);
1225 }
1226
1227 #[test]
1228 pub fn test_certificate() {
1229 let key_pair = ValidatorKeypair::generate();
1230 let certificate = ValidatedBlockCertificate::new(
1231 ValidatedBlock::new(
1232 BlockExecutionOutcome {
1233 state_hash: CryptoHash::new(&Foo("test".into())),
1234 ..BlockExecutionOutcome::default()
1235 }
1236 .with(get_block()),
1237 ),
1238 Round::MultiLeader(3),
1239 vec![(
1240 key_pair.public_key,
1241 ValidatorSignature::new(&Foo("test".into()), &key_pair.secret_key),
1242 )],
1243 );
1244 let request = HandleValidatedCertificateRequest { certificate };
1245
1246 round_trip_check::<_, api::HandleValidatedCertificateRequest>(request);
1247 }
1248
1249 #[test]
1250 pub fn test_cross_chain_request() {
1251 let cross_chain_request_update_recipient = CrossChainRequest::UpdateRecipient {
1252 sender: dummy_chain_id(0),
1253 recipient: dummy_chain_id(0),
1254 bundles: vec![],
1255 };
1256 round_trip_check::<_, api::CrossChainRequest>(cross_chain_request_update_recipient);
1257
1258 let cross_chain_request_confirm_updated_recipient =
1259 CrossChainRequest::ConfirmUpdatedRecipient {
1260 sender: dummy_chain_id(0),
1261 recipient: dummy_chain_id(0),
1262 latest_height: BlockHeight(1),
1263 };
1264 round_trip_check::<_, api::CrossChainRequest>(
1265 cross_chain_request_confirm_updated_recipient,
1266 );
1267 }
1268
1269 #[test]
1270 pub fn test_block_proposal() {
1271 let key_pair = ValidatorKeypair::generate();
1272 let outcome = BlockExecutionOutcome {
1273 state_hash: CryptoHash::new(&Foo("validated".into())),
1274 ..BlockExecutionOutcome::default()
1275 };
1276 let certificate = ValidatedBlockCertificate::new(
1277 ValidatedBlock::new(outcome.clone().with(get_block())),
1278 Round::SingleLeader(2),
1279 vec![(
1280 key_pair.public_key,
1281 ValidatorSignature::new(&Foo("signed".into()), &key_pair.secret_key),
1282 )],
1283 )
1284 .lite_certificate()
1285 .cloned();
1286 let key_pair = AccountSecretKey::Secp256k1(Secp256k1SecretKey::generate());
1287 let block_proposal = BlockProposal {
1288 content: ProposalContent {
1289 block: get_block(),
1290 round: Round::SingleLeader(4),
1291 outcome: Some(outcome),
1292 },
1293 signature: key_pair.sign(&Foo("test".into())),
1294 original_proposal: Some(OriginalProposal::Regular { certificate }),
1295 };
1296
1297 round_trip_check::<_, api::BlockProposal>(block_proposal);
1298 }
1299
1300 #[test]
1301 pub fn test_notification() {
1302 let notification = Notification {
1303 chain_id: dummy_chain_id(0),
1304 reason: linera_core::worker::Reason::NewBlock {
1305 height: BlockHeight(0),
1306 hash: CryptoHash::new(&Foo("".into())),
1307 },
1308 };
1309 let message = api::Notification::try_from(notification.clone()).unwrap();
1310 assert_eq!(
1311 Some(notification),
1312 Option::<Notification>::try_from(message).unwrap()
1313 );
1314
1315 let ack = api::Notification::default();
1316 assert_eq!(None, Option::<Notification>::try_from(ack).unwrap());
1317 }
1318}