fuel_core_p2p/codecs/
postcard.rs1use super::{
2 Decode,
3 Encode,
4 gossipsub::GossipsubMessageHandler,
5 request_response::RequestResponseMessageHandler,
6};
7
8use std::{
9 borrow::Cow,
10 io,
11 num::NonZeroU32,
12};
13
14#[derive(Clone, Default)]
15pub struct PostcardCodec;
16
17impl RequestResponseMessageHandler<PostcardCodec> {
18 pub fn new(max_block_size: NonZeroU32) -> Self {
19 Self {
20 codec: PostcardCodec,
21 max_response_size: max_block_size,
22 }
23 }
24}
25
26impl GossipsubMessageHandler<PostcardCodec> {
27 pub fn new() -> Self {
28 GossipsubMessageHandler {
29 codec: PostcardCodec,
30 }
31 }
32}
33
34impl<T> Encode<T> for PostcardCodec
35where
36 T: ?Sized + serde::Serialize,
37{
38 type Encoder<'a>
39 = Cow<'a, [u8]>
40 where
41 T: 'a;
42 type Error = io::Error;
43
44 fn encode<'a>(&self, value: &'a T) -> Result<Self::Encoder<'a>, Self::Error> {
45 Ok(Cow::Owned(
46 postcard::to_allocvec(value).map_err(|e| io::Error::other(e.to_string()))?,
47 ))
48 }
49}
50
51impl<T> Decode<T> for PostcardCodec
52where
53 T: serde::de::DeserializeOwned,
54{
55 type Error = io::Error;
56
57 fn decode(&self, bytes: &[u8]) -> Result<T, Self::Error> {
58 postcard::from_bytes(bytes).map_err(|e| io::Error::other(e.to_string()))
59 }
60}
61
62#[cfg(test)]
63#[allow(non_snake_case)]
64mod tests {
65 use fuel_core_types::{
66 blockchain::SealedBlockHeader,
67 fuel_tx::Transaction,
68 services::p2p::NetworkableTransactionPool,
69 };
70 use libp2p::request_response::Codec;
71
72 use super::*;
73 use crate::{
74 codecs::request_response::RequestResponseMessageHandler,
75 request_response::{
76 messages::{
77 RequestMessage,
78 ResponseMessageErrorCode,
79 V1ResponseMessage,
80 V2ResponseMessage,
81 },
82 protocols::RequestResponseProtocol,
83 },
84 };
85
86 const MAX_REQUEST_SIZE: NonZeroU32 = NonZeroU32::new(1024).unwrap();
87
88 #[test]
89 fn test_request_size_fits() {
90 let arbitrary_range = 2..6;
91 let m = RequestMessage::Transactions(arbitrary_range);
92 assert!(
93 postcard::to_stdvec(&m).unwrap().len() <= MAX_REQUEST_SIZE.get() as usize
94 );
95 }
96
97 #[tokio::test]
98 async fn codec__serialization_roundtrip_using_v2_on_successful_response_returns_original_value__sealed_headers()
99 {
100 let sealed_block_headers = vec![SealedBlockHeader::default()];
102 let response = V2ResponseMessage::SealedHeaders(Ok(sealed_block_headers.clone()));
103 let mut codec: RequestResponseMessageHandler<PostcardCodec> =
104 RequestResponseMessageHandler::new(MAX_REQUEST_SIZE);
105 let mut buf = Vec::with_capacity(1024);
106
107 codec
109 .write_response(&RequestResponseProtocol::V2, &mut buf, response)
110 .await
111 .expect("Valid Vec<SealedBlockHeader> should be serialized using v1");
112
113 let deserialized = codec
114 .read_response(&RequestResponseProtocol::V2, &mut buf.as_slice())
115 .await
116 .expect("Valid Vec<SealedBlockHeader> should be deserialized using v1");
117
118 assert!(matches!(
120 deserialized,
121 V2ResponseMessage::SealedHeaders(Ok(sealed_headers)) if sealed_headers == sealed_block_headers
122 ));
123 }
124
125 #[tokio::test]
126 async fn codec__serialization_roundtrip_using_v2_on_successful_response_returns_original_value__full_transactions()
127 {
128 let full_transactions = vec![Some(NetworkableTransactionPool::Transaction(
130 Transaction::default_test_tx(),
131 ))];
132 let response =
133 V2ResponseMessage::TxPoolFullTransactions(Ok(full_transactions.clone()));
134 let mut codec: RequestResponseMessageHandler<PostcardCodec> =
135 RequestResponseMessageHandler::new(MAX_REQUEST_SIZE);
136 let mut buf = Vec::with_capacity(1024);
137
138 codec
140 .write_response(&RequestResponseProtocol::V2, &mut buf, response)
141 .await
142 .expect("Valid full transactions should be serialized using v2");
143
144 let deserialized = codec
145 .read_response(&RequestResponseProtocol::V2, &mut buf.as_slice())
146 .await
147 .expect("Valid full transactions should be deserialized using v2");
148
149 assert!(matches!(
151 deserialized,
152 V2ResponseMessage::TxPoolFullTransactions(Ok(actual)) if actual == full_transactions
153 ));
154 }
155
156 #[tokio::test]
157 async fn codec__serialization_roundtrip_using_v1_on_successful_response_returns_original_value()
158 {
159 let sealed_block_headers = vec![SealedBlockHeader::default()];
161 let response = V2ResponseMessage::SealedHeaders(Ok(sealed_block_headers.clone()));
162 let mut codec: RequestResponseMessageHandler<PostcardCodec> =
163 RequestResponseMessageHandler::new(MAX_REQUEST_SIZE);
164 let mut buf = Vec::with_capacity(1024);
165
166 codec
168 .write_response(&RequestResponseProtocol::V1, &mut buf, response)
169 .await
170 .expect("Valid Vec<SealedBlockHeader> should be serialized using v1");
171
172 let deserialized = codec
173 .read_response(&RequestResponseProtocol::V1, &mut buf.as_slice())
174 .await
175 .expect("Valid Vec<SealedBlockHeader> should be deserialized using v1");
176
177 assert!(
179 matches!(deserialized, V2ResponseMessage::SealedHeaders(Ok(sealed_headers)) if sealed_headers == sealed_block_headers)
180 );
181 }
182
183 #[tokio::test]
184 async fn codec__serialization_roundtrip_using_v2_on_error_response_returns_original_value()
185 {
186 let response = V2ResponseMessage::SealedHeaders(Err(
188 ResponseMessageErrorCode::ProtocolV1EmptyResponse,
189 ));
190 let mut codec: RequestResponseMessageHandler<PostcardCodec> =
191 RequestResponseMessageHandler::new(MAX_REQUEST_SIZE);
192 let mut buf = Vec::with_capacity(1024);
193
194 codec
196 .write_response(&RequestResponseProtocol::V2, &mut buf, response.clone())
197 .await
198 .expect("Valid Vec<SealedBlockHeader> is serialized using v1");
199
200 let deserialized = codec
201 .read_response(&RequestResponseProtocol::V2, &mut buf.as_slice())
202 .await
203 .expect("Valid Vec<SealedBlockHeader> is deserialized using v1");
204
205 assert!(matches!(
207 deserialized,
208 V2ResponseMessage::SealedHeaders(Err(
209 ResponseMessageErrorCode::ProtocolV1EmptyResponse
210 ))
211 ));
212 }
213
214 #[tokio::test]
215 async fn codec__serialization_roundtrip_using_v1_on_error_response_returns_predefined_error_code()
216 {
217 let response = V2ResponseMessage::SealedHeaders(Err(
219 ResponseMessageErrorCode::RequestedRangeTooLarge,
220 ));
221 let mut codec: RequestResponseMessageHandler<PostcardCodec> =
222 RequestResponseMessageHandler::new(MAX_REQUEST_SIZE);
223 let mut buf = Vec::with_capacity(1024);
224
225 codec
227 .write_response(&RequestResponseProtocol::V1, &mut buf, response.clone())
228 .await
229 .expect("Valid Vec<SealedBlockHeader> is serialized using v1");
230
231 let deserialized = codec
232 .read_response(&RequestResponseProtocol::V1, &mut buf.as_slice())
233 .await
234 .expect("Valid Vec<SealedBlockHeader> is deserialized using v1");
235
236 assert!(matches!(
238 deserialized,
239 V2ResponseMessage::SealedHeaders(Err(
240 ResponseMessageErrorCode::ProtocolV1EmptyResponse
241 ))
242 ));
243 }
244
245 #[tokio::test]
246 async fn codec__write_response_is_backwards_compatible_with_v1() {
247 let response = V2ResponseMessage::SealedHeaders(Err(
249 ResponseMessageErrorCode::ProtocolV1EmptyResponse,
250 ));
251 let mut codec: RequestResponseMessageHandler<PostcardCodec> =
252 RequestResponseMessageHandler::new(MAX_REQUEST_SIZE);
253 let mut buf = Vec::with_capacity(1024);
254
255 codec
257 .write_response(&RequestResponseProtocol::V1, &mut buf, response.clone())
258 .await
259 .expect("Valid Vec<SealedBlockHeader> is serialized using v1");
260
261 let deserialized_as_v1 =
262 codec.codec.decode(&buf).expect("Deserialization as V1ResponseMessage should succeed");
265
266 assert!(matches!(
268 deserialized_as_v1,
269 V1ResponseMessage::SealedHeaders(None)
270 ));
271 }
272
273 #[tokio::test]
274 async fn codec__read_response_is_backwards_compatible_with_v1() {
275 let response = V1ResponseMessage::SealedHeaders(None);
277 let mut codec: RequestResponseMessageHandler<PostcardCodec> =
278 RequestResponseMessageHandler::new(MAX_REQUEST_SIZE);
279
280 let buf = codec
282 .codec
283 .encode(&response)
284 .expect("Serialization as V1ResponseMessage should succeed");
285 let deserialized = codec
286 .read_response(&RequestResponseProtocol::V1, &mut &*buf)
287 .await
288 .expect("Valid Vec<SealedBlockHeader> is deserialized using v1");
289
290 assert!(matches!(
292 deserialized,
293 V2ResponseMessage::SealedHeaders(Err(
294 ResponseMessageErrorCode::ProtocolV1EmptyResponse
295 ))
296 ));
297 }
298}