Skip to content

Commit 111a5e7

Browse files
committed
init contract function
1 parent 0cca309 commit 111a5e7

8 files changed

Lines changed: 179 additions & 42 deletions

File tree

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

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -160,8 +160,6 @@ macro_rules! uint_declare_wrapper_and_serde {
160160
tree_hash::Hash256::from(bytes)
161161
}
162162
}
163-
164-
165163
};
166164
}
167165

contracts/near/eth2-client/src/data/dump_sepolia_data.py

Lines changed: 17 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -67,29 +67,29 @@ def fetch_execution_block(number: int) -> BlockData:
6767

6868
def normalize_block(raw: BlockData) -> dict:
6969
return {
70-
"parent_hash": raw.get("parentHash"),
71-
"uncles_hash": raw.get("sha3Uncles"),
72-
"author": raw.get("miner"),
73-
"state_root": raw.get("stateRoot"),
74-
"transactions_root": raw.get("transactionsRoot"),
75-
"receipts_root": raw.get("receiptsRoot"),
76-
"log_bloom": raw.get("logsBloom"),
70+
"parentHash": raw.get("parentHash"),
71+
"sha3Uncles": raw.get("sha3Uncles"),
72+
"miner": raw.get("miner"),
73+
"stateRoot": raw.get("stateRoot"),
74+
"transactionsRoot": raw.get("transactionsRoot"),
75+
"receiptsRoot": raw.get("receiptsRoot"),
76+
"logsBloom": raw.get("logsBloom"),
7777
"difficulty": hex(raw.get("difficulty", 0)),
7878
"number": hex(raw.get("number", 0)),
79-
"gas_limit": hex(raw.get("gasLimit", 0)),
80-
"gas_used": hex(raw.get("gasUsed", 0)),
79+
"gasLimit": hex(raw.get("gasLimit", 0)),
80+
"gasUsed": hex(raw.get("gasUsed", 0)),
8181
"timestamp": hex(raw.get("timestamp", 0)),
82-
"extra_data": raw.get("extraData"),
83-
"mix_hash": raw.get("mixHash"),
82+
"extraData": raw.get("extraData"),
83+
"mixHash": raw.get("mixHash"),
8484
"nonce": raw.get("nonce"),
85-
"base_fee_per_gas": hex(raw.get("baseFeePerGas", 0))
85+
"baseFeePerGas": hex(raw.get("baseFeePerGas", 0))
8686
if raw.get("baseFeePerGas") is not None
8787
else None, # Convert to hex
88-
"withdrawals_root": raw.get("withdrawalsRoot"),
89-
"blob_gas_used": hex(raw.get("blobGasUsed", 0)),
90-
"excess_blob_gas": hex(raw.get("excessBlobGas", 0)),
91-
"parent_beacon_block_root": raw.get("parentBeaconBlockRoot"),
92-
"requests_hash": raw.get("requestsHash"),
88+
"withdrawalsRoot": raw.get("withdrawalsRoot"),
89+
"blobGasUsed": hex(raw.get("blobGasUsed", 0)),
90+
"excessBlobGas": hex(raw.get("excessBlobGas", 0)),
91+
"parentBeaconBlockRoot": raw.get("parentBeaconBlockRoot"),
92+
"requestsHash": raw.get("requestsHash"),
9393
}
9494

9595

contracts/near/eth2-client/src/tests/unit_tests.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -490,7 +490,8 @@ mod tests {
490490
for i in 0..342 {
491491
sync_committee_bits.set(i, true);
492492
}
493-
update.sync_aggregate.sync_committee_bits = sync_committee_bits.as_raw_mut_slice().to_vec().into();
493+
update.sync_aggregate.sync_committee_bits =
494+
sync_committee_bits.as_raw_mut_slice().to_vec().into();
494495

495496
contract.submit_beacon_chain_light_client_update(update);
496497
}

relayer/relayer.toml

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,13 @@ submission_sleep_secs = 12
2121
dry_run = false
2222
fast_mode = false
2323

24+
[init]
25+
network = "sepolia"
26+
init_update = "../contracts/near/eth2-client/src/data/sepolia/light_client_update_period_925.json"
27+
first_update = "../contracts/near/eth2-client/src/data/sepolia/light_client_update_period_926.json"
28+
headers = "../contracts/near/eth2-client/src/data/sepolia/execution_blocks_8286935_8295112.json"
29+
hashes_gc_threshold = 51000
30+
2431
[logging]
2532
level = "info"
2633
json = false

relayer/src/clients/near.rs

Lines changed: 58 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -67,13 +67,19 @@ impl ContractClient {
6767
e
6868
})
6969
.wrap_err(format!("Failed to call view method '{}'", method_name))?;
70-
let result = response.borsh::<T>().map_err(|e| {
71-
error!("Failed to deserialize response from '{}': {:#}", method_name, e);
72-
e
73-
}).wrap_err(format!(
74-
"Failed to deserialize result from '{}'",
75-
method_name
76-
))?;
70+
let result = response
71+
.borsh::<T>()
72+
.map_err(|e| {
73+
error!(
74+
"Failed to deserialize response from '{}': {:#}",
75+
method_name, e
76+
);
77+
e
78+
})
79+
.wrap_err(format!(
80+
"Failed to deserialize result from '{}'",
81+
method_name
82+
))?;
7783
Ok(result)
7884
}
7985

