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}