tempo_node/rpc/consensus/
types.rs1use std::fmt::Display;
4
5use alloy_primitives::B256;
6use futures::Future;
7use serde::{Deserialize, Serialize};
8use tempo_alloy::rpc::TempoHeaderResponse;
9use tempo_primitives::Block;
10use tokio::sync::broadcast;
11
12#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
14#[serde(rename_all = "camelCase")]
15pub struct CertifiedBlock {
16 pub epoch: u64,
17 pub view: u64,
18 pub digest: B256,
19
20 pub certificate: String,
22
23 pub block: Block,
25}
26
27impl Display for CertifiedBlock {
28 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
29 match serde_json::to_string(self) {
30 Ok(s) => f.write_str(&s),
31 Err(err) => write!(f, "<failed formatting certified block: {err}"),
32 }
33 }
34}
35
36#[derive(Clone, Debug, Serialize, Deserialize)]
38#[serde(tag = "type", rename_all = "camelCase")]
39pub enum Event {
40 Notarized {
42 #[serde(flatten)]
43 block: CertifiedBlock,
44 seen: u64,
46 },
47 Finalized {
49 #[serde(flatten)]
50 block: CertifiedBlock,
51 seen: u64,
53 },
54 Nullified {
56 epoch: u64,
57 view: u64,
58 seen: u64,
60 },
61}
62
63#[derive(Debug, Clone, Serialize, Deserialize)]
65#[serde(rename_all = "camelCase")]
66pub enum Query {
67 Latest,
69 Height(u64),
71}
72
73impl Display for Query {
74 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
75 match serde_json::to_string(self) {
76 Ok(s) => f.write_str(&s),
77 Err(err) => write!(f, "<failed formatting query: {err}"),
78 }
79 }
80}
81
82#[derive(Clone, Debug, Default, Serialize, Deserialize)]
84#[serde(rename_all = "camelCase")]
85pub struct ConsensusState {
86 pub finalized: Option<CertifiedBlock>,
88 pub notarized: Option<CertifiedBlock>,
90}
91
92#[derive(Clone, Debug, thiserror::Error)]
94pub enum IdentityProofError {
95 #[error("node not ready")]
97 NotReady,
98 #[error("block data pruned at height {0}")]
100 PrunedData(u64),
101 #[error("malformed DKG outcome at height {0}")]
103 MalformedData(u64),
104}
105
106#[derive(Clone, Debug, Serialize, Deserialize)]
112#[serde(rename_all = "camelCase")]
113pub struct IdentityTransitionResponse {
114 pub identity: String,
116 pub transitions: Vec<IdentityTransition>,
119}
120
121#[derive(Clone, Debug, Serialize, Deserialize)]
130#[serde(rename_all = "camelCase")]
131pub struct IdentityTransition {
132 pub transition_epoch: u64,
134 pub old_identity: String,
136 pub new_identity: String,
138 #[serde(skip_serializing_if = "Option::is_none")]
140 pub proof: Option<TransitionProofData>,
141}
142
143#[derive(Clone, Debug, Serialize, Deserialize)]
145#[serde(rename_all = "camelCase")]
146pub struct TransitionProofData {
147 pub header: TempoHeaderResponse,
149 pub finalization_certificate: String,
151}
152
153#[derive(Debug)]
154pub enum Response<T> {
155 Success(T),
156 NotReady,
157 Missing(&'static str),
158}
159
160impl<T> Response<T>
161where
162 T: std::fmt::Debug,
163{
164 pub fn unwrap(self) -> T {
165 let Self::Success(val) = self else {
166 panic!("not a success: {self:?}")
167 };
168 val
169 }
170}
171
172impl<T> Display for Response<T>
173where
174 T: Display,
175{
176 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
177 match self {
178 Self::Success(obj) => write!(f, "success: {obj}`"),
179 Self::NotReady => write!(f, "service not ready"),
180 Self::Missing(msg) => write!(f, "missing: {msg}`"),
181 }
182 }
183}
184
185pub trait ConsensusFeed: Send + Sync + 'static {
187 fn get_finalization(
189 &self,
190 query: Query,
191 ) -> impl Future<Output = Response<CertifiedBlock>> + Send;
192
193 fn get_latest(&self) -> impl Future<Output = ConsensusState> + Send;
195
196 fn subscribe(&self) -> impl Future<Output = Option<broadcast::Receiver<Event>>> + Send;
198
199 fn get_identity_transition_proof(
204 &self,
205 from_epoch: Option<u64>,
206 full: bool,
207 ) -> impl Future<Output = Result<IdentityTransitionResponse, IdentityProofError>> + Send;
208}