1use crate::{
4 config::{EXTRA_DATA_SIZE, FEE_RECIPIENT_SIZE, LOGS_BLOOM_SIZE, PUBKEY_SIZE, SIGNATURE_SIZE},
5 types::{
6 BeaconHeader, ExecutionPayloadHeader, ForkData, SigningData, SyncAggregate, SyncCommittee,
7 },
8};
9use byte_slice_cast::AsByteSlice;
10use sp_core::H256;
11use sp_std::{vec, vec::Vec};
12use ssz_rs::{
13 prelude::{List, Vector},
14 Bitvector, Deserialize, DeserializeError, SimpleSerialize, SimpleSerializeError, Sized, U256,
15};
16use ssz_rs_derive::SimpleSerialize as SimpleSerializeDerive;
17
18#[derive(Default, SimpleSerializeDerive, Clone, Debug)]
19pub struct SSZBeaconBlockHeader {
20 pub slot: u64,
21 pub proposer_index: u64,
22 pub parent_root: [u8; 32],
23 pub state_root: [u8; 32],
24 pub body_root: [u8; 32],
25}
26
27impl From<BeaconHeader> for SSZBeaconBlockHeader {
28 fn from(beacon_header: BeaconHeader) -> Self {
29 SSZBeaconBlockHeader {
30 slot: beacon_header.slot,
31 proposer_index: beacon_header.proposer_index,
32 parent_root: beacon_header.parent_root.to_fixed_bytes(),
33 state_root: beacon_header.state_root.to_fixed_bytes(),
34 body_root: beacon_header.body_root.to_fixed_bytes(),
35 }
36 }
37}
38
39#[derive(Default, SimpleSerializeDerive, Clone)]
40pub struct SSZSyncCommittee<const COMMITTEE_SIZE: usize> {
41 pub pubkeys: Vector<Vector<u8, PUBKEY_SIZE>, COMMITTEE_SIZE>,
42 pub aggregate_pubkey: Vector<u8, PUBKEY_SIZE>,
43}
44
45impl<const COMMITTEE_SIZE: usize> From<SyncCommittee<COMMITTEE_SIZE>>
46 for SSZSyncCommittee<COMMITTEE_SIZE>
47{
48 fn from(sync_committee: SyncCommittee<COMMITTEE_SIZE>) -> Self {
49 let mut pubkeys_vec = Vec::new();
50
51 for pubkey in sync_committee.pubkeys.iter() {
52 let conv_pubkey = Vector::<u8, PUBKEY_SIZE>::try_from(pubkey.0.to_vec())
58 .expect("checked statically; qed");
59
60 pubkeys_vec.push(conv_pubkey);
61 }
62
63 let pubkeys = Vector::<Vector<u8, PUBKEY_SIZE>, { COMMITTEE_SIZE }>::try_from(pubkeys_vec)
64 .expect("checked statically; qed");
65
66 let aggregate_pubkey =
67 Vector::<u8, PUBKEY_SIZE>::try_from(sync_committee.aggregate_pubkey.0.to_vec())
68 .expect("checked statically; qed");
69
70 SSZSyncCommittee { pubkeys, aggregate_pubkey }
71 }
72}
73
74#[derive(Default, Debug, SimpleSerializeDerive, Clone)]
75pub struct SSZSyncAggregate<const COMMITTEE_SIZE: usize> {
76 pub sync_committee_bits: Bitvector<COMMITTEE_SIZE>,
77 pub sync_committee_signature: Vector<u8, SIGNATURE_SIZE>,
78}
79
80impl<const COMMITTEE_SIZE: usize, const COMMITTEE_BITS_SIZE: usize>
81 From<SyncAggregate<COMMITTEE_SIZE, COMMITTEE_BITS_SIZE>> for SSZSyncAggregate<COMMITTEE_SIZE>
82{
83 fn from(sync_aggregate: SyncAggregate<COMMITTEE_SIZE, COMMITTEE_BITS_SIZE>) -> Self {
84 SSZSyncAggregate {
85 sync_committee_bits: Bitvector::<COMMITTEE_SIZE>::deserialize(
86 &sync_aggregate.sync_committee_bits,
87 )
88 .expect("checked statically; qed"),
89 sync_committee_signature: Vector::<u8, SIGNATURE_SIZE>::try_from(
90 sync_aggregate.sync_committee_signature.0.to_vec(),
91 )
92 .expect("checked statically; qed"),
93 }
94 }
95}
96
97#[derive(Default, SimpleSerializeDerive, Clone)]
98pub struct SSZForkData {
99 pub current_version: [u8; 4],
100 pub genesis_validators_root: [u8; 32],
101}
102
103impl From<ForkData> for SSZForkData {
104 fn from(fork_data: ForkData) -> Self {
105 SSZForkData {
106 current_version: fork_data.current_version,
107 genesis_validators_root: fork_data.genesis_validators_root,
108 }
109 }
110}
111
112#[derive(Default, SimpleSerializeDerive, Clone)]
113pub struct SSZSigningData {
114 pub object_root: [u8; 32],
115 pub domain: [u8; 32],
116}
117
118impl From<SigningData> for SSZSigningData {
119 fn from(signing_data: SigningData) -> Self {
120 SSZSigningData {
121 object_root: signing_data.object_root.into(),
122 domain: signing_data.domain.into(),
123 }
124 }
125}
126
127#[derive(Default, SimpleSerializeDerive, Clone, Debug)]
128pub struct SSZExecutionPayloadHeader {
129 pub parent_hash: [u8; 32],
130 pub fee_recipient: Vector<u8, FEE_RECIPIENT_SIZE>,
131 pub state_root: [u8; 32],
132 pub receipts_root: [u8; 32],
133 pub logs_bloom: Vector<u8, LOGS_BLOOM_SIZE>,
134 pub prev_randao: [u8; 32],
135 pub block_number: u64,
136 pub gas_limit: u64,
137 pub gas_used: u64,
138 pub timestamp: u64,
139 pub extra_data: List<u8, EXTRA_DATA_SIZE>,
140 pub base_fee_per_gas: U256,
141 pub block_hash: [u8; 32],
142 pub transactions_root: [u8; 32],
143 pub withdrawals_root: [u8; 32],
144}
145
146impl TryFrom<ExecutionPayloadHeader> for SSZExecutionPayloadHeader {
147 type Error = SimpleSerializeError;
148
149 fn try_from(payload: ExecutionPayloadHeader) -> Result<Self, Self::Error> {
150 Ok(SSZExecutionPayloadHeader {
151 parent_hash: payload.parent_hash.to_fixed_bytes(),
152 fee_recipient: Vector::<u8, FEE_RECIPIENT_SIZE>::try_from(
153 payload.fee_recipient.to_fixed_bytes().to_vec(),
154 )
155 .expect("checked statically; qed"),
156 state_root: payload.state_root.to_fixed_bytes(),
157 receipts_root: payload.receipts_root.to_fixed_bytes(),
158 logs_bloom: Vector::<u8, LOGS_BLOOM_SIZE>::try_from(payload.logs_bloom)
161 .map_err(|(_, err)| err)?,
162 prev_randao: payload.prev_randao.to_fixed_bytes(),
163 block_number: payload.block_number,
164 gas_limit: payload.gas_limit,
165 gas_used: payload.gas_used,
166 timestamp: payload.timestamp,
167 extra_data: List::<u8, EXTRA_DATA_SIZE>::try_from(payload.extra_data)
170 .map_err(|(_, err)| err)?,
171 base_fee_per_gas: U256::from_bytes_le(
172 payload
173 .base_fee_per_gas
174 .as_byte_slice()
175 .try_into()
176 .expect("checked in prep; qed"),
177 ),
178 block_hash: payload.block_hash.to_fixed_bytes(),
179 transactions_root: payload.transactions_root.to_fixed_bytes(),
180 withdrawals_root: payload.withdrawals_root.to_fixed_bytes(),
181 })
182 }
183}
184
185pub fn hash_tree_root<T: SimpleSerialize>(mut object: T) -> Result<H256, SimpleSerializeError> {
186 match object.hash_tree_root() {
187 Ok(node) => {
188 let fixed_bytes: [u8; 32] =
189 node.as_ref().try_into().expect("Node is a newtype over [u8; 32]; qed");
190 Ok(fixed_bytes.into())
191 },
192 Err(err) => Err(err.into()),
193 }
194}
195
196pub mod deneb {
197 use crate::{
198 config::{EXTRA_DATA_SIZE, FEE_RECIPIENT_SIZE, LOGS_BLOOM_SIZE},
199 ssz::hash_tree_root,
200 types::deneb::ExecutionPayloadHeader,
201 };
202 use byte_slice_cast::AsByteSlice;
203 use sp_core::H256;
204 use sp_std::{vec, vec::Vec};
205 use ssz_rs::{
206 prelude::{List, Vector},
207 Deserialize, DeserializeError, SimpleSerializeError, Sized, U256,
208 };
209 use ssz_rs_derive::SimpleSerialize as SimpleSerializeDerive;
210
211 #[derive(Default, SimpleSerializeDerive, Clone, Debug)]
212 pub struct SSZExecutionPayloadHeader {
213 pub parent_hash: [u8; 32],
214 pub fee_recipient: Vector<u8, FEE_RECIPIENT_SIZE>,
215 pub state_root: [u8; 32],
216 pub receipts_root: [u8; 32],
217 pub logs_bloom: Vector<u8, LOGS_BLOOM_SIZE>,
218 pub prev_randao: [u8; 32],
219 pub block_number: u64,
220 pub gas_limit: u64,
221 pub gas_used: u64,
222 pub timestamp: u64,
223 pub extra_data: List<u8, EXTRA_DATA_SIZE>,
224 pub base_fee_per_gas: U256,
225 pub block_hash: [u8; 32],
226 pub transactions_root: [u8; 32],
227 pub withdrawals_root: [u8; 32],
228 pub blob_gas_used: u64,
229 pub excess_blob_gas: u64,
230 }
231
232 impl TryFrom<ExecutionPayloadHeader> for SSZExecutionPayloadHeader {
233 type Error = SimpleSerializeError;
234
235 fn try_from(payload: ExecutionPayloadHeader) -> Result<Self, Self::Error> {
236 Ok(SSZExecutionPayloadHeader {
237 parent_hash: payload.parent_hash.to_fixed_bytes(),
238 fee_recipient: Vector::<u8, FEE_RECIPIENT_SIZE>::try_from(
239 payload.fee_recipient.to_fixed_bytes().to_vec(),
240 )
241 .expect("checked statically; qed"),
242 state_root: payload.state_root.to_fixed_bytes(),
243 receipts_root: payload.receipts_root.to_fixed_bytes(),
244 logs_bloom: Vector::<u8, LOGS_BLOOM_SIZE>::try_from(payload.logs_bloom)
247 .map_err(|(_, err)| err)?,
248 prev_randao: payload.prev_randao.to_fixed_bytes(),
249 block_number: payload.block_number,
250 gas_limit: payload.gas_limit,
251 gas_used: payload.gas_used,
252 timestamp: payload.timestamp,
253 extra_data: List::<u8, EXTRA_DATA_SIZE>::try_from(payload.extra_data)
256 .map_err(|(_, err)| err)?,
257 base_fee_per_gas: U256::from_bytes_le(
258 payload
259 .base_fee_per_gas
260 .as_byte_slice()
261 .try_into()
262 .expect("checked in prep; qed"),
263 ),
264 block_hash: payload.block_hash.to_fixed_bytes(),
265 transactions_root: payload.transactions_root.to_fixed_bytes(),
266 withdrawals_root: payload.withdrawals_root.to_fixed_bytes(),
267 blob_gas_used: payload.blob_gas_used,
268 excess_blob_gas: payload.excess_blob_gas,
269 })
270 }
271 }
272
273 impl ExecutionPayloadHeader {
274 pub fn hash_tree_root(&self) -> Result<H256, SimpleSerializeError> {
275 hash_tree_root::<SSZExecutionPayloadHeader>(self.clone().try_into()?)
276 }
277 }
278}