reth_optimism_flashblocks/ws/decoding.rs
1use crate::FlashBlock;
2use alloy_primitives::bytes::Bytes;
3use std::io;
4
5/// A trait for decoding flashblocks from bytes.
6pub trait FlashBlockDecoder: Send + 'static {
7 /// Decodes `bytes` into a [`FlashBlock`].
8 fn decode(&self, bytes: Bytes) -> eyre::Result<FlashBlock>;
9}
10
11/// Default implementation of the decoder.
12impl FlashBlockDecoder for () {
13 fn decode(&self, bytes: Bytes) -> eyre::Result<FlashBlock> {
14 decode_flashblock(bytes)
15 }
16}
17
18pub(crate) fn decode_flashblock(bytes: Bytes) -> eyre::Result<FlashBlock> {
19 let bytes = crate::ws::decoding::try_parse_message(bytes)?;
20
21 let payload: FlashBlock =
22 serde_json::from_slice(&bytes).map_err(|e| eyre::eyre!("failed to parse message: {e}"))?;
23
24 Ok(payload)
25}
26
27/// Maps `bytes` into a potentially different [`Bytes`].
28///
29/// If the bytes start with a "{" character, prepended by any number of ASCII-whitespaces,
30/// then it assumes that it is JSON-encoded and returns it as-is.
31///
32/// Otherwise, the `bytes` are passed through a brotli decompressor and returned.
33fn try_parse_message(bytes: Bytes) -> eyre::Result<Bytes> {
34 if bytes.trim_ascii_start().starts_with(b"{") {
35 return Ok(bytes);
36 }
37
38 let mut decompressor = brotli::Decompressor::new(bytes.as_ref(), 4096);
39 let mut decompressed = Vec::new();
40 io::copy(&mut decompressor, &mut decompressed)?;
41
42 Ok(decompressed.into())
43}