Skip to main content

espresso_node/api/
context.rs

1//! [`ApiState`](super::ApiState) reaches consensus and node-wide state only through
2//! [`ApiContext`], so the same API modules can be served by a validator ([`SequencerContext`])
3//! or by a node that follows the chain without taking part in consensus.
4
5use std::{collections::HashMap, sync::Arc, time::Duration};
6
7use ::light_client::{
8    LightClient,
9    client::{FallbackClient, QueryServiceClient},
10    storage::SqlStorage,
11};
12use async_lock::RwLock;
13use async_trait::async_trait;
14use committable::{Commitment, Committable};
15use espresso_types::{
16    Leaf2, NodeState, PubKey, SeqTypes, Transaction, ValidatedState,
17    v0::traits::{MembershipPersistence, SequencerPersistence, StateCertPersistence},
18};
19use futures::future::BoxFuture;
20use hotshot_query_service::availability::VidCommonQueryData;
21use hotshot_types::{
22    ValidatorConfig,
23    data::{EpochNumber, VidShare, ViewNumber},
24    epoch_membership::EpochMembershipCoordinator,
25    message::UpgradeLock,
26    network::NetworkConfig,
27    utils::StateAndDelta,
28};
29
30use crate::{
31    SequencerContext, consensus_handle::ConsensusHandle, context::TaskList,
32    state_signature::StateSignatureMemStorage,
33};
34
35pub type NodeLightClient = LightClient<SqlStorage, FallbackClient<QueryServiceClient>>;
36
37pub type Delta = <ValidatedState as hotshot_types::traits::ValidatedState<SeqTypes>>::Delta;
38
39#[async_trait]
40pub trait ConsensusSource: Send + Sync + 'static {
41    async fn decided_leaf(&self) -> Leaf2;
42    async fn decided_state(&self) -> Option<Arc<ValidatedState>>;
43    async fn state(&self, view: ViewNumber) -> Option<Arc<ValidatedState>>;
44    async fn state_and_delta(&self, view: ViewNumber) -> StateAndDelta<SeqTypes>;
45    async fn undecided_leaves(&self) -> Vec<Leaf2>;
46    async fn current_epoch(&self) -> Option<EpochNumber>;
47    async fn membership_coordinator(&self) -> EpochMembershipCoordinator<SeqTypes>;
48    async fn upgrade_lock(&self) -> UpgradeLock<SeqTypes>;
49    /// The commitment the accepting node reports, which the submit API returns.
50    async fn submit_transaction(&self, tx: Transaction) -> anyhow::Result<Commitment<Transaction>>;
51    /// How catchup pushes a state it recovered from storage back into memory.
52    async fn update_leaf(
53        &self,
54        leaf: Leaf2,
55        state: Arc<ValidatedState>,
56        delta: Option<Arc<Delta>>,
57    ) -> anyhow::Result<()>;
58    async fn current_proposal_participation(&self) -> HashMap<PubKey, f64>;
59    async fn proposal_participation(&self, epoch: EpochNumber) -> HashMap<PubKey, f64>;
60    async fn current_vote_participation(&self) -> HashMap<PubKey, f64>;
61    async fn vote_participation(&self, epoch: EpochNumber) -> HashMap<PubKey, f64>;
62}
63
64pub trait ApiContext: Send + Sync + 'static {
65    fn consensus(&self) -> Arc<dyn ConsensusSource>;
66    fn membership(&self) -> Arc<dyn MembershipPersistence>;
67    fn state_certs(&self) -> Arc<dyn StateCertPersistence>;
68    fn node_state(&self) -> NodeState;
69    fn network_config(&self) -> NetworkConfig<SeqTypes>;
70    fn validator_config(&self) -> Option<&ValidatorConfig<SeqTypes>>;
71    fn state_signatures(&self) -> Option<Arc<RwLock<StateSignatureMemStorage>>>;
72
73    /// A light client the node already runs, for the query service to fetch through.
74    fn light_client(&self) -> Option<Arc<NodeLightClient>>;
75    fn request_vid_shares(
76        &self,
77        block_number: u64,
78        vid_common: VidCommonQueryData<SeqTypes>,
79        timeout: Duration,
80    ) -> BoxFuture<'static, anyhow::Result<Vec<VidShare>>>;
81    /// [`Options::serve`](super::Options::serve) hands a clone of the context to the API before
82    /// calling this, so the tasks attached here must be shared with that clone: [`TaskList`] is
83    /// that shared handle, and dropping any clone of it aborts every task.
84    fn with_task_list(self, tasks: TaskList) -> Self
85    where
86        Self: Sized;
87}
88
89#[async_trait]
90impl<P: SequencerPersistence> ConsensusSource for ConsensusHandle<SeqTypes, Arc<P>> {
91    async fn decided_leaf(&self) -> Leaf2 {
92        ConsensusHandle::decided_leaf(self).await
93    }
94
95    async fn decided_state(&self) -> Option<Arc<ValidatedState>> {
96        ConsensusHandle::decided_state(self).await
97    }
98
99    async fn state(&self, view: ViewNumber) -> Option<Arc<ValidatedState>> {
100        ConsensusHandle::state(self, view).await
101    }
102
103    async fn state_and_delta(&self, view: ViewNumber) -> StateAndDelta<SeqTypes> {
104        ConsensusHandle::state_and_delta(self, view).await
105    }
106
107    async fn undecided_leaves(&self) -> Vec<Leaf2> {
108        ConsensusHandle::undecided_leaves(self).await
109    }
110
111    async fn current_epoch(&self) -> Option<EpochNumber> {
112        ConsensusHandle::current_epoch(self).await
113    }
114
115    async fn membership_coordinator(&self) -> EpochMembershipCoordinator<SeqTypes> {
116        ConsensusHandle::membership_coordinator(self)
117    }
118
119    async fn upgrade_lock(&self) -> UpgradeLock<SeqTypes> {
120        ConsensusHandle::upgrade_lock(self)
121    }
122
123    async fn submit_transaction(&self, tx: Transaction) -> anyhow::Result<Commitment<Transaction>> {
124        let commitment = tx.commit();
125        ConsensusHandle::submit_transaction(self, tx).await?;
126        Ok(commitment)
127    }
128
129    async fn update_leaf(
130        &self,
131        leaf: Leaf2,
132        state: Arc<ValidatedState>,
133        delta: Option<Arc<Delta>>,
134    ) -> anyhow::Result<()> {
135        ConsensusHandle::update_leaf(self, leaf, state, delta).await
136    }
137
138    async fn current_proposal_participation(&self) -> HashMap<PubKey, f64> {
139        ConsensusHandle::current_proposal_participation(self).await
140    }
141
142    async fn proposal_participation(&self, epoch: EpochNumber) -> HashMap<PubKey, f64> {
143        ConsensusHandle::proposal_participation(self, epoch).await
144    }
145
146    async fn current_vote_participation(&self) -> HashMap<PubKey, f64> {
147        ConsensusHandle::current_vote_participation(self).await
148    }
149
150    async fn vote_participation(&self, epoch: EpochNumber) -> HashMap<PubKey, f64> {
151        ConsensusHandle::vote_participation(self, epoch).await
152    }
153}
154
155impl<P> ApiContext for SequencerContext<P>
156where
157    P: SequencerPersistence,
158{
159    fn consensus(&self) -> Arc<dyn ConsensusSource> {
160        self.consensus_handle()
161    }
162
163    fn membership(&self) -> Arc<dyn MembershipPersistence> {
164        SequencerContext::persistence(self)
165    }
166
167    fn state_certs(&self) -> Arc<dyn StateCertPersistence> {
168        SequencerContext::persistence(self)
169    }
170
171    fn node_state(&self) -> NodeState {
172        SequencerContext::node_state(self)
173    }
174
175    fn network_config(&self) -> NetworkConfig<SeqTypes> {
176        SequencerContext::network_config(self)
177    }
178
179    fn validator_config(&self) -> Option<&ValidatorConfig<SeqTypes>> {
180        Some(SequencerContext::validator_config(self))
181    }
182
183    fn state_signatures(&self) -> Option<Arc<RwLock<StateSignatureMemStorage>>> {
184        Some(SequencerContext::state_signatures(self))
185    }
186
187    fn light_client(&self) -> Option<Arc<NodeLightClient>> {
188        None
189    }
190
191    fn request_vid_shares(
192        &self,
193        block_number: u64,
194        vid_common: VidCommonQueryData<SeqTypes>,
195        timeout: Duration,
196    ) -> BoxFuture<'static, anyhow::Result<Vec<VidShare>>> {
197        super::request_vid_shares(
198            self.request_response_protocol.clone(),
199            block_number,
200            vid_common,
201            timeout,
202        )
203    }
204
205    fn with_task_list(self, tasks: TaskList) -> Self {
206        SequencerContext::with_task_list(self, tasks)
207    }
208}