1use std::{collections::HashMap, fmt::Debug, hash::Hash};
14
15use committable::{Commitment, Committable};
16use hotshot_types::{
17 data::{Leaf, Leaf2, VidCommitment, VidCommon, VidShare},
18 simple_certificate::QuorumCertificate2,
19 traits::{
20 self, EncodeBytes,
21 block_contents::{BlockHeader, GENESIS_VID_NUM_STORAGE_NODES},
22 node_implementation::NodeType,
23 },
24 vid::advz::{ADVZCommitment, ADVZCommon, advz_scheme},
25};
26use jf_advz::VidScheme;
27use serde::{Deserialize, Serialize, de::DeserializeOwned};
28use snafu::{Snafu, ensure};
29use vbs::version::Version;
30use versions::Upgrade;
31
32use crate::{Header, Metadata, Payload, QuorumCertificate, Transaction, types::HeightIndexed};
33
34pub type LeafHash<Types> = Commitment<Leaf2<Types>>;
35pub type LeafHashLegacy<Types> = Commitment<Leaf<Types>>;
36pub type QcHash<Types> = Commitment<QuorumCertificate2<Types>>;
37
38pub type BlockHash<Types> = Commitment<Header<Types>>;
43pub type TransactionHash<Types> = Commitment<Transaction<Types>>;
44pub type TransactionInclusionProof<Types> =
45 <Payload<Types> as QueryablePayload<Types>>::InclusionProof;
46pub type NamespaceIndex<Types> = <Header<Types> as QueryableHeader<Types>>::NamespaceIndex;
47pub type NamespaceId<Types> = <Header<Types> as QueryableHeader<Types>>::NamespaceId;
48
49pub type Timestamp = time::OffsetDateTime;
50
51pub trait QueryableHeader<Types: NodeType>: BlockHeader<Types> {
52 type NamespaceIndex: Clone + Debug + Hash + PartialEq + Eq + From<i64> + Into<i64> + Send + Sync;
54
55 type NamespaceId: Clone
57 + Debug
58 + Serialize
59 + DeserializeOwned
60 + Send
61 + Sync
62 + Hash
63 + PartialEq
64 + Eq
65 + Copy
66 + From<i64>
67 + Into<i64>;
68
69 fn namespace_id(&self, i: &Self::NamespaceIndex) -> Option<Self::NamespaceId>;
71
72 fn namespace_size(&self, i: &Self::NamespaceIndex, payload_size: usize) -> u64;
74
75 fn ns_table(&self) -> String;
77}
78
79#[derive(Clone, Debug, PartialEq, Eq)]
80pub struct TransactionIndex<Types: NodeType>
81where
82 Header<Types>: QueryableHeader<Types>,
83{
84 pub ns_index: NamespaceIndex<Types>,
86 pub position: u32,
88}
89
90pub trait VerifiableInclusion<Types: NodeType>:
97 Clone + Debug + PartialEq + Eq + Serialize + DeserializeOwned + Send + Sync
98{
99 fn verify(
102 &self,
103 metadata: &Metadata<Types>,
104 tx: &Transaction<Types>,
105 payload_commitment: &VidCommitment,
106 common: &VidCommon,
107 ) -> bool;
108}
109
110pub trait QueryablePayload<Types: NodeType>: traits::BlockPayload<Types>
119where
120 Header<Types>: QueryableHeader<Types>,
121{
122 type Iter<'a>: Iterator<Item = TransactionIndex<Types>>
124 where
125 Self: 'a;
126
127 type InclusionProof: VerifiableInclusion<Types>;
129
130 fn len(&self, meta: &Self::Metadata) -> usize;
132
133 fn is_empty(&self, meta: &Self::Metadata) -> bool {
135 self.len(meta) == 0
136 }
137
138 fn iter<'a>(&'a self, meta: &'a Self::Metadata) -> Self::Iter<'a>;
140
141 fn enumerate<'a>(
143 &'a self,
144 meta: &'a Self::Metadata,
145 ) -> Box<dyn 'a + Iterator<Item = (TransactionIndex<Types>, Self::Transaction)>> {
146 Box::new(self.iter(meta).map(|ix| {
147 let tx = self.transaction(meta, &ix).unwrap();
150 (ix, tx)
151 }))
152 }
153
154 fn transaction(
156 &self,
157 meta: &Self::Metadata,
158 index: &TransactionIndex<Types>,
159 ) -> Option<Self::Transaction>;
160
161 fn transaction_proof(
165 &self,
166 meta: &Self::Metadata,
167 vid: &VidCommonQueryData<Types>,
168 index: &TransactionIndex<Types>,
169 ) -> Option<Self::InclusionProof>;
170
171 fn nth(&self, meta: &Self::Metadata, n: usize) -> Option<TransactionIndex<Types>> {
173 self.iter(meta).nth(n)
174 }
175
176 fn nth_transaction(&self, meta: &Self::Metadata, n: usize) -> Option<Self::Transaction> {
178 self.transaction(meta, &self.nth(meta, n)?)
179 }
180
181 fn by_hash(
183 &self,
184 meta: &Self::Metadata,
185 hash: Commitment<Self::Transaction>,
186 ) -> Option<TransactionIndex<Types>> {
187 self.iter(meta).find(|i| {
188 if let Some(tx) = self.transaction(meta, i) {
189 tx.commit() == hash
190 } else {
191 false
192 }
193 })
194 }
195
196 fn transaction_by_hash(
198 &self,
199 meta: &Self::Metadata,
200 hash: Commitment<Self::Transaction>,
201 ) -> Option<Self::Transaction> {
202 self.transaction(meta, &self.by_hash(meta, hash)?)
203 }
204}
205
206#[derive(Clone, Debug, Serialize, Deserialize, PartialEq, Eq)]
207#[serde(bound = "")]
208pub struct LeafQueryData<Types: NodeType> {
209 pub(crate) leaf: Leaf2<Types>,
210 pub(crate) qc: QuorumCertificate2<Types>,
211}
212
213#[derive(Clone, Debug, Serialize, Deserialize, PartialEq, Eq)]
214#[serde(bound = "")]
215pub struct LeafQueryDataLegacy<Types: NodeType> {
216 pub(crate) leaf: Leaf<Types>,
217 pub(crate) qc: QuorumCertificate<Types>,
218}
219
220impl<Types: NodeType> From<LeafQueryDataLegacy<Types>> for LeafQueryData<Types> {
221 fn from(legacy: LeafQueryDataLegacy<Types>) -> Self {
222 Self {
223 leaf: legacy.leaf.into(),
224 qc: legacy.qc.to_qc2(),
225 }
226 }
227}
228
229#[derive(Clone, Debug, Snafu)]
230#[snafu(display("QC references leaf {qc_leaf}, but expected {leaf}"))]
231pub struct InconsistentLeafError<Types: NodeType> {
232 pub leaf: LeafHash<Types>,
233 pub qc_leaf: LeafHash<Types>,
234}
235
236#[derive(Clone, Debug, Snafu)]
237#[snafu(display("QC references leaf {qc_leaf}, but expected {leaf}"))]
238pub struct InconsistentLeafLegacyError<Types: NodeType> {
239 pub leaf: LeafHashLegacy<Types>,
240 pub qc_leaf: LeafHashLegacy<Types>,
241}
242
243impl<Types: NodeType> LeafQueryDataLegacy<Types> {
244 pub fn new(
252 mut leaf: Leaf<Types>,
253 qc: QuorumCertificate<Types>,
254 ) -> Result<Self, InconsistentLeafLegacyError<Types>> {
255 let leaf_commit = <Leaf<Types> as Committable>::commit(&leaf);
259 ensure!(
260 qc.data.leaf_commit == leaf_commit,
261 InconsistentLeafLegacySnafu {
262 leaf: leaf_commit,
263 qc_leaf: qc.data.leaf_commit
264 }
265 );
266
267 leaf.unfill_block_payload();
270
271 Ok(Self { leaf, qc })
272 }
273
274 pub async fn genesis(
275 validated_state: &Types::ValidatedState,
276 instance_state: &Types::InstanceState,
277 upgrade: Upgrade,
278 ) -> Self {
279 Self {
280 leaf: Leaf::genesis(validated_state, instance_state, upgrade.base).await,
281 qc: QuorumCertificate::genesis(validated_state, instance_state, upgrade).await,
282 }
283 }
284
285 pub fn leaf(&self) -> &Leaf<Types> {
286 &self.leaf
287 }
288
289 pub fn qc(&self) -> &QuorumCertificate<Types> {
290 &self.qc
291 }
292
293 pub fn header(&self) -> &Header<Types> {
294 self.leaf.block_header()
295 }
296
297 pub fn hash(&self) -> LeafHashLegacy<Types> {
298 <Leaf<Types> as Committable>::commit(&self.leaf)
302 }
303
304 pub fn block_hash(&self) -> BlockHash<Types> {
305 self.header().commit()
306 }
307
308 pub fn payload_hash(&self) -> VidCommitment {
309 self.header().payload_commitment()
310 }
311}
312
313impl<Types: NodeType> LeafQueryData<Types> {
314 pub fn new(
322 mut leaf: Leaf2<Types>,
323 qc: QuorumCertificate2<Types>,
324 ) -> Result<Self, InconsistentLeafError<Types>> {
325 let leaf_commit = <Leaf2<Types> as Committable>::commit(&leaf);
329 ensure!(
330 qc.data.leaf_commit == leaf_commit,
331 InconsistentLeafSnafu {
332 leaf: leaf_commit,
333 qc_leaf: qc.data.leaf_commit
334 }
335 );
336
337 leaf.unfill_block_payload();
340
341 Ok(Self { leaf, qc })
342 }
343
344 pub async fn genesis(
345 validated_state: &Types::ValidatedState,
346 instance_state: &Types::InstanceState,
347 upgrade: Upgrade,
348 ) -> Self {
349 Self {
350 leaf: Leaf2::genesis(validated_state, instance_state, upgrade.base).await,
351 qc: QuorumCertificate2::genesis(validated_state, instance_state, upgrade).await,
352 }
353 }
354
355 pub fn leaf(&self) -> &Leaf2<Types> {
356 &self.leaf
357 }
358
359 pub fn qc(&self) -> &QuorumCertificate2<Types> {
360 &self.qc
361 }
362
363 pub fn header(&self) -> &Header<Types> {
364 self.leaf.block_header()
365 }
366
367 pub fn hash(&self) -> LeafHash<Types> {
368 <Leaf2<Types> as Committable>::commit(&self.leaf)
372 }
373
374 pub fn block_hash(&self) -> BlockHash<Types> {
375 self.header().commit()
376 }
377
378 pub fn payload_hash(&self) -> VidCommitment {
379 self.header().payload_commitment()
380 }
381}
382
383impl<Types: NodeType> HeightIndexed for LeafQueryData<Types> {
384 fn height(&self) -> u64 {
385 self.header().block_number()
386 }
387}
388
389impl<Types: NodeType> HeightIndexed for LeafQueryDataLegacy<Types> {
390 fn height(&self) -> u64 {
391 self.header().block_number()
392 }
393}
394
395#[derive(Clone, Debug, Serialize, serde::Deserialize, PartialEq, Eq)]
396#[serde(bound = "")]
397pub struct HeaderQueryData<Types: NodeType> {
398 pub header: Header<Types>,
399}
400
401impl<Types: NodeType> HeaderQueryData<Types> {
402 pub fn new(header: Header<Types>) -> Self {
403 Self { header }
404 }
405
406 pub fn header(&self) -> &Header<Types> {
407 &self.header
408 }
409}
410
411#[derive(Clone, Debug, Serialize, Deserialize, PartialEq, Eq)]
412#[serde(bound = "")]
413pub struct BlockQueryData<Types: NodeType> {
414 pub(crate) header: Header<Types>,
415 pub(crate) payload: Payload<Types>,
416 pub(crate) hash: BlockHash<Types>,
417 pub(crate) size: u64,
418 pub(crate) num_transactions: u64,
419}
420
421impl<Types: NodeType> BlockQueryData<Types> {
422 pub fn new(header: Header<Types>, payload: Payload<Types>) -> Self
423 where
424 Header<Types>: QueryableHeader<Types>,
425 Payload<Types>: QueryablePayload<Types>,
426 {
427 Self {
428 hash: header.commit(),
429 size: payload_size::<Types>(&payload),
430 num_transactions: payload.len(header.metadata()) as u64,
431 header,
432 payload,
433 }
434 }
435
436 pub async fn genesis(
437 validated_state: &Types::ValidatedState,
438 instance_state: &Types::InstanceState,
439 base: Version,
440 ) -> Self
441 where
442 Header<Types>: QueryableHeader<Types>,
443 Payload<Types>: QueryablePayload<Types>,
444 {
445 let leaf = Leaf2::<Types>::genesis(validated_state, instance_state, base).await;
446 Self::new(leaf.block_header().clone(), leaf.block_payload().unwrap())
447 }
448
449 pub fn header(&self) -> &Header<Types> {
450 &self.header
451 }
452
453 pub fn metadata(&self) -> &Metadata<Types> {
454 self.header.metadata()
455 }
456
457 pub fn payload_hash(&self) -> VidCommitment {
458 self.header.payload_commitment()
459 }
460
461 pub fn payload(&self) -> &Payload<Types> {
462 &self.payload
463 }
464
465 pub fn hash(&self) -> BlockHash<Types> {
466 self.hash
467 }
468
469 pub fn size(&self) -> u64 {
470 self.size
471 }
472
473 pub fn num_transactions(&self) -> u64 {
474 self.num_transactions
475 }
476
477 pub fn namespace_info(&self) -> NamespaceMap<Types>
478 where
479 Header<Types>: QueryableHeader<Types>,
480 Payload<Types>: QueryablePayload<Types>,
481 {
482 let mut map = NamespaceMap::<Types>::new();
483 for tx in self.payload.iter(self.header.metadata()) {
484 let Some(ns_id) = self.header.namespace_id(&tx.ns_index) else {
485 continue;
486 };
487 map.entry(ns_id)
488 .or_insert_with(|| NamespaceInfo {
489 num_transactions: 0,
490 size: self.header.namespace_size(&tx.ns_index, self.size as usize),
491 })
492 .num_transactions += 1;
493 }
494 map
495 }
496}
497
498impl<Types: NodeType> BlockQueryData<Types>
499where
500 Header<Types>: QueryableHeader<Types>,
501 Payload<Types>: QueryablePayload<Types>,
502{
503 pub fn transaction(&self, ix: &TransactionIndex<Types>) -> Option<Transaction<Types>> {
504 self.payload().transaction(self.metadata(), ix)
505 }
506
507 pub fn transaction_by_hash(
508 &self,
509 hash: Commitment<Transaction<Types>>,
510 ) -> Option<TransactionIndex<Types>> {
511 self.payload().by_hash(self.metadata(), hash)
512 }
513
514 pub fn transaction_proof(
515 &self,
516 vid_common: &VidCommonQueryData<Types>,
517 ix: &TransactionIndex<Types>,
518 ) -> Option<TransactionInclusionProof<Types>> {
519 self.payload()
520 .transaction_proof(self.metadata(), vid_common, ix)
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(
592 validated_state: &Types::ValidatedState,
593 instance_state: &Types::InstanceState,
594 base: Version,
595 ) -> Self
596 where
597 Header<Types>: QueryableHeader<Types>,
598 Payload<Types>: QueryablePayload<Types>,
599 {
600 BlockQueryData::genesis(validated_state, instance_state, base)
601 .await
602 .into()
603 }
604
605 pub fn hash(&self) -> VidCommitment {
606 self.hash
607 }
608
609 pub fn block_hash(&self) -> BlockHash<Types> {
610 self.block_hash
611 }
612
613 pub fn size(&self) -> u64 {
614 self.size
615 }
616
617 pub fn data(&self) -> &Payload<Types> {
618 &self.data
619 }
620}
621
622impl<Types: NodeType> HeightIndexed for PayloadQueryData<Types> {
623 fn height(&self) -> u64 {
624 self.height
625 }
626}
627
628#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
630#[serde(bound = "")]
631pub struct ADVZCommonQueryData<Types: NodeType> {
632 pub(crate) height: u64,
633 pub(crate) block_hash: BlockHash<Types>,
634 pub(crate) payload_hash: ADVZCommitment,
635 pub(crate) common: ADVZCommon,
636}
637
638impl<Types: NodeType> ADVZCommonQueryData<Types> {
639 pub fn new(header: Header<Types>, common: ADVZCommon) -> anyhow::Result<Self> {
640 let VidCommitment::V0(payload_hash) = header.payload_commitment() else {
641 return Err(anyhow::anyhow!("Inconsistent header type."));
642 };
643 Ok(Self {
644 height: header.block_number(),
645 block_hash: header.commit(),
646 payload_hash,
647 common,
648 })
649 }
650
651 pub async fn genesis(
652 validated_state: &Types::ValidatedState,
653 instance_state: &Types::InstanceState,
654 base: Version,
655 ) -> anyhow::Result<Self> {
656 let leaf = Leaf::<Types>::genesis(validated_state, instance_state, base).await;
657 let payload = leaf.block_payload().unwrap();
658 let bytes = payload.encode();
659 let disperse = advz_scheme(GENESIS_VID_NUM_STORAGE_NODES)
660 .disperse(bytes)
661 .unwrap();
662
663 Self::new(leaf.block_header().clone(), disperse.common)
664 }
665
666 pub fn block_hash(&self) -> BlockHash<Types> {
667 self.block_hash
668 }
669
670 pub fn payload_hash(&self) -> ADVZCommitment {
671 self.payload_hash
672 }
673
674 pub fn common(&self) -> &ADVZCommon {
675 &self.common
676 }
677}
678
679impl<Types: NodeType> HeightIndexed for ADVZCommonQueryData<Types> {
680 fn height(&self) -> u64 {
681 self.height
682 }
683}
684
685impl<Types: NodeType> HeightIndexed for (ADVZCommonQueryData<Types>, Option<VidShare>) {
686 fn height(&self) -> u64 {
687 self.0.height
688 }
689}
690
691#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
692#[serde(bound = "")]
693pub struct VidCommonQueryData<Types: NodeType> {
694 pub(crate) height: u64,
695 pub(crate) block_hash: BlockHash<Types>,
696 pub(crate) payload_hash: VidCommitment,
697 pub(crate) common: VidCommon,
698}
699
700impl<Types: NodeType> VidCommonQueryData<Types> {
701 pub fn new(header: Header<Types>, common: VidCommon) -> Self {
702 Self {
703 height: header.block_number(),
704 block_hash: header.commit(),
705 payload_hash: header.payload_commitment(),
706 common,
707 }
708 }
709
710 pub async fn genesis(
711 validated_state: &Types::ValidatedState,
712 instance_state: &Types::InstanceState,
713 base: Version,
714 ) -> Self {
715 let leaf = Leaf::<Types>::genesis(validated_state, instance_state, base).await;
716 let payload = leaf.block_payload().unwrap();
717 let bytes = payload.encode();
718 let disperse = advz_scheme(GENESIS_VID_NUM_STORAGE_NODES)
719 .disperse(bytes)
720 .unwrap();
721
722 Self::new(leaf.block_header().clone(), VidCommon::V0(disperse.common))
723 }
724
725 pub fn block_hash(&self) -> BlockHash<Types> {
726 self.block_hash
727 }
728
729 pub fn payload_hash(&self) -> VidCommitment {
730 self.payload_hash
731 }
732
733 pub fn common(&self) -> &VidCommon {
734 &self.common
735 }
736}
737
738impl<Types: NodeType> HeightIndexed for VidCommonQueryData<Types> {
739 fn height(&self) -> u64 {
740 self.height
741 }
742}
743
744impl<Types: NodeType> HeightIndexed for (VidCommonQueryData<Types>, Option<VidShare>) {
745 fn height(&self) -> u64 {
746 self.0.height
747 }
748}
749
750#[derive(Clone, Debug, PartialEq, Eq)]
751pub struct BlockWithTransaction<Types: NodeType>
752where
753 Header<Types>: QueryableHeader<Types>,
754 Payload<Types>: QueryablePayload<Types>,
755{
756 pub block: BlockQueryData<Types>,
757 pub transaction: TransactionQueryData<Types>,
758 pub index: TransactionIndex<Types>,
759}
760
761impl<Types: NodeType> BlockWithTransaction<Types>
762where
763 Header<Types>: QueryableHeader<Types>,
764 Payload<Types>: QueryablePayload<Types>,
765{
766 pub fn with_hash(block: BlockQueryData<Types>, hash: TransactionHash<Types>) -> Option<Self> {
767 let (tx, i, index) = block.enumerate().enumerate().find_map(|(i, (index, tx))| {
768 if tx.commit() == hash {
769 Some((tx, i as u64, index))
770 } else {
771 None
772 }
773 })?;
774 let transaction = TransactionQueryData::new(tx, &block, &index, i)?;
775
776 Some(BlockWithTransaction {
777 block,
778 transaction,
779 index,
780 })
781 }
782}
783
784#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
785#[serde(bound = "")]
786pub struct TransactionQueryData<Types: NodeType>
787where
788 Header<Types>: QueryableHeader<Types>,
789 Payload<Types>: QueryablePayload<Types>,
790{
791 transaction: Transaction<Types>,
792 hash: TransactionHash<Types>,
793 index: u64,
794 block_hash: BlockHash<Types>,
795 block_height: u64,
796 namespace: NamespaceId<Types>,
797 pos_in_namespace: u32,
798}
799
800#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
801#[serde(bound = "")]
802pub struct TransactionWithProofQueryData<Types: NodeType>
803where
804 Header<Types>: QueryableHeader<Types>,
805 Payload<Types>: QueryablePayload<Types>,
806{
807 transaction: Transaction<Types>,
815 hash: TransactionHash<Types>,
816 index: u64,
817 proof: TransactionInclusionProof<Types>,
818 block_hash: BlockHash<Types>,
819 block_height: u64,
820 namespace: NamespaceId<Types>,
821 pos_in_namespace: u32,
822}
823
824impl<Types: NodeType> TransactionQueryData<Types>
825where
826 Header<Types>: QueryableHeader<Types>,
827 Payload<Types>: QueryablePayload<Types>,
828{
829 pub fn new(
830 transaction: Transaction<Types>,
831 block: &BlockQueryData<Types>,
832 i: &TransactionIndex<Types>,
833 index: u64,
834 ) -> Option<Self> {
835 Some(Self {
836 hash: transaction.commit(),
837 transaction,
838 index,
839 block_hash: block.hash(),
840 block_height: block.height(),
841 namespace: block.header().namespace_id(&i.ns_index)?,
842 pos_in_namespace: i.position,
843 })
844 }
845
846 pub fn transaction(&self) -> &Transaction<Types> {
848 &self.transaction
849 }
850
851 pub fn hash(&self) -> TransactionHash<Types> {
853 self.hash
854 }
855
856 pub fn index(&self) -> u64 {
858 self.index
859 }
860
861 pub fn block_height(&self) -> u64 {
863 self.block_height
864 }
865
866 pub fn block_hash(&self) -> BlockHash<Types> {
868 self.block_hash
869 }
870}
871
872impl<Types: NodeType> TransactionWithProofQueryData<Types>
873where
874 Header<Types>: QueryableHeader<Types>,
875 Payload<Types>: QueryablePayload<Types>,
876{
877 pub fn new(data: TransactionQueryData<Types>, proof: TransactionInclusionProof<Types>) -> Self {
878 Self {
879 proof,
880 transaction: data.transaction,
881 hash: data.hash,
882 index: data.index,
883 block_hash: data.block_hash,
884 block_height: data.block_height,
885 namespace: data.namespace,
886 pos_in_namespace: data.pos_in_namespace,
887 }
888 }
889
890 pub fn proof(&self) -> &TransactionInclusionProof<Types> {
892 &self.proof
893 }
894
895 pub fn transaction(&self) -> &Transaction<Types> {
897 &self.transaction
898 }
899
900 pub fn hash(&self) -> TransactionHash<Types> {
902 self.hash
903 }
904
905 pub fn index(&self) -> u64 {
907 self.index
908 }
909
910 pub fn block_height(&self) -> u64 {
912 self.block_height
913 }
914
915 pub fn block_hash(&self) -> BlockHash<Types> {
917 self.block_hash
918 }
919}
920
921pub(crate) fn payload_size<Types: NodeType>(payload: &Payload<Types>) -> u64 {
922 payload.encode().len() as u64
923}
924
925#[derive(Clone, Debug, Serialize, Deserialize, PartialEq, Eq)]
926#[serde(bound = "")]
927pub struct BlockSummaryQueryData<Types: NodeType>
928where
929 Header<Types>: QueryableHeader<Types>,
930{
931 pub(crate) header: Header<Types>,
932 pub(crate) hash: BlockHash<Types>,
933 pub(crate) size: u64,
934 pub(crate) num_transactions: u64,
935 pub(crate) namespaces: NamespaceMap<Types>,
936}
937
938impl<Types: NodeType> BlockSummaryQueryData<Types>
940where
941 Header<Types>: QueryableHeader<Types>,
942{
943 pub fn header(&self) -> &Header<Types> {
944 &self.header
945 }
946
947 pub fn hash(&self) -> BlockHash<Types> {
948 self.hash
949 }
950
951 pub fn size(&self) -> u64 {
952 self.size
953 }
954
955 pub fn num_transactions(&self) -> u64 {
956 self.num_transactions
957 }
958
959 pub fn namespaces(&self) -> &NamespaceMap<Types> {
960 &self.namespaces
961 }
962}
963
964impl<Types: NodeType> HeightIndexed for BlockSummaryQueryData<Types>
965where
966 Header<Types>: QueryableHeader<Types>,
967{
968 fn height(&self) -> u64 {
969 self.header.block_number()
970 }
971}
972
973#[derive(Clone, Debug, Serialize, Deserialize, PartialEq, Eq)]
974#[serde(bound = "")]
975pub struct TransactionSummaryQueryData<Types: NodeType> {
976 pub(crate) hash: TransactionHash<Types>,
977 pub(crate) header: Header<Types>,
978 pub(crate) transaction: Transaction<Types>,
982}
983
984impl<Types: NodeType> From<BlockQueryData<Types>> for BlockSummaryQueryData<Types>
988where
989 Header<Types>: QueryableHeader<Types>,
990 Payload<Types>: QueryablePayload<Types>,
991{
992 fn from(value: BlockQueryData<Types>) -> Self {
993 BlockSummaryQueryData {
994 namespaces: value.namespace_info(),
995 header: value.header,
996 hash: value.hash,
997 size: value.size,
998 num_transactions: value.num_transactions,
999 }
1000 }
1001}
1002
1003#[derive(Clone, Copy, Debug, Default, PartialEq, Eq, Deserialize, Serialize)]
1004pub struct NamespaceInfo {
1005 pub num_transactions: u64,
1006 pub size: u64,
1007}
1008
1009pub type NamespaceMap<Types> = HashMap<NamespaceId<Types>, NamespaceInfo>;
1010
1011#[derive(Clone, Debug, PartialEq, Eq)]
1016pub struct PayloadMetadata<Types>
1017where
1018 Types: NodeType,
1019 Header<Types>: QueryableHeader<Types>,
1020{
1021 pub height: u64,
1022 pub block_hash: BlockHash<Types>,
1023 pub hash: VidCommitment,
1024 pub size: u64,
1025 pub num_transactions: u64,
1026 pub namespaces: NamespaceMap<Types>,
1027}
1028
1029impl<Types> HeightIndexed for PayloadMetadata<Types>
1030where
1031 Types: NodeType,
1032 Header<Types>: QueryableHeader<Types>,
1033{
1034 fn height(&self) -> u64 {
1035 self.height
1036 }
1037}
1038
1039impl<Types> From<BlockQueryData<Types>> for PayloadMetadata<Types>
1040where
1041 Types: NodeType,
1042 Header<Types>: QueryableHeader<Types>,
1043 Payload<Types>: QueryablePayload<Types>,
1044{
1045 fn from(block: BlockQueryData<Types>) -> Self {
1046 Self {
1047 height: block.height(),
1048 block_hash: block.hash(),
1049 hash: block.payload_hash(),
1050 size: block.size(),
1051 num_transactions: block.num_transactions(),
1052 namespaces: block.namespace_info(),
1053 }
1054 }
1055}
1056
1057#[derive(Clone, Copy, Debug, PartialEq, Eq)]
1062pub struct VidCommonMetadata<Types>
1063where
1064 Types: NodeType,
1065{
1066 pub height: u64,
1067 pub block_hash: BlockHash<Types>,
1068 pub payload_hash: VidCommitment,
1069}
1070
1071impl<Types> HeightIndexed for VidCommonMetadata<Types>
1072where
1073 Types: NodeType,
1074{
1075 fn height(&self) -> u64 {
1076 self.height
1077 }
1078}
1079
1080impl<Types> From<VidCommonQueryData<Types>> for VidCommonMetadata<Types>
1081where
1082 Types: NodeType,
1083{
1084 fn from(common: VidCommonQueryData<Types>) -> Self {
1085 Self {
1086 height: common.height(),
1087 block_hash: common.block_hash(),
1088 payload_hash: common.payload_hash(),
1089 }
1090 }
1091}
1092
1093#[derive(Clone, Copy, Debug, Deserialize, Serialize, PartialEq, Eq)]
1094pub struct Limits {
1095 pub small_object_range_limit: usize,
1096 pub large_object_range_limit: usize,
1097}