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