@@ -118,26 +124,38 @@ impl ContractClient {
118124
)
119125
.await
120126
.map_err(|e| {
121-
error!("NEAR view call 'block_hash_safe' for block {} timed out: {:#}", block_number, e);
127+
error!(
128+
"NEAR view call 'block_hash_safe' for block {} timed out: {:#}",
129+
block_number, e
130+
);
122131
e
123132
})
124133
.wrap_err("NEAR view timed out")?
125134
.map_err(|e| {
126-
error!("NEAR view call 'block_hash_safe' for block {} failed: {:#}", block_number, e);
135+
error!(
136+
"NEAR view call 'block_hash_safe' for block {} failed: {:#}",
137+
block_number, e
138+
);
127139
e
128140
})
129141
.wrap_err(format!(
130142
"Failed to call view method 'block_hash_safe' with block number {}",
131143
block_number
132144
))?;
133145

134-
let result = response.borsh::<Option<H256>>().map_err(|e| {
135-
error!("Failed to deserialize block hash for block {}: {:#}", block_number, e);
136-
e
137-
}).wrap_err(format!(
138-
"Failed to get block hash result for block number {}",
139-
block_number
140-
))?;
146+
let result = response
147+
.borsh::<Option<H256>>()
148+
.map_err(|e| {
149+
error!(
150+
"Failed to deserialize block hash for block {}: {:#}",
151+
block_number, e
152+
);
153+
e
154+
})
155+
.wrap_err(format!(
156+
"Failed to get block hash result for block number {}",
157+
block_number
158+
))?;
141159
Ok(result)
142160
}
143161

