reth_optimism_flashblocks/ws/
decoding.rs1use crate::{ExecutionPayloadBaseV1, ExecutionPayloadFlashblockDeltaV1, FlashBlock, Metadata};
2use alloy_primitives::bytes::Bytes;
3use alloy_rpc_types_engine::PayloadId;
4use serde::{Deserialize, Serialize};
5use std::{fmt::Debug, io};
6
7#[derive(Clone, Debug, PartialEq, Default, Deserialize, Serialize)]
9struct FlashblocksPayloadV1 {
10 pub payload_id: PayloadId,
12 pub index: u64,
14 #[serde(skip_serializing_if = "Option::is_none")]
16 pub base: Option<ExecutionPayloadBaseV1>,
17 pub diff: ExecutionPayloadFlashblockDeltaV1,
19 pub metadata: serde_json::Value,
21}
22
23impl FlashBlock {
24 pub(crate) fn decode(bytes: Bytes) -> eyre::Result<Self> {
32 let bytes = try_parse_message(bytes)?;
33
34 let payload: FlashblocksPayloadV1 = serde_json::from_slice(&bytes)
35 .map_err(|e| eyre::eyre!("failed to parse message: {e}"))?;
36
37 let metadata: Metadata = serde_json::from_value(payload.metadata)
38 .map_err(|e| eyre::eyre!("failed to parse message metadata: {e}"))?;
39
40 Ok(Self {
41 payload_id: payload.payload_id,
42 index: payload.index,
43 base: payload.base,
44 diff: payload.diff,
45 metadata,
46 })
47 }
48}
49
50fn try_parse_message(bytes: Bytes) -> eyre::Result<Bytes> {
57 if bytes.trim_ascii_start().starts_with(b"{") {
58 return Ok(bytes);
59 }
60
61 let mut decompressor = brotli::Decompressor::new(bytes.as_ref(), 4096);
62 let mut decompressed = Vec::new();
63 io::copy(&mut decompressor, &mut decompressed)?;
64
65 Ok(decompressed.into())
66}