sequencer/request_response/
recipient_source.rs

1use std::sync::Arc;
2
3use anyhow::{Context, Result};
4use async_trait::async_trait;
5use espresso_types::{PubKey, SeqTypes};
6use hotshot::{traits::NodeImplementation, SystemContext};
7use hotshot_types::{
8    data::EpochNumber,
9    epoch_membership::EpochMembershipCoordinator,
10    traits::node_implementation::{ConsensusTime, Versions},
11};
12use request_response::recipient_source::RecipientSource as RecipientSourceTrait;
13use tracing::warn;
14
15use super::request::Request;
16
17/// A type alias for the consensus context
18type Consensus<I, V> = Arc<SystemContext<SeqTypes, I, V>>;
19
20#[derive(Clone)]
21pub struct RecipientSource<I: NodeImplementation<SeqTypes>, V: Versions> {
22    /// A copy of the consensus context
23    pub consensus: Consensus<I, V>,
24    /// A copy of the membership coordinator
25    pub memberships: EpochMembershipCoordinator<SeqTypes>,
26    /// The public key of the node
27    pub public_key: PubKey,
28}
29
30/// Implement the RecipientSourceTrait, which allows the request-response protocol to derive the
31/// intended recipients for a given request
32#[async_trait]
33impl<I: NodeImplementation<SeqTypes>, V: Versions> RecipientSourceTrait<Request, PubKey>
34    for RecipientSource<I, V>
35{
36    async fn get_expected_responders(&self, _request: &Request) -> Result<Vec<PubKey>> {
37        // Get the current epoch number
38        let epoch_number = self
39            .consensus
40            .consensus()
41            .read()
42            .await
43            .cur_epoch()
44            .unwrap_or(EpochNumber::genesis());
45
46        // Attempt to get the membership for the current epoch
47        let membership = match self
48            .memberships
49            .stake_table_for_epoch(Some(epoch_number))
50            .await
51        {
52            Ok(membership) => membership,
53            Err(e) => {
54                warn!(
55                    "Failed to get membership for epoch {}: {e:#}. Failing over to genesis",
56                    epoch_number
57                );
58                self.memberships
59                    .stake_table_for_epoch(Some(EpochNumber::genesis()))
60                    .await
61                    .with_context(|| "failed to get stake table for epoch")?
62            },
63        };
64
65        // Sum all participants in the membership
66        Ok(membership
67            .stake_table()
68            .await
69            .iter()
70            .map(|entry| entry.stake_table_entry.stake_key)
71            .filter(|key| *key != self.public_key)
72            .collect())
73    }
74}