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 create_network_actions: chain_info_query.create_network_actions.unwrap_or(true),
617 })
618 }
619}
620
621impl TryFrom<ChainInfoQuery> for api::ChainInfoQuery {
622 type Error = GrpcProtoConversionError;
623
624 fn try_from(chain_info_query: ChainInfoQuery) -> Result<Self, Self::Error> {
625 let request_sent_certificate_hashes_by_heights =
626 bincode::serialize(&chain_info_query.request_sent_certificate_hashes_by_heights)?;
627 let request_owner_balance = Some(chain_info_query.request_owner_balance.try_into()?);
628 let request_leader_timeout = chain_info_query
629 .request_leader_timeout
630 .map(|height_and_round| bincode::serialize(&height_and_round))
631 .transpose()?;
632
633 Ok(Self {
634 chain_id: Some(chain_info_query.chain_id.into()),
635 request_committees: chain_info_query.request_committees,
636 request_owner_balance,
637 request_pending_message_bundles: chain_info_query.request_pending_message_bundles,
638 test_next_block_height: chain_info_query.test_next_block_height.map(Into::into),
639 request_sent_certificate_hashes_by_heights: Some(
640 request_sent_certificate_hashes_by_heights,
641 ),
642 request_received_log_excluding_first_n: chain_info_query
643 .request_received_log_excluding_first_n,
644 request_manager_values: chain_info_query.request_manager_values,
645 request_leader_timeout,
646 request_fallback: chain_info_query.request_fallback,
647 create_network_actions: Some(chain_info_query.create_network_actions),
648 })
649 }
650}
651
652impl From<ChainId> for api::ChainId {
653 fn from(chain_id: ChainId) -> Self {
654 Self {
655 bytes: chain_id.0.as_bytes().to_vec(),
656 }
657 }
658}
659
660impl TryFrom<api::ChainId> for ChainId {
661 type Error = GrpcProtoConversionError;
662
663 fn try_from(chain_id: api::ChainId) -> Result<Self, Self::Error> {
664 Ok(ChainId::try_from(chain_id.bytes.as_slice())?)
665 }
666}
667
668impl From<AccountPublicKey> for api::AccountPublicKey {
669 fn from(public_key: AccountPublicKey) -> Self {
670 Self {
671 bytes: public_key.as_bytes(),
672 }
673 }
674}
675
676impl From<ValidatorPublicKey> for api::ValidatorPublicKey {
677 fn from(public_key: ValidatorPublicKey) -> Self {
678 Self {
679 bytes: public_key.as_bytes().to_vec(),
680 }
681 }
682}
683
684impl TryFrom<api::ValidatorPublicKey> for ValidatorPublicKey {
685 type Error = GrpcProtoConversionError;
686
687 fn try_from(public_key: api::ValidatorPublicKey) -> Result<Self, Self::Error> {
688 Ok(Self::from_bytes(public_key.bytes.as_slice())?)
689 }
690}
691
692impl TryFrom<api::AccountPublicKey> for AccountPublicKey {
693 type Error = GrpcProtoConversionError;
694
695 fn try_from(public_key: api::AccountPublicKey) -> Result<Self, Self::Error> {
696 Ok(Self::from_slice(public_key.bytes.as_slice())?)
697 }
698}
699
700impl From<AccountSignature> for api::AccountSignature {
701 fn from(signature: AccountSignature) -> Self {
702 Self {
703 bytes: signature.to_bytes(),
704 }
705 }
706}
707
708impl From<ValidatorSignature> for api::ValidatorSignature {
709 fn from(signature: ValidatorSignature) -> Self {
710 Self {
711 bytes: signature.as_bytes().to_vec(),
712 }
713 }
714}
715
716impl TryFrom<api::ValidatorSignature> for ValidatorSignature {
717 type Error = GrpcProtoConversionError;
718
719 fn try_from(signature: api::ValidatorSignature) -> Result<Self, Self::Error> {
720 Self::from_slice(signature.bytes.as_slice()).map_err(GrpcProtoConversionError::CryptoError)
721 }
722}
723
724impl TryFrom<api::AccountSignature> for AccountSignature {
725 type Error = GrpcProtoConversionError;
726
727 fn try_from(signature: api::AccountSignature) -> Result<Self, Self::Error> {
728 Ok(Self::from_slice(signature.bytes.as_slice())?)
729 }
730}
731
732impl TryFrom<ChainInfoResponse> for api::ChainInfoResponse {
733 type Error = GrpcProtoConversionError;
734
735 fn try_from(chain_info_response: ChainInfoResponse) -> Result<Self, Self::Error> {
736 Ok(Self {
737 chain_info: bincode::serialize(&chain_info_response.info)?,
738 signature: chain_info_response.signature.map(Into::into),
739 })
740 }
741}
742
743impl TryFrom<api::ChainInfoResponse> for ChainInfoResponse {
744 type Error = GrpcProtoConversionError;
745
746 fn try_from(chain_info_response: api::ChainInfoResponse) -> Result<Self, Self::Error> {
747 let signature = chain_info_response
748 .signature
749 .map(TryInto::try_into)
750 .transpose()?;
751 let info = bincode::deserialize(chain_info_response.chain_info.as_slice())?;
752 Ok(Self { info, signature })
753 }
754}
755
756impl TryFrom<(ChainId, BlobId)> for api::PendingBlobRequest {
757 type Error = GrpcProtoConversionError;
758
759 fn try_from((chain_id, blob_id): (ChainId, BlobId)) -> Result<Self, Self::Error> {
760 Ok(Self {
761 chain_id: Some(chain_id.into()),
762 blob_id: Some(blob_id.try_into()?),
763 })
764 }
765}
766
767impl TryFrom<api::PendingBlobRequest> for (ChainId, BlobId) {
768 type Error = GrpcProtoConversionError;
769
770 fn try_from(request: PendingBlobRequest) -> Result<Self, Self::Error> {
771 Ok((
772 try_proto_convert(request.chain_id)?,
773 try_proto_convert(request.blob_id)?,
774 ))
775 }
776}
777
778impl TryFrom<(ChainId, BlobContent)> for api::HandlePendingBlobRequest {
779 type Error = GrpcProtoConversionError;
780
781 fn try_from((chain_id, blob_content): (ChainId, BlobContent)) -> Result<Self, Self::Error> {
782 Ok(Self {
783 chain_id: Some(chain_id.into()),
784 blob: Some(blob_content.try_into()?),
785 })
786 }
787}
788
789impl TryFrom<api::HandlePendingBlobRequest> for (ChainId, BlobContent) {
790 type Error = GrpcProtoConversionError;
791
792 fn try_from(request: api::HandlePendingBlobRequest) -> Result<Self, Self::Error> {
793 Ok((
794 try_proto_convert(request.chain_id)?,
795 try_proto_convert(request.blob)?,
796 ))
797 }
798}
799
800impl TryFrom<BlobContent> for api::PendingBlobResult {
801 type Error = GrpcProtoConversionError;
802
803 fn try_from(blob: BlobContent) -> Result<Self, Self::Error> {
804 Ok(Self {
805 inner: Some(api::pending_blob_result::Inner::Blob(blob.try_into()?)),
806 })
807 }
808}
809
810impl TryFrom<NodeError> for api::PendingBlobResult {
811 type Error = GrpcProtoConversionError;
812
813 fn try_from(node_error: NodeError) -> Result<Self, Self::Error> {
814 let error = bincode::serialize(&node_error)?;
815 Ok(api::PendingBlobResult {
816 inner: Some(api::pending_blob_result::Inner::Error(error)),
817 })
818 }
819}
820
821impl From<BlockHeight> for api::BlockHeight {
822 fn from(block_height: BlockHeight) -> Self {
823 Self {
824 height: block_height.0,
825 }
826 }
827}
828
829impl From<api::BlockHeight> for BlockHeight {
830 fn from(block_height: api::BlockHeight) -> Self {
831 Self(block_height.height)
832 }
833}
834
835impl TryFrom<AccountOwner> for api::AccountOwner {
836 type Error = GrpcProtoConversionError;
837
838 fn try_from(account_owner: AccountOwner) -> Result<Self, Self::Error> {
839 Ok(Self {
840 bytes: bincode::serialize(&account_owner)?,
841 })
842 }
843}
844
845impl TryFrom<api::AccountOwner> for AccountOwner {
846 type Error = GrpcProtoConversionError;
847
848 fn try_from(account_owner: api::AccountOwner) -> Result<Self, Self::Error> {
849 Ok(bincode::deserialize(&account_owner.bytes)?)
850 }
851}
852
853impl TryFrom<api::BlobId> for BlobId {
854 type Error = GrpcProtoConversionError;
855
856 fn try_from(blob_id: api::BlobId) -> Result<Self, Self::Error> {
857 Ok(bincode::deserialize(blob_id.bytes.as_slice())?)
858 }
859}
860
861impl TryFrom<api::BlobIds> for Vec<BlobId> {
862 type Error = GrpcProtoConversionError;
863
864 fn try_from(blob_ids: api::BlobIds) -> Result<Self, Self::Error> {
865 Ok(blob_ids
866 .bytes
867 .into_iter()
868 .map(|x| bincode::deserialize(x.as_slice()))
869 .collect::<Result<_, _>>()?)
870 }
871}
872
873impl TryFrom<BlobId> for api::BlobId {
874 type Error = GrpcProtoConversionError;
875
876 fn try_from(blob_id: BlobId) -> Result<Self, Self::Error> {
877 Ok(Self {
878 bytes: bincode::serialize(&blob_id)?,
879 })
880 }
881}
882
883impl TryFrom<Vec<BlobId>> for api::BlobIds {
884 type Error = GrpcProtoConversionError;
885
886 fn try_from(blob_ids: Vec<BlobId>) -> Result<Self, Self::Error> {
887 let bytes = blob_ids
888 .into_iter()
889 .map(|blob_id| bincode::serialize(&blob_id))
890 .collect::<Result<_, _>>()?;
891 Ok(Self { bytes })
892 }
893}
894
895impl TryFrom<api::CryptoHash> for CryptoHash {
896 type Error = GrpcProtoConversionError;
897
898 fn try_from(hash: api::CryptoHash) -> Result<Self, Self::Error> {
899 Ok(CryptoHash::try_from(hash.bytes.as_slice())?)
900 }
901}
902
903impl TryFrom<BlobContent> for api::BlobContent {
904 type Error = GrpcProtoConversionError;
905
906 fn try_from(blob: BlobContent) -> Result<Self, Self::Error> {
907 Ok(Self {
908 bytes: bincode::serialize(&blob)?,
909 })
910 }
911}
912
913impl TryFrom<api::BlobContent> for BlobContent {
914 type Error = GrpcProtoConversionError;
915
916 fn try_from(blob: api::BlobContent) -> Result<Self, Self::Error> {
917 Ok(bincode::deserialize(blob.bytes.as_slice())?)
918 }
919}
920
921impl From<CryptoHash> for api::CryptoHash {
922 fn from(hash: CryptoHash) -> Self {
923 Self {
924 bytes: hash.as_bytes().to_vec(),
925 }
926 }
927}
928
929impl From<Vec<CryptoHash>> for api::CertificatesBatchRequest {
930 fn from(certs: Vec<CryptoHash>) -> Self {
931 Self {
932 hashes: certs.into_iter().map(Into::into).collect(),
933 }
934 }
935}
936
937impl TryFrom<Certificate> for api::Certificate {
938 type Error = GrpcProtoConversionError;
939
940 fn try_from(certificate: Certificate) -> Result<Self, Self::Error> {
941 let round = bincode::serialize(&certificate.round())?;
942 let signatures = bincode::serialize(certificate.signatures())?;
943
944 let (kind, value) = match certificate {
945 Certificate::Confirmed(confirmed) => (
946 api::CertificateKind::Confirmed,
947 bincode::serialize(confirmed.value())?,
948 ),
949 Certificate::Validated(validated) => (
950 api::CertificateKind::Validated,
951 bincode::serialize(validated.value())?,
952 ),
953 Certificate::Timeout(timeout) => (
954 api::CertificateKind::Timeout,
955 bincode::serialize(timeout.value())?,
956 ),
957 };
958
959 Ok(Self {
960 value,
961 round,
962 signatures,
963 kind: kind as i32,
964 })
965 }
966}
967
968impl TryFrom<api::Certificate> for Certificate {
969 type Error = GrpcProtoConversionError;
970
971 fn try_from(certificate: api::Certificate) -> Result<Self, Self::Error> {
972 let round = bincode::deserialize(&certificate.round)?;
973 let signatures = bincode::deserialize(&certificate.signatures)?;
974
975 let value = if certificate.kind == api::CertificateKind::Confirmed as i32 {
976 let value: ConfirmedBlock = bincode::deserialize(&certificate.value)?;
977 Certificate::Confirmed(ConfirmedBlockCertificate::new(value, round, signatures))
978 } else if certificate.kind == api::CertificateKind::Validated as i32 {
979 let value: ValidatedBlock = bincode::deserialize(&certificate.value)?;
980 Certificate::Validated(ValidatedBlockCertificate::new(value, round, signatures))
981 } else if certificate.kind == api::CertificateKind::Timeout as i32 {
982 let value: Timeout = bincode::deserialize(&certificate.value)?;
983 Certificate::Timeout(TimeoutCertificate::new(value, round, signatures))
984 } else {
985 return Err(GrpcProtoConversionError::InvalidCertificateType);
986 };
987
988 Ok(value)
989 }
990}
991
992impl TryFrom<Vec<Certificate>> for api::CertificatesBatchResponse {
993 type Error = GrpcProtoConversionError;
994
995 fn try_from(certs: Vec<Certificate>) -> Result<Self, Self::Error> {
996 Ok(Self {
997 certificates: certs
998 .into_iter()
999 .map(TryInto::try_into)
1000 .collect::<Result<_, _>>()?,
1001 })
1002 }
1003}
1004
1005impl TryFrom<api::CertificatesBatchResponse> for Vec<Certificate> {
1006 type Error = GrpcProtoConversionError;
1007
1008 fn try_from(response: api::CertificatesBatchResponse) -> Result<Self, Self::Error> {
1009 response
1010 .certificates
1011 .into_iter()
1012 .map(Certificate::try_from)
1013 .collect()
1014 }
1015}
1016
1017impl From<CertificatesByHeightRequest> for api::DownloadCertificatesByHeightsRequest {
1018 fn from(request: CertificatesByHeightRequest) -> Self {
1019 Self {
1020 chain_id: Some(request.chain_id.into()),
1021 heights: request.heights.into_iter().map(Into::into).collect(),
1022 }
1023 }
1024}
1025
1026impl TryFrom<api::DownloadCertificatesByHeightsRequest> for CertificatesByHeightRequest {
1027 type Error = GrpcProtoConversionError;
1028
1029 fn try_from(request: api::DownloadCertificatesByHeightsRequest) -> Result<Self, Self::Error> {
1030 Ok(Self {
1031 chain_id: try_proto_convert(request.chain_id)?,
1032 heights: request.heights.into_iter().map(Into::into).collect(),
1033 })
1034 }
1035}
1036
1037#[cfg(test)]
1038pub mod tests {
1039 use std::{borrow::Cow, fmt::Debug};
1040
1041 use linera_base::{
1042 crypto::{AccountSecretKey, BcsSignable, CryptoHash, Secp256k1SecretKey, ValidatorKeypair},
1043 data_types::{Amount, Blob, Epoch, Round, Timestamp},
1044 };
1045 use linera_chain::{
1046 data_types::{BlockExecutionOutcome, OriginalProposal, ProposedBlock},
1047 test::make_first_block,
1048 types::CertificateKind,
1049 };
1050 use linera_core::data_types::ChainInfo;
1051 use serde::{Deserialize, Serialize};
1052
1053 use super::*;
1054
1055 #[derive(Debug, Serialize, Deserialize)]
1056 struct Foo(String);
1057
1058 impl BcsSignable<'_> for Foo {}
1059
1060 fn dummy_chain_id(index: u32) -> ChainId {
1061 ChainId(CryptoHash::test_hash(format!("chain{}", index)))
1062 }
1063
1064 fn get_block() -> ProposedBlock {
1065 make_first_block(dummy_chain_id(0))
1066 }
1067
1068 fn round_trip_check<T, M>(value: &T)
1071 where
1072 T: TryFrom<M> + Clone + Debug + Eq,
1073 M: TryFrom<T>,
1074 T::Error: Debug,
1075 M::Error: Debug,
1076 {
1077 let message = M::try_from(value.clone()).unwrap();
1078 let round_trip_value: T = message.try_into().unwrap();
1079 assert_eq!(value, &round_trip_value);
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 create_network_actions: true,
1177 };
1178 round_trip_check::<_, api::ChainInfoQuery>(&chain_info_query_some);
1179 }
1180
1181 #[test]
1182 pub fn test_pending_blob_request() {
1183 let chain_id = dummy_chain_id(2);
1184 let blob_id = Blob::new(BlobContent::new_data(*b"foo")).id();
1185 let pending_blob_request = (chain_id, blob_id);
1186 round_trip_check::<_, api::PendingBlobRequest>(&pending_blob_request);
1187 }
1188
1189 #[test]
1190 pub fn test_pending_blob_result() {
1191 let blob = BlobContent::new_data(*b"foo");
1192 round_trip_check::<_, api::PendingBlobResult>(&blob);
1193 }
1194
1195 #[test]
1196 pub fn test_handle_pending_blob_request() {
1197 let chain_id = dummy_chain_id(2);
1198 let blob_content = BlobContent::new_data(*b"foo");
1199 let pending_blob_request = (chain_id, blob_content);
1200 round_trip_check::<_, api::HandlePendingBlobRequest>(&pending_blob_request);
1201 }
1202
1203 #[test]
1204 pub fn test_lite_certificate() {
1205 let key_pair = ValidatorKeypair::generate();
1206 let certificate = LiteCertificate {
1207 value: LiteValue {
1208 value_hash: CryptoHash::new(&Foo("value".into())),
1209 chain_id: dummy_chain_id(0),
1210 kind: CertificateKind::Validated,
1211 },
1212 round: Round::MultiLeader(2),
1213 signatures: Cow::Owned(vec![(
1214 key_pair.public_key,
1215 ValidatorSignature::new(&Foo("test".into()), &key_pair.secret_key),
1216 )]),
1217 };
1218 let request = HandleLiteCertRequest {
1219 certificate,
1220 wait_for_outgoing_messages: true,
1221 };
1222
1223 round_trip_check::<_, api::LiteCertificate>(&request);
1224 }
1225
1226 #[test]
1227 pub fn test_certificate() {
1228 let key_pair = ValidatorKeypair::generate();
1229 let certificate = ValidatedBlockCertificate::new(
1230 ValidatedBlock::new(
1231 BlockExecutionOutcome {
1232 state_hash: CryptoHash::new(&Foo("test".into())),
1233 ..BlockExecutionOutcome::default()
1234 }
1235 .with(get_block()),
1236 ),
1237 Round::MultiLeader(3),
1238 vec![(
1239 key_pair.public_key,
1240 ValidatorSignature::new(&Foo("test".into()), &key_pair.secret_key),
1241 )],
1242 );
1243 let request = HandleValidatedCertificateRequest { certificate };
1244
1245 round_trip_check::<_, api::HandleValidatedCertificateRequest>(&request);
1246 }
1247
1248 #[test]
1249 pub fn test_cross_chain_request() {
1250 let cross_chain_request_update_recipient = CrossChainRequest::UpdateRecipient {
1251 sender: dummy_chain_id(0),
1252 recipient: dummy_chain_id(0),
1253 bundles: vec![],
1254 };
1255 round_trip_check::<_, api::CrossChainRequest>(&cross_chain_request_update_recipient);
1256
1257 let cross_chain_request_confirm_updated_recipient =
1258 CrossChainRequest::ConfirmUpdatedRecipient {
1259 sender: dummy_chain_id(0),
1260 recipient: dummy_chain_id(0),
1261 latest_height: BlockHeight(1),
1262 };
1263 round_trip_check::<_, api::CrossChainRequest>(
1264 &cross_chain_request_confirm_updated_recipient,
1265 );
1266 }
1267
1268 #[test]
1269 pub fn test_block_proposal() {
1270 let key_pair = ValidatorKeypair::generate();
1271 let outcome = BlockExecutionOutcome {
1272 state_hash: CryptoHash::new(&Foo("validated".into())),
1273 ..BlockExecutionOutcome::default()
1274 };
1275 let certificate = ValidatedBlockCertificate::new(
1276 ValidatedBlock::new(outcome.clone().with(get_block())),
1277 Round::SingleLeader(2),
1278 vec![(
1279 key_pair.public_key,
1280 ValidatorSignature::new(&Foo("signed".into()), &key_pair.secret_key),
1281 )],
1282 )
1283 .lite_certificate()
1284 .cloned();
1285 let key_pair = AccountSecretKey::Secp256k1(Secp256k1SecretKey::generate());
1286 let block_proposal = BlockProposal {
1287 content: ProposalContent {
1288 block: get_block(),
1289 round: Round::SingleLeader(4),
1290 outcome: Some(outcome),
1291 },
1292 signature: key_pair.sign(&Foo("test".into())),
1293 original_proposal: Some(OriginalProposal::Regular { certificate }),
1294 };
1295
1296 round_trip_check::<_, api::BlockProposal>(&block_proposal);
1297 }
1298
1299 #[test]
1300 pub fn test_notification() {
1301 let notification = Notification {
1302 chain_id: dummy_chain_id(0),
1303 reason: linera_core::worker::Reason::NewBlock {
1304 height: BlockHeight(0),
1305 hash: CryptoHash::new(&Foo("".into())),
1306 },
1307 };
1308 let message = api::Notification::try_from(notification.clone()).unwrap();
1309 assert_eq!(
1310 Some(notification),
1311 Option::<Notification>::try_from(message).unwrap()
1312 );
1313
1314 let ack = api::Notification::default();
1315 assert_eq!(None, Option::<Notification>::try_from(ack).unwrap());
1316 }
1317}