bankai_types/
block.rs

1//! Bankai block representation
2//!
3//! A Bankai block represents a verified state of both the beacon chain and execution layer,
4//! containing their respective MMR roots that can be used to verify individual headers.
5
6use alloy_primitives::FixedBytes;
7use cairo_air::utils::VerificationOutput;
8
9#[cfg(feature = "serde")]
10use serde::{Deserialize, Serialize};
11
12/// A Bankai block containing verified beacon and execution chain state
13///
14/// Each Bankai block is the output of an STWO zero-knowledge proof and contains
15/// MMR roots for both the beacon chain and execution layer. These roots establish
16/// trust for all headers committed in the MMRs.
17///
18/// This is the foundation of stateless verification - once you have a verified
19/// Bankai block, you can trustlessly verify any header in its MMRs.
20#[derive(Debug, Clone)]
21#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
22pub struct BankaiBlock {
23    /// Bankai block number (sequential)
24    pub block_number: u64,
25    /// Beacon chain state at this Bankai block
26    pub beacon: BeaconClient,
27    /// Execution layer state at this Bankai block
28    pub execution: ExecutionClient,
29}
30
31/// Beacon chain state in a Bankai block
32///
33/// Contains the beacon chain's MMR roots and consensus information.
34#[derive(Debug, Clone)]
35#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
36pub struct BeaconClient {
37    /// Latest beacon slot processed
38    pub slot_number: u64,
39    /// Beacon block root at this slot
40    pub header_root: FixedBytes<32>,
41    /// Last justified beacon slot
42    pub justified_height: u64,
43    /// Last finalized beacon slot
44    pub finalized_height: u64,
45    /// Number of validators that signed
46    pub num_signers: u64,
47    /// MMR root using Keccak hash
48    pub mmr_root_keccak: FixedBytes<32>,
49    /// MMR root using Poseidon hash
50    pub mmr_root_poseidon: FixedBytes<32>,
51    /// Hash of current validator committee
52    pub current_committee_hash: FixedBytes<32>,
53    /// Hash of next validator committee
54    pub next_committee_hash: FixedBytes<32>,
55}
56
57/// Execution layer state in a Bankai block
58///
59/// Contains the execution chain's MMR roots and block information.
60#[derive(Debug, Clone)]
61#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
62pub struct ExecutionClient {
63    /// Latest execution block processed
64    pub block_number: u64,
65    /// Block hash at this height
66    pub header_hash: FixedBytes<32>,
67    /// Last justified block height
68    pub justified_height: u64,
69    /// Last finalized block height
70    pub finalized_height: u64,
71    /// MMR root using Keccak hash
72    pub mmr_root_keccak: FixedBytes<32>,
73    /// MMR root using Poseidon hash
74    pub mmr_root_poseidon: FixedBytes<32>,
75}
76
77impl BankaiBlock {
78    pub fn from_verication_output(output: &VerificationOutput) -> Self {
79        let output = &output.output;
80
81        fn bytes32_from_limbs(low: &[u8], high: &[u8]) -> FixedBytes<32> {
82            let mut bytes = [0u8; 32];
83            bytes[0..16].copy_from_slice(high);
84            bytes[16..32].copy_from_slice(low);
85            FixedBytes::from(bytes)
86        }
87
88        Self {
89            block_number: output[0].try_into().unwrap(),
90            beacon: BeaconClient {
91                slot_number: output[1].try_into().unwrap(),
92                header_root: bytes32_from_limbs(
93                    &output[2].to_bytes_be()[16..],
94                    &output[3].to_bytes_be()[16..],
95                ),
96                justified_height: output[4].try_into().unwrap(),
97                finalized_height: output[5].try_into().unwrap(),
98                num_signers: output[6].try_into().unwrap(),
99                mmr_root_keccak: bytes32_from_limbs(
100                    &output[7].to_bytes_be()[16..],
101                    &output[8].to_bytes_be()[16..],
102                ),
103                mmr_root_poseidon: FixedBytes::from_slice(output[9].to_bytes_be().as_slice()),
104                current_committee_hash: bytes32_from_limbs(
105                    &output[10].to_bytes_be()[16..],
106                    &output[11].to_bytes_be()[16..],
107                ),
108                next_committee_hash: bytes32_from_limbs(
109                    &output[12].to_bytes_be()[16..],
110                    &output[13].to_bytes_be()[16..],
111                ),
112            },
113            execution: ExecutionClient {
114                block_number: output[14].try_into().unwrap(),
115                header_hash: bytes32_from_limbs(
116                    &output[15].to_bytes_be()[16..],
117                    &output[16].to_bytes_be()[16..],
118                ),
119                justified_height: output[17].try_into().unwrap(),
120                finalized_height: output[18].try_into().unwrap(),
121                mmr_root_keccak: bytes32_from_limbs(
122                    &output[19].to_bytes_be()[16..],
123                    &output[20].to_bytes_be()[16..],
124                ),
125                mmr_root_poseidon: FixedBytes::from_slice(output[21].to_bytes_be().as_slice()),
126            },
127        }
128    }
129}