1use std::{collections::HashMap, fmt::Debug, hash::Hash};
14
15use committable::{Commitment, Committable};
16use derive_more::derive::From;
17use hotshot_types::{
18 data::{Leaf, Leaf2, VidCommitment, VidShare},
19 simple_certificate::{LightClientStateUpdateCertificate, QuorumCertificate2},
20 traits::{
21 self,
22 block_contents::{BlockHeader, GENESIS_VID_NUM_STORAGE_NODES},
23 node_implementation::{NodeType, Versions},
24 EncodeBytes,
25 },
26 vid::advz::{advz_scheme, ADVZCommitment, ADVZCommon},
27};
28use jf_vid::VidScheme;
29use serde::{de::DeserializeOwned, Deserialize, Serialize};
30use snafu::{ensure, Snafu};
31
32use crate::{
33 types::HeightIndexed, Header, Metadata, Payload, QuorumCertificate, Transaction, VidCommon,
34};
35
36pub type LeafHash<Types> = Commitment<Leaf2<Types>>;
37pub type LeafHashLegacy<Types> = Commitment<Leaf<Types>>;
38pub type QcHash<Types> = Commitment<QuorumCertificate2<Types>>;
39
40pub type BlockHash<Types> = Commitment<Header<Types>>;
45pub type TransactionHash<Types> = Commitment<Transaction<Types>>;
46pub type TransactionInclusionProof<Types> =
47 <Payload<Types> as QueryablePayload<Types>>::InclusionProof;
48pub type NamespaceIndex<Types> = <Header<Types> as QueryableHeader<Types>>::NamespaceIndex;
49pub type NamespaceId<Types> = <Header<Types> as QueryableHeader<Types>>::NamespaceId;
50
51pub type Timestamp = time::OffsetDateTime;
52
53pub trait QueryableHeader<Types: NodeType>: BlockHeader<Types> {
54 type NamespaceIndex: Clone + Debug + Hash + PartialEq + Eq + From<i64> + Into<i64> + Send + Sync;
56
57 type NamespaceId: Clone
59 + Debug
60 + Serialize
61 + DeserializeOwned
62 + Send
63 + Sync
64 + Hash
65 + PartialEq
66 + Eq
67 + Copy
68 + From<i64>
69 + Into<i64>;
70
71 fn namespace_id(&self, i: &Self::NamespaceIndex) -> Option<Self::NamespaceId>;
73
74 fn namespace_size(&self, i: &Self::NamespaceIndex, payload_size: usize) -> u64;
76}
77
78#[derive(Clone, Debug)]
79pub struct TransactionIndex<Types: NodeType>
80where
81 Header<Types>: QueryableHeader<Types>,
82{
83 pub ns_index: NamespaceIndex<Types>,
85 pub position: u32,
87}
88
89pub trait QueryablePayload<Types: NodeType>: traits::BlockPayload<Types>
98where
99 Header<Types>: QueryableHeader<Types>,
100{
101 type Iter<'a>: Iterator<Item = TransactionIndex<Types>>
103 where
104 Self: 'a;
105
106 type InclusionProof: Clone + Debug + PartialEq + Eq + Serialize + DeserializeOwned + Send + Sync;
115
116 fn len(&self, meta: &Self::Metadata) -> usize;
118
119 fn is_empty(&self, meta: &Self::Metadata) -> bool {
121 self.len(meta) == 0
122 }
123
124 fn iter<'a>(&'a self, meta: &'a Self::Metadata) -> Self::Iter<'a>;
126
127 fn enumerate<'a>(
129 &'a self,
130 meta: &'a Self::Metadata,
131 ) -> Box<dyn 'a + Iterator<Item = (TransactionIndex<Types>, Self::Transaction)>> {
132 Box::new(self.iter(meta).map(|ix| {
133 let tx = self.transaction(meta, &ix).unwrap();
136 (ix, tx)
137 }))
138 }
139
140 fn transaction_with_proof(
142 &self,
143 meta: &Self::Metadata,
144 index: &TransactionIndex<Types>,
145 ) -> Option<(Self::Transaction, Self::InclusionProof)>;
146
147 fn transaction(
149 &self,
150 meta: &Self::Metadata,
151 index: &TransactionIndex<Types>,
152 ) -> Option<Self::Transaction> {
153 Some(self.transaction_with_proof(meta, index)?.0)
154 }
155
156 fn proof(
158 &self,
159 meta: &Self::Metadata,
160 index: &TransactionIndex<Types>,
161 ) -> Option<Self::InclusionProof> {
162 Some(self.transaction_with_proof(meta, index)?.1)
163 }
164
165 fn nth(&self, meta: &Self::Metadata, n: usize) -> Option<TransactionIndex<Types>> {
167 self.iter(meta).nth(n)
168 }
169
170 fn nth_transaction(&self, meta: &Self::Metadata, n: usize) -> Option<Self::Transaction> {
172 self.transaction(meta, &self.nth(meta, n)?)
173 }
174
175 fn nth_transaction_with_proof(
177 &self,
178 meta: &Self::Metadata,
179 n: usize,
180 ) -> Option<(Self::Transaction, Self::InclusionProof)> {
181 self.transaction_with_proof(meta, &self.nth(meta, n)?)
182 }
183
184 fn by_hash(
186 &self,
187 meta: &Self::Metadata,
188 hash: Commitment<Self::Transaction>,
189 ) -> Option<TransactionIndex<Types>> {
190 self.iter(meta).find(|i| {
191 if let Some(tx) = self.transaction(meta, i) {
192 tx.commit() == hash
193 } else {
194 false
195 }
196 })
197 }
198
199 fn transaction_by_hash(
201 &self,
202 meta: &Self::Metadata,
203 hash: Commitment<Self::Transaction>,
204 ) -> Option<Self::Transaction> {
205 self.transaction(meta, &self.by_hash(meta, hash)?)
206 }
207
208 fn transaction_by_hash_with_proof(
210 &self,
211 meta: &Self::Metadata,
212 hash: Commitment<Self::Transaction>,
213 ) -> Option<(Self::Transaction, Self::InclusionProof)> {
214 self.transaction_with_proof(meta, &self.by_hash(meta, hash)?)
215 }
216}
217
218#[derive(Clone, Debug, Serialize, Deserialize, PartialEq, Eq)]
219#[serde(bound = "")]
220pub struct LeafQueryData<Types: NodeType> {
221 pub(crate) leaf: Leaf2<Types>,
222 pub(crate) qc: QuorumCertificate2<Types>,
223}
224
225#[derive(Clone, Debug, Serialize, Deserialize, PartialEq, Eq)]
226#[serde(bound = "")]
227pub struct LeafQueryDataLegacy<Types: NodeType> {
228 pub(crate) leaf: Leaf<Types>,
229 pub(crate) qc: QuorumCertificate<Types>,
230}
231
232impl<Types: NodeType> From<LeafQueryDataLegacy<Types>> for LeafQueryData<Types> {
233 fn from(legacy: LeafQueryDataLegacy<Types>) -> Self {
234 Self {
235 leaf: legacy.leaf.into(),
236 qc: legacy.qc.to_qc2(),
237 }
238 }
239}
240
241#[derive(Clone, Debug, Snafu)]
242#[snafu(display("QC references leaf {qc_leaf}, but expected {leaf}"))]
243pub struct InconsistentLeafError<Types: NodeType> {
244 pub leaf: LeafHash<Types>,
245 pub qc_leaf: LeafHash<Types>,
246}
247
248#[derive(Clone, Debug, Snafu)]
249#[snafu(display("QC references leaf {qc_leaf}, but expected {leaf}"))]
250pub struct InconsistentLeafLegacyError<Types: NodeType> {
251 pub leaf: LeafHashLegacy<Types>,
252 pub qc_leaf: LeafHashLegacy<Types>,
253}
254
255impl<Types: NodeType> LeafQueryDataLegacy<Types> {
256 pub fn new(
264 mut leaf: Leaf<Types>,
265 qc: QuorumCertificate<Types>,
266 ) -> Result<Self, InconsistentLeafLegacyError<Types>> {
267 let leaf_commit = <Leaf<Types> as Committable>::commit(&leaf);
271 ensure!(
272 qc.data.leaf_commit == leaf_commit,
273 InconsistentLeafLegacySnafu {
274 leaf: leaf_commit,
275 qc_leaf: qc.data.leaf_commit
276 }
277 );
278
279 leaf.unfill_block_payload();
282
283 Ok(Self { leaf, qc })
284 }
285
286 pub async fn genesis<HsVer: Versions>(
287 validated_state: &Types::ValidatedState,
288 instance_state: &Types::InstanceState,
289 ) -> Self {
290 Self {
291 leaf: Leaf::genesis::<HsVer>(validated_state, instance_state).await,
292 qc: QuorumCertificate::genesis::<HsVer>(validated_state, instance_state).await,
293 }
294 }
295
296 pub fn leaf(&self) -> &Leaf<Types> {
297 &self.leaf
298 }
299
300 pub fn qc(&self) -> &QuorumCertificate<Types> {
301 &self.qc
302 }
303
304 pub fn header(&self) -> &Header<Types> {
305 self.leaf.block_header()
306 }
307
308 pub fn hash(&self) -> LeafHashLegacy<Types> {
309 <Leaf<Types> as Committable>::commit(&self.leaf)
313 }
314
315 pub fn block_hash(&self) -> BlockHash<Types> {
316 self.header().commit()
317 }
318
319 pub fn payload_hash(&self) -> VidCommitment {
320 self.header().payload_commitment()
321 }
322}
323
324impl<Types: NodeType> LeafQueryData<Types> {
325 pub fn new(
333 mut leaf: Leaf2<Types>,
334 qc: QuorumCertificate2<Types>,
335 ) -> Result<Self, InconsistentLeafError<Types>> {
336 let leaf_commit = <Leaf2<Types> as Committable>::commit(&leaf);
340 ensure!(
341 qc.data.leaf_commit == leaf_commit,
342 InconsistentLeafSnafu {
343 leaf: leaf_commit,
344 qc_leaf: qc.data.leaf_commit
345 }
346 );
347
348 leaf.unfill_block_payload();
351
352 Ok(Self { leaf, qc })
353 }
354
355 pub async fn genesis<HsVer: Versions>(
356 validated_state: &Types::ValidatedState,
357 instance_state: &Types::InstanceState,
358 ) -> Self {
359 Self {
360 leaf: Leaf2::genesis::<HsVer>(validated_state, instance_state).await,
361 qc: QuorumCertificate2::genesis::<HsVer>(validated_state, instance_state).await,
362 }
363 }
364
365 pub fn leaf(&self) -> &Leaf2<Types> {
366 &self.leaf
367 }
368
369 pub fn qc(&self) -> &QuorumCertificate2<Types> {
370 &self.qc
371 }
372
373 pub fn header(&self) -> &Header<Types> {
374 self.leaf.block_header()
375 }
376
377 pub fn hash(&self) -> LeafHash<Types> {
378 <Leaf2<Types> as Committable>::commit(&self.leaf)
382 }
383
384 pub fn block_hash(&self) -> BlockHash<Types> {
385 self.header().commit()
386 }
387
388 pub fn payload_hash(&self) -> VidCommitment {
389 self.header().payload_commitment()
390 }
391}
392
393impl<Types: NodeType> HeightIndexed for LeafQueryData<Types> {
394 fn height(&self) -> u64 {
395 self.header().block_number()
396 }
397}
398
399impl<Types: NodeType> HeightIndexed for LeafQueryDataLegacy<Types> {
400 fn height(&self) -> u64 {
401 self.header().block_number()
402 }
403}
404
405#[derive(Clone, Debug, Serialize, serde::Deserialize, PartialEq, Eq)]
406#[serde(bound = "")]
407pub struct HeaderQueryData<Types: NodeType> {
408 pub header: Header<Types>,
409}
410
411impl<Types: NodeType> HeaderQueryData<Types> {
412 pub fn new(header: Header<Types>) -> Self {
413 Self { header }
414 }
415
416 pub fn header(&self) -> &Header<Types> {
417 &self.header
418 }
419}
420
421#[derive(Clone, Debug, Serialize, Deserialize, PartialEq, Eq)]
422#[serde(bound = "")]
423pub struct BlockQueryData<Types: NodeType> {
424 pub(crate) header: Header<Types>,
425 pub(crate) payload: Payload<Types>,
426 pub(crate) hash: BlockHash<Types>,
427 pub(crate) size: u64,
428 pub(crate) num_transactions: u64,
429}
430
431impl<Types: NodeType> BlockQueryData<Types> {
432 pub fn new(header: Header<Types>, payload: Payload<Types>) -> Self
433 where
434 Header<Types>: QueryableHeader<Types>,
435 Payload<Types>: QueryablePayload<Types>,
436 {
437 Self {
438 hash: header.commit(),
439 size: payload_size::<Types>(&payload),
440 num_transactions: payload.len(header.metadata()) as u64,
441 header,
442 payload,
443 }
444 }
445
446 pub async fn genesis<HsVer: Versions>(
447 validated_state: &Types::ValidatedState,
448 instance_state: &Types::InstanceState,
449 ) -> Self
450 where
451 Header<Types>: QueryableHeader<Types>,
452 Payload<Types>: QueryablePayload<Types>,
453 {
454 let leaf = Leaf2::<Types>::genesis::<HsVer>(validated_state, instance_state).await;
455 Self::new(leaf.block_header().clone(), leaf.block_payload().unwrap())
456 }
457
458 pub fn header(&self) -> &Header<Types> {
459 &self.header
460 }
461
462 pub fn metadata(&self) -> &Metadata<Types> {
463 self.header.metadata()
464 }
465
466 pub fn payload_hash(&self) -> VidCommitment {
467 self.header.payload_commitment()
468 }
469
470 pub fn payload(&self) -> &Payload<Types> {
471 &self.payload
472 }
473
474 pub fn hash(&self) -> BlockHash<Types> {
475 self.hash
476 }
477
478 pub fn size(&self) -> u64 {
479 self.size
480 }
481
482 pub fn num_transactions(&self) -> u64 {
483 self.num_transactions
484 }
485
486 pub fn namespace_info(&self) -> NamespaceMap<Types>
487 where
488 Header<Types>: QueryableHeader<Types>,
489 Payload<Types>: QueryablePayload<Types>,
490 {
491 let mut map = NamespaceMap::<Types>::new();
492 for tx in self.payload.iter(self.header.metadata()) {
493 let Some(ns_id) = self.header.namespace_id(&tx.ns_index) else {
494 continue;
495 };
496 map.entry(ns_id)
497 .or_insert_with(|| NamespaceInfo {
498 num_transactions: 0,
499 size: self.header.namespace_size(&tx.ns_index, self.size as usize),
500 })
501 .num_transactions += 1;
502 }
503 map
504 }
505}
506
507impl<Types: NodeType> BlockQueryData<Types>
508where
509 Header<Types>: QueryableHeader<Types>,
510 Payload<Types>: QueryablePayload<Types>,
511{
512 pub fn transaction(&self, ix: &TransactionIndex<Types>) -> Option<Transaction<Types>> {
513 self.payload().transaction(self.metadata(), ix)
514 }
515
516 pub fn transaction_by_hash(
517 &self,
518 hash: Commitment<Transaction<Types>>,
519 ) -> Option<TransactionIndex<Types>> {
520 self.payload().by_hash(self.metadata(), hash)
521 }
522
523 pub fn len(&self) -> usize {
524 self.payload.len(self.metadata())
525 }
526
527 pub fn is_empty(&self) -> bool {
528 self.len() == 0
529 }
530
531 pub fn enumerate(
532 &self,
533 ) -> impl '_ + Iterator<Item = (TransactionIndex<Types>, Transaction<Types>)> {
534 self.payload.enumerate(self.metadata())
535 }
536}
537
538impl<Types: NodeType> HeightIndexed for BlockQueryData<Types> {
539 fn height(&self) -> u64 {
540 self.header.block_number()
541 }
542}
543
544#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
545#[serde(bound = "")]
546pub struct ADVZPayloadQueryData<Types: NodeType> {
547 pub(crate) height: u64,
548 pub(crate) block_hash: BlockHash<Types>,
549 pub(crate) hash: ADVZCommitment,
550 pub(crate) size: u64,
551 pub(crate) data: Payload<Types>,
552}
553
554#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
555#[serde(bound = "")]
556pub struct PayloadQueryData<Types: NodeType> {
557 pub(crate) height: u64,
558 pub(crate) block_hash: BlockHash<Types>,
559 pub(crate) hash: VidCommitment,
560 pub(crate) size: u64,
561 pub(crate) data: Payload<Types>,
562}
563
564impl<Types: NodeType> From<BlockQueryData<Types>> for PayloadQueryData<Types> {
565 fn from(block: BlockQueryData<Types>) -> Self {
566 Self {
567 height: block.height(),
568 block_hash: block.hash(),
569 hash: block.header.payload_commitment(),
570 size: block.size(),
571 data: block.payload,
572 }
573 }
574}
575
576impl<Types: NodeType> PayloadQueryData<Types> {
577 pub fn to_legacy(&self) -> Option<ADVZPayloadQueryData<Types>> {
578 let VidCommitment::V0(advz_commit) = self.hash else {
579 return None;
580 };
581
582 Some(ADVZPayloadQueryData {
583 height: self.height,
584 block_hash: self.block_hash,
585 hash: advz_commit,
586 size: self.size,
587 data: self.data.clone(),
588 })
589 }
590
591 pub async fn genesis<HsVer: Versions>(
592 validated_state: &Types::ValidatedState,
593 instance_state: &Types::InstanceState,
594 ) -> Self
595 where
596 Header<Types>: QueryableHeader<Types>,
597 Payload<Types>: QueryablePayload<Types>,
598 {
599 BlockQueryData::genesis::<HsVer>(validated_state, instance_state)
600 .await
601 .into()
602 }
603
604 pub fn hash(&self) -> VidCommitment {
605 self.hash
606 }
607
608 pub fn block_hash(&self) -> BlockHash<Types> {
609 self.block_hash
610 }
611
612 pub fn size(&self) -> u64 {
613 self.size
614 }
615
616 pub fn data(&self) -> &Payload<Types> {
617 &self.data
618 }
619}
620
621impl<Types: NodeType> HeightIndexed for PayloadQueryData<Types> {
622 fn height(&self) -> u64 {
623 self.height
624 }
625}
626
627#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
629#[serde(bound = "")]
630pub struct ADVZCommonQueryData<Types: NodeType> {
631 pub(crate) height: u64,
632 pub(crate) block_hash: BlockHash<Types>,
633 pub(crate) payload_hash: ADVZCommitment,
634 pub(crate) common: ADVZCommon,
635}
636
637impl<Types: NodeType> ADVZCommonQueryData<Types> {
638 pub fn new(header: Header<Types>, common: ADVZCommon) -> anyhow::Result<Self> {
639 let VidCommitment::V0(payload_hash) = header.payload_commitment() else {
640 return Err(anyhow::anyhow!("Inconsistent header type."));
641 };
642 Ok(Self {
643 height: header.block_number(),
644 block_hash: header.commit(),
645 payload_hash,
646 common,
647 })
648 }
649
650 pub async fn genesis<HsVer: Versions>(
651 validated_state: &Types::ValidatedState,
652 instance_state: &Types::InstanceState,
653 ) -> anyhow::Result<Self> {
654 let leaf = Leaf::<Types>::genesis::<HsVer>(validated_state, instance_state).await;
655 let payload = leaf.block_payload().unwrap();
656 let bytes = payload.encode();
657 let disperse = advz_scheme(GENESIS_VID_NUM_STORAGE_NODES)
658 .disperse(bytes)
659 .unwrap();
660
661 Self::new(leaf.block_header().clone(), disperse.common)
662 }
663
664 pub fn block_hash(&self) -> BlockHash<Types> {
665 self.block_hash
666 }
667
668 pub fn payload_hash(&self) -> ADVZCommitment {
669 self.payload_hash
670 }
671
672 pub fn common(&self) -> &ADVZCommon {
673 &self.common
674 }
675}
676
677impl<Types: NodeType> HeightIndexed for ADVZCommonQueryData<Types> {
678 fn height(&self) -> u64 {
679 self.height
680 }
681}
682
683impl<Types: NodeType> HeightIndexed for (ADVZCommonQueryData<Types>, Option<VidShare>) {
684 fn height(&self) -> u64 {
685 self.0.height
686 }
687}
688
689#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
690#[serde(bound = "")]
691pub struct VidCommonQueryData<Types: NodeType> {
692 pub(crate) height: u64,
693 pub(crate) block_hash: BlockHash<Types>,
694 pub(crate) payload_hash: VidCommitment,
695 pub(crate) common: VidCommon,
696}
697
698impl<Types: NodeType> VidCommonQueryData<Types> {
699 pub fn new(header: Header<Types>, common: VidCommon) -> Self {
700 Self {
701 height: header.block_number(),
702 block_hash: header.commit(),
703 payload_hash: header.payload_commitment(),
704 common,
705 }
706 }
707
708 pub async fn genesis<HsVer: Versions>(
709 validated_state: &Types::ValidatedState,
710 instance_state: &Types::InstanceState,
711 ) -> Self {
712 let leaf = Leaf::<Types>::genesis::<HsVer>(validated_state, instance_state).await;
713 let payload = leaf.block_payload().unwrap();
714 let bytes = payload.encode();
715 let disperse = advz_scheme(GENESIS_VID_NUM_STORAGE_NODES)
716 .disperse(bytes)
717 .unwrap();
718
719 Self::new(leaf.block_header().clone(), VidCommon::V0(disperse.common))
720 }
721
722 pub fn block_hash(&self) -> BlockHash<Types> {
723 self.block_hash
724 }
725
726 pub fn payload_hash(&self) -> VidCommitment {
727 self.payload_hash
728 }
729
730 pub fn common(&self) -> &VidCommon {
731 &self.common
732 }
733}
734
735impl<Types: NodeType> HeightIndexed for VidCommonQueryData<Types> {
736 fn height(&self) -> u64 {
737 self.height
738 }
739}
740
741impl<Types: NodeType> HeightIndexed for (VidCommonQueryData<Types>, Option<VidShare>) {
742 fn height(&self) -> u64 {
743 self.0.height
744 }
745}
746
747#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
748#[serde(bound = "")]
749pub struct TransactionQueryData<Types: NodeType>
750where
751 Header<Types>: QueryableHeader<Types>,
752 Payload<Types>: QueryablePayload<Types>,
753{
754 transaction: Transaction<Types>,
755 hash: TransactionHash<Types>,
756 index: u64,
757 proof: TransactionInclusionProof<Types>,
758 block_hash: BlockHash<Types>,
759 block_height: u64,
760 namespace: NamespaceId<Types>,
761 pos_in_namespace: u32,
762}
763
764impl<Types: NodeType> TransactionQueryData<Types>
765where
766 Header<Types>: QueryableHeader<Types>,
767 Payload<Types>: QueryablePayload<Types>,
768{
769 pub(crate) fn new(
770 block: &BlockQueryData<Types>,
771 i: TransactionIndex<Types>,
772 index: u64,
773 ) -> Option<Self> {
774 let (transaction, proof) = block
775 .payload()
776 .transaction_with_proof(block.metadata(), &i)?;
777 Some(Self {
778 hash: transaction.commit(),
779 transaction,
780 index,
781 proof,
782 block_hash: block.hash(),
783 block_height: block.height(),
784 namespace: block.header().namespace_id(&i.ns_index)?,
785 pos_in_namespace: i.position,
786 })
787 }
788
789 pub(crate) fn with_hash(
790 block: &BlockQueryData<Types>,
791 hash: TransactionHash<Types>,
792 ) -> Option<Self> {
793 block
794 .enumerate()
795 .enumerate()
796 .find_map(|(i, (index, tx))| {
797 if tx.commit() == hash {
798 Some(Self::new(block, index, i as u64))
799 } else {
800 None
801 }
802 })
803 .flatten()
804 }
805
806 pub fn transaction(&self) -> &Transaction<Types> {
808 &self.transaction
809 }
810
811 pub fn hash(&self) -> TransactionHash<Types> {
813 self.hash
814 }
815
816 pub fn index(&self) -> u64 {
818 self.index
819 }
820
821 pub fn proof(&self) -> &TransactionInclusionProof<Types> {
823 &self.proof
824 }
825
826 pub fn block_height(&self) -> u64 {
828 self.block_height
829 }
830
831 pub fn block_hash(&self) -> BlockHash<Types> {
833 self.block_hash
834 }
835}
836
837pub(crate) fn payload_size<Types: NodeType>(payload: &Payload<Types>) -> u64 {
838 payload.encode().len() as u64
839}
840
841#[derive(Clone, Debug, Serialize, Deserialize, PartialEq, Eq)]
842#[serde(bound = "")]
843pub struct BlockSummaryQueryData<Types: NodeType>
844where
845 Header<Types>: QueryableHeader<Types>,
846{
847 pub(crate) header: Header<Types>,
848 pub(crate) hash: BlockHash<Types>,
849 pub(crate) size: u64,
850 pub(crate) num_transactions: u64,
851 pub(crate) namespaces: NamespaceMap<Types>,
852}
853
854impl<Types: NodeType> BlockSummaryQueryData<Types>
856where
857 Header<Types>: QueryableHeader<Types>,
858{
859 pub fn header(&self) -> &Header<Types> {
860 &self.header
861 }
862
863 pub fn hash(&self) -> BlockHash<Types> {
864 self.hash
865 }
866
867 pub fn size(&self) -> u64 {
868 self.size
869 }
870
871 pub fn num_transactions(&self) -> u64 {
872 self.num_transactions
873 }
874
875 pub fn namespaces(&self) -> &NamespaceMap<Types> {
876 &self.namespaces
877 }
878}
879
880impl<Types: NodeType> HeightIndexed for BlockSummaryQueryData<Types>
881where
882 Header<Types>: QueryableHeader<Types>,
883{
884 fn height(&self) -> u64 {
885 self.header.block_number()
886 }
887}
888
889#[derive(Clone, Debug, Serialize, Deserialize, PartialEq, Eq)]
890#[serde(bound = "")]
891pub struct TransactionSummaryQueryData<Types: NodeType> {
892 pub(crate) hash: TransactionHash<Types>,
893 pub(crate) header: Header<Types>,
894 pub(crate) transaction: Transaction<Types>,
898}
899
900impl<Types: NodeType> From<BlockQueryData<Types>> for BlockSummaryQueryData<Types>
904where
905 Header<Types>: QueryableHeader<Types>,
906 Payload<Types>: QueryablePayload<Types>,
907{
908 fn from(value: BlockQueryData<Types>) -> Self {
909 BlockSummaryQueryData {
910 namespaces: value.namespace_info(),
911 header: value.header,
912 hash: value.hash,
913 size: value.size,
914 num_transactions: value.num_transactions,
915 }
916 }
917}
918
919#[derive(Clone, Copy, Debug, Default, PartialEq, Eq, Deserialize, Serialize)]
920pub struct NamespaceInfo {
921 pub num_transactions: u64,
922 pub size: u64,
923}
924
925pub type NamespaceMap<Types> = HashMap<NamespaceId<Types>, NamespaceInfo>;
926
927#[derive(Clone, Debug, PartialEq, Eq)]
932pub struct PayloadMetadata<Types>
933where
934 Types: NodeType,
935 Header<Types>: QueryableHeader<Types>,
936{
937 pub height: u64,
938 pub block_hash: BlockHash<Types>,
939 pub hash: VidCommitment,
940 pub size: u64,
941 pub num_transactions: u64,
942 pub namespaces: NamespaceMap<Types>,
943}
944
945impl<Types> HeightIndexed for PayloadMetadata<Types>
946where
947 Types: NodeType,
948 Header<Types>: QueryableHeader<Types>,
949{
950 fn height(&self) -> u64 {
951 self.height
952 }
953}
954
955impl<Types> From<BlockQueryData<Types>> for PayloadMetadata<Types>
956where
957 Types: NodeType,
958 Header<Types>: QueryableHeader<Types>,
959 Payload<Types>: QueryablePayload<Types>,
960{
961 fn from(block: BlockQueryData<Types>) -> Self {
962 Self {
963 height: block.height(),
964 block_hash: block.hash(),
965 hash: block.payload_hash(),
966 size: block.size(),
967 num_transactions: block.num_transactions(),
968 namespaces: block.namespace_info(),
969 }
970 }
971}
972
973#[derive(Clone, Copy, Debug, PartialEq, Eq)]
978pub struct VidCommonMetadata<Types>
979where
980 Types: NodeType,
981{
982 pub height: u64,
983 pub block_hash: BlockHash<Types>,
984 pub payload_hash: VidCommitment,
985}
986
987impl<Types> HeightIndexed for VidCommonMetadata<Types>
988where
989 Types: NodeType,
990{
991 fn height(&self) -> u64 {
992 self.height
993 }
994}
995
996impl<Types> From<VidCommonQueryData<Types>> for VidCommonMetadata<Types>
997where
998 Types: NodeType,
999{
1000 fn from(common: VidCommonQueryData<Types>) -> Self {
1001 Self {
1002 height: common.height(),
1003 block_hash: common.block_hash(),
1004 payload_hash: common.payload_hash(),
1005 }
1006 }
1007}
1008
1009#[derive(Clone, Debug, Deserialize, Serialize, PartialEq, Eq, From)]
1010#[serde(bound = "")]
1011pub struct StateCertQueryData<Types: NodeType>(pub LightClientStateUpdateCertificate<Types>);
1012
1013#[derive(Clone, Copy, Debug, Deserialize, Serialize, PartialEq, Eq)]
1014pub struct Limits {
1015 pub small_object_range_limit: usize,
1016 pub large_object_range_limit: usize,
1017}
1018
1019impl<Types: NodeType> HeightIndexed for StateCertQueryData<Types> {
1020 fn height(&self) -> u64 {
1021 self.0.light_client_state.block_height
1022 }
1023}