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