Skip to main content

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::{Deserialize, Serialize, de::DeserializeOwned};
24use vbs::version::Version;
25
26use super::signature_key::BuilderSignatureKey;
27use crate::{
28    data::{Leaf2, VidCommitment, ViewNumber},
29    light_client::LightClientState,
30    traits::{ValidatedState, node_implementation::NodeType, states::InstanceState},
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    ///
96    /// The payload may leave out some of `transactions`, but must not change, repeat or add one:
97    /// when a payload kept them all, the new protocol's leader takes their hashes from its pool.
98    /// # Errors
99    /// If the transaction length conversion fails.
100    async fn from_transactions(
101        transactions: &[Self::Transaction],
102        validated_state: &Self::ValidatedState,
103        instance_state: &Self::Instance,
104    ) -> Result<(Self, Self::Metadata), Self::Error>;
105
106    /// Build a payload with the encoded transaction bytes, metadata,
107    /// and the associated number of VID storage nodes
108    fn from_bytes(encoded_transactions: &[u8], metadata: &Self::Metadata) -> Self;
109
110    /// Build the payload and metadata for genesis/null block.
111    fn empty() -> (Self, Self::Metadata);
112
113    /// List of transaction commitments.
114    fn transaction_commitments(
115        &self,
116        metadata: &Self::Metadata,
117    ) -> Vec<Commitment<Self::Transaction>> {
118        self.transactions(metadata).map(|tx| tx.commit()).collect()
119    }
120
121    /// Number of transactions in the block.
122    fn num_transactions(&self, metadata: &Self::Metadata) -> usize {
123        self.transactions(metadata).count()
124    }
125
126    /// Generate commitment that builders use to sign block options.
127    fn builder_commitment(&self, metadata: &Self::Metadata) -> BuilderCommitment;
128
129    /// Get the transactions in the payload.
130    fn transactions<'a>(
131        &'a self,
132        metadata: &'a Self::Metadata,
133    ) -> impl 'a + Iterator<Item = Self::Transaction>;
134
135    /// Get the number of bytes of transactions in the payload.
136    fn txn_bytes(&self) -> usize;
137}
138
139/// extra functions required on block to be usable by hotshot-testing
140pub trait TestableBlock<TYPES: NodeType>: BlockPayload<TYPES> + Debug {
141    /// generate a genesis block
142    fn genesis() -> Self;
143
144    /// the number of transactions in this block
145    fn txn_count(&self) -> u64;
146}
147
148/// The number of storage nodes to use when computing the genesis VID commitment.
149///
150/// The number of storage nodes for the genesis VID commitment is arbitrary, since we don't actually
151/// do dispersal for the genesis block. For simplicity and performance, we use 1.
152pub const GENESIS_VID_NUM_STORAGE_NODES: usize = 1;
153
154#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
155/// Information about builder fee for proposed block
156pub struct BuilderFee<TYPES: NodeType> {
157    /// Proposed fee amount
158    pub fee_amount: u64,
159    /// Account authorizing the fee.
160    pub fee_account: TYPES::BuilderSignatureKey,
161    /// Signature over fee amount by `fee_account`.
162    pub fee_signature: <TYPES::BuilderSignatureKey as BuilderSignatureKey>::BuilderSignature,
163}
164
165/// Header of a block, which commits to a [`BlockPayload`].
166pub trait BlockHeader<TYPES: NodeType>:
167    Serialize + Clone + Debug + Hash + PartialEq + Eq + Send + Sync + DeserializeOwned + Committable
168{
169    /// Error type for this type of block header
170    type Error: Error + Debug + Send + Sync;
171
172    /// Build a header with the parent validate state, instance-level state, parent leaf, payload
173    /// and builder commitments, and metadata. This is only used in pre-marketplace versions
174    #[allow(clippy::too_many_arguments)]
175    fn new(
176        parent_state: &TYPES::ValidatedState,
177        instance_state: &<TYPES::ValidatedState as ValidatedState<TYPES>>::Instance,
178        parent_leaf: &Leaf2<TYPES>,
179        payload_commitment: VidCommitment,
180        builder_commitment: BuilderCommitment,
181        metadata: <TYPES::BlockPayload as BlockPayload<TYPES>>::Metadata,
182        builder_fee: BuilderFee<TYPES>,
183        version: Version,
184        view_number: u64,
185    ) -> impl Future<Output = Result<Self, Self::Error>> + Send;
186
187    /// Build the genesis header, payload, and metadata.
188    fn genesis(
189        instance_state: &<TYPES::ValidatedState as ValidatedState<TYPES>>::Instance,
190        payload: TYPES::BlockPayload,
191        metadata: &<TYPES::BlockPayload as BlockPayload<TYPES>>::Metadata,
192        version: Version,
193    ) -> Self;
194
195    /// Get the block number.
196    fn block_number(&self) -> u64;
197
198    /// Get the timestamp.
199    fn timestamp(&self) -> u64;
200
201    /// Get the timestamp in milliseconds.
202    fn timestamp_millis(&self) -> u64;
203
204    /// Get the payload commitment.
205    fn payload_commitment(&self) -> VidCommitment;
206
207    /// Get the metadata.
208    fn metadata(&self) -> &<TYPES::BlockPayload as BlockPayload<TYPES>>::Metadata;
209
210    /// Get the protocol version for this block.
211    fn version(&self) -> Version;
212
213    /// Get the builder commitment
214    fn builder_commitment(&self) -> BuilderCommitment;
215
216    /// Get the light client state
217    fn get_light_client_state(&self, view: ViewNumber) -> anyhow::Result<LightClientState>;
218
219    /// Returns the `auth_root` value for versions >= V4 (`DrbAndHeaderUpgrade`).
220    ///
221    /// For versions < V4, this will return `None`.
222    ///
223    /// The `auth_root` is a 32-byte hash calculated using the reward Merkle tree
224    /// digest and other values.
225    /// It is used by the reward claim contract to verify the reward claim
226    fn auth_root(&self) -> anyhow::Result<FixedBytes<32>>;
227}