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