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