hotshot_types/traits/
storage.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//! Abstract storage type for storing DA proposals and VID shares
8//!
9//! This modules provides the [`Storage`] trait.
10//!
11
12use std::sync::Arc;
13
14use anyhow::{anyhow, ensure, Result};
15use async_trait::async_trait;
16use futures::future::BoxFuture;
17
18use super::node_implementation::NodeType;
19use crate::{
20    data::{
21        DaProposal, DaProposal2, QuorumProposal, QuorumProposal2, QuorumProposalWrapper,
22        VidCommitment, VidDisperseShare,
23    },
24    drb::{DrbInput, DrbResult},
25    event::HotShotAction,
26    message::{convert_proposal, Proposal},
27    simple_certificate::{
28        LightClientStateUpdateCertificateV2, NextEpochQuorumCertificate2, QuorumCertificate,
29        QuorumCertificate2, UpgradeCertificate,
30    },
31};
32
33/// Abstraction for storing a variety of consensus payload datum.
34#[async_trait]
35pub trait Storage<TYPES: NodeType>: Send + Sync + Clone + 'static {
36    /// Add a proposal to the stored VID proposals.
37    async fn append_vid(&self, proposal: &Proposal<TYPES, VidDisperseShare<TYPES>>) -> Result<()>;
38
39    /// Add a proposal to the stored DA proposals.
40    async fn append_da(
41        &self,
42        proposal: &Proposal<TYPES, DaProposal<TYPES>>,
43        vid_commit: VidCommitment,
44    ) -> Result<()>;
45    /// Add a proposal to the stored DA proposals.
46    async fn append_da2(
47        &self,
48        proposal: &Proposal<TYPES, DaProposal2<TYPES>>,
49        vid_commit: VidCommitment,
50    ) -> Result<()> {
51        self.append_da(&convert_proposal(proposal.clone()), vid_commit)
52            .await
53    }
54    /// Add a proposal we sent to the store
55    async fn append_proposal(
56        &self,
57        proposal: &Proposal<TYPES, QuorumProposal<TYPES>>,
58    ) -> Result<()>;
59    /// Add a proposal we sent to the store
60    async fn append_proposal2(
61        &self,
62        proposal: &Proposal<TYPES, QuorumProposal2<TYPES>>,
63    ) -> Result<()>;
64    /// Add a proposal we sent to the store
65    async fn append_proposal_wrapper(
66        &self,
67        proposal: &Proposal<TYPES, QuorumProposalWrapper<TYPES>>,
68    ) -> Result<()> {
69        self.append_proposal2(&convert_proposal(proposal.clone()))
70            .await
71    }
72    /// Record a HotShotAction taken.
73    async fn record_action(
74        &self,
75        view: TYPES::View,
76        epoch: Option<TYPES::Epoch>,
77        action: HotShotAction,
78    ) -> Result<()>;
79    /// Update the current high QC in storage.
80    async fn update_high_qc(&self, high_qc: QuorumCertificate<TYPES>) -> Result<()>;
81    /// Update the current high QC in storage.
82    async fn update_high_qc2(&self, high_qc: QuorumCertificate2<TYPES>) -> Result<()> {
83        self.update_high_qc(high_qc.to_qc()).await
84    }
85    /// Update the light client state update certificate in storage.
86    async fn update_state_cert(
87        &self,
88        state_cert: LightClientStateUpdateCertificateV2<TYPES>,
89    ) -> Result<()>;
90
91    async fn update_high_qc2_and_state_cert(
92        &self,
93        high_qc: QuorumCertificate2<TYPES>,
94        state_cert: LightClientStateUpdateCertificateV2<TYPES>,
95    ) -> Result<()> {
96        self.update_high_qc2(high_qc).await?;
97        self.update_state_cert(state_cert).await
98    }
99    /// Update the current high QC in storage.
100    async fn update_next_epoch_high_qc2(
101        &self,
102        _next_epoch_high_qc: NextEpochQuorumCertificate2<TYPES>,
103    ) -> Result<()>;
104
105    /// Update the current eQC in storage.
106    async fn update_eqc(
107        &self,
108        _high_qc: QuorumCertificate2<TYPES>,
109        _next_epoch_high_qc: NextEpochQuorumCertificate2<TYPES>,
110    ) -> Result<()>;
111
112    /// Upgrade the current decided upgrade certificate in storage.
113    async fn update_decided_upgrade_certificate(
114        &self,
115        decided_upgrade_certificate: Option<UpgradeCertificate<TYPES>>,
116    ) -> Result<()>;
117    /// Migrate leaves from `Leaf` to `Leaf2`, and proposals from `QuorumProposal` to `QuorumProposal2`
118    async fn migrate_storage(&self) -> Result<()> {
119        Ok(())
120    }
121    /// Add a drb result
122    async fn store_drb_result(&self, epoch: TYPES::Epoch, drb_result: DrbResult) -> Result<()>;
123    /// Add an epoch block header
124    async fn store_epoch_root(
125        &self,
126        epoch: TYPES::Epoch,
127        block_header: TYPES::BlockHeader,
128    ) -> Result<()>;
129    async fn load_drb_result(&self, epoch: TYPES::Epoch) -> Result<DrbResult> {
130        match self.load_drb_input(*epoch).await {
131            Ok(drb_input) => {
132                ensure!(drb_input.iteration == drb_input.difficulty_level);
133
134                Ok(drb_input.value)
135            },
136            Err(e) => Err(e),
137        }
138    }
139    async fn store_drb_input(&self, drb_input: DrbInput) -> Result<()>;
140    async fn load_drb_input(&self, _epoch: u64) -> Result<DrbInput>;
141}
142
143pub async fn load_drb_input_impl<TYPES: NodeType>(
144    storage: impl Storage<TYPES>,
145    epoch: u64,
146) -> Result<DrbInput> {
147    storage.load_drb_input(epoch).await
148}
149
150pub type LoadDrbProgressFn =
151    std::sync::Arc<dyn Fn(u64) -> BoxFuture<'static, Result<DrbInput>> + Send + Sync>;
152
153pub fn load_drb_progress_fn<TYPES: NodeType>(
154    storage: impl Storage<TYPES> + 'static,
155) -> LoadDrbProgressFn {
156    Arc::new(move |epoch| {
157        let storage = storage.clone();
158        Box::pin(load_drb_input_impl(storage, epoch))
159    })
160}
161
162pub fn null_load_drb_progress_fn() -> LoadDrbProgressFn {
163    Arc::new(move |_drb_input| {
164        Box::pin(async { Err(anyhow!("Using null implementation of load_drb_input")) })
165    })
166}
167
168pub async fn store_drb_input_impl<TYPES: NodeType>(
169    storage: impl Storage<TYPES>,
170    drb_input: DrbInput,
171) -> Result<()> {
172    storage.store_drb_input(drb_input).await
173}
174
175pub type StoreDrbProgressFn =
176    std::sync::Arc<dyn Fn(DrbInput) -> BoxFuture<'static, Result<()>> + Send + Sync>;
177
178pub fn store_drb_progress_fn<TYPES: NodeType>(
179    storage: impl Storage<TYPES> + 'static,
180) -> StoreDrbProgressFn {
181    Arc::new(move |drb_input| {
182        let storage = storage.clone();
183        Box::pin(store_drb_input_impl(storage, drb_input))
184    })
185}
186
187pub fn null_store_drb_progress_fn() -> StoreDrbProgressFn {
188    Arc::new(move |_drb_input| Box::pin(async { Ok(()) }))
189}
190
191pub type StoreDrbResultFn<TYPES> = Arc<
192    Box<
193        dyn Fn(<TYPES as NodeType>::Epoch, DrbResult) -> BoxFuture<'static, Result<()>>
194            + Send
195            + Sync
196            + 'static,
197    >,
198>;
199
200async fn store_drb_result_impl<TYPES: NodeType>(
201    storage: impl Storage<TYPES>,
202    epoch: TYPES::Epoch,
203    drb_result: DrbResult,
204) -> Result<()> {
205    storage.store_drb_result(epoch, drb_result).await
206}
207
208/// Helper function to create a callback to add a drb result to storage
209pub fn store_drb_result_fn<TYPES: NodeType>(
210    storage: impl Storage<TYPES> + 'static,
211) -> StoreDrbResultFn<TYPES> {
212    Arc::new(Box::new(move |epoch, drb_result| {
213        let st = storage.clone();
214        Box::pin(store_drb_result_impl(st, epoch, drb_result))
215    }))
216}