tempo_node/rpc/consensus/
types.rs1use std::fmt::Display;
4
5use alloy_primitives::B256;
6use futures::Future;
7use reth_primitives_traits::SealedOrRecoveredBlock;
8use serde::{Deserialize, Serialize};
9use tempo_alloy::rpc::TempoHeaderResponse;
10use tempo_primitives::Block;
11use tokio::sync::broadcast;
12
13#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
15#[serde(rename_all = "camelCase")]
16pub struct CertifiedBlock {
17 pub epoch: u64,
18 pub view: u64,
19 pub digest: B256,
20
21 pub certificate: String,
23
24 pub block: SealedOrRecoveredBlock<Block>,
26}
27
28impl Display for CertifiedBlock {
29 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
30 match serde_json::to_string(self) {
31 Ok(s) => f.write_str(&s),
32 Err(err) => write!(f, "<failed formatting certified block: {err}"),
33 }
34 }
35}
36
37#[derive(Clone, Debug, Serialize, Deserialize)]
39#[serde(tag = "type", rename_all = "camelCase")]
40pub enum Event {
41 Notarized {
43 #[serde(flatten)]
44 block: CertifiedBlock,
45 seen: u64,
47 },
48 Finalized {
50 #[serde(flatten)]
51 block: CertifiedBlock,
52 seen: u64,
54 },
55 Nullified {
57 epoch: u64,
58 view: u64,
59 seen: u64,
61 },
62}
63
64#[derive(Debug, Clone, Serialize, Deserialize)]
66#[serde(rename_all = "camelCase")]
67pub enum Query {
68 Latest,
70 Height(u64),
72}
73
74impl Display for Query {
75 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
76 match serde_json::to_string(self) {
77 Ok(s) => f.write_str(&s),
78 Err(err) => write!(f, "<failed formatting query: {err}>"),
79 }
80 }
81}
82
83#[derive(Clone, Debug, Default, Serialize, Deserialize)]
85#[serde(rename_all = "camelCase")]
86pub struct ConsensusState {
87 pub finalized: Option<CertifiedBlock>,
89 pub notarized: Option<CertifiedBlock>,
91}
92
93#[derive(Clone, Debug, thiserror::Error)]
95pub enum IdentityProofError {
96 #[error("node not ready")]
98 NotReady,
99 #[error("block data pruned at height {0}")]
101 PrunedData(u64),
102 #[error("malformed DKG outcome at height {0}")]
104 MalformedData(u64),
105}
106
107#[derive(Clone, Debug, Serialize, Deserialize)]
113#[serde(rename_all = "camelCase")]
114pub struct IdentityTransitionResponse {
115 pub identity: String,
117 pub transitions: Vec<IdentityTransition>,
120}
121
122#[derive(Clone, Debug, Serialize, Deserialize)]
131#[serde(rename_all = "camelCase")]
132pub struct IdentityTransition {
133 pub transition_epoch: u64,
135 pub old_identity: String,
137 pub new_identity: String,
139 #[serde(skip_serializing_if = "Option::is_none")]
141 pub proof: Option<TransitionProofData>,
142}
143
144#[derive(Clone, Debug, Serialize, Deserialize)]
146#[serde(rename_all = "camelCase")]
147pub struct TransitionProofData {
148 pub header: TempoHeaderResponse,
150 pub finalization_certificate: String,
152}
153
154#[derive(Debug)]
155pub enum Response<T> {
156 Success(T),
157 NotReady,
158 Missing(&'static str),
159}
160
161impl<T> Response<T>
162where
163 T: std::fmt::Debug,
164{
165 pub fn unwrap(self) -> T {
166 let Self::Success(val) = self else {
167 panic!("not a success: {self:?}")
168 };
169 val
170 }
171}
172
173impl<T> Display for Response<T>
174where
175 T: Display,
176{
177 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
178 match self {
179 Self::Success(obj) => write!(f, "success: {obj}"),
180 Self::NotReady => write!(f, "service not ready"),
181 Self::Missing(msg) => write!(f, "missing: {msg}"),
182 }
183 }
184}
185
186pub trait ConsensusFeed: Send + Sync + 'static {
188 fn get_finalization(
190 &self,
191 query: Query,
192 ) -> impl Future<Output = Response<CertifiedBlock>> + Send;
193
194 fn get_latest(&self) -> impl Future<Output = ConsensusState> + Send;
196
197 fn subscribe(&self) -> impl Future<Output = Option<broadcast::Receiver<Event>>> + Send;
199
200 fn get_identity_transition_proof(
205 &self,
206 from_epoch: Option<u64>,
207 full: bool,
208 ) -> impl Future<Output = Result<IdentityTransitionResponse, IdentityProofError>> + Send;
209}