pallas_network/miniprotocols/chainsync/
client.rs1use pallas_codec::Fragment;
2use std::marker::PhantomData;
3use thiserror::Error;
4use tracing::debug;
5
6use crate::miniprotocols::Point;
7use crate::multiplexer;
8
9use super::{BlockContent, HeaderContent, IntersectResponse, Message, State, Tip};
10
11#[derive(Error, Debug)]
13pub enum ClientError {
14 #[error("attempted to receive message while agency is ours")]
16 AgencyIsOurs,
17
18 #[error("attempted to send message while agency is theirs")]
20 AgencyIsTheirs,
21
22 #[error("inbound message is not valid for current state")]
24 InvalidInbound,
25
26 #[error("outbound message is not valid for current state")]
28 InvalidOutbound,
29
30 #[error("no intersection point found")]
32 IntersectionNotFound,
33
34 #[error("error while sending or receiving data through the channel")]
36 Plexer(multiplexer::Error),
37}
38
39#[derive(Debug)]
41pub enum NextResponse<CONTENT> {
42 RollForward(CONTENT, Tip),
44 RollBackward(Point, Tip),
46 Await,
48}
49
50pub struct Client<O>(State, multiplexer::ChannelBuffer, PhantomData<O>)
53where
54 Message<O>: Fragment;
55
56impl<O> Client<O>
57where
58 Message<O>: Fragment,
59{
60 pub fn new(channel: multiplexer::AgentChannel) -> Self {
67 Self(
68 State::Idle,
69 multiplexer::ChannelBuffer::new(channel),
70 PhantomData {},
71 )
72 }
73
74 pub fn state(&self) -> &State {
76 &self.0
77 }
78
79 pub fn is_done(&self) -> bool {
81 self.0 == State::Done
82 }
83
84 pub fn has_agency(&self) -> bool {
86 match self.state() {
87 State::Idle => true,
88 State::CanAwait => false,
89 State::MustReply => false,
90 State::Intersect => false,
91 State::Done => false,
92 }
93 }
94
95 fn assert_agency_is_ours(&self) -> Result<(), ClientError> {
96 if !self.has_agency() {
97 Err(ClientError::AgencyIsTheirs)
98 } else {
99 Ok(())
100 }
101 }
102
103 fn assert_agency_is_theirs(&self) -> Result<(), ClientError> {
104 if self.has_agency() {
105 Err(ClientError::AgencyIsOurs)
106 } else {
107 Ok(())
108 }
109 }
110
111 fn assert_outbound_state(&self, msg: &Message<O>) -> Result<(), ClientError> {
112 match (&self.0, msg) {
113 (State::Idle, Message::RequestNext) => Ok(()),
114 (State::Idle, Message::FindIntersect(_)) => Ok(()),
115 (State::Idle, Message::Done) => Ok(()),
116 _ => Err(ClientError::InvalidOutbound),
117 }
118 }
119
120 fn assert_inbound_state(&self, msg: &Message<O>) -> Result<(), ClientError> {
121 match (&self.0, msg) {
122 (State::CanAwait, Message::RollForward(_, _)) => Ok(()),
123 (State::CanAwait, Message::RollBackward(_, _)) => Ok(()),
124 (State::CanAwait, Message::AwaitReply) => Ok(()),
125 (State::MustReply, Message::RollForward(_, _)) => Ok(()),
126 (State::MustReply, Message::RollBackward(_, _)) => Ok(()),
127 (State::Intersect, Message::IntersectFound(_, _)) => Ok(()),
128 (State::Intersect, Message::IntersectNotFound(_)) => Ok(()),
129 _ => Err(ClientError::InvalidInbound),
130 }
131 }
132
133 pub async fn send_message(&mut self, msg: &Message<O>) -> Result<(), ClientError> {
144 self.assert_agency_is_ours()?;
145 self.assert_outbound_state(msg)?;
146
147 self.1
148 .send_msg_chunks(msg)
149 .await
150 .map_err(ClientError::Plexer)?;
151
152 Ok(())
153 }
154
155 pub async fn recv_message(&mut self) -> Result<Message<O>, ClientError> {
162 self.assert_agency_is_theirs()?;
163
164 let msg = self.1.recv_full_msg().await.map_err(ClientError::Plexer)?;
165
166 self.assert_inbound_state(&msg)?;
167
168 Ok(msg)
169 }
170
171 pub async fn send_find_intersect(&mut self, points: Vec<Point>) -> Result<(), ClientError> {
183 let msg = Message::FindIntersect(points);
184 self.send_message(&msg).await?;
185 self.0 = State::Intersect;
186
187 debug!("send find intersect");
188
189 Ok(())
190 }
191
192 pub async fn recv_intersect_response(&mut self) -> Result<IntersectResponse, ClientError> {
198 debug!("waiting for intersect response");
199
200 match self.recv_message().await? {
201 Message::IntersectFound(point, tip) => {
202 self.0 = State::Idle;
203 Ok((Some(point), tip))
204 }
205 Message::IntersectNotFound(tip) => {
206 self.0 = State::Idle;
207 Ok((None, tip))
208 }
209 _ => Err(ClientError::InvalidInbound),
210 }
211 }
212
213 pub async fn find_intersect(
225 &mut self,
226 points: Vec<Point>,
227 ) -> Result<IntersectResponse, ClientError> {
228 self.send_find_intersect(points).await?;
229 self.recv_intersect_response().await
230 }
231
232 pub async fn send_request_next(&mut self) -> Result<(), ClientError> {
234 let msg = Message::RequestNext;
235 self.send_message(&msg).await?;
236 self.0 = State::CanAwait;
237
238 Ok(())
239 }
240
241 pub async fn recv_while_can_await(&mut self) -> Result<NextResponse<O>, ClientError> {
247 match self.recv_message().await? {
248 Message::AwaitReply => {
249 self.0 = State::MustReply;
250 Ok(NextResponse::Await)
251 }
252 Message::RollForward(a, b) => {
253 self.0 = State::Idle;
254 Ok(NextResponse::RollForward(a, b))
255 }
256 Message::RollBackward(a, b) => {
257 self.0 = State::Idle;
258 Ok(NextResponse::RollBackward(a, b))
259 }
260 _ => Err(ClientError::InvalidInbound),
261 }
262 }
263
264 pub async fn recv_while_must_reply(&mut self) -> Result<NextResponse<O>, ClientError> {
270 match self.recv_message().await? {
271 Message::RollForward(a, b) => {
272 self.0 = State::Idle;
273 Ok(NextResponse::RollForward(a, b))
274 }
275 Message::RollBackward(a, b) => {
276 self.0 = State::Idle;
277 Ok(NextResponse::RollBackward(a, b))
278 }
279 _ => Err(ClientError::InvalidInbound),
280 }
281 }
282
283 pub async fn request_next(&mut self) -> Result<NextResponse<O>, ClientError> {
290 debug!("requesting next block");
291
292 self.send_request_next().await?;
293
294 self.recv_while_can_await().await
295 }
296
297 pub async fn request_or_await_next(&mut self) -> Result<NextResponse<O>, ClientError> {
304 if self.has_agency() {
305 self.request_next().await
306 } else {
307 self.recv_while_must_reply().await
308 }
309 }
310
311 pub async fn intersect_origin(&mut self) -> Result<Point, ClientError> {
318 debug!("intersecting origin");
319
320 let (point, _) = self.find_intersect(vec![Point::Origin]).await?;
321
322 point.ok_or(ClientError::IntersectionNotFound)
323 }
324
325 pub async fn intersect_tip(&mut self) -> Result<Point, ClientError> {
332 let (_, Tip(point, _)) = self.find_intersect(vec![Point::Origin]).await?;
333
334 debug!(?point, "found tip value");
335
336 let (point, _) = self.find_intersect(vec![point]).await?;
337
338 point.ok_or(ClientError::IntersectionNotFound)
339 }
340
341 pub async fn send_done(&mut self) -> Result<(), ClientError> {
343 let msg = Message::Done;
344 self.send_message(&msg).await?;
345 self.0 = State::Done;
346
347 Ok(())
348 }
349}
350
351pub type N2NClient = Client<HeaderContent>;
353
354pub type N2CClient = Client<BlockContent>;