referrerpolicy=no-referrer-when-downgrade

snowbridge_beacon_primitives/
types.rs

1// SPDX-License-Identifier: Apache-2.0
2// SPDX-FileCopyrightText: 2023 Snowfork <hello@snowfork.com>
3use codec::{Decode, DecodeWithMemTracking, Encode, MaxEncodedLen};
4use frame_support::{CloneNoBound, PartialEqNoBound, RuntimeDebugNoBound};
5use scale_info::TypeInfo;
6use sp_core::{H160, H256, U256};
7use sp_runtime::RuntimeDebug;
8use sp_std::{boxed::Box, iter::repeat, prelude::*};
9
10use crate::config::{PUBKEY_SIZE, SIGNATURE_SIZE};
11
12#[cfg(feature = "std")]
13use serde::{Deserialize, Deserializer, Serialize, Serializer};
14
15#[cfg(feature = "std")]
16use crate::serde_utils::HexVisitor;
17
18use crate::ssz::{
19	hash_tree_root, SSZBeaconBlockHeader, SSZExecutionPayloadHeader, SSZForkData, SSZSigningData,
20	SSZSyncAggregate, SSZSyncCommittee,
21};
22use ssz_rs::SimpleSerializeError;
23
24pub use crate::bits::decompress_sync_committee_bits;
25
26use crate::bls::{prepare_g1_pubkeys, prepare_milagro_pubkey, BlsError};
27use milagro_bls::PublicKey as PublicKeyPrepared;
28
29pub type ValidatorIndex = u64;
30pub type ForkVersion = [u8; 4];
31
32#[derive(Clone, Encode, Decode, PartialEq, RuntimeDebug, TypeInfo)]
33pub struct ForkVersions {
34	pub genesis: Fork,
35	pub altair: Fork,
36	pub bellatrix: Fork,
37	pub capella: Fork,
38	pub deneb: Fork,
39	pub electra: Fork,
40}
41
42#[derive(Clone, Encode, Decode, PartialEq, RuntimeDebug, TypeInfo)]
43pub struct Fork {
44	pub version: [u8; 4],
45	pub epoch: u64,
46}
47
48#[derive(Copy, Clone, Encode, Decode, DecodeWithMemTracking, PartialEq, RuntimeDebug, TypeInfo)]
49pub struct PublicKey(pub [u8; PUBKEY_SIZE]);
50
51impl Default for PublicKey {
52	fn default() -> Self {
53		PublicKey([0u8; PUBKEY_SIZE])
54	}
55}
56
57impl From<[u8; PUBKEY_SIZE]> for PublicKey {
58	fn from(v: [u8; PUBKEY_SIZE]) -> Self {
59		Self(v)
60	}
61}
62
63impl MaxEncodedLen for PublicKey {
64	fn max_encoded_len() -> usize {
65		PUBKEY_SIZE
66	}
67}
68
69#[cfg(feature = "std")]
70impl<'de> Deserialize<'de> for PublicKey {
71	fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
72	where
73		D: Deserializer<'de>,
74	{
75		deserializer.deserialize_str(HexVisitor::<PUBKEY_SIZE>()).map(|v| v.into())
76	}
77}
78
79#[cfg(feature = "std")]
80impl Serialize for PublicKey {
81	fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
82	where
83		S: Serializer,
84	{
85		serializer.serialize_bytes(&self.0)
86	}
87}
88
89#[derive(Copy, Clone, Encode, Decode, DecodeWithMemTracking, PartialEq, RuntimeDebug, TypeInfo)]
90pub struct Signature(pub [u8; SIGNATURE_SIZE]);
91
92impl Default for Signature {
93	fn default() -> Self {
94		Signature([0u8; SIGNATURE_SIZE])
95	}
96}
97
98impl From<[u8; SIGNATURE_SIZE]> for Signature {
99	fn from(v: [u8; SIGNATURE_SIZE]) -> Self {
100		Self(v)
101	}
102}
103
104#[cfg(feature = "std")]
105impl<'de> Deserialize<'de> for Signature {
106	fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
107	where
108		D: Deserializer<'de>,
109	{
110		deserializer.deserialize_str(HexVisitor::<SIGNATURE_SIZE>()).map(|v| v.into())
111	}
112}
113
114#[derive(Copy, Clone, Default, Encode, Decode, TypeInfo, MaxEncodedLen)]
115pub struct FinalizedHeaderState {
116	pub beacon_block_root: H256,
117	pub beacon_slot: u64,
118}
119
120#[derive(Clone, Default, Encode, Decode, PartialEq, RuntimeDebug)]
121pub struct ForkData {
122	// 1 or 0 bit, indicates whether a sync committee participated in a vote
123	pub current_version: [u8; 4],
124	pub genesis_validators_root: [u8; 32],
125}
126
127impl ForkData {
128	pub fn hash_tree_root(&self) -> Result<H256, SimpleSerializeError> {
129		hash_tree_root::<SSZForkData>(self.clone().into())
130	}
131}
132
133#[derive(Clone, Default, Encode, Decode, PartialEq, RuntimeDebug)]
134pub struct SigningData {
135	pub object_root: H256,
136	pub domain: H256,
137}
138
139impl SigningData {
140	pub fn hash_tree_root(&self) -> Result<H256, SimpleSerializeError> {
141		hash_tree_root::<SSZSigningData>(self.clone().into())
142	}
143}
144
145/// Sync committee as it is stored in the runtime storage.
146#[derive(
147	Encode,
148	Decode,
149	DecodeWithMemTracking,
150	PartialEqNoBound,
151	CloneNoBound,
152	RuntimeDebugNoBound,
153	TypeInfo,
154	MaxEncodedLen,
155)]
156#[cfg_attr(
157	feature = "std",
158	derive(Serialize, Deserialize),
159	serde(deny_unknown_fields, bound(serialize = ""), bound(deserialize = ""))
160)]
161#[codec(mel_bound())]
162pub struct SyncCommittee<const COMMITTEE_SIZE: usize> {
163	#[cfg_attr(feature = "std", serde(with = "crate::serde_utils::arrays"))]
164	pub pubkeys: [PublicKey; COMMITTEE_SIZE],
165	pub aggregate_pubkey: PublicKey,
166}
167
168impl<const COMMITTEE_SIZE: usize> Default for SyncCommittee<COMMITTEE_SIZE> {
169	fn default() -> Self {
170		SyncCommittee {
171			pubkeys: [Default::default(); COMMITTEE_SIZE],
172			aggregate_pubkey: Default::default(),
173		}
174	}
175}
176
177impl<const COMMITTEE_SIZE: usize> SyncCommittee<COMMITTEE_SIZE> {
178	pub fn hash_tree_root(&self) -> Result<H256, SimpleSerializeError> {
179		hash_tree_root::<SSZSyncCommittee<COMMITTEE_SIZE>>(self.clone().into())
180	}
181}
182
183/// Prepared G1 public key of sync committee as it is stored in the runtime storage.
184#[derive(Clone, PartialEq, Eq, Encode, Decode, TypeInfo, MaxEncodedLen)]
185pub struct SyncCommitteePrepared<const COMMITTEE_SIZE: usize> {
186	pub root: H256,
187	pub pubkeys: Box<[PublicKeyPrepared; COMMITTEE_SIZE]>,
188	pub aggregate_pubkey: PublicKeyPrepared,
189}
190
191impl<const COMMITTEE_SIZE: usize> Default for SyncCommitteePrepared<COMMITTEE_SIZE> {
192	fn default() -> Self {
193		let pubkeys: Vec<PublicKeyPrepared> =
194			repeat(PublicKeyPrepared::default()).take(COMMITTEE_SIZE).collect();
195		let pubkeys: Box<[PublicKeyPrepared; COMMITTEE_SIZE]> =
196			Box::new(pubkeys.try_into().map_err(|_| ()).expect("checked statically; qed"));
197
198		SyncCommitteePrepared {
199			root: H256::default(),
200			pubkeys,
201			aggregate_pubkey: PublicKeyPrepared::default(),
202		}
203	}
204}
205
206impl<const COMMITTEE_SIZE: usize> TryFrom<&SyncCommittee<COMMITTEE_SIZE>>
207	for SyncCommitteePrepared<COMMITTEE_SIZE>
208{
209	type Error = BlsError;
210
211	fn try_from(sync_committee: &SyncCommittee<COMMITTEE_SIZE>) -> Result<Self, Self::Error> {
212		let g1_pubkeys = prepare_g1_pubkeys(&sync_committee.pubkeys)?;
213		let sync_committee_root = sync_committee.hash_tree_root().expect("checked statically; qed");
214
215		Ok(SyncCommitteePrepared::<COMMITTEE_SIZE> {
216			pubkeys: g1_pubkeys.try_into().map_err(|_| ()).expect("checked statically; qed"),
217			aggregate_pubkey: prepare_milagro_pubkey(&sync_committee.aggregate_pubkey)?,
218			root: sync_committee_root,
219		})
220	}
221}
222
223/// Beacon block header as it is stored in the runtime storage. The block root is the
224/// Merkleization of a BeaconHeader.
225#[derive(
226	Copy,
227	Clone,
228	Default,
229	Encode,
230	Decode,
231	DecodeWithMemTracking,
232	PartialEq,
233	RuntimeDebug,
234	TypeInfo,
235	MaxEncodedLen,
236)]
237#[cfg_attr(feature = "std", derive(Serialize, Deserialize))]
238pub struct BeaconHeader {
239	// The slot for which this block is created. Must be greater than the slot of the block defined
240	// by parent root.
241	pub slot: u64,
242	// The index of the validator that proposed the block.
243	pub proposer_index: ValidatorIndex,
244	// The block root of the parent block, forming a block chain.
245	pub parent_root: H256,
246	// The hash root of the post state of running the state transition through this block.
247	pub state_root: H256,
248	// The hash root of the beacon block body
249	pub body_root: H256,
250}
251
252impl BeaconHeader {
253	pub fn hash_tree_root(&self) -> Result<H256, SimpleSerializeError> {
254		hash_tree_root::<SSZBeaconBlockHeader>((*self).into())
255	}
256}
257
258#[derive(
259	Encode,
260	Decode,
261	DecodeWithMemTracking,
262	CloneNoBound,
263	PartialEqNoBound,
264	RuntimeDebugNoBound,
265	TypeInfo,
266)]
267#[cfg_attr(
268	feature = "std",
269	derive(Deserialize),
270	serde(
271		try_from = "IntermediateSyncAggregate",
272		deny_unknown_fields,
273		bound(serialize = ""),
274		bound(deserialize = "")
275	)
276)]
277#[codec(mel_bound())]
278pub struct SyncAggregate<const COMMITTEE_SIZE: usize, const COMMITTEE_BITS_SIZE: usize> {
279	pub sync_committee_bits: [u8; COMMITTEE_BITS_SIZE],
280	pub sync_committee_signature: Signature,
281}
282
283impl<const COMMITTEE_SIZE: usize, const COMMITTEE_BITS_SIZE: usize> Default
284	for SyncAggregate<COMMITTEE_SIZE, COMMITTEE_BITS_SIZE>
285{
286	fn default() -> Self {
287		SyncAggregate {
288			sync_committee_bits: [0; COMMITTEE_BITS_SIZE],
289			sync_committee_signature: Default::default(),
290		}
291	}
292}
293
294impl<const COMMITTEE_SIZE: usize, const COMMITTEE_BITS_SIZE: usize>
295	SyncAggregate<COMMITTEE_SIZE, COMMITTEE_BITS_SIZE>
296{
297	pub fn hash_tree_root(&self) -> Result<H256, SimpleSerializeError> {
298		hash_tree_root::<SSZSyncAggregate<COMMITTEE_SIZE>>(self.clone().into())
299	}
300}
301
302/// Serde deserialization helper for SyncAggregate
303#[cfg(feature = "std")]
304#[derive(Deserialize)]
305struct IntermediateSyncAggregate {
306	#[cfg_attr(feature = "std", serde(deserialize_with = "crate::serde_utils::from_hex_to_bytes"))]
307	pub sync_committee_bits: Vec<u8>,
308	pub sync_committee_signature: Signature,
309}
310
311#[cfg(feature = "std")]
312impl<const COMMITTEE_SIZE: usize, const COMMITTEE_BITS_SIZE: usize>
313	TryFrom<IntermediateSyncAggregate> for SyncAggregate<COMMITTEE_SIZE, COMMITTEE_BITS_SIZE>
314{
315	type Error = String;
316
317	fn try_from(other: IntermediateSyncAggregate) -> Result<Self, Self::Error> {
318		Ok(Self {
319			sync_committee_bits: other
320				.sync_committee_bits
321				.try_into()
322				.map_err(|_| "unexpected length".to_owned())?,
323			sync_committee_signature: other.sync_committee_signature,
324		})
325	}
326}
327
328/// ExecutionPayloadHeader
329/// <https://github.com/ethereum/annotated-spec/blob/master/capella/beacon-chain.md#executionpayloadheader>
330#[derive(
331	Default,
332	Encode,
333	Decode,
334	DecodeWithMemTracking,
335	CloneNoBound,
336	PartialEqNoBound,
337	RuntimeDebugNoBound,
338	TypeInfo,
339)]
340#[cfg_attr(
341	feature = "std",
342	derive(Serialize, Deserialize),
343	serde(deny_unknown_fields, bound(serialize = ""), bound(deserialize = ""))
344)]
345#[codec(mel_bound())]
346pub struct ExecutionPayloadHeader {
347	pub parent_hash: H256,
348	pub fee_recipient: H160,
349	pub state_root: H256,
350	pub receipts_root: H256,
351	#[cfg_attr(feature = "std", serde(deserialize_with = "crate::serde_utils::from_hex_to_bytes"))]
352	pub logs_bloom: Vec<u8>,
353	pub prev_randao: H256,
354	pub block_number: u64,
355	pub gas_limit: u64,
356	pub gas_used: u64,
357	pub timestamp: u64,
358	#[cfg_attr(feature = "std", serde(deserialize_with = "crate::serde_utils::from_hex_to_bytes"))]
359	pub extra_data: Vec<u8>,
360	#[cfg_attr(feature = "std", serde(deserialize_with = "crate::serde_utils::from_int_to_u256"))]
361	pub base_fee_per_gas: U256,
362	pub block_hash: H256,
363	pub transactions_root: H256,
364	pub withdrawals_root: H256,
365}
366
367impl ExecutionPayloadHeader {
368	pub fn hash_tree_root(&self) -> Result<H256, SimpleSerializeError> {
369		hash_tree_root::<SSZExecutionPayloadHeader>(self.clone().try_into()?)
370	}
371}
372
373#[derive(
374	Default,
375	Encode,
376	Decode,
377	Copy,
378	Clone,
379	PartialEqNoBound,
380	RuntimeDebugNoBound,
381	TypeInfo,
382	MaxEncodedLen,
383)]
384pub struct CompactBeaconState {
385	#[codec(compact)]
386	pub slot: u64,
387	pub block_roots_root: H256,
388}
389
390/// VersionedExecutionPayloadHeader
391#[derive(
392	Encode,
393	Decode,
394	DecodeWithMemTracking,
395	CloneNoBound,
396	PartialEqNoBound,
397	RuntimeDebugNoBound,
398	TypeInfo,
399)]
400#[cfg_attr(
401	feature = "std",
402	derive(Serialize, Deserialize),
403	serde(deny_unknown_fields, bound(serialize = ""), bound(deserialize = ""))
404)]
405#[codec(mel_bound())]
406pub enum VersionedExecutionPayloadHeader {
407	Capella(ExecutionPayloadHeader),
408	Deneb(deneb::ExecutionPayloadHeader),
409}
410
411impl VersionedExecutionPayloadHeader {
412	pub fn hash_tree_root(&self) -> Result<H256, SimpleSerializeError> {
413		match self {
414			VersionedExecutionPayloadHeader::Capella(execution_payload_header) =>
415				hash_tree_root::<SSZExecutionPayloadHeader>(
416					execution_payload_header.clone().try_into()?,
417				),
418			VersionedExecutionPayloadHeader::Deneb(execution_payload_header) =>
419				hash_tree_root::<crate::ssz::deneb::SSZExecutionPayloadHeader>(
420					execution_payload_header.clone().try_into()?,
421				),
422		}
423	}
424
425	pub fn block_hash(&self) -> H256 {
426		match self {
427			VersionedExecutionPayloadHeader::Capella(execution_payload_header) =>
428				execution_payload_header.block_hash,
429			VersionedExecutionPayloadHeader::Deneb(execution_payload_header) =>
430				execution_payload_header.block_hash,
431		}
432	}
433
434	pub fn block_number(&self) -> u64 {
435		match self {
436			VersionedExecutionPayloadHeader::Capella(execution_payload_header) =>
437				execution_payload_header.block_number,
438			VersionedExecutionPayloadHeader::Deneb(execution_payload_header) =>
439				execution_payload_header.block_number,
440		}
441	}
442
443	pub fn receipts_root(&self) -> H256 {
444		match self {
445			VersionedExecutionPayloadHeader::Capella(execution_payload_header) =>
446				execution_payload_header.receipts_root,
447			VersionedExecutionPayloadHeader::Deneb(execution_payload_header) =>
448				execution_payload_header.receipts_root,
449		}
450	}
451}
452
453#[derive(
454	Encode,
455	Decode,
456	DecodeWithMemTracking,
457	CloneNoBound,
458	PartialEqNoBound,
459	RuntimeDebugNoBound,
460	TypeInfo,
461)]
462#[cfg_attr(
463	feature = "std",
464	derive(serde::Deserialize),
465	serde(deny_unknown_fields, bound(serialize = ""), bound(deserialize = ""))
466)]
467pub struct ExecutionProof {
468	/// Header for the beacon block containing the execution payload
469	pub header: BeaconHeader,
470	/// Proof that `header` is an ancestor of a finalized header
471	pub ancestry_proof: Option<AncestryProof>,
472	/// The execution header to be verified
473	pub execution_header: VersionedExecutionPayloadHeader,
474	/// Merkle proof that execution payload is contained within `header`
475	pub execution_branch: Vec<H256>,
476}
477
478#[derive(
479	Encode,
480	Decode,
481	DecodeWithMemTracking,
482	CloneNoBound,
483	PartialEqNoBound,
484	RuntimeDebugNoBound,
485	TypeInfo,
486)]
487#[cfg_attr(
488	feature = "std",
489	derive(serde::Deserialize),
490	serde(deny_unknown_fields, bound(serialize = ""), bound(deserialize = ""))
491)]
492pub struct AncestryProof {
493	/// Merkle proof that `header` is an ancestor of `finalized_header`
494	pub header_branch: Vec<H256>,
495	/// Root of a finalized block that has already been imported into the light client
496	pub finalized_block_root: H256,
497}
498
499#[cfg(test)]
500mod tests {
501	use super::*;
502	use hex_literal::hex;
503
504	#[test]
505	pub fn test_hash_beacon_header1() {
506		let hash_root = BeaconHeader {
507			slot: 3,
508			proposer_index: 2,
509			parent_root: hex!("796ea53efb534eab7777809cc5ee2d84e7f25024b9d0c4d7e5bcaab657e4bdbd")
510				.into(),
511			state_root: hex!("ba3ff080912be5c9c158b2e962c1b39a91bc0615762ba6fa2ecacafa94e9ae0a")
512				.into(),
513			body_root: hex!("a18d7fcefbb74a177c959160e0ee89c23546482154e6831237710414465dcae5")
514				.into(),
515		}
516		.hash_tree_root();
517
518		assert!(hash_root.is_ok());
519		assert_eq!(
520			hash_root.unwrap(),
521			hex!("7d42595818709e805dd2fa710a2d2c1f62576ef1ab7273941ac9130fb94b91f7").into()
522		);
523	}
524
525	#[test]
526	pub fn test_hash_beacon_header2() {
527		let hash_root = BeaconHeader {
528			slot: 3476424,
529			proposer_index: 314905,
530			parent_root: hex!("c069d7b49cffd2b815b0fb8007eb9ca91202ea548df6f3db60000f29b2489f28")
531				.into(),
532			state_root: hex!("444d293e4533501ee508ad608783a7d677c3c566f001313e8a02ce08adf590a3")
533				.into(),
534			body_root: hex!("6508a0241047f21ba88f05d05b15534156ab6a6f8e029a9a5423da429834e04a")
535				.into(),
536		}
537		.hash_tree_root();
538
539		assert!(hash_root.is_ok());
540		assert_eq!(
541			hash_root.unwrap(),
542			hex!("0aa41166ff01e58e111ac8c42309a738ab453cf8d7285ed8477b1c484acb123e").into()
543		);
544	}
545
546	#[test]
547	pub fn test_hash_fork_data() {
548		let hash_root = ForkData {
549			current_version: hex!("83f38a34"),
550			genesis_validators_root: hex!(
551				"22370bbbb358800f5711a10ea9845284272d8493bed0348cab87b8ab1e127930"
552			),
553		}
554		.hash_tree_root();
555
556		assert!(hash_root.is_ok());
557		assert_eq!(
558			hash_root.unwrap(),
559			hex!("57c12c4246bc7152b174b51920506bf943eff9c7ffa50b9533708e9cc1f680fc").into()
560		);
561	}
562
563	#[test]
564	pub fn test_hash_signing_data() {
565		let hash_root = SigningData {
566			object_root: hex!("63654cbe64fc07853f1198c165dd3d49c54fc53bc417989bbcc66da15f850c54")
567				.into(),
568			domain: hex!("037da907d1c3a03c0091b2254e1480d9b1783476e228ab29adaaa8f133e08f7a").into(),
569		}
570		.hash_tree_root();
571
572		assert!(hash_root.is_ok());
573		assert_eq!(
574			hash_root.unwrap(),
575			hex!("b9eb2caf2d691b183c2d57f322afe505c078cd08101324f61c3641714789a54e").into()
576		);
577	}
578
579	#[test]
580	pub fn test_hash_sync_aggregate() {
581		let hash_root = SyncAggregate::<512, 64>{
582				sync_committee_bits: hex!("cefffffefffffff767fffbedffffeffffeeffdffffdebffffff7f7dbdf7fffdffffbffcfffdff79dfffbbfefff2ffffff7ddeff7ffffc98ff7fbfffffffffff7"),
583				sync_committee_signature: hex!("8af1a8577bba419fe054ee49b16ed28e081dda6d3ba41651634685e890992a0b675e20f8d9f2ec137fe9eb50e838aa6117f9f5410e2e1024c4b4f0e098e55144843ce90b7acde52fe7b94f2a1037342c951dc59f501c92acf7ed944cb6d2b5f7").into(),
584		}.hash_tree_root();
585
586		assert!(hash_root.is_ok());
587		assert_eq!(
588			hash_root.unwrap(),
589			hex!("e6dcad4f60ce9ff8a587b110facbaf94721f06cd810b6d8bf6cffa641272808d").into()
590		);
591	}
592
593	#[test]
594	pub fn test_hash_execution_payload() {
595		let hash_root =
596            ExecutionPayloadHeader{
597                parent_hash: hex!("eadee5ab098dde64e9fd02ae5858064bad67064070679625b09f8d82dec183f7").into(),
598                fee_recipient: hex!("f97e180c050e5ab072211ad2c213eb5aee4df134").into(),
599                state_root: hex!("564fa064c2a324c2b5978d7fdfc5d4224d4f421a45388af1ed405a399c845dff").into(),
600                receipts_root: hex!("56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421").into(),
601                logs_bloom: hex!("00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000").to_vec(),
602                prev_randao: hex!("6bf538bdfbdf1c96ff528726a40658a91d0bda0f1351448c4c4f3604db2a0ccf").into(),
603                block_number: 477434,
604                gas_limit: 8154925,
605                gas_used: 0,
606                timestamp: 1652816940,
607                extra_data: vec![],
608                base_fee_per_gas: U256::from(7_i16),
609                block_hash: hex!("cd8df91b4503adb8f2f1c7a4f60e07a1f1a2cbdfa2a95bceba581f3ff65c1968").into(),
610                transactions_root: hex!("7ffe241ea60187fdb0187bfa22de35d1f9bed7ab061d9401fd47e34a54fbede1").into(),
611				withdrawals_root: hex!("28ba1834a3a7b657460ce79fa3a1d909ab8828fd557659d4d0554a9bdbc0ec30").into(),
612			}.hash_tree_root();
613		assert!(hash_root.is_ok());
614	}
615}
616
617/// Operating modes for beacon client
618#[derive(Encode, Decode, Copy, Clone, PartialEq, RuntimeDebug, TypeInfo)]
619pub enum Mode {
620	Active,
621	Blocked,
622}
623
624pub mod deneb {
625	use codec::{Decode, DecodeWithMemTracking, Encode};
626	use frame_support::{CloneNoBound, PartialEqNoBound, RuntimeDebugNoBound};
627	use scale_info::TypeInfo;
628	#[cfg(feature = "std")]
629	use serde::{Deserialize, Serialize};
630	use sp_core::{H160, H256, U256};
631	use sp_std::prelude::*;
632
633	/// ExecutionPayloadHeader
634	/// <https://github.com/ethereum/consensus-specs/blob/dev/specs/deneb/beacon-chain.md#executionpayloadheader>
635	#[derive(
636		Default,
637		Encode,
638		Decode,
639		DecodeWithMemTracking,
640		CloneNoBound,
641		PartialEqNoBound,
642		RuntimeDebugNoBound,
643		TypeInfo,
644	)]
645	#[cfg_attr(
646		feature = "std",
647		derive(Serialize, Deserialize),
648		serde(deny_unknown_fields, bound(serialize = ""), bound(deserialize = ""))
649	)]
650	#[codec(mel_bound())]
651	pub struct ExecutionPayloadHeader {
652		pub parent_hash: H256,
653		pub fee_recipient: H160,
654		pub state_root: H256,
655		pub receipts_root: H256,
656		#[cfg_attr(
657			feature = "std",
658			serde(deserialize_with = "crate::serde_utils::from_hex_to_bytes")
659		)]
660		pub logs_bloom: Vec<u8>,
661		pub prev_randao: H256,
662		pub block_number: u64,
663		pub gas_limit: u64,
664		pub gas_used: u64,
665		pub timestamp: u64,
666		#[cfg_attr(
667			feature = "std",
668			serde(deserialize_with = "crate::serde_utils::from_hex_to_bytes")
669		)]
670		pub extra_data: Vec<u8>,
671		#[cfg_attr(
672			feature = "std",
673			serde(deserialize_with = "crate::serde_utils::from_int_to_u256")
674		)]
675		pub base_fee_per_gas: U256,
676		pub block_hash: H256,
677		pub transactions_root: H256,
678		pub withdrawals_root: H256,
679		pub blob_gas_used: u64,   // [New in Deneb:EIP4844]
680		pub excess_blob_gas: u64, // [New in Deneb:EIP4844]
681	}
682}