hotshot_types/traits/
block_contents.rs

1// Copyright (c) 2021-2024 Espresso Systems (espressosys.com)
2// This file is part of the HotShot repository.
3
4// You should have received a copy of the MIT License
5// along with the HotShot repository. If not, see <https://mit-license.org/>.
6
7//! Abstraction over the contents of a block
8//!
9//! This module provides the [`Transaction`], [`BlockPayload`], and [`BlockHeader`] traits, which
10//! describe the behaviors that a block is expected to have.
11
12use std::{
13    error::Error,
14    fmt::{Debug, Display},
15    future::Future,
16    hash::Hash,
17    sync::Arc,
18};
19
20use alloy::primitives::FixedBytes;
21use async_trait::async_trait;
22use committable::{Commitment, Committable};
23use serde::{de::DeserializeOwned, Deserialize, Serialize};
24use vbs::version::Version;
25
26use super::{node_implementation::Versions, signature_key::BuilderSignatureKey};
27use crate::{
28    data::{Leaf2, VidCommitment},
29    light_client::LightClientState,
30    traits::{node_implementation::NodeType, states::InstanceState, ValidatedState},
31    utils::BuilderCommitment,
32};
33
34/// Trait for structures that need to be unambiguously encoded as bytes.
35pub trait EncodeBytes {
36    /// Encode `&self`
37    fn encode(&self) -> Arc<[u8]>;
38}
39
40/// Abstraction over any type of transaction. Used by [`BlockPayload`].
41pub trait Transaction:
42    Clone + Serialize + DeserializeOwned + Debug + PartialEq + Eq + Sync + Send + Committable + Hash
43{
44    /// The function to estimate the transaction size
45    /// It takes in the transaction itself and a boolean indicating if the transaction adds a new namespace
46    /// Since each new namespace adds overhead
47    /// just ignore this parameter by default and use it when needed
48    fn minimum_block_size(&self) -> u64;
49}
50
51/// Abstraction over the full contents of a block
52///
53/// This trait encapsulates the behaviors that the transactions of a block must have in order to be
54/// used by consensus
55///   * Must have a predefined error type ([`BlockPayload::Error`])
56///   * Must have a transaction type that can be compared for equality, serialized and serialized,
57///     sent between threads, and can have a hash produced of it
58///   * Must be hashable
59#[async_trait]
60pub trait BlockPayload<TYPES: NodeType>:
61    Serialize
62    + Clone
63    + Debug
64    + Display
65    + Hash
66    + PartialEq
67    + Eq
68    + Send
69    + Sync
70    + DeserializeOwned
71    + EncodeBytes
72{
73    /// The error type for this type of block
74    type Error: Error + Debug + Send + Sync + Serialize + DeserializeOwned;
75
76    /// The type of the instance-level state this state is associated with
77    type Instance: InstanceState;
78    /// The type of the transitions we are applying
79    type Transaction: Transaction + Serialize + DeserializeOwned;
80    /// Validated State
81    type ValidatedState: ValidatedState<TYPES>;
82    /// Data created during block building which feeds into the block header
83    type Metadata: Clone
84        + Debug
85        + DeserializeOwned
86        + Eq
87        + Hash
88        + Send
89        + Sync
90        + Serialize
91        + EncodeBytes;
92
93    /// Build a payload and associated metadata with the transactions.
94    /// This function is asynchronous because it may need to request updated state from the peers via GET requests.
95    /// # Errors
96    /// If the transaction length conversion fails.
97    async fn from_transactions(
98        transactions: impl IntoIterator<Item = Self::Transaction> + Send,
99        validated_state: &Self::ValidatedState,
100        instance_state: &Self::Instance,
101    ) -> Result<(Self, Self::Metadata), Self::Error>;
102
103    /// Build a payload with the encoded transaction bytes, metadata,
104    /// and the associated number of VID storage nodes
105    fn from_bytes(encoded_transactions: &[u8], metadata: &Self::Metadata) -> Self;
106
107    /// Build the payload and metadata for genesis/null block.
108    fn empty() -> (Self, Self::Metadata);
109
110    /// List of transaction commitments.
111    fn transaction_commitments(
112        &self,
113        metadata: &Self::Metadata,
114    ) -> Vec<Commitment<Self::Transaction>> {
115        self.transactions(metadata).map(|tx| tx.commit()).collect()
116    }
117
118    /// Number of transactions in the block.
119    fn num_transactions(&self, metadata: &Self::Metadata) -> usize {
120        self.transactions(metadata).count()
121    }
122
123    /// Generate commitment that builders use to sign block options.
124    fn builder_commitment(&self, metadata: &Self::Metadata) -> BuilderCommitment;
125
126    /// Get the transactions in the payload.
127    fn transactions<'a>(
128        &'a self,
129        metadata: &'a Self::Metadata,
130    ) -> impl 'a + Iterator<Item = Self::Transaction>;
131
132    /// Get the number of bytes of transactions in the payload.
133    fn txn_bytes(&self) -> usize;
134}
135
136/// extra functions required on block to be usable by hotshot-testing
137pub trait TestableBlock<TYPES: NodeType>: BlockPayload<TYPES> + Debug {
138    /// generate a genesis block
139    fn genesis() -> Self;
140
141    /// the number of transactions in this block
142    fn txn_count(&self) -> u64;
143}
144
145/// The number of storage nodes to use when computing the genesis VID commitment.
146///
147/// The number of storage nodes for the genesis VID commitment is arbitrary, since we don't actually
148/// do dispersal for the genesis block. For simplicity and performance, we use 1.
149pub const GENESIS_VID_NUM_STORAGE_NODES: usize = 1;
150
151#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
152/// Information about builder fee for proposed block
153pub struct BuilderFee<TYPES: NodeType> {
154    /// Proposed fee amount
155    pub fee_amount: u64,
156    /// Account authorizing the fee.
157    pub fee_account: TYPES::BuilderSignatureKey,
158    /// Signature over fee amount by `fee_account`.
159    pub fee_signature: <TYPES::BuilderSignatureKey as BuilderSignatureKey>::BuilderSignature,
160}
161
162/// Header of a block, which commits to a [`BlockPayload`].
163pub trait BlockHeader<TYPES: NodeType>:
164    Serialize + Clone + Debug + Hash + PartialEq + Eq + Send + Sync + DeserializeOwned + Committable
165{
166    /// Error type for this type of block header
167    type Error: Error + Debug + Send + Sync;
168
169    /// Build a header with the parent validate state, instance-level state, parent leaf, payload
170    /// and builder commitments, and metadata. This is only used in pre-marketplace versions
171    #[allow(clippy::too_many_arguments)]
172    fn new(
173        parent_state: &TYPES::ValidatedState,
174        instance_state: &<TYPES::ValidatedState as ValidatedState<TYPES>>::Instance,
175        parent_leaf: &Leaf2<TYPES>,
176        payload_commitment: VidCommitment,
177        builder_commitment: BuilderCommitment,
178        metadata: <TYPES::BlockPayload as BlockPayload<TYPES>>::Metadata,
179        builder_fee: BuilderFee<TYPES>,
180        version: Version,
181        view_number: u64,
182    ) -> impl Future<Output = Result<Self, Self::Error>> + Send;
183
184    /// Build the genesis header, payload, and metadata.
185    fn genesis<V: Versions>(
186        instance_state: &<TYPES::ValidatedState as ValidatedState<TYPES>>::Instance,
187        payload: TYPES::BlockPayload,
188        metadata: &<TYPES::BlockPayload as BlockPayload<TYPES>>::Metadata,
189    ) -> Self;
190
191    /// Get the block number.
192    fn block_number(&self) -> u64;
193
194    /// Get the timestamp.
195    fn timestamp(&self) -> u64;
196
197    /// Get the timestamp in milliseconds.
198    fn timestamp_millis(&self) -> u64;
199
200    /// Get the payload commitment.
201    fn payload_commitment(&self) -> VidCommitment;
202
203    /// Get the metadata.
204    fn metadata(&self) -> &<TYPES::BlockPayload as BlockPayload<TYPES>>::Metadata;
205
206    /// Get the builder commitment
207    fn builder_commitment(&self) -> BuilderCommitment;
208
209    /// Get the light client state
210    fn get_light_client_state(&self, view: TYPES::View) -> anyhow::Result<LightClientState>;
211
212    /// Returns the `auth_root` value for versions >= V4 (`DrbAndHeaderUpgrade`).
213    ///
214    /// For versions < V4, this will return `None`.
215    ///
216    /// The `auth_root` is a 32-byte hash calculated using the reward Merkle tree
217    /// digest and other values.  
218    /// It is used by the reward claim contract to verify the reward claim
219    fn auth_root(&self) -> anyhow::Result<FixedBytes<32>>;
220}