1use std::{borrow::Borrow, collections::HashMap};
4
5use ark_serialize::CanonicalSerialize;
6use espresso_types::{
7 AccountQueryData, BuilderSignature, FeeAccount, FeeAccountProof, FeeInfo, FeeMerkleProof,
8 Header, L1BlockInfo, NamespaceProofQueryData, NsProof, Payload, PubKey, SeqTypes, Transaction,
9 TxProof,
10 config::PublicNetworkConfig,
11 v0_3::{
12 self, AvidMIncorrectEncodingNsProof, AvidMNsProof, RegisteredValidator,
13 ResolvableChainConfig, StakeTableEvent, StateCertQueryDataV1,
14 },
15 v0_4::{
16 RewardAccountProofV2, RewardAccountQueryDataV2, RewardMerkleProofV2, StateCertQueryDataV2,
17 },
18 v0_6::AvidmGf2NsProof,
19};
20use hotshot_contract_adapter::sol_types::{
21 EdOnBN254PointSol, G2PointSol, stake_table_v3::BN254::G1Point as G1PointSol,
22};
23use hotshot_query_service_types::{
24 availability::{
25 BlockQueryData, BlockSummaryQueryData, LeafQueryData, PayloadQueryData,
26 TransactionQueryData, TransactionWithProofQueryData, VidCommonQueryData,
27 },
28 explorer,
29 node::{
30 Limits as NodeLimits, ResourceSyncStatus, SyncStatus, SyncStatusQueryData,
31 TimeWindowQueryData,
32 },
33};
34use hotshot_types::{
35 HotShotConfig, PeerConfig,
36 data::{Leaf2, VidCommon, VidShare, ViewChangeEvidence2},
37 light_client::LCV3StateSignatureRequestBody,
38 network::BuilderType,
39 simple_certificate::{
40 Certificate2, CertificatePair, SimpleCertificate, SuccessThreshold, Threshold,
41 TimeoutCertificate2, TimeoutCertificate3, UpgradeCertificate, ViewSyncFinalizeCertificate2,
42 },
43 simple_vote::{LockView, QuorumData2, Voteable},
44 traits::{EncodeBytes as _, signature_key::SignatureKey},
45 vid::advz::{LargeRangeProofType, SmallRangeProofType},
46};
47use jf_merkle_tree_compat::{
48 Element, Index, NodeValue,
49 prelude::{MerkleNode, MerkleProof},
50};
51use light_client::consensus::{
52 leaf::{FinalityProof, LeafProof},
53 namespace::NamespaceProof,
54 payload::PayloadProof,
55};
56use tagged_base64::TaggedBase64;
57
58use crate::{
59 proto::{
60 self, advz_merkle_node::Node, header_response::Header as Shape,
61 resolvable_chain_config::ChainConfig,
62 },
63 v1::node::StakeTableWithEpochNumber,
64};
65
66impl From<ResolvableChainConfig> for proto::ResolvableChainConfig {
67 fn from(chain_config: ResolvableChainConfig) -> Self {
68 let resolved = match chain_config.resolve() {
70 Some(config) => ChainConfig::Full((&config).into()),
71 None => ChainConfig::Commitment(chain_config.commit().to_string()),
72 };
73 proto::ResolvableChainConfig {
74 chain_config: Some(resolved),
75 }
76 }
77}
78
79impl From<&v0_3::ChainConfig> for proto::ChainConfig {
80 fn from(config: &v0_3::ChainConfig) -> Self {
81 proto::ChainConfig {
82 chain_id: config.chain_id.to_string(),
83 max_block_size: *config.max_block_size,
84 base_fee: config.base_fee.to_string(),
85 fee_contract: config.fee_contract.map(|address| format!("{address:#x}")),
88 fee_recipient: format!("{:#x}", config.fee_recipient.0),
89 stake_table_contract: config
90 .stake_table_contract
91 .map(|address| format!("{address:#x}")),
92 }
93 }
94}
95
96impl From<L1BlockInfo> for proto::L1BlockInfo {
97 fn from(info: L1BlockInfo) -> Self {
98 proto::L1BlockInfo {
99 number: info.number,
100 timestamp: format!("{:#x}", info.timestamp),
101 hash: format!("{:#x}", info.hash),
102 }
103 }
104}
105
106impl From<&FeeInfo> for proto::FeeInfo {
107 fn from(fee: &FeeInfo) -> Self {
108 proto::FeeInfo {
109 account: format!("{:#x}", fee.account.0),
110 amount: fee.amount.to_string(),
111 }
112 }
113}
114
115impl From<&BuilderSignature> for proto::BuilderSignature {
116 fn from(signature: &BuilderSignature) -> Self {
117 proto::BuilderSignature {
118 r: format!("{:#x}", signature.r()),
119 s: format!("{:#x}", signature.s()),
120 v: if signature.v() { 28 } else { 27 },
122 }
123 }
124}
125
126impl From<&Header> for proto::HeaderResponse {
129 fn from(header: &Header) -> Self {
130 let shape = match header {
131 Header::V1(_) => Shape::V1(header.into()),
132 Header::V2(_) => Shape::V2(header.into()),
133 Header::V3(_) => Shape::V3(header.into()),
134 Header::V4(_) => Shape::V4(header_v4(header)),
135 Header::V5(_) => Shape::V5(header_v5(header)),
136 Header::V6(_) => Shape::V6(header_v5(header)),
137 Header::V7(_) => Shape::V7(header_v5(header)),
138 };
139 proto::HeaderResponse {
140 header: Some(shape),
141 }
142 }
143}
144
145fn builder_commitment(header: &Header) -> String {
147 header
148 .builder_commitment()
149 .map(ToString::to_string)
150 .unwrap_or_default()
151}
152
153impl From<&Header> for proto::HeaderV1 {
154 fn from(header: &Header) -> Self {
155 proto::HeaderV1 {
156 chain_config: Some(header.chain_config().into()),
157 height: header.height(),
158 timestamp: header.timestamp_internal(),
159 l1_head: header.l1_head(),
160 l1_finalized: header.l1_finalized().map(Into::into),
161 payload_commitment: header.payload_commitment().to_string(),
162 builder_commitment: builder_commitment(header),
163 ns_table: Some(proto::NsTable {
164 bytes: header.ns_table().encode().to_vec(),
165 }),
166 block_merkle_tree_root: header.block_merkle_tree_root().to_string(),
167 fee_merkle_tree_root: header.fee_merkle_tree_root().to_string(),
168 fee_info: header.fee_info().first().map(Into::into),
169 builder_signature: header.builder_signature().first().map(Into::into),
171 }
172 }
173}
174
175impl From<&Header> for proto::HeaderV3 {
176 fn from(header: &Header) -> Self {
177 proto::HeaderV3 {
178 chain_config: Some(header.chain_config().into()),
179 height: header.height(),
180 timestamp: header.timestamp_internal(),
181 l1_head: header.l1_head(),
182 l1_finalized: header.l1_finalized().map(Into::into),
183 payload_commitment: header.payload_commitment().to_string(),
184 builder_commitment: builder_commitment(header),
185 ns_table: Some(proto::NsTable {
186 bytes: header.ns_table().encode().to_vec(),
187 }),
188 block_merkle_tree_root: header.block_merkle_tree_root().to_string(),
189 fee_merkle_tree_root: header.fee_merkle_tree_root().to_string(),
190 fee_info: header.fee_info().first().map(Into::into),
191 builder_signature: header.builder_signature().first().map(Into::into),
192 reward_merkle_tree_root: reward_merkle_tree_root(header),
193 }
194 }
195}
196
197fn header_v4(header: &Header) -> proto::HeaderV4 {
201 proto::HeaderV4 {
202 chain_config: Some(header.chain_config().into()),
203 height: header.height(),
204 timestamp: header.timestamp_internal(),
205 timestamp_millis: header.timestamp_millis_internal(),
206 l1_head: header.l1_head(),
207 l1_finalized: header.l1_finalized().map(Into::into),
208 payload_commitment: header.payload_commitment().to_string(),
209 builder_commitment: builder_commitment(header),
210 ns_table: Some(proto::NsTable {
211 bytes: header.ns_table().encode().to_vec(),
212 }),
213 block_merkle_tree_root: header.block_merkle_tree_root().to_string(),
214 fee_merkle_tree_root: header.fee_merkle_tree_root().to_string(),
215 fee_info: header.fee_info().first().map(Into::into),
216 builder_signature: header.builder_signature().first().map(Into::into),
217 reward_merkle_tree_root: reward_merkle_tree_root(header),
218 total_reward_distributed: header
219 .total_reward_distributed()
220 .expect("0.4 and later headers carry total_reward_distributed")
221 .to_string(),
222 next_stake_table_hash: header.next_stake_table_hash().map(|hash| hash.to_string()),
223 }
224}
225
226fn header_v5(header: &Header) -> proto::HeaderV5 {
228 proto::HeaderV5 {
229 chain_config: Some(header.chain_config().into()),
230 height: header.height(),
231 timestamp: header.timestamp_internal(),
232 timestamp_millis: header.timestamp_millis_internal(),
233 l1_head: header.l1_head(),
234 l1_finalized: header.l1_finalized().map(Into::into),
235 payload_commitment: header.payload_commitment().to_string(),
236 builder_commitment: builder_commitment(header),
237 ns_table: Some(proto::NsTable {
238 bytes: header.ns_table().encode().to_vec(),
239 }),
240 block_merkle_tree_root: header.block_merkle_tree_root().to_string(),
241 fee_merkle_tree_root: header.fee_merkle_tree_root().to_string(),
242 fee_info: header.fee_info().first().map(Into::into),
243 builder_signature: header.builder_signature().first().map(Into::into),
244 reward_merkle_tree_root: reward_merkle_tree_root(header),
245 total_reward_distributed: header
246 .total_reward_distributed()
247 .expect("0.4 and later headers carry total_reward_distributed")
248 .to_string(),
249 next_stake_table_hash: header.next_stake_table_hash().map(|hash| hash.to_string()),
250 leader_counts: header
251 .leader_counts()
252 .expect("0.5 and later headers carry leader_counts")
253 .iter()
254 .map(|count| *count as u32)
255 .collect(),
256 }
257}
258
259fn reward_merkle_tree_root(header: &Header) -> String {
262 match header.reward_merkle_tree_root() {
263 either::Either::Left(root) => root.to_string(),
264 either::Either::Right(root) => root.to_string(),
265 }
266}
267
268impl From<ResourceSyncStatus> for proto::ResourceSyncStatus {
269 fn from(status: ResourceSyncStatus) -> Self {
270 proto::ResourceSyncStatus {
271 missing: status.missing as u64,
272 ranges: status
273 .ranges
274 .into_iter()
275 .map(|range| proto::SyncStatusRange {
276 start: range.start as u64,
277 end: range.end as u64,
278 status: match range.status {
279 SyncStatus::Present => proto::SyncStatus::Present,
280 SyncStatus::Missing => proto::SyncStatus::Missing,
281 SyncStatus::Pruned => proto::SyncStatus::Pruned,
282 }
283 .into(),
284 })
285 .collect(),
286 }
287 }
288}
289
290impl From<SyncStatusQueryData> for proto::SyncStatusResponse {
291 fn from(status: SyncStatusQueryData) -> Self {
292 proto::SyncStatusResponse {
293 blocks: Some(status.blocks.into()),
294 leaves: Some(status.leaves.into()),
295 vid_common: Some(status.vid_common.into()),
296 pruned_height: status.pruned_height.map(|height| height as u64),
297 }
298 }
299}
300
301impl From<&TimeWindowQueryData<Header>> for proto::HeaderWindowResponse {
302 fn from(window: &TimeWindowQueryData<Header>) -> Self {
303 proto::HeaderWindowResponse {
304 window: window.window.iter().map(Into::into).collect(),
305 prev: window.prev.as_ref().map(Into::into),
306 next: window.next.as_ref().map(Into::into),
307 }
308 }
309}
310
311impl From<NodeLimits> for proto::NodeLimitsResponse {
312 fn from(limits: NodeLimits) -> Self {
313 proto::NodeLimitsResponse {
314 window_limit: limits.window_limit as u64,
315 }
316 }
317}
318
319impl From<PeerConfig<SeqTypes>> for proto::PeerConfig {
320 fn from(peer: PeerConfig<SeqTypes>) -> Self {
321 proto::PeerConfig {
322 stake_table_entry: Some(proto::StakeTableEntry {
323 stake_key: Some(proto::BlsPublicKey {
324 key: peer.stake_table_entry.stake_key.to_string(),
325 }),
326 stake_amount: format!("{:#x}", peer.stake_table_entry.stake_amount),
327 }),
328 state_ver_key: Some(proto::SchnorrPublicKey {
329 key: peer.state_ver_key.to_string(),
330 }),
331 connect_info: peer.connect_info.map(|info| proto::PeerConnectInfo {
332 p2p_addr: info.p2p_addr.unbracketed_string(),
333 x25519_key: info.x25519_key.to_string(),
334 }),
335 }
336 }
337}
338
339impl From<StakeTableWithEpochNumber<SeqTypes>> for proto::StakeTableResponse {
340 fn from(table: StakeTableWithEpochNumber<SeqTypes>) -> Self {
341 Self {
342 epoch: table.epoch.map(|epoch| *epoch),
343 stake_table: table.stake_table.into_iter().map(Into::into).collect(),
344 }
345 }
346}
347
348impl From<RegisteredValidator<PubKey>> for proto::Validator {
349 fn from(registered: RegisteredValidator<PubKey>) -> Self {
350 let mut delegators: Vec<_> = registered
351 .delegators
352 .into_iter()
353 .map(|(account, amount)| proto::Delegator {
354 account: format!("{account:#x}"),
355 amount: format!("{amount:#x}"),
356 })
357 .collect();
358 delegators.sort_by(|a, b| a.account.cmp(&b.account));
360
361 proto::Validator {
362 account: format!("{:#x}", registered.account),
363 stake_table_key: registered.stake_table_key.map(|key| proto::BlsPublicKey {
364 key: key.to_string(),
365 }),
366 state_ver_key: registered.state_ver_key.map(|key| proto::SchnorrPublicKey {
367 key: key.to_string(),
368 }),
369 stake: format!("{:#x}", registered.stake),
370 commission: registered.commission.into(),
371 delegators,
372 authenticated: registered.authenticated,
373 x25519_key: registered.x25519_key.as_ref().map(ToString::to_string),
374 p2p_addr: registered
375 .p2p_addr
376 .as_ref()
377 .map(|addr| addr.unbracketed_string()),
378 }
379 }
380}
381
382impl From<HashMap<PubKey, f64>> for proto::ParticipationResponse {
383 fn from(fractions: HashMap<PubKey, f64>) -> Self {
384 let mut entries: Vec<(String, f64)> = fractions
385 .into_iter()
386 .map(|(key, participation)| (key.to_string(), participation))
387 .collect();
388 entries.sort_by(|a, b| a.0.cmp(&b.0));
390 proto::ParticipationResponse {
391 participation: entries
392 .into_iter()
393 .map(|(key, participation)| proto::ParticipationEntry {
394 key: Some(proto::BlsPublicKey { key }),
395 participation,
396 })
397 .collect(),
398 }
399 }
400}
401
402impl TryFrom<&VidShare> for proto::VidShareResponse {
407 type Error = tonic::Status;
408
409 fn try_from(share: &VidShare) -> Result<Self, Self::Error> {
410 let arm = match share {
413 VidShare::V0(_) => {
414 let json = to_json(share)?;
415 let share = json_entry(&json, "V0")?;
416 let evals_proof = json_entry(share, "evals_proof")?;
417 proto::vid_share_response::Share::V0(proto::AdvzVidShare {
418 index: json_field(share, "index")?,
419 aggregate_proofs: json_field(share, "aggregate_proofs")?,
420 evals: json_field(share, "evals")?,
421 evals_proof: Some(proto::AdvzMerkleProof {
422 pos: json_field(evals_proof, "pos")?,
423 proof: json_array(evals_proof, "proof")?
424 .iter()
425 .map(advz_merkle_node)
426 .collect::<Result<_, _>>()?,
427 }),
428 })
429 },
430 VidShare::V1(_) => {
431 let json = to_json(share)?;
432 let share = json_entry(&json, "V1")?;
433 proto::vid_share_response::Share::V1(proto::AvidmVidShare {
434 index: json_field(share, "index")?,
435 ns_commits: json_field(share, "ns_commits")?,
436 ns_lens: json_field(share, "ns_lens")?,
437 content: json_array(share, "content")?
438 .iter()
439 .map(|content| {
440 let range = json_entry(content, "range")?;
441 Ok(proto::AvidmShareContent {
442 range: Some(proto::ShardRange {
443 start: json_field(range, "start")?,
444 end: json_field(range, "end")?,
445 }),
446 payload: json_field(content, "payload")?,
447 mt_proofs: json_field(content, "mt_proofs")?,
448 })
449 })
450 .collect::<Result<_, tonic::Status>>()?,
451 })
452 },
453 VidShare::V2(gf2) => proto::vid_share_response::Share::V2(proto::AvidmGf2VidShare {
454 namespaces: gf2
455 .ns_shares()
456 .iter()
457 .map(|namespace| proto::AvidmGf2Namespace {
458 range: Some(proto::ShardRange {
459 start: namespace.range().start as u64,
460 end: namespace.range().end as u64,
461 }),
462 payload: namespace.payload().to_vec(),
463 mt_proofs: namespace
464 .mt_proofs()
465 .iter()
466 .map(ToString::to_string)
467 .collect(),
468 })
469 .collect(),
470 }),
471 };
472 Ok(proto::VidShareResponse { share: Some(arm) })
473 }
474}
475
476fn advz_merkle_node(value: &serde_json::Value) -> Result<proto::AdvzMerkleNode, tonic::Status> {
477 let node = if let Some(leaf) = value.get("Leaf") {
478 Node::Leaf(proto::AdvzMerkleNodeLeaf {
479 elem: json_field(leaf, "elem")?,
480 pos: json_field(leaf, "pos")?,
481 value: json_field(leaf, "value")?,
482 })
483 } else if let Some(branch) = value.get("Branch") {
484 Node::Branch(proto::AdvzMerkleNodeBranch {
485 children: json_array(branch, "children")?
486 .iter()
487 .map(advz_merkle_node)
488 .collect::<Result<_, _>>()?,
489 value: json_field(branch, "value")?,
490 })
491 } else if let Some(subtree) = value.get("ForgettenSubtree") {
492 Node::ForgottenSubtree(proto::AdvzMerkleNodeForgottenSubtree {
494 value: json_field(subtree, "value")?,
495 })
496 } else if value.as_str() == Some("Empty") {
497 Node::Empty(proto::AdvzMerkleNodeEmpty {})
499 } else {
500 let arms: Vec<&str> = value
501 .as_object()
502 .map(|node| node.keys().map(String::as_str).collect())
503 .unwrap_or_default();
504 return Err(tonic::Status::internal(format!(
505 "VID share JSON has an unknown Merkle node arm: {arms:?}"
506 )));
507 };
508 Ok(proto::AdvzMerkleNode { node: Some(node) })
509}
510
511impl From<&[Header]> for proto::HeaderRangeResponse {
512 fn from(headers: &[Header]) -> Self {
513 proto::HeaderRangeResponse {
514 headers: headers.iter().map(Into::into).collect(),
515 }
516 }
517}
518
519impl From<&[LeafQueryData<SeqTypes>]> for proto::LeafRangeResponse {
520 fn from(leaves: &[LeafQueryData<SeqTypes>]) -> Self {
521 proto::LeafRangeResponse {
522 leaves: leaves.iter().map(Into::into).collect(),
523 }
524 }
525}
526
527impl From<&[BlockQueryData<SeqTypes>]> for proto::BlockRangeResponse {
528 fn from(blocks: &[BlockQueryData<SeqTypes>]) -> Self {
529 proto::BlockRangeResponse {
530 blocks: blocks.iter().map(Into::into).collect(),
531 }
532 }
533}
534
535impl From<&[PayloadQueryData<SeqTypes>]> for proto::PayloadRangeResponse {
536 fn from(payloads: &[PayloadQueryData<SeqTypes>]) -> Self {
537 proto::PayloadRangeResponse {
538 payloads: payloads.iter().map(Into::into).collect(),
539 }
540 }
541}
542
543impl TryFrom<&[VidCommonQueryData<SeqTypes>]> for proto::VidCommonRangeResponse {
544 type Error = tonic::Status;
545
546 fn try_from(items: &[VidCommonQueryData<SeqTypes>]) -> Result<Self, Self::Error> {
547 Ok(proto::VidCommonRangeResponse {
548 vid_common: items
549 .iter()
550 .map(TryInto::try_into)
551 .collect::<Result<_, _>>()?,
552 })
553 }
554}
555
556impl From<&[BlockSummaryQueryData<SeqTypes>]> for proto::BlockSummaryRangeResponse {
557 fn from(summaries: &[BlockSummaryQueryData<SeqTypes>]) -> Self {
558 proto::BlockSummaryRangeResponse {
559 summaries: summaries.iter().map(Into::into).collect(),
560 }
561 }
562}
563
564impl From<&[Leaf2<SeqTypes>]> for proto::CatchupLeafChainResponse {
565 fn from(leaves: &[Leaf2<SeqTypes>]) -> Self {
566 proto::CatchupLeafChainResponse {
567 leaves: leaves.iter().map(Into::into).collect(),
568 }
569 }
570}
571
572impl TryFrom<&[NamespaceProofQueryData]> for proto::NamespaceProofRangeResponse {
573 type Error = tonic::Status;
574
575 fn try_from(proofs: &[NamespaceProofQueryData]) -> Result<Self, Self::Error> {
576 Ok(proto::NamespaceProofRangeResponse {
577 proofs: proofs
578 .iter()
579 .map(TryInto::try_into)
580 .collect::<Result<_, _>>()?,
581 })
582 }
583}
584
585impl<E, I, T, const ARITY: usize> From<&MerkleProof<E, I, T, ARITY>> for proto::MerklePathResponse
586where
587 E: Element + CanonicalSerialize,
588 I: Index + CanonicalSerialize,
589 T: NodeValue,
590{
591 fn from(proof: &MerkleProof<E, I, T, ARITY>) -> Self {
592 proto::MerklePathResponse {
593 pos: field_tb64(&proof.pos),
594 proof: proof.proof.iter().map(Into::into).collect(),
595 }
596 }
597}
598
599impl<E, I, T> From<&MerkleNode<E, I, T>> for proto::AdvzMerkleNode
600where
601 E: Element + CanonicalSerialize,
602 I: Index + CanonicalSerialize,
603 T: NodeValue,
604{
605 fn from(node: &MerkleNode<E, I, T>) -> Self {
606 let node = match node {
607 MerkleNode::Empty => Node::Empty(proto::AdvzMerkleNodeEmpty {}),
608 MerkleNode::Branch { value, children } => Node::Branch(proto::AdvzMerkleNodeBranch {
609 value: field_tb64(value),
610 children: children
611 .iter()
612 .map(|child| proto::AdvzMerkleNode::from(&**child))
613 .collect(),
614 }),
615 MerkleNode::Leaf { value, pos, elem } => Node::Leaf(proto::AdvzMerkleNodeLeaf {
616 value: field_tb64(value),
617 pos: field_tb64(pos),
618 elem: field_tb64(elem),
619 }),
620 MerkleNode::ForgettenSubtree { value } => {
621 Node::ForgottenSubtree(proto::AdvzMerkleNodeForgottenSubtree {
622 value: field_tb64(value),
623 })
624 },
625 };
626 proto::AdvzMerkleNode { node: Some(node) }
627 }
628}
629
630impl From<RewardAccountQueryDataV2> for proto::RewardAccountProofResponse {
631 fn from(query: RewardAccountQueryDataV2) -> proto::RewardAccountProofResponse {
632 let RewardAccountQueryDataV2 {
633 balance,
634 proof: RewardAccountProofV2 { account, proof },
635 } = query;
636 let proof = match proof {
637 RewardMerkleProofV2::Presence(proof) => {
638 proto::reward_merkle_proof::Proof::Presence(proto::MerklePathResponse::from(&proof))
639 },
640 RewardMerkleProofV2::Absence(proof) => {
641 proto::reward_merkle_proof::Proof::Absence(proto::MerklePathResponse::from(&proof))
642 },
643 };
644 proto::RewardAccountProofResponse {
645 balance: balance.to_string(),
646 proof: Some(proto::RewardAccountProof {
647 account: format!("{account:#x}"),
648 proof: Some(proto::RewardMerkleProof { proof: Some(proof) }),
649 }),
650 }
651 }
652}
653
654impl From<v0_3::RewardAccountQueryDataV1> for proto::RewardAccountProofResponse {
657 fn from(query: v0_3::RewardAccountQueryDataV1) -> proto::RewardAccountProofResponse {
658 let v0_3::RewardAccountQueryDataV1 {
659 balance,
660 proof: v0_3::RewardAccountProofV1 { account, proof },
661 } = query;
662 let proof = match proof {
663 v0_3::RewardMerkleProofV1::Presence(proof) => {
664 proto::reward_merkle_proof::Proof::Presence(proto::MerklePathResponse::from(&proof))
665 },
666 v0_3::RewardMerkleProofV1::Absence(proof) => {
667 proto::reward_merkle_proof::Proof::Absence(proto::MerklePathResponse::from(&proof))
668 },
669 };
670 proto::RewardAccountProofResponse {
671 balance: balance.to_string(),
672 proof: Some(proto::RewardAccountProof {
673 account: format!("{account:#x}"),
674 proof: Some(proto::RewardMerkleProof { proof: Some(proof) }),
675 }),
676 }
677 }
678}
679
680impl From<AccountQueryData> for proto::FeeAccountProofResponse {
681 fn from(query: AccountQueryData) -> Self {
682 let AccountQueryData {
683 balance,
684 proof: FeeAccountProof { account, proof },
685 } = query;
686 let proof = match proof {
687 FeeMerkleProof::Presence(proof) => {
688 proto::fee_merkle_proof::Proof::Presence(proto::MerklePathResponse::from(&proof))
689 },
690 FeeMerkleProof::Absence(proof) => {
691 proto::fee_merkle_proof::Proof::Absence(proto::MerklePathResponse::from(&proof))
692 },
693 };
694 proto::FeeAccountProofResponse {
695 balance: balance.to_string(),
696 proof: Some(proto::FeeAccountProof {
697 account: format!("{account:#x}"),
698 proof: Some(proto::FeeMerkleProof { proof: Some(proof) }),
699 }),
700 }
701 }
702}
703
704fn field_tb64<T>(value: &T) -> String
708where
709 T: CanonicalSerialize,
710{
711 let mut bytes = Vec::new();
712 value
713 .serialize_compressed(&mut bytes)
714 .expect("serializing to a Vec cannot fail");
715 TaggedBase64::new("FIELD", &bytes)
716 .expect("FIELD is a valid tag")
717 .to_string()
718}
719
720fn to_json(value: &impl serde::Serialize) -> Result<serde_json::Value, tonic::Status> {
723 serde_json::to_value(value)
724 .map_err(|err| tonic::Status::internal(format!("v1 encoding failed: {err}")))
725}
726
727fn json_field<T>(value: &serde_json::Value, field: &str) -> Result<T, tonic::Status>
730where
731 T: serde::de::DeserializeOwned,
732{
733 T::deserialize(json_entry(value, field)?)
734 .map_err(|err| tonic::Status::internal(format!("v1 JSON {field}: {err}")))
735}
736
737fn json_entry<'a>(
738 value: &'a serde_json::Value,
739 field: &str,
740) -> Result<&'a serde_json::Value, tonic::Status> {
741 value
742 .get(field)
743 .ok_or_else(|| tonic::Status::internal(format!("v1 JSON has no {field}")))
744}
745
746fn json_array<'a>(
747 value: &'a serde_json::Value,
748 field: &str,
749) -> Result<&'a [serde_json::Value], tonic::Status> {
750 json_entry(value, field)?
751 .as_array()
752 .map(Vec::as_slice)
753 .ok_or_else(|| tonic::Status::internal(format!("v1 JSON {field}: not an array")))
754}
755
756impl From<PublicNetworkConfig> for proto::HotshotConfigResponse {
760 fn from(public_config: PublicNetworkConfig) -> Self {
761 let config = public_config.hotshot_config().into_hotshot_config();
762 let HotShotConfig {
765 start_threshold: (start_threshold_numerator, start_threshold_denominator),
766 num_nodes_with_stake,
767 known_nodes_with_stake,
768 known_da_nodes,
769 da_committees,
770 da_staked_committee_size,
771 fixed_leader_for_gpuvid,
772 next_view_timeout,
773 view_sync_timeout,
774 num_bootstrap,
775 builder_timeout,
776 data_request_delay,
777 builder_urls,
778 start_proposing_view,
779 stop_proposing_view,
780 start_voting_view,
781 stop_voting_view,
782 start_proposing_time,
783 stop_proposing_time,
784 start_voting_time,
785 stop_voting_time,
786 epoch_height,
787 epoch_start_block,
788 stake_table_capacity,
789 drb_difficulty,
790 drb_upgrade_difficulty,
791 } = config;
792 proto::HotshotConfigResponse {
793 start_threshold_numerator,
794 start_threshold_denominator,
795 num_nodes_with_stake: num_nodes_with_stake.get() as u64,
796 da_staked_committee_size: da_staked_committee_size as u64,
797 next_view_timeout_ms: next_view_timeout,
798 view_sync_timeout_ms: view_sync_timeout.as_millis() as u64,
799 builder_timeout_ms: builder_timeout.as_millis() as u64,
800 data_request_delay_ms: data_request_delay.as_millis() as u64,
801 builder_urls: builder_urls.iter().map(ToString::to_string).collect(),
802 start_proposing_view,
803 stop_proposing_view,
804 start_voting_view,
805 stop_voting_view,
806 start_proposing_time,
807 stop_proposing_time,
808 start_voting_time,
809 stop_voting_time,
810 epoch_height,
811 epoch_start_block,
812 stake_table_capacity: stake_table_capacity as u64,
813 drb_difficulty,
814 drb_upgrade_difficulty,
815 known_nodes_with_stake: known_nodes_with_stake.into_iter().map(Into::into).collect(),
816 known_da_nodes: known_da_nodes.into_iter().map(Into::into).collect(),
817 da_committees: da_committees
818 .into_iter()
819 .map(|da_committee| proto::VersionedDaCommittee {
820 start_version: da_committee.start_version.to_string(),
821 start_epoch: da_committee.start_epoch,
822 committee: da_committee.committee.into_iter().map(Into::into).collect(),
823 })
824 .collect(),
825 fixed_leader_for_gpuvid: fixed_leader_for_gpuvid as u64,
826 num_bootstrap: num_bootstrap as u64,
827 commit_sha: public_config.commit_sha().to_string(),
828 indexed_da: public_config.indexed_da(),
829 builder: match public_config.builder() {
830 BuilderType::External => proto::BuilderType::External,
831 BuilderType::Simple => proto::BuilderType::Simple,
832 BuilderType::Random => proto::BuilderType::Random,
833 }
834 .into(),
835 ..Default::default()
837 }
838 }
839}
840
841fn quorum_signatures<V, T>(
842 cert: &SimpleCertificate<SeqTypes, V, T>,
843) -> Option<proto::QuorumSignatures>
844where
845 V: Voteable<SeqTypes>,
846 T: Threshold<SeqTypes>,
847{
848 cert.signatures.as_ref().map(qc_signatures)
849}
850
851fn qc_signatures(
853 (signature, signers): &<PubKey as SignatureKey>::QcType,
854) -> proto::QuorumSignatures {
855 proto::QuorumSignatures {
857 signature: signature.to_string(),
858 signers: signers.iter().by_vals().collect(),
859 }
860}
861
862impl From<&QuorumData2<SeqTypes>> for proto::QuorumData2 {
863 fn from(data: &QuorumData2<SeqTypes>) -> Self {
864 proto::QuorumData2 {
865 leaf_commit: data.leaf_commit.to_string(),
866 epoch: data.epoch.map(|epoch| epoch.u64()),
867 block_number: data.block_number,
868 }
869 }
870}
871
872impl<V> From<&SimpleCertificate<SeqTypes, V, SuccessThreshold>> for proto::QuorumCertificate2
874where
875 V: Voteable<SeqTypes> + Borrow<QuorumData2<SeqTypes>>,
876{
877 fn from(cert: &SimpleCertificate<SeqTypes, V, SuccessThreshold>) -> Self {
878 proto::QuorumCertificate2 {
879 data: Some(cert.data.borrow().into()),
880 vote_commitment: cert.vote_commitment().to_string(),
881 view_number: cert.view_number.u64(),
882 signatures: quorum_signatures(cert),
883 }
884 }
885}
886
887impl From<&CertificatePair<SeqTypes>> for proto::CertificatePair {
888 fn from(pair: &CertificatePair<SeqTypes>) -> Self {
889 proto::CertificatePair {
890 qc: Some(pair.qc().into()),
891 next_epoch_qc: pair.next_epoch_qc().map(Into::into),
892 }
893 }
894}
895
896impl From<&Certificate2<SeqTypes>> for proto::Certificate2 {
897 fn from(cert: &Certificate2<SeqTypes>) -> Self {
898 proto::Certificate2 {
899 data: Some(proto::Vote2Data {
900 leaf_commit: cert.data.leaf_commit.to_string(),
901 epoch: cert.data.epoch.u64(),
902 block_number: cert.data.block_number,
903 }),
904 vote_commitment: cert.vote_commitment().to_string(),
905 view_number: cert.view_number.u64(),
906 signatures: quorum_signatures(cert),
907 }
908 }
909}
910
911impl From<vbs::version::Version> for proto::ProtocolVersion {
912 fn from(version: vbs::version::Version) -> Self {
913 proto::ProtocolVersion {
914 major: u32::from(version.major),
915 minor: u32::from(version.minor),
916 }
917 }
918}
919
920impl From<&UpgradeCertificate<SeqTypes>> for proto::UpgradeCertificate {
921 fn from(cert: &UpgradeCertificate<SeqTypes>) -> Self {
922 proto::UpgradeCertificate {
923 data: Some(proto::UpgradeProposalData {
924 old_version: Some(cert.data.old_version.into()),
925 new_version: Some(cert.data.new_version.into()),
926 decide_by: cert.data.decide_by.u64(),
927 new_version_hash: cert.data.new_version_hash.clone(),
928 old_version_last_view: cert.data.old_version_last_view.u64(),
929 new_version_first_view: cert.data.new_version_first_view.u64(),
930 }),
931 vote_commitment: cert.vote_commitment().to_string(),
932 view_number: cert.view_number.u64(),
933 signatures: quorum_signatures(cert),
934 }
935 }
936}
937
938impl From<&ViewChangeEvidence2<SeqTypes>> for proto::ViewChangeEvidence2 {
939 fn from(evidence: &ViewChangeEvidence2<SeqTypes>) -> Self {
940 use proto::view_change_evidence2::Evidence;
941
942 let evidence = match evidence {
943 ViewChangeEvidence2::Timeout(cert) => Evidence::Timeout(cert.into()),
944 ViewChangeEvidence2::Timeout3(cert) => Evidence::Timeout3(cert.into()),
945 ViewChangeEvidence2::ViewSync(cert) => Evidence::ViewSync(cert.into()),
946 };
947 proto::ViewChangeEvidence2 {
948 evidence: Some(evidence),
949 }
950 }
951}
952
953impl From<&TimeoutCertificate2<SeqTypes>> for proto::TimeoutCertificate2 {
954 fn from(cert: &TimeoutCertificate2<SeqTypes>) -> Self {
955 proto::TimeoutCertificate2 {
956 data: Some(proto::TimeoutData2 {
957 view: cert.data.view.u64(),
958 epoch: cert.data.epoch.map(|epoch| epoch.u64()),
959 }),
960 vote_commitment: cert.vote_commitment().to_string(),
961 view_number: cert.view_number.u64(),
962 signatures: quorum_signatures(cert),
963 }
964 }
965}
966
967impl From<&TimeoutCertificate3<SeqTypes>> for proto::TimeoutCertificate3 {
968 fn from(cert: &TimeoutCertificate3<SeqTypes>) -> Self {
969 let lock_view = |lock: &LockView| proto::LockView {
970 epoch: lock.epoch.u64(),
971 view: lock.view.u64(),
972 };
973 proto::TimeoutCertificate3 {
974 view_number: cert.view_number.u64(),
975 epoch: cert.epoch.u64(),
976 lock_cert: cert.lock_cert().map(Into::into),
977 signatures: Some(qc_signatures(&cert.latest.signatures)),
978 earlier: cert
979 .earlier
980 .iter()
981 .map(|group| proto::TimeoutSignatures {
982 lock: group.lock.as_ref().map(lock_view),
983 signatures: Some(qc_signatures(&group.signatures)),
984 })
985 .collect(),
986 }
987 }
988}
989
990impl From<&ViewSyncFinalizeCertificate2<SeqTypes>> for proto::ViewSyncFinalizeCertificate2 {
991 fn from(cert: &ViewSyncFinalizeCertificate2<SeqTypes>) -> Self {
992 proto::ViewSyncFinalizeCertificate2 {
993 data: Some(proto::ViewSyncFinalizeData2 {
994 relay: cert.data.relay,
995 round: cert.data.round.u64(),
996 epoch: cert.data.epoch.map(|epoch| epoch.u64()),
997 }),
998 vote_commitment: cert.vote_commitment().to_string(),
999 view_number: cert.view_number.u64(),
1000 signatures: quorum_signatures(cert),
1001 }
1002 }
1003}
1004
1005impl From<&Payload> for proto::Payload {
1006 fn from(payload: &Payload) -> Self {
1007 proto::Payload {
1008 raw_payload: payload.raw_payload().to_vec(),
1009 ns_table: Some(proto::NsTable {
1010 bytes: payload.ns_table().encode().to_vec(),
1011 }),
1012 }
1013 }
1014}
1015
1016impl From<&Leaf2<SeqTypes>> for proto::Leaf2 {
1017 fn from(leaf: &Leaf2<SeqTypes>) -> Self {
1018 proto::Leaf2 {
1019 view_number: leaf.view_number().u64(),
1020 justify_qc: Some(leaf.justify_qc().into()),
1021 next_epoch_justify_qc: leaf.next_epoch_justify_qc().map(Into::into),
1022 parent_commitment: leaf.parent_commitment().to_string(),
1023 block_header: Some(leaf.block_header().into()),
1024 upgrade_certificate: leaf.upgrade_certificate().map(Into::into),
1025 block_payload: leaf.block_payload_ref().map(Into::into),
1026 view_change_evidence: leaf.view_change_evidence.as_ref().map(Into::into),
1027 next_drb_result: leaf
1028 .next_drb_result
1029 .map(|result| result.to_vec())
1030 .unwrap_or_default(),
1031 with_epoch: leaf.with_epoch,
1032 }
1033 }
1034}
1035
1036impl From<&LeafQueryData<SeqTypes>> for proto::LeafResponse {
1037 fn from(leaf: &LeafQueryData<SeqTypes>) -> Self {
1038 proto::LeafResponse {
1039 leaf: Some(leaf.leaf().into()),
1040 qc: Some(leaf.qc().into()),
1041 }
1042 }
1043}
1044
1045impl From<&BlockQueryData<SeqTypes>> for proto::BlockResponse {
1046 fn from(block: &BlockQueryData<SeqTypes>) -> Self {
1047 proto::BlockResponse {
1048 header: Some(block.header().into()),
1049 payload: Some(block.payload().into()),
1050 hash: block.hash().to_string(),
1051 size: block.size(),
1052 num_transactions: block.num_transactions(),
1053 }
1054 }
1055}
1056
1057impl From<&PayloadQueryData<SeqTypes>> for proto::PayloadResponse {
1058 fn from(payload: &PayloadQueryData<SeqTypes>) -> Self {
1059 proto::PayloadResponse {
1060 height: payload.height,
1061 block_hash: payload.block_hash().to_string(),
1062 hash: payload.hash().to_string(),
1063 size: payload.size(),
1064 data: Some(payload.data().into()),
1065 }
1066 }
1067}
1068
1069impl TryFrom<&VidCommonQueryData<SeqTypes>> for proto::VidCommonResponse {
1070 type Error = tonic::Status;
1071
1072 fn try_from(common: &VidCommonQueryData<SeqTypes>) -> Result<Self, Self::Error> {
1073 Ok(proto::VidCommonResponse {
1074 height: common.height,
1075 block_hash: common.block_hash().to_string(),
1076 payload_hash: common.payload_hash().to_string(),
1077 common: Some(common.common().try_into()?),
1078 })
1079 }
1080}
1081
1082impl TryFrom<&VidCommon> for proto::vid_common::Common {
1083 type Error = tonic::Status;
1084
1085 fn try_from(common: &VidCommon) -> Result<Self, Self::Error> {
1086 use proto::vid_common::Common;
1087
1088 Ok(match common {
1089 VidCommon::V0(advz) => {
1090 let value = to_json(advz)?;
1091 Common::V0(proto::AdvzCommon {
1092 poly_commits: json_field(&value, "poly_commits")?,
1093 all_evals_digest: json_field(&value, "all_evals_digest")?,
1094 payload_byte_len: json_field(&value, "payload_byte_len")?,
1095 num_storage_nodes: json_field(&value, "num_storage_nodes")?,
1096 multiplicity: json_field(&value, "multiplicity")?,
1097 })
1098 },
1099 VidCommon::V1(param) => Common::V1(proto::AvidmCommon {
1100 total_weights: param.total_weights as u64,
1101 recovery_threshold: param.recovery_threshold as u64,
1102 }),
1103 VidCommon::V2(namespaced) => Common::V2(proto::AvidmGf2Common {
1104 param: Some(proto::AvidmGf2Param {
1105 total_weights: namespaced.param.total_weights as u64,
1106 recovery_threshold: namespaced.param.recovery_threshold as u64,
1107 }),
1108 ns_commits: namespaced
1109 .ns_commits
1110 .iter()
1111 .map(ToString::to_string)
1112 .collect(),
1113 ns_lens: namespaced.ns_lens.iter().map(|len| *len as u64).collect(),
1114 }),
1115 })
1116 }
1117}
1118
1119impl TryFrom<&VidCommon> for proto::VidCommon {
1120 type Error = tonic::Status;
1121
1122 fn try_from(common: &VidCommon) -> Result<Self, Self::Error> {
1123 Ok(proto::VidCommon {
1124 common: Some(common.try_into()?),
1125 })
1126 }
1127}
1128
1129impl From<&LeafProof> for proto::LightClientLeafProofResponse {
1130 fn from(proof: &LeafProof) -> Self {
1131 proto::LightClientLeafProofResponse {
1132 leaves: proof.leaves().iter().map(Into::into).collect(),
1133 proof: Some(proof.proof().into()),
1134 }
1135 }
1136}
1137
1138impl From<&FinalityProof> for proto::FinalityProof {
1139 fn from(proof: &FinalityProof) -> Self {
1140 use proto::finality_proof::Proof;
1141
1142 let arm = match proof {
1143 FinalityProof::Assumption => Proof::Assumption(proto::FinalityAssumption {}),
1144 FinalityProof::HotStuff2 {
1145 committing_qc,
1146 deciding_qc,
1147 } => Proof::HotStuff2(proto::HotStuff2Finality {
1148 committing_qc: Some(committing_qc.as_ref().into()),
1149 deciding_qc: Some(deciding_qc.as_ref().into()),
1150 }),
1151 FinalityProof::NewProtocol { cert2, leaf_qc } => {
1152 Proof::NewProtocol(proto::NewProtocolFinality {
1153 cert2: Some(cert2.as_ref().into()),
1154 leaf_qc: Some(leaf_qc.as_ref().into()),
1155 })
1156 },
1157 FinalityProof::HotStuff {
1158 precommit_qc,
1159 committing_qc,
1160 deciding_qc,
1161 } => Proof::HotStuff(proto::HotStuffFinality {
1162 precommit_qc: Some(precommit_qc.as_ref().into()),
1163 committing_qc: Some(committing_qc.as_ref().into()),
1164 deciding_qc: Some(deciding_qc.as_ref().into()),
1165 }),
1166 };
1167 proto::FinalityProof { proof: Some(arm) }
1168 }
1169}
1170
1171impl TryFrom<&PayloadProof> for proto::LightClientPayloadProofResponse {
1172 type Error = tonic::Status;
1173
1174 fn try_from(proof: &PayloadProof) -> Result<Self, Self::Error> {
1175 Ok(proto::LightClientPayloadProofResponse {
1176 payload: Some(proof.payload().into()),
1177 vid_common: Some(proof.vid_common().try_into()?),
1178 })
1179 }
1180}
1181
1182impl TryFrom<&NamespaceProof> for proto::LightClientNamespaceProofResponse {
1183 type Error = tonic::Status;
1184
1185 fn try_from(proof: &NamespaceProof) -> Result<Self, Self::Error> {
1186 Ok(proto::LightClientNamespaceProofResponse {
1187 contents: proof.contents().map(TryInto::try_into).transpose()?,
1188 })
1189 }
1190}
1191
1192impl TryFrom<(&NsProof, &VidCommon)> for proto::LightClientNamespaceProofContents {
1194 type Error = tonic::Status;
1195
1196 fn try_from((proof, common): (&NsProof, &VidCommon)) -> Result<Self, Self::Error> {
1197 Ok(proto::LightClientNamespaceProofContents {
1198 proof: Some(proof.try_into()?),
1199 vid_common: Some(common.try_into()?),
1200 })
1201 }
1202}
1203
1204impl From<&StakeTableEvent> for proto::StakeTableEvent {
1205 fn from(event: &StakeTableEvent) -> Self {
1206 use proto::stake_table_event::Event;
1207
1208 let arm = match event {
1209 StakeTableEvent::Register(event) => Event::Register(proto::ValidatorRegistered {
1210 account: format!("{:#x}", event.account),
1211 bls_vk: Some((&event.blsVk).into()),
1212 schnorr_vk: Some((&event.schnorrVk).into()),
1213 commission: u32::from(event.commission),
1214 }),
1215 StakeTableEvent::RegisterV2(event) => Event::RegisterV2(proto::ValidatorRegisteredV2 {
1216 account: format!("{:#x}", event.account),
1217 bls_vk: Some((&event.blsVK).into()),
1218 schnorr_vk: Some((&event.schnorrVK).into()),
1219 commission: u32::from(event.commission),
1220 bls_sig: Some((&event.blsSig).into()),
1221 schnorr_sig: event.schnorrSig.to_vec(),
1222 metadata_uri: event.metadataUri.clone(),
1223 }),
1224 StakeTableEvent::RegisterV3(event) => Event::RegisterV3(proto::ValidatorRegisteredV3 {
1225 account: format!("{:#x}", event.account),
1226 bls_vk: Some((&event.blsVK).into()),
1227 schnorr_vk: Some((&event.schnorrVK).into()),
1228 commission: u32::from(event.commission),
1229 bls_sig: Some((&event.blsSig).into()),
1230 schnorr_sig: event.schnorrSig.to_vec(),
1231 metadata_uri: event.metadataUri.clone(),
1232 x25519_key: event.x25519Key.to_vec(),
1233 p2p_addr: event.p2pAddr.clone(),
1234 }),
1235 StakeTableEvent::Deregister(event) => Event::Deregister(proto::ValidatorExit {
1236 validator: format!("{:#x}", event.validator),
1237 }),
1238 StakeTableEvent::DeregisterV2(event) => Event::DeregisterV2(proto::ValidatorExitV2 {
1239 validator: format!("{:#x}", event.validator),
1240 unlocks_at: event.unlocksAt.to_string(),
1241 }),
1242 StakeTableEvent::Delegate(event) => Event::Delegate(proto::Delegated {
1243 delegator: format!("{:#x}", event.delegator),
1244 validator: format!("{:#x}", event.validator),
1245 amount: event.amount.to_string(),
1246 }),
1247 StakeTableEvent::Undelegate(event) => Event::Undelegate(proto::Undelegated {
1248 delegator: format!("{:#x}", event.delegator),
1249 validator: format!("{:#x}", event.validator),
1250 amount: event.amount.to_string(),
1251 }),
1252 StakeTableEvent::UndelegateV2(event) => Event::UndelegateV2(proto::UndelegatedV2 {
1253 delegator: format!("{:#x}", event.delegator),
1254 validator: format!("{:#x}", event.validator),
1255 undelegation_id: event.undelegationId,
1256 amount: event.amount.to_string(),
1257 unlocks_at: event.unlocksAt.to_string(),
1258 }),
1259 StakeTableEvent::KeyUpdate(event) => Event::KeyUpdate(proto::ConsensusKeysUpdated {
1260 account: format!("{:#x}", event.account),
1261 bls_vk: Some((&event.blsVK).into()),
1262 schnorr_vk: Some((&event.schnorrVK).into()),
1263 }),
1264 StakeTableEvent::KeyUpdateV2(event) => {
1265 Event::KeyUpdateV2(proto::ConsensusKeysUpdatedV2 {
1266 account: format!("{:#x}", event.account),
1267 bls_vk: Some((&event.blsVK).into()),
1268 schnorr_vk: Some((&event.schnorrVK).into()),
1269 bls_sig: Some((&event.blsSig).into()),
1270 schnorr_sig: event.schnorrSig.to_vec(),
1271 })
1272 },
1273 StakeTableEvent::CommissionUpdate(event) => {
1274 Event::CommissionUpdate(proto::CommissionUpdated {
1275 validator: format!("{:#x}", event.validator),
1276 timestamp: event.timestamp.to_string(),
1277 old_commission: u32::from(event.oldCommission),
1278 new_commission: u32::from(event.newCommission),
1279 })
1280 },
1281 StakeTableEvent::X25519KeyUpdate(event) => {
1282 Event::X25519KeyUpdate(proto::X25519KeyUpdated {
1283 validator: format!("{:#x}", event.validator),
1284 x25519_key: event.x25519Key.to_vec(),
1285 })
1286 },
1287 StakeTableEvent::P2pAddrUpdate(event) => Event::P2pAddrUpdate(proto::P2pAddrUpdated {
1288 validator: format!("{:#x}", event.validator),
1289 p2p_addr: event.p2pAddr.clone(),
1290 }),
1291 };
1292 proto::StakeTableEvent { event: Some(arm) }
1293 }
1294}
1295
1296impl From<&G1PointSol> for proto::Bn254G1Point {
1297 fn from(point: &G1PointSol) -> Self {
1298 proto::Bn254G1Point {
1299 x: format!("{:#x}", point.x),
1300 y: format!("{:#x}", point.y),
1301 }
1302 }
1303}
1304
1305impl From<&G2PointSol> for proto::Bn254G2Point {
1306 fn from(point: &G2PointSol) -> Self {
1307 proto::Bn254G2Point {
1308 x0: format!("{:#x}", point.x0),
1309 x1: format!("{:#x}", point.x1),
1310 y0: format!("{:#x}", point.y0),
1311 y1: format!("{:#x}", point.y1),
1312 }
1313 }
1314}
1315
1316impl From<&EdOnBN254PointSol> for proto::EdOnBn254Point {
1317 fn from(point: &EdOnBN254PointSol) -> Self {
1318 proto::EdOnBn254Point {
1319 x: format!("{:#x}", point.x),
1320 y: format!("{:#x}", point.y),
1321 }
1322 }
1323}
1324
1325impl From<&AvidMNsProof> for proto::NsProofPayload {
1326 fn from(proof: &AvidMNsProof) -> Self {
1327 proto::NsProofPayload {
1328 ns_index: proof.0.ns_index as u64,
1329 ns_payload: proof.0.ns_payload.to_vec(),
1330 ns_proof: proof.0.ns_proof.to_string(),
1331 }
1332 }
1333}
1334
1335impl From<&AvidmGf2NsProof> for proto::NsProofPayload {
1336 fn from(proof: &AvidmGf2NsProof) -> Self {
1337 proto::NsProofPayload {
1338 ns_index: proof.0.ns_index as u64,
1339 ns_payload: proof.0.ns_payload.to_vec(),
1340 ns_proof: proof.0.ns_proof.to_string(),
1341 }
1342 }
1343}
1344
1345impl TryFrom<&TxProof> for proto::TxProof {
1346 type Error = tonic::Status;
1347
1348 fn try_from(proof: &TxProof) -> Result<Self, Self::Error> {
1349 use proto::tx_proof::Proof;
1350
1351 let arm = match proof {
1352 TxProof::V0(advz) => Proof::V0(proto::AdvzTxProof {
1353 tx_index: advz.tx_index().to_bytes().to_vec(),
1354 payload_num_txs: advz.payload_num_txs().to_payload_bytes().to_vec(),
1355 payload_proof_num_txs: Some(advz.payload_proof_num_txs().try_into()?),
1356 payload_tx_table_entries: advz.payload_tx_table_entries().to_payload_bytes(),
1357 payload_proof_tx_table_entries: Some(
1358 advz.payload_proof_tx_table_entries().try_into()?,
1359 ),
1360 payload_proof_tx: advz.payload_proof_tx().map(TryInto::try_into).transpose()?,
1361 }),
1362 TxProof::V1(avidm) => Proof::V1(proto::AvidmTxProof {
1363 tx_index: avidm.tx_index().to_bytes().to_vec(),
1364 ns_proof: Some(avidm.ns_proof().into()),
1365 }),
1366 TxProof::V2(gf2) => Proof::V2(proto::AvidmGf2TxProof {
1367 tx_index: gf2.tx_index().to_bytes().to_vec(),
1368 ns_proof: Some(gf2.ns_proof().into()),
1369 }),
1370 };
1371 Ok(proto::TxProof { proof: Some(arm) })
1372 }
1373}
1374
1375impl TryFrom<&SmallRangeProofType> for proto::SmallRangeProof {
1376 type Error = tonic::Status;
1377
1378 fn try_from(proof: &SmallRangeProofType) -> Result<Self, Self::Error> {
1379 let value = to_json(proof)?;
1380 Ok(proto::SmallRangeProof {
1381 proofs: json_field(&value, "proofs")?,
1382 prefix_bytes: json_field(&value, "prefix_bytes")?,
1383 suffix_bytes: json_field(&value, "suffix_bytes")?,
1384 })
1385 }
1386}
1387
1388impl TryFrom<&LargeRangeProofType> for proto::LargeRangeProof {
1389 type Error = tonic::Status;
1390
1391 fn try_from(proof: &LargeRangeProofType) -> Result<Self, Self::Error> {
1392 let value = to_json(proof)?;
1393 Ok(proto::LargeRangeProof {
1394 prefix_elems: json_field(&value, "prefix_elems")?,
1395 suffix_elems: json_field(&value, "suffix_elems")?,
1396 prefix_bytes: json_field(&value, "prefix_bytes")?,
1397 suffix_bytes: json_field(&value, "suffix_bytes")?,
1398 })
1399 }
1400}
1401
1402impl From<&Transaction> for proto::Transaction {
1403 fn from(tx: &Transaction) -> Self {
1404 proto::Transaction {
1405 namespace: tx.namespace().0,
1406 payload: tx.payload().to_vec(),
1407 }
1408 }
1409}
1410
1411impl From<&TransactionQueryData<SeqTypes>> for proto::TransactionResponse {
1412 fn from(tx: &TransactionQueryData<SeqTypes>) -> Self {
1413 proto::TransactionResponse {
1414 transaction: Some(tx.transaction().into()),
1415 hash: tx.hash().to_string(),
1416 index: tx.index(),
1417 block_hash: tx.block_hash().to_string(),
1418 block_height: tx.block_height(),
1419 namespace: tx.namespace().0,
1420 pos_in_namespace: tx.pos_in_namespace(),
1421 }
1422 }
1423}
1424
1425impl TryFrom<&TransactionWithProofQueryData<SeqTypes>> for proto::TransactionWithProofResponse {
1426 type Error = tonic::Status;
1427
1428 fn try_from(tx: &TransactionWithProofQueryData<SeqTypes>) -> Result<Self, Self::Error> {
1429 Ok(proto::TransactionWithProofResponse {
1430 transaction: Some(tx.transaction().into()),
1431 hash: tx.hash().to_string(),
1432 index: tx.index(),
1433 block_hash: tx.block_hash().to_string(),
1434 block_height: tx.block_height(),
1435 namespace: tx.namespace().0,
1436 pos_in_namespace: tx.pos_in_namespace(),
1437 proof: Some(tx.proof().try_into()?),
1438 })
1439 }
1440}
1441
1442impl From<&BlockSummaryQueryData<SeqTypes>> for proto::BlockSummaryResponse {
1443 fn from(summary: &BlockSummaryQueryData<SeqTypes>) -> Self {
1444 proto::BlockSummaryResponse {
1445 header: Some((&summary.header).into()),
1446 hash: summary.hash.to_string(),
1447 size: summary.size,
1448 num_transactions: summary.num_transactions,
1449 namespaces: summary
1450 .namespaces
1451 .iter()
1452 .map(|(namespace, info)| {
1453 (
1454 namespace.0,
1455 proto::NamespaceInfo {
1456 num_transactions: info.num_transactions,
1457 size: info.size,
1458 },
1459 )
1460 })
1461 .collect(),
1462 }
1463 }
1464}
1465
1466impl TryFrom<&AvidMIncorrectEncodingNsProof> for proto::AvidmBadEncodingNsProof {
1467 type Error = tonic::Status;
1468
1469 fn try_from(proof: &AvidMIncorrectEncodingNsProof) -> Result<Self, Self::Error> {
1470 let inner = &proof.0;
1471 let value = to_json(&inner.ns_proof)?;
1472 Ok(proto::AvidmBadEncodingNsProof {
1473 ns_index: inner.ns_index as u64,
1474 ns_commit: inner.ns_commit.to_string(),
1475 ns_mt_proof: inner.ns_mt_proof.to_string(),
1476 ns_proof: Some(proto::AvidmBadEncodingProof {
1477 recovered_poly: json_field(&value, "recovered_poly")?,
1478 raw_shares: json_field(&value, "raw_shares")?,
1479 }),
1480 })
1481 }
1482}
1483
1484impl TryFrom<&NsProof> for proto::NsProof {
1485 type Error = tonic::Status;
1486
1487 fn try_from(proof: &NsProof) -> Result<Self, Self::Error> {
1488 use proto::ns_proof::Proof;
1489
1490 let arm = match proof {
1491 NsProof::V0(advz) => Proof::V0(proto::AdvzNsProof {
1492 ns_index: advz.ns_index.to_bytes().to_vec(),
1493 ns_payload: advz.ns_payload.as_bytes_slice().to_vec(),
1494 ns_proof: advz.ns_proof.as_ref().map(TryInto::try_into).transpose()?,
1495 }),
1496 NsProof::V1(avidm) => Proof::V1(avidm.into()),
1497 NsProof::V1IncorrectEncoding(bad) => Proof::V1IncorrectEncoding(bad.try_into()?),
1498 NsProof::V2(gf2) => Proof::V2(gf2.into()),
1499 };
1500 Ok(proto::NsProof { proof: Some(arm) })
1501 }
1502}
1503
1504impl TryFrom<&NamespaceProofQueryData> for proto::NamespaceProofResponse {
1505 type Error = tonic::Status;
1506
1507 fn try_from(data: &NamespaceProofQueryData) -> Result<Self, Self::Error> {
1508 Ok(proto::NamespaceProofResponse {
1509 proof: data.proof.as_ref().map(TryInto::try_into).transpose()?,
1510 transactions: data.transactions.iter().map(Into::into).collect(),
1511 })
1512 }
1513}
1514
1515impl From<&StateCertQueryDataV1<SeqTypes>> for proto::StateCertV1Response {
1516 fn from(cert: &StateCertQueryDataV1<SeqTypes>) -> Self {
1517 let cert = &cert.0;
1518 proto::StateCertV1Response {
1519 epoch: cert.epoch.u64(),
1520 light_client_state: cert.light_client_state.to_string(),
1521 next_stake_table_state: cert.next_stake_table_state.to_string(),
1522 signatures: cert
1523 .signatures
1524 .iter()
1525 .map(|(key, signature)| proto::StateSignatureV1 {
1526 key: key.to_string(),
1527 signature: signature.to_string(),
1528 })
1529 .collect(),
1530 }
1531 }
1532}
1533
1534impl From<&StateCertQueryDataV2<SeqTypes>> for proto::StateCertV2Response {
1535 fn from(cert: &StateCertQueryDataV2<SeqTypes>) -> Self {
1536 let cert = &cert.0;
1537 proto::StateCertV2Response {
1538 epoch: cert.epoch.u64(),
1539 light_client_state: cert.light_client_state.to_string(),
1540 next_stake_table_state: cert.next_stake_table_state.to_string(),
1541 signatures: cert
1542 .signatures
1543 .iter()
1544 .map(|(key, lcv3, lcv2)| proto::StateSignatureV2 {
1545 key: key.to_string(),
1546 lcv3_signature: lcv3.to_string(),
1547 lcv2_signature: lcv2.to_string(),
1548 })
1549 .collect(),
1550 auth_root: format!("{:#x}", cert.auth_root),
1551 }
1552 }
1553}
1554
1555impl From<&LCV3StateSignatureRequestBody> for proto::StateSignatureResponse {
1556 fn from(body: &LCV3StateSignatureRequestBody) -> Self {
1557 proto::StateSignatureResponse {
1558 key: body.key.to_string(),
1559 light_client_state: body.state.to_string(),
1560 next_stake_table_state: body.next_stake.to_string(),
1561 auth_root: format!("{:#x}", body.auth_root),
1562 lcv3_signature: body.signature.to_string(),
1563 lcv2_signature: body.v2_signature.to_string(),
1564 }
1565 }
1566}
1567
1568impl From<&explorer::BlockDetail<SeqTypes>> for proto::ExplorerBlockDetail {
1569 fn from(block: &explorer::BlockDetail<SeqTypes>) -> Self {
1570 proto::ExplorerBlockDetail {
1571 hash: block.hash.to_string(),
1572 height: block.height,
1573 time: explorer_time(block.time),
1574 num_transactions: block.num_transactions,
1575 proposer_id: explorer_accounts(&block.proposer_id),
1576 fee_recipient: explorer_accounts(&block.fee_recipient),
1577 size: block.size,
1578 block_reward: block.block_reward.iter().map(ToString::to_string).collect(),
1580 }
1581 }
1582}
1583
1584impl From<&explorer::BlockSummary<SeqTypes>> for proto::ExplorerBlockSummary {
1585 fn from(block: &explorer::BlockSummary<SeqTypes>) -> Self {
1586 proto::ExplorerBlockSummary {
1587 hash: block.hash.to_string(),
1588 height: block.height,
1589 proposer_id: explorer_accounts(&block.proposer_id),
1590 num_transactions: block.num_transactions,
1591 size: block.size,
1592 time: explorer_time(block.time),
1593 }
1594 }
1595}
1596
1597impl From<&explorer::TransactionSummary<SeqTypes>> for proto::ExplorerTransactionSummary {
1598 fn from(transaction: &explorer::TransactionSummary<SeqTypes>) -> Self {
1599 proto::ExplorerTransactionSummary {
1600 hash: transaction.hash.to_string(),
1601 rollups: transaction
1602 .rollups
1603 .iter()
1604 .map(|namespace| u64::from(*namespace))
1605 .collect(),
1606 height: transaction.height,
1607 offset: transaction.offset,
1608 num_transactions: transaction.num_transactions,
1609 time: explorer_time(transaction.time),
1610 }
1611 }
1612}
1613
1614impl From<&explorer::TransactionDetail<SeqTypes>> for proto::ExplorerTransactionDetail {
1615 fn from(details: &explorer::TransactionDetail<SeqTypes>) -> Self {
1616 proto::ExplorerTransactionDetail {
1617 hash: details.hash.to_string(),
1618 height: details.height,
1619 block_confirmed: details.block_confirmed,
1620 offset: details.offset,
1621 num_transactions: details.num_transactions,
1622 size: details.size,
1623 time: explorer_time(details.time),
1624 sequencing_fees: details
1625 .sequencing_fees
1626 .iter()
1627 .map(ToString::to_string)
1628 .collect(),
1629 fee_details: details.fee_details.iter().map(Into::into).collect(),
1630 }
1631 }
1632}
1633
1634impl From<&explorer::FeeAttribution> for proto::ExplorerFeeAttribution {
1635 fn from(attribution: &explorer::FeeAttribution) -> Self {
1636 proto::ExplorerFeeAttribution {
1637 target: attribution.target.clone(),
1638 fees: attribution.fees.iter().map(ToString::to_string).collect(),
1639 }
1640 }
1641}
1642
1643impl From<&explorer::ExplorerSummary<SeqTypes>> for proto::ExplorerSummaryResponse {
1644 fn from(summary: &explorer::ExplorerSummary<SeqTypes>) -> Self {
1645 let explorer::GenesisOverview {
1646 rollups,
1647 transactions,
1648 blocks,
1649 } = summary.genesis_overview;
1650 let histograms = &summary.histograms;
1653 let histograms = histograms
1654 .block_heights
1655 .iter()
1656 .zip(&histograms.block_time)
1657 .zip(&histograms.block_size)
1658 .zip(&histograms.block_transactions)
1659 .map(|(((height, block_time), block_size), block_transactions)| {
1660 proto::ExplorerHistogramPoint {
1661 height: *height,
1662 block_time: *block_time,
1663 block_size: *block_size,
1664 block_transactions: *block_transactions,
1665 }
1666 })
1667 .collect();
1668 proto::ExplorerSummaryResponse {
1669 latest_block: Some((&summary.latest_block).into()),
1670 genesis_overview: Some(proto::ExplorerGenesisOverview {
1671 rollups,
1672 transactions,
1673 blocks,
1674 }),
1675 latest_blocks: summary.latest_blocks.iter().map(Into::into).collect(),
1676 latest_transactions: summary.latest_transactions.iter().map(Into::into).collect(),
1677 histograms,
1678 }
1679 }
1680}
1681
1682impl From<&explorer::SearchResult<SeqTypes>> for proto::ExplorerSearchResponse {
1683 fn from(results: &explorer::SearchResult<SeqTypes>) -> Self {
1684 proto::ExplorerSearchResponse {
1685 blocks: results.blocks.iter().map(Into::into).collect(),
1686 transactions: results.transactions.iter().map(Into::into).collect(),
1687 }
1688 }
1689}
1690
1691fn explorer_time(time: explorer::Timestamp) -> String {
1693 time.0
1694 .format(&time::format_description::well_known::Rfc3339)
1695 .expect("a Timestamp is built from a unix time inside RFC 3339's year range")
1696}
1697
1698fn explorer_accounts(accounts: &[FeeAccount]) -> Vec<String> {
1700 accounts
1701 .iter()
1702 .map(|account| format!("{:#x}", account.0))
1703 .collect()
1704}