Skip to content

Commit 117a089

Browse files
committed
Initial commit
1 parent 22f3db8 commit 117a089

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

54 files changed

+33426
-198
lines changed

contracts/near/Cargo.lock

Lines changed: 34 additions & 5 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

contracts/near/Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ tree_hash = "0.8"
2828
tree_hash_derive = "0.8"
2929
ethereum_ssz = "0.7"
3030
ethereum_ssz_derive = "0.7"
31-
ethereum_serde_utils = "0.7"
31+
ethereum_serde_utils = "0.8"
3232
ethereum_hashing = "0.7.0"
3333
derive_more = "^0.99.2"
3434
hex = "0.4.2"

contracts/near/eth-prover/Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ repository.workspace = true
99
# in https://github.com/near/NEPs/blob/master/neps/nep-0330.md
1010
[package.metadata.near.reproducible_build]
1111
# docker image, descriptor of build environment
12-
image = "sourcescan/cargo-near:0.13.2-rust-1.84.0"
12+
image = "sourcescan/cargo-near:0.16.0-rust-1.86.0"
1313
# tag after colon above serves only descriptive purpose; image is identified by digest
1414
image_digest = "sha256:b41cb89907f92b114da9e2be4e109bff30ab792c22ddcbd2a4cff8e340cb9acb"
1515
# list of environment variables names, whose values, if set, will be used as external build parameters
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,2 @@
11
[toolchain]
2-
channel = "1.84.0"
2+
channel = "1.86.0"

