Snowbridge Ethereum Deneb fork preparation (#3029)

- Prepares for the Deneb hardfork on Sepolia testnet on 31 January
(needs to be deployed to Rococo before then)
- Removes `beacon-minimal-spec` flag for simpler config
- Adds test comments

---------

Co-authored-by: Ron <yrong1997@gmail.com>
Co-authored-by: claravanstaden <Cats 4 life!>
Co-authored-by: Alistair Singh <alistair.singh7@gmail.com>
This commit is contained in:
Clara van Staden
2024-01-30 08:24:04 +02:00
committed by GitHub
parent b8f55d1b76
commit 85191e94b5
79 changed files with 4721 additions and 4296 deletions
@@ -31,7 +31,7 @@ byte-slice-cast = { version = "1.2.1", default-features = false }
snowbridge-ethereum = { path = "../ethereum", default-features = false }
static_assertions = { version = "1.1.0" }
milagro_bls = { git = "https://github.com/snowfork/milagro_bls", default-features = false, rev = "a6d66e4eb89015e352fb1c9f7b661ecdbb5b2176" }
milagro-bls = { package = "snowbridge-milagro-bls", version = "1.5.4", default-features = false }
[dev-dependencies]
hex-literal = { version = "0.4.1" }
@@ -44,7 +44,7 @@ std = [
"frame-support/std",
"frame-system/std",
"hex/std",
"milagro_bls/std",
"milagro-bls/std",
"rlp/std",
"scale-info/std",
"serde",
@@ -18,6 +18,7 @@ pub use types::{
BeaconHeader, CompactBeaconState, CompactExecutionHeader, ExecutionHeaderState,
ExecutionPayloadHeader, FinalizedHeaderState, Fork, ForkData, ForkVersion, ForkVersions, Mode,
PublicKey, Signature, SigningData, SyncAggregate, SyncCommittee, SyncCommitteePrepared,
VersionedExecutionPayloadHeader,
};
pub use updates::{CheckpointUpdate, ExecutionHeaderUpdate, NextSyncCommitteeUpdate, Update};
@@ -192,3 +192,87 @@ pub fn hash_tree_root<T: SimpleSerialize>(mut object: T) -> Result<H256, SimpleS
Err(err) => Err(err.into()),
}
}
pub mod deneb {
use crate::{
config::{EXTRA_DATA_SIZE, FEE_RECIPIENT_SIZE, LOGS_BLOOM_SIZE},
ssz::hash_tree_root,
types::deneb::ExecutionPayloadHeader,
};
use byte_slice_cast::AsByteSlice;
use sp_core::H256;
use sp_std::{vec, vec::Vec};
use ssz_rs::{
prelude::{List, Vector},
Deserialize, DeserializeError, SimpleSerializeError, Sized, U256,
};
use ssz_rs_derive::SimpleSerialize as SimpleSerializeDerive;
#[derive(Default, SimpleSerializeDerive, Clone, Debug)]
pub struct SSZExecutionPayloadHeader {
pub parent_hash: [u8; 32],
pub fee_recipient: Vector<u8, FEE_RECIPIENT_SIZE>,
pub state_root: [u8; 32],
pub receipts_root: [u8; 32],
pub logs_bloom: Vector<u8, LOGS_BLOOM_SIZE>,
pub prev_randao: [u8; 32],
pub block_number: u64,
pub gas_limit: u64,
pub gas_used: u64,
pub timestamp: u64,
pub extra_data: List<u8, EXTRA_DATA_SIZE>,
pub base_fee_per_gas: U256,
pub block_hash: [u8; 32],
pub transactions_root: [u8; 32],
pub withdrawals_root: [u8; 32],
pub blob_gas_used: u64,
pub excess_blob_gas: u64,
}
impl TryFrom<ExecutionPayloadHeader> for SSZExecutionPayloadHeader {
type Error = SimpleSerializeError;
fn try_from(payload: ExecutionPayloadHeader) -> Result<Self, Self::Error> {
Ok(SSZExecutionPayloadHeader {
parent_hash: payload.parent_hash.to_fixed_bytes(),
fee_recipient: Vector::<u8, FEE_RECIPIENT_SIZE>::try_from(
payload.fee_recipient.to_fixed_bytes().to_vec(),
)
.expect("checked statically; qed"),
state_root: payload.state_root.to_fixed_bytes(),
receipts_root: payload.receipts_root.to_fixed_bytes(),
// Logs bloom bytes size is not constrained, so here we do need to check the
// try_from error
logs_bloom: Vector::<u8, LOGS_BLOOM_SIZE>::try_from(payload.logs_bloom)
.map_err(|(_, err)| err)?,
prev_randao: payload.prev_randao.to_fixed_bytes(),
block_number: payload.block_number,
gas_limit: payload.gas_limit,
gas_used: payload.gas_used,
timestamp: payload.timestamp,
// Extra data bytes size is not constrained, so here we do need to check the
// try_from error
extra_data: List::<u8, EXTRA_DATA_SIZE>::try_from(payload.extra_data)
.map_err(|(_, err)| err)?,
base_fee_per_gas: U256::from_bytes_le(
payload
.base_fee_per_gas
.as_byte_slice()
.try_into()
.expect("checked in prep; qed"),
),
block_hash: payload.block_hash.to_fixed_bytes(),
transactions_root: payload.transactions_root.to_fixed_bytes(),
withdrawals_root: payload.withdrawals_root.to_fixed_bytes(),
blob_gas_used: payload.blob_gas_used,
excess_blob_gas: payload.excess_blob_gas,
})
}
}
impl ExecutionPayloadHeader {
pub fn hash_tree_root(&self) -> Result<H256, SimpleSerializeError> {
hash_tree_root::<SSZExecutionPayloadHeader>(self.clone().try_into()?)
}
}
}
@@ -5,7 +5,7 @@ use frame_support::{CloneNoBound, PartialEqNoBound, RuntimeDebugNoBound};
use scale_info::TypeInfo;
use sp_core::{H160, H256, U256};
use sp_runtime::RuntimeDebug;
use sp_std::{boxed::Box, prelude::*};
use sp_std::{boxed::Box, iter::repeat, prelude::*};
use crate::config::{PUBKEY_SIZE, SIGNATURE_SIZE};
@@ -35,6 +35,7 @@ pub struct ForkVersions {
pub altair: Fork,
pub bellatrix: Fork,
pub capella: Fork,
pub deneb: Fork,
}
#[derive(Clone, Encode, Decode, PartialEq, RuntimeDebug, TypeInfo)]
@@ -189,9 +190,14 @@ pub struct SyncCommitteePrepared<const COMMITTEE_SIZE: usize> {
impl<const COMMITTEE_SIZE: usize> Default for SyncCommitteePrepared<COMMITTEE_SIZE> {
fn default() -> Self {
let pubkeys: Vec<PublicKeyPrepared> =
repeat(PublicKeyPrepared::default()).take(COMMITTEE_SIZE).collect();
let pubkeys: Box<[PublicKeyPrepared; COMMITTEE_SIZE]> =
Box::new(pubkeys.try_into().map_err(|_| ()).expect("checked statically; qed"));
SyncCommitteePrepared {
root: H256::default(),
pubkeys: Box::new([PublicKeyPrepared::default(); COMMITTEE_SIZE]),
pubkeys,
aggregate_pubkey: PublicKeyPrepared::default(),
}
}
@@ -207,7 +213,7 @@ impl<const COMMITTEE_SIZE: usize> TryFrom<&SyncCommittee<COMMITTEE_SIZE>>
let sync_committee_root = sync_committee.hash_tree_root().expect("checked statically; qed");
Ok(SyncCommitteePrepared::<COMMITTEE_SIZE> {
pubkeys: g1_pubkeys.try_into().expect("checked statically; qed"),
pubkeys: g1_pubkeys.try_into().map_err(|_| ()).expect("checked statically; qed"),
aggregate_pubkey: prepare_milagro_pubkey(&sync_committee.aggregate_pubkey)?,
root: sync_committee_root,
})
@@ -309,7 +315,7 @@ impl<const COMMITTEE_SIZE: usize, const COMMITTEE_BITS_SIZE: usize>
)]
#[cfg_attr(
feature = "std",
derive(Deserialize),
derive(Serialize, Deserialize),
serde(deny_unknown_fields, bound(serialize = ""), bound(deserialize = ""))
)]
#[codec(mel_bound())]
@@ -386,6 +392,64 @@ pub struct CompactBeaconState {
pub block_roots_root: H256,
}
/// VersionedExecutionPayloadHeader
#[derive(Encode, Decode, CloneNoBound, PartialEqNoBound, RuntimeDebugNoBound, TypeInfo)]
#[cfg_attr(
feature = "std",
derive(Serialize, Deserialize),
serde(deny_unknown_fields, bound(serialize = ""), bound(deserialize = ""))
)]
#[codec(mel_bound())]
pub enum VersionedExecutionPayloadHeader {
Capella(ExecutionPayloadHeader),
Deneb(deneb::ExecutionPayloadHeader),
}
/// Convert VersionedExecutionPayloadHeader to CompactExecutionHeader
impl From<VersionedExecutionPayloadHeader> for CompactExecutionHeader {
fn from(versioned_execution_header: VersionedExecutionPayloadHeader) -> Self {
match versioned_execution_header {
VersionedExecutionPayloadHeader::Capella(execution_payload_header) =>
execution_payload_header.into(),
VersionedExecutionPayloadHeader::Deneb(execution_payload_header) =>
execution_payload_header.into(),
}
}
}
impl VersionedExecutionPayloadHeader {
pub fn hash_tree_root(&self) -> Result<H256, SimpleSerializeError> {
match self {
VersionedExecutionPayloadHeader::Capella(execution_payload_header) =>
hash_tree_root::<SSZExecutionPayloadHeader>(
execution_payload_header.clone().try_into()?,
),
VersionedExecutionPayloadHeader::Deneb(execution_payload_header) =>
hash_tree_root::<crate::ssz::deneb::SSZExecutionPayloadHeader>(
execution_payload_header.clone().try_into()?,
),
}
}
pub fn block_hash(&self) -> H256 {
match self {
VersionedExecutionPayloadHeader::Capella(execution_payload_header) =>
execution_payload_header.block_hash,
VersionedExecutionPayloadHeader::Deneb(execution_payload_header) =>
execution_payload_header.block_hash,
}
}
pub fn block_number(&self) -> u64 {
match self {
VersionedExecutionPayloadHeader::Capella(execution_payload_header) =>
execution_payload_header.block_number,
VersionedExecutionPayloadHeader::Deneb(execution_payload_header) =>
execution_payload_header.block_number,
}
}
}
#[cfg(test)]
mod tests {
use super::*;
@@ -510,3 +574,68 @@ pub enum Mode {
Active,
Blocked,
}
pub mod deneb {
use crate::CompactExecutionHeader;
use codec::{Decode, Encode};
use frame_support::{CloneNoBound, PartialEqNoBound, RuntimeDebugNoBound};
use scale_info::TypeInfo;
#[cfg(feature = "std")]
use serde::{Deserialize, Serialize};
use sp_core::{H160, H256, U256};
use sp_std::prelude::*;
/// ExecutionPayloadHeader
/// <https://github.com/ethereum/consensus-specs/blob/dev/specs/deneb/beacon-chain.md#executionpayloadheader>
#[derive(
Default, Encode, Decode, CloneNoBound, PartialEqNoBound, RuntimeDebugNoBound, TypeInfo,
)]
#[cfg_attr(
feature = "std",
derive(Serialize, Deserialize),
serde(deny_unknown_fields, bound(serialize = ""), bound(deserialize = ""))
)]
#[codec(mel_bound())]
pub struct ExecutionPayloadHeader {
pub parent_hash: H256,
pub fee_recipient: H160,
pub state_root: H256,
pub receipts_root: H256,
#[cfg_attr(
feature = "std",
serde(deserialize_with = "crate::serde_utils::from_hex_to_bytes")
)]
pub logs_bloom: Vec<u8>,
pub prev_randao: H256,
pub block_number: u64,
pub gas_limit: u64,
pub gas_used: u64,
pub timestamp: u64,
#[cfg_attr(
feature = "std",
serde(deserialize_with = "crate::serde_utils::from_hex_to_bytes")
)]
pub extra_data: Vec<u8>,
#[cfg_attr(
feature = "std",
serde(deserialize_with = "crate::serde_utils::from_int_to_u256")
)]
pub base_fee_per_gas: U256,
pub block_hash: H256,
pub transactions_root: H256,
pub withdrawals_root: H256,
pub blob_gas_used: u64, // [New in Deneb:EIP4844]
pub excess_blob_gas: u64, // [New in Deneb:EIP4844]
}
impl From<ExecutionPayloadHeader> for CompactExecutionHeader {
fn from(execution_payload: ExecutionPayloadHeader) -> Self {
Self {
parent_hash: execution_payload.parent_hash,
block_number: execution_payload.block_number,
state_root: execution_payload.state_root,
receipts_root: execution_payload.receipts_root,
}
}
}
}
@@ -6,7 +6,7 @@ use scale_info::TypeInfo;
use sp_core::H256;
use sp_std::prelude::*;
use crate::types::{BeaconHeader, ExecutionPayloadHeader, SyncAggregate, SyncCommittee};
use crate::types::{BeaconHeader, SyncAggregate, SyncCommittee, VersionedExecutionPayloadHeader};
#[derive(Encode, Decode, CloneNoBound, PartialEqNoBound, RuntimeDebugNoBound, TypeInfo)]
#[cfg_attr(
@@ -91,7 +91,7 @@ pub struct ExecutionHeaderUpdate {
/// Proof that `header` is an ancestor of a finalized header
pub ancestry_proof: Option<AncestryProof>,
/// Execution header to be imported
pub execution_header: ExecutionPayloadHeader,
pub execution_header: VersionedExecutionPayloadHeader,
/// Merkle proof that execution payload is contained within `header`
pub execution_branch: Vec<H256>,
}
@@ -31,7 +31,7 @@ sp-arithmetic = { path = "../../../../../substrate/primitives/arithmetic", defau
snowbridge-beacon-primitives = { path = "../beacon", default-features = false }
ethabi = { git = "https://github.com/Snowfork/ethabi-decode.git", package = "ethabi-decode", branch = "master", default-features = false }
ethabi = { package = "ethabi-decode", version = "1.0.0", default-features = false }
[dev-dependencies]
hex = { version = "0.4.3" }
@@ -44,10 +44,6 @@ where
SiblingParaId::from(para_id).into_account_truncating()
}
pub fn sibling_sovereign_account_raw(para_id: ParaId) -> [u8; 32] {
SiblingParaId::from(para_id).into_account_truncating()
}
pub struct AllowSiblingsOnly;
impl Contains<Location> for AllowSiblingsOnly {
fn contains(location: &Location) -> bool {
@@ -28,7 +28,7 @@ sp-std = { path = "../../../../../substrate/primitives/std", default-features =
sp-core = { path = "../../../../../substrate/primitives/core", default-features = false }
sp-runtime = { path = "../../../../../substrate/primitives/runtime", default-features = false }
ethabi = { git = "https://github.com/snowfork/ethabi-decode.git", package = "ethabi-decode", branch = "master", default-features = false }
ethabi = { package = "ethabi-decode", version = "1.0.0", default-features = false }
[dev-dependencies]
wasm-bindgen-test = "0.3.19"
@@ -30,7 +30,7 @@ xcm-executor = { package = "staging-xcm-executor", path = "../../../../../polkad
snowbridge-core = { path = "../core", default-features = false }
ethabi = { git = "https://github.com/Snowfork/ethabi-decode.git", package = "ethabi-decode", branch = "master", default-features = false }
ethabi = { package = "ethabi-decode", version = "1.0.0", default-features = false }
hex-literal = { version = "0.4.1" }
@@ -2,7 +2,7 @@ use super::GlobalConsensusEthereumConvertsFor;
use crate::inbound::CallIndex;
use frame_support::parameter_types;
use hex_literal::hex;
use xcm::v4::prelude::*;
use xcm::prelude::*;
use xcm_executor::traits::ConvertLocation;
const NETWORK: NetworkId = Ethereum { chain_id: 11155111 };
@@ -16,7 +16,7 @@ use snowbridge_core::{
};
use sp_core::{H160, H256};
use sp_std::{iter::Peekable, marker::PhantomData, prelude::*};
use xcm::v4::prelude::*;
use xcm::prelude::*;
use xcm_executor::traits::{ConvertLocation, ExportXcm};
pub struct EthereumBlobExporter<