@@ -259,7 +277,12 @@ impl ContractClient {
259277
)
260278
.await
261279
.map_err(|e| {
262-
error!("Batch {}/{} submission timed out: {:#}", batch_index + 1, total_batches, e);
280+
error!(
281+
"Batch {}/{} submission timed out: {:#}",
282+
batch_index + 1,
283+
total_batches,
284+
e
285+
);
263286
e
264287
})
265288
.wrap_err(format!(
@@ -283,12 +306,22 @@ impl ContractClient {
283306
)
284307
.await
285308
.map_err(|e| {
286-
error!("Batch {}/{} submission timed out: {:#}", batch_index + 1, total_batches, e);
309+
error!(
310+
"Batch {}/{} submission timed out: {:#}",
311+
batch_index + 1,
312+
total_batches,
313+
e
314+
);
287315
e
288316
})
289317
.wrap_err("NEAR call timed out")?
290318
.map_err(|e| {
291-
error!("Batch {}/{} transaction failed: {:#}", batch_index + 1, total_batches, e);
319+
error!(
320+
"Batch {}/{} transaction failed: {:#}",
321+
batch_index + 1,
322+
total_batches,
323+
e
324+
);
292325
e
293326
})
294327
.wrap_err(format!(
@@ -299,7 +332,12 @@ impl ContractClient {
299332
.status;
300333

301334
if let FinalExecutionStatus::Failure(err) = status {
302-
error!("Batch {}/{} rejected by contract: {}", batch_index + 1, total_batches, err);
335+
error!(
336+
"Batch {}/{} rejected by contract: {}",
337+
batch_index + 1,
338+
total_batches,
339+
err
340+
);
303341
return Err(eyre::Report::msg(format!(
304342
"Batch {}/{} submission failed: {}",
305343
batch_index + 1,

relayer/src/config.rs

Lines changed: 50 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,10 @@ impl FromStr for Network {
2525
match s.to_lowercase().as_str() {
2626
"testnet" | "sepolia" => Ok(Network::Testnet),
2727
"mainnet" => Ok(Network::Mainnet),
28-
_ => Err(format!("Unknown network: {}. Use 'testnet' or 'mainnet'", s)),
28+
_ => Err(format!(
29+
"Unknown network: {}. Use 'testnet' or 'mainnet'",
30+
s
31+
)),
2932
}
3033
}
3134
}
@@ -48,6 +51,10 @@ pub struct Config {
4851
#[serde(default)]
4952
pub relayer: RelayerConfig,
5053

54+
/// Config for EthLightClient contract initialization
55+
#[serde(default)]
56+
pub init: InitConfig,
57+
5158
/// Logging configuration
5259
#[serde(default)]
5360
pub logging: LoggingConfig,
@@ -125,6 +132,28 @@ pub struct RelayerConfig {
125132
pub fast_mode: bool,
126133
}
127134

135+
#[derive(Debug, Clone, Serialize, Deserialize)]
136+
pub struct InitConfig {
137+
#[serde(default)]
138+
pub network: String,
139+
140+
/// Path to the file with init Light Client Update
141+
#[serde(default)]
142+
pub init_update: String,
143+
144+
/// Path to the file with the first (next after init) Light Client Update
145+
#[serde(default)]
146+
pub first_update: String,
147+
148+
/// Path to the file with headers
149+
#[serde(default)]
150+
pub headers: String,
151+
152+
/// Hashes threshold for Garbage Collection
153+
#[serde(default)]
154+
pub hashes_gc_threshold: u64,
155+
}
156+
128157
#[derive(Debug, Clone, Serialize, Deserialize)]
129158
pub struct LoggingConfig {
130159
/// Log level: trace, debug, info, warn, error
@@ -183,6 +212,18 @@ impl Default for RelayerConfig {
183212
}
184213
}
185214

215+
impl Default for InitConfig {
216+
fn default() -> Self {
217+
Self {
218+
network: "sepolia".to_string(),
219+
init_update: "".to_string(),
220+
first_update: "".to_string(),
221+
headers: "".to_string(),
222+
hashes_gc_threshold: 51000,
223+
}
224+
}
225+
}
226+
186227
impl Default for LoggingConfig {
187228
fn default() -> Self {
188229
Self {
@@ -359,6 +400,13 @@ impl Config {
359400
timeout_secs: defaults::TIMEOUT_SECS,
360401
},
361402
relayer: RelayerConfig::default(),
403+
init: InitConfig {
404+
network: "mainnet".to_string(),
405+
init_update: "".to_string(),
406+
first_update: "".to_string(),
407+
headers: "".to_string(),
408+
hashes_gc_threshold: 51000,
409+
},
362410
logging: LoggingConfig::default(),
363411
},
364412
}
@@ -393,6 +441,7 @@ mod tests {
393441
assert!(toml.contains("[beacon]"));
394442
assert!(toml.contains("[near]"));
395443
assert!(toml.contains("[relayer]"));
444+
assert!(toml.contains("[init]"));
396445
assert!(toml.contains("[logging]"));
397446
}
398447
}

relayer/src/main.rs

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,8 @@ enum Commands {
6060
Run,
6161
/// Run a single relay job and exit
6262
RunJob,
63+
/// Init Eth Light Client contract
64+
Init,
6365
}
6466

6567
fn setup_logging(level: &str, json: bool) -> Result<()> {
@@ -121,6 +123,14 @@ async fn handle_command(command: Commands, config_path: Option<PathBuf>) -> Resu
121123

122124
EthRelayer::new(config).await?.run_job().await?;
123125
}
126+
Commands::Init => {
127+
let config = Config::load(config_path)?;
128+
config.validate()?;
129+
setup_logging(&config.logging.level, config.logging.json)?;
130+
config.print_summary();
131+
132+
EthRelayer::new(config).await?.init_eth_client().await?;
133+
}
124134
}
125135
Ok(())
126136
}

relayer/src/relay.rs

Lines changed: 35 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,12 @@
1+
use std::str::FromStr;
12
use std::time::Duration;
23

34
use crate::constants::protocol::SLOTS_PER_EPOCH;
45
use crate::{BeaconClient, ContractClient, ExecutionClient};
56
use color_eyre::Result;
6-
use eth2_utility::types::ClientMode;
7+
use eth_types::BlockHeader;
8+
use eth_types::eth2::LightClientUpdate;
9+
use eth2_utility::types::{ClientMode, InitInput};
710
use near_crypto::{InMemorySigner, SecretKey};
811
use tokio::time::sleep;
912
use tracing::{debug, error, info, warn};
@@ -125,6 +128,37 @@ impl EthRelayer {
125128
Ok(())
126129
}
127130

131+
pub async fn init_eth_client(&self) -> Result<()> {
132+
let init_update: LightClientUpdate =
133+
serde_json::from_reader(std::fs::File::open(&self.config.init.init_update)?)?;
134+
let first_update: LightClientUpdate =
135+
serde_json::from_reader(std::fs::File::open(&self.config.init.first_update)?)?;
136+
let headers: Vec<BlockHeader> =
137+
serde_json::from_reader(std::fs::File::open(&self.config.init.headers)?)?;
138+
139+
let init_input = InitInput {
140+
network: eth2_utility::consensus::Network::from_str(&self.config.init.network)
141+
.map_err(|err| color_eyre::eyre::eyre!("Incorrect network name: {err:?}"))?,
142+
finalized_execution_header: headers[0].clone(),
143+
finalized_beacon_header: first_update.finalized_header.clone().into(),
144+
current_sync_committee: init_update
145+
.next_sync_committee
146+
.ok_or_else(|| color_eyre::eyre::eyre!("Missing sync committee in init update"))?,
147+
next_sync_committee: first_update
148+
.next_sync_committee
149+
.ok_or_else(|| color_eyre::eyre::eyre!("Missing sync committee in first update"))?,
150+
validate_updates: true,
151+
verify_bls_signatures: true,
152+
hashes_gc_threshold: self.config.init.hashes_gc_threshold,
153+
trusted_signer: None,
154+
};
155+
156+
self.near_client
157+
.init_contract(init_input)
158+
.await
159+
.map_err(Into::into)
160+
}
161+
128162
async fn run_iteration(&self) -> RelayResult {
129163
// Early return pattern - convert all errors to RelayResult::Error
130164
let mode = match self.get_mode_if_synced().await {

0 commit comments

Comments
 (0)