contracts/near/eth-prover/src/tests.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ mod tests {
3030

3131
// TESTS
3232

33-
use near_sdk::{testing_env, VMContext, NearToken};
33+
use near_sdk::{testing_env, NearToken, VMContext};
3434

3535
fn get_context(input: Vec<u8>) -> VMContext {
3636
VMContext {

contracts/near/eth-prover/src/tests_storage_proof.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -80,7 +80,7 @@ mod tests_storage_proof {
8080

8181
// TESTS
8282

83-
use near_sdk::{testing_env, VMContext, NearToken};
83+
use near_sdk::{testing_env, NearToken, VMContext};
8484

8585
fn get_context(input: Vec<u8>) -> VMContext {
8686
VMContext {

contracts/near/eth-types/src/eth2.rs

Lines changed: 184 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
use super::*;
22
use borsh::{BorshDeserialize, BorshSerialize};
33
use std::io::{Error, Write};
4-
use tree_hash::MerkleHasher;
4+
use tree_hash::{MerkleHasher, TreeHash};
55

66
#[cfg(not(target_arch = "wasm32"))]
77
use {
@@ -29,6 +29,74 @@ arr_wrapper_impl_tree_hash_and_borsh!(PublicKeyBytes, PUBLIC_KEY_BYTES_LEN);
2929
arr_wrapper_impl_tree_hash_and_borsh!(SignatureBytes, SIGNATURE_BYTES_LEN);
3030
arr_wrapper_impl_tree_hash_and_borsh!(SyncCommitteeBits, SYNC_COMMITTEE_BITS_SIZE_IN_BYTES);
3131

32+
#[derive(Debug, Clone, BorshSchema)]
33+
pub struct ExtraData(pub Vec<u8>);
34+
35+
impl tree_hash::TreeHash for ExtraData {
36+
fn tree_hash_type() -> tree_hash::TreeHashType {
37+
tree_hash::TreeHashType::List
38+
}
39+
40+
fn tree_hash_packed_encoding(&self) -> tree_hash::PackedEncoding {
41+
unreachable!("List should never be packed.")
42+
}
43+
44+
fn tree_hash_packing_factor() -> usize {
45+
unreachable!("List should never be packed.")
46+
}
47+
48+
fn tree_hash_root(&self) -> tree_hash::Hash256 {
49+
let mut hasher =
50+
tree_hash::MerkleHasher::with_leaves(self.0.len().div_ceil(tree_hash::BYTES_PER_CHUNK));
51+
52+
for item in &self.0 {
53+
hasher.write(&item.tree_hash_packed_encoding()).unwrap();
54+
}
55+
56+
let root = hasher.finish().unwrap();
57+
tree_hash::mix_in_length(&root, self.0.len())
58+
}
59+
}
60+
61+
// Add Borsh implementations
62+
impl borsh::BorshSerialize for ExtraData {
63+
fn serialize<W: std::io::Write>(&self, writer: &mut W) -> std::io::Result<()> {
64+
BorshSerialize::serialize(&self.0, writer)
65+
}
66+
}
67+
68+
impl borsh::BorshDeserialize for ExtraData {
69+
fn deserialize_reader<R: std::io::Read>(reader: &mut R) -> std::io::Result<Self> {
70+
Ok(ExtraData(Vec::<u8>::deserialize_reader(reader)?))
71+
}
72+
}
73+
74+
#[cfg(not(target_arch = "wasm32"))]
75+
impl serde::Serialize for ExtraData {
76+
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
77+
where
78+
S: serde::Serializer,
79+
{
80+
// Always serialize as hex string
81+
let hex_string = format!("0x{}", hex::encode(&self.0));
82+
serializer.serialize_str(&hex_string)
83+
}
84+
}
85+
86+
#[cfg(not(target_arch = "wasm32"))]
87+
impl<'de> serde::Deserialize<'de> for ExtraData {
88+
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
89+
where
90+
D: serde::Deserializer<'de>,
91+
{
92+
let hex_string = <std::string::String as Deserialize>::deserialize(deserializer)?;
93+
let hex_string = hex_string.strip_prefix("0x").unwrap_or(&hex_string);
94+
let bytes = hex::decode(hex_string)
95+
.map_err(|e| serde::de::Error::custom(format!("Invalid hex: {}", e)))?;
96+
Ok(ExtraData(bytes))
97+
}
98+
}
99+
32100
#[derive(
33101
Debug, Clone, BorshDeserialize, BorshSchema, BorshSerialize, tree_hash_derive::TreeHash,
34102
)]
@@ -43,18 +111,62 @@ pub struct BeaconBlockHeader {
43111
pub body_root: H256,
44112
}
45113

114+
// New execution header structure for Electra
115+
#[derive(
116+
Debug, Clone, BorshDeserialize, BorshSchema, BorshSerialize, tree_hash_derive::TreeHash,
117+
)]
118+
#[cfg_attr(not(target_arch = "wasm32"), derive(Serialize, Deserialize))]
119+
pub struct ExecutionHeader {
120+
pub parent_hash: H256,
121+
pub fee_recipient: H160,
122+
pub state_root: H256,
123+
pub receipts_root: H256,
124+
pub logs_bloom: Bloom,
125+
pub prev_randao: H256,
126+
#[cfg_attr(not(target_arch = "wasm32"), serde(with = "serde_utils::quoted_u64"))]
127+
pub block_number: u64,
128+
#[cfg_attr(not(target_arch = "wasm32"), serde(with = "serde_utils::quoted_u64"))]
129+
pub gas_limit: u64,
130+
#[cfg_attr(not(target_arch = "wasm32"), serde(with = "serde_utils::quoted_u64"))]
131+
pub gas_used: u64,
132+
#[cfg_attr(not(target_arch = "wasm32"), serde(with = "serde_utils::quoted_u64"))]
133+
pub timestamp: u64,
134+
pub extra_data: ExtraData,
135+
#[cfg_attr(not(target_arch = "wasm32"), serde(with = "serde_utils::quoted_u64"))]
136+
pub base_fee_per_gas: u64,
137+
pub block_hash: H256,
138+
pub transactions_root: H256,
139+
pub withdrawals_root: H256,
140+
#[cfg_attr(not(target_arch = "wasm32"), serde(with = "serde_utils::quoted_u64"))]
141+
pub blob_gas_used: u64,
142+
#[cfg_attr(not(target_arch = "wasm32"), serde(with = "serde_utils::quoted_u64"))]
143+
pub excess_blob_gas: u64,
144+
}
145+
146+
// New combined header structure
147+
#[derive(Debug, Clone, BorshDeserialize, BorshSchema, BorshSerialize)]
148+
#[cfg_attr(not(target_arch = "wasm32"), derive(Serialize, Deserialize))]
149+
pub struct AttestedHeader {
150+
pub beacon: BeaconBlockHeader,
151+
pub execution: ExecutionHeader,
152+
pub execution_branch: Vec<H256>,
153+
}
154+
155+
#[derive(Debug, Clone, BorshDeserialize, BorshSchema, BorshSerialize)]
156+
#[cfg_attr(not(target_arch = "wasm32"), derive(Serialize, Deserialize))]
157+
pub struct FinalizedHeader {
158+
pub beacon: BeaconBlockHeader,
159+
pub execution: ExecutionHeader,
160+
pub execution_branch: Vec<H256>,
161+
}
162+
46163
#[derive(Debug, Clone, PartialEq, tree_hash_derive::TreeHash)]
47164
pub struct ForkData {
48165
pub current_version: ForkVersion,
49166
pub genesis_validators_root: H256,
50167
}
51168

52-
#[derive(Debug, PartialEq, Clone, tree_hash_derive::TreeHash)]
53-
pub struct SigningData {
54-
pub object_root: H256,
55-
pub domain: H256,
56-
}
57-
169+
/// This is used specifically for backwards-compatibility, storing state in the contract
58170
#[derive(Debug, Clone, BorshDeserialize, BorshSchema, BorshSerialize)]
59171
#[cfg_attr(not(target_arch = "wasm32"), derive(Serialize, Deserialize))]
60172
pub struct ExtendedBeaconBlockHeader {
@@ -63,17 +175,23 @@ pub struct ExtendedBeaconBlockHeader {
63175
pub execution_block_hash: H256,
64176
}
65177

66-
impl From<HeaderUpdate> for ExtendedBeaconBlockHeader {
67-
fn from(item: HeaderUpdate) -> Self {
68-
let root = item.beacon_header.tree_hash_root();
69-
ExtendedBeaconBlockHeader {
70-
header: item.beacon_header,
71-
beacon_block_root: H256(root.0.into()),
72-
execution_block_hash: item.execution_block_hash,
178+
impl From<FinalizedHeader> for ExtendedBeaconBlockHeader {
179+
fn from(finalized_header: FinalizedHeader) -> Self {
180+
let beacon = finalized_header.beacon;
181+
Self {
182+
header: beacon.clone(),
183+
beacon_block_root: beacon.tree_hash_root().0.into(),
184+
execution_block_hash: finalized_header.execution.block_hash,
73185
}
74186
}
75187
}
76188

189+
#[derive(Debug, PartialEq, Clone, tree_hash_derive::TreeHash)]
190+
pub struct SigningData {
191+
pub object_root: H256,
192+
pub domain: H256,
193+
}
194+
77195
#[derive(Debug, Clone, BorshDeserialize, BorshSchema, BorshSerialize)]
78196
#[cfg_attr(not(target_arch = "wasm32"), derive(Serialize, Deserialize))]
79197
pub struct SyncCommitteePublicKeys(pub Vec<PublicKeyBytes>);
@@ -95,40 +213,73 @@ pub struct SyncAggregate {
95213
pub sync_committee_signature: SignatureBytes,
96214
}
97215

216+
// Updated light client update structure for Electra
98217
#[derive(Debug, Clone, BorshDeserialize, BorshSchema, BorshSerialize)]
99218
#[cfg_attr(not(target_arch = "wasm32"), derive(Serialize, Deserialize))]
100-
pub struct SyncCommitteeUpdate {
101-
pub next_sync_committee: SyncCommittee,
102-
pub next_sync_committee_branch: Vec<H256>,
219+
pub struct LightClientUpdate {
220+
pub attested_header: AttestedHeader,
221+
pub next_sync_committee: Option<SyncCommittee>,
222+
pub next_sync_committee_branch: Option<Vec<H256>>,
223+
pub finalized_header: FinalizedHeader,
224+
pub finality_branch: Vec<H256>,
225+
pub sync_aggregate: SyncAggregate,
226+
#[cfg_attr(not(target_arch = "wasm32"), serde(with = "serde_utils::quoted_u64"))]
227+
pub signature_slot: Slot,
103228
}
104229

105-
#[derive(Debug, Clone, BorshDeserialize, BorshSchema, BorshSerialize)]
230+
// Version enum for different Ethereum fork versions
231+
#[derive(Debug, Clone, Copy, PartialEq, Eq, BorshDeserialize, BorshSchema, BorshSerialize)]
106232
#[cfg_attr(not(target_arch = "wasm32"), derive(Serialize, Deserialize))]
107-
pub struct HeaderUpdate {
108-
pub beacon_header: BeaconBlockHeader,
109-
pub execution_block_hash: H256,
110-
pub execution_hash_branch: Vec<H256>,
233+
#[cfg_attr(not(target_arch = "wasm32"), serde(rename_all = "lowercase"))]
234+
pub enum LightClientVersion {
235+
Altair,
236+
Bellatrix,
237+
Capella,
238+
Deneb,
239+
Electra,
111240
}
112241

242+
impl LightClientVersion {
243+
pub fn as_str(&self) -> &'static str {
244+
match self {
245+
LightClientVersion::Altair => "altair",
246+
LightClientVersion::Bellatrix => "bellatrix",
247+
LightClientVersion::Capella => "capella",
248+
LightClientVersion::Deneb => "deneb",
249+
LightClientVersion::Electra => "electra",
250+
}
251+
}
252+
}
253+
254+
impl std::fmt::Display for LightClientVersion {
255+
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
256+
write!(f, "{}", self.as_str())
257+
}
258+
}
259+
260+
// Top-level wrapper with version (optional, for when you need versioning)
113261
#[derive(Debug, Clone, BorshDeserialize, BorshSchema, BorshSerialize)]
114262
#[cfg_attr(not(target_arch = "wasm32"), derive(Serialize, Deserialize))]
115-
pub struct FinalizedHeaderUpdate {
116-
pub header_update: HeaderUpdate,
117-
pub finality_branch: Vec<H256>,
263+
pub struct VersionedLightClientUpdate {
264+
pub version: LightClientVersion,
265+
pub data: LightClientUpdate,
118266
}
119267

268+
// For arrays of light client updates
120269
#[derive(Debug, Clone, BorshDeserialize, BorshSchema, BorshSerialize)]
121270
#[cfg_attr(not(target_arch = "wasm32"), derive(Serialize, Deserialize))]
122-
pub struct LightClientUpdate {
123-
pub attested_beacon_header: BeaconBlockHeader,
124-
pub sync_aggregate: SyncAggregate,
125-
#[cfg_attr(not(target_arch = "wasm32"), serde(with = "serde_utils::quoted_u64"))]
126-
pub signature_slot: Slot,
127-
pub finality_update: FinalizedHeaderUpdate,
128-
pub sync_committee_update: Option<SyncCommitteeUpdate>,
271+
pub struct LightClientUpdates(pub Vec<LightClientUpdate>);
272+
273+
// Alternative: Version-specific data if structures differ significantly between versions
274+
#[derive(Debug, Clone, BorshDeserialize, BorshSchema, BorshSerialize)]
275+
#[cfg_attr(not(target_arch = "wasm32"), derive(Serialize, Deserialize))]
276+
pub enum LightClientUpdateVariant {
277+
Electra(LightClientUpdate),
278+
// Future versions can be added here with different data structures
279+
// Deneb(DenebLightClientUpdate),
129280
}
130281

131-
#[derive(Clone, BorshDeserialize, BorshSchema, BorshSerialize)]
282+
#[derive(Clone, BorshDeserialize, BorshSchema, BorshSerialize, Debug)]
132283
pub struct LightClientState {
133284
pub finalized_beacon_header: ExtendedBeaconBlockHeader,
134285
pub current_sync_committee: SyncCommittee,

0 commit comments

Comments
 (0)