diff --git a/eth2near/eth2near-block-relay-rs/Cargo.lock b/eth2near/eth2near-block-relay-rs/Cargo.lock index 34e332352..81e22b499 100644 --- a/eth2near/eth2near-block-relay-rs/Cargo.lock +++ b/eth2near/eth2near-block-relay-rs/Cargo.lock @@ -1231,6 +1231,7 @@ dependencies = [ "near-jsonrpc-primitives", "near-primitives 0.14.0", "near-sdk", + "primitive-types 0.7.3", "prometheus", "reqwest", "serde", diff --git a/eth2near/eth2near-block-relay-rs/Cargo.toml b/eth2near/eth2near-block-relay-rs/Cargo.toml index 49f7db0aa..6d602cffa 100644 --- a/eth2near/eth2near-block-relay-rs/Cargo.toml +++ b/eth2near/eth2near-block-relay-rs/Cargo.toml @@ -32,6 +32,7 @@ hex = "*" toml = "0.5.9" atomic_refcell = "0.1.8" bitvec = "*" +primitive-types = "0.7.3" near-jsonrpc-client = "=0.4.0-beta.0" near-crypto = "0.14.0" diff --git a/eth2near/eth2near-block-relay-rs/src/beacon_rpc_client.rs b/eth2near/eth2near-block-relay-rs/src/beacon_rpc_client.rs index 7e18aefc2..96f20a73e 100644 --- a/eth2near/eth2near-block-relay-rs/src/beacon_rpc_client.rs +++ b/eth2near/eth2near-block-relay-rs/src/beacon_rpc_client.rs @@ -1,10 +1,10 @@ use crate::execution_block_proof::ExecutionBlockProof; use crate::light_client_snapshot_with_proof::LightClientSnapshotWithProof; -use contract_wrapper::utils; use crate::relay_errors::{ ErrorOnJsonParse, ExecutionPayloadError, FailOnGettingJson, MissSyncAggregationError, NoBlockForSlotError, SignatureSlotNotFoundError, }; +use contract_wrapper::utils; use eth_types::eth2::BeaconBlockHeader; use eth_types::eth2::FinalizedHeaderUpdate; use eth_types::eth2::HeaderUpdate; @@ -198,7 +198,8 @@ impl BeaconRPCClient { &self, beacon_block_hash: H256, ) -> Result> { - let beacon_block_hash_str: String = utils::trim_quotes(serde_json::to_string(&beacon_block_hash)?); + let beacon_block_hash_str: String = + utils::trim_quotes(serde_json::to_string(&beacon_block_hash)?); let url = format!( "{}/{}/{}", @@ -251,43 +252,8 @@ impl BeaconRPCClient { pub fn get_finality_light_client_update_with_sync_commity_update( &self, ) -> Result> { - let url_finality = format!( - "{}/{}", - self.endpoint_url, - Self::URL_FINALITY_LIGHT_CLIENT_UPDATE_PATH - ); let last_period = Self::get_period_for_slot(self.get_last_slot_number()?.as_u64()); - let url_update = format!( - "{}/{}?start_period={}&count=1", - self.endpoint_url, - Self::URL_GET_LIGHT_CLIENT_UPDATE_API, - last_period - ); - let finality_light_client_update_json_str = - self.get_json_from_raw_request(&url_finality)?; - let light_client_update_json_str = self.get_json_from_raw_request(&url_update)?; - - let v: Value = serde_json::from_str(&finality_light_client_update_json_str)?; - let finality_light_client_update_json_str = - serde_json::to_string(&json!({"data": [v["data"]]}))?; - - Ok(LightClientUpdate { - attested_beacon_header: Self::get_attested_header_from_light_client_update_json_str( - &finality_light_client_update_json_str, - )?, - sync_aggregate: Self::get_sync_aggregate_from_light_client_update_json_str( - &finality_light_client_update_json_str, - )?, - signature_slot: self.get_signature_slot(&finality_light_client_update_json_str)?, - finality_update: self.get_finality_update_from_light_client_update_json_str( - &finality_light_client_update_json_str, - )?, - sync_committee_update: Some( - Self::get_sync_committee_update_from_light_client_update_json_str( - &light_client_update_json_str, - )?, - ), - }) + self.get_light_client_update(last_period) } pub fn get_beacon_state( @@ -490,14 +456,13 @@ impl BeaconRPCClient { Err(err) => match err.downcast_ref::() { Some(_) => continue, None => return Err(err), - } + }, } } Err(format!( "Unable to get non empty beacon block in range [`{}`-`{}`)", - start_slot, - finalized_slot + start_slot, finalized_slot ))? } diff --git a/eth2near/eth2near-block-relay-rs/src/eth2near_relay.rs b/eth2near/eth2near-block-relay-rs/src/eth2near_relay.rs index 4983e3fa2..1c4bfb97e 100644 --- a/eth2near/eth2near-block-relay-rs/src/eth2near_relay.rs +++ b/eth2near/eth2near-block-relay-rs/src/eth2near_relay.rs @@ -1,4 +1,3 @@ -use std::cmp; use crate::beacon_rpc_client::BeaconRPCClient; use crate::config::Config; use crate::eth1_rpc_client::Eth1RPCClient; @@ -19,6 +18,7 @@ use eth_types::eth2::LightClientUpdate; use eth_types::BlockHeader; use log::{debug, info, trace, warn}; use near_primitives::views::FinalExecutionStatus; +use std::cmp; use std::cmp::{max, min}; use std::error::Error; use std::thread; @@ -466,7 +466,8 @@ impl Eth2NearRelay { last_finalized_slot_on_eth: u64, ) -> bool { if (last_submitted_slot as i64) - (last_finalized_slot_on_near as i64) - < (ONE_EPOCH_IN_SLOTS * self.interval_between_light_client_updates_submission_in_epochs) as i64 + < (ONE_EPOCH_IN_SLOTS * self.interval_between_light_client_updates_submission_in_epochs) + as i64 { info!(target: "relay", "Light client update were send less then {} epochs ago. Skipping sending light client update", self.interval_between_light_client_updates_submission_in_epochs); return false; @@ -725,6 +726,7 @@ mod tests { use eth_types::BlockHeader; use std::thread::sleep; use std::time::Duration; + use tree_hash::TreeHash; const TIMEOUT_SECONDS: u64 = 30; const TIMEOUT_STATE_SECONDS: u64 = 1000; @@ -839,6 +841,73 @@ mod tests { assert_eq!(finalized_slot, finalized_slot_1); } + #[test] + fn test_finality_light_client_update_correctness() { + const TREE_FINALITY_DEPTH: usize = 6; + const TREE_FINALITY_INDEX: usize = 41; + const TREE_NEXT_SYNC_COMMITTEE_DEPTH: usize = 5; + const TREE_NEXT_SYNC_COMMITTEE_INDEX: usize = 23; + + let config_for_test = get_test_config(); + + let relay = get_relay(true, true, &config_for_test); + + let light_client_update = relay + .beacon_rpc_client + .get_finality_light_client_update_with_sync_commity_update() + .unwrap(); + + let branch: Vec = light_client_update + .finality_update + .finality_branch + .iter() + .map(|h| h.0) + .collect(); + assert!( + merkle_proof::verify_merkle_proof( + light_client_update + .finality_update + .header_update + .beacon_header + .tree_hash_root(), + branch.as_slice(), + TREE_FINALITY_DEPTH, + TREE_FINALITY_INDEX, + light_client_update.attested_beacon_header.state_root.0 + ), + "Incorrect proof of inclusion the finality checkpoint to attested beacon state" + ); + + let branch = light_client_update + .sync_committee_update + .as_ref() + .unwrap() + .next_sync_committee_branch + .iter() + .map(|h| h.0) + .collect::>(); + assert!( + merkle_proof::verify_merkle_proof( + light_client_update + .sync_committee_update + .as_ref() + .unwrap() + .next_sync_committee + .tree_hash_root(), + branch.as_slice(), + TREE_NEXT_SYNC_COMMITTEE_DEPTH, + TREE_NEXT_SYNC_COMMITTEE_INDEX, + light_client_update + .finality_update + .header_update + .beacon_header + .state_root + .0 + ), + "Incorrect proof of inclusion the next sync committee to finality beacon state" + ); + } + #[test] #[ignore] fn test_hand_made_light_client_update() { diff --git a/eth2near/eth2near-block-relay-rs/src/execution_block_proof.rs b/eth2near/eth2near-block-relay-rs/src/execution_block_proof.rs index 898ae9f75..d974e601a 100644 --- a/eth2near/eth2near-block-relay-rs/src/execution_block_proof.rs +++ b/eth2near/eth2near-block-relay-rs/src/execution_block_proof.rs @@ -1,6 +1,6 @@ use crate::beacon_block_body_merkle_tree::{BeaconBlockBodyMerkleTree, ExecutionPayloadMerkleTree}; -use eth2_hashing; use crate::relay_errors::MissExecutionPayload; +use eth2_hashing; use ethereum_types::H256; use std::error::Error; use std::fmt; @@ -122,7 +122,8 @@ impl ExecutionBlockProof { for (i, leaf) in branch.iter().enumerate().take(depth) { let ith_bit = (index >> i) & 0x01; if ith_bit == 1 { - merkle_root = eth2_hashing::hash32_concat(leaf.as_bytes(), &merkle_root)[..].to_vec(); + merkle_root = + eth2_hashing::hash32_concat(leaf.as_bytes(), &merkle_root)[..].to_vec(); } else { let mut input = merkle_root; input.extend_from_slice(leaf.as_bytes()); diff --git a/eth2near/eth2near-block-relay-rs/src/hand_made_finality_light_client_update.rs b/eth2near/eth2near-block-relay-rs/src/hand_made_finality_light_client_update.rs index 79e76a9e4..db780e074 100644 --- a/eth2near/eth2near-block-relay-rs/src/hand_made_finality_light_client_update.rs +++ b/eth2near/eth2near-block-relay-rs/src/hand_made_finality_light_client_update.rs @@ -111,8 +111,7 @@ impl HandMadeFinalityLightClientUpdate { let sync_aggregate = signature_beacon_body .sync_aggregate() .map_err(|_| MissSyncAggregationError)?; - let sync_committee_bits: [u8; 64] = - Self::get_sync_committee_bits(sync_aggregate)?; + let sync_committee_bits: [u8; 64] = Self::get_sync_committee_bits(sync_aggregate)?; let sync_committee_bits_sum: u32 = sync_committee_bits .into_iter() .map(|x| x.count_ones()) diff --git a/eth2near/eth2near-block-relay-rs/src/init_contract.rs b/eth2near/eth2near-block-relay-rs/src/init_contract.rs index faf109522..6063a438d 100644 --- a/eth2near/eth2near-block-relay-rs/src/init_contract.rs +++ b/eth2near/eth2near-block-relay-rs/src/init_contract.rs @@ -12,7 +12,8 @@ use tree_hash::TreeHash; const CURRENT_SYNC_COMMITTEE_INDEX: u32 = 54; const CURRENT_SYNC_COMMITTEE_TREE_DEPTH: u32 = consensus::floorlog2(CURRENT_SYNC_COMMITTEE_INDEX); -const CURRENT_SYNC_COMMITTEE_TREE_INDEX: u32 = consensus::get_subtree_index(CURRENT_SYNC_COMMITTEE_INDEX); +const CURRENT_SYNC_COMMITTEE_TREE_INDEX: u32 = + consensus::get_subtree_index(CURRENT_SYNC_COMMITTEE_INDEX); pub fn verify_light_client_snapshot( block_root: String, diff --git a/eth2near/eth2near-block-relay-rs/src/last_slot_searcher.rs b/eth2near/eth2near-block-relay-rs/src/last_slot_searcher.rs index 45b8b2637..829a5997a 100644 --- a/eth2near/eth2near-block-relay-rs/src/last_slot_searcher.rs +++ b/eth2near/eth2near-block-relay-rs/src/last_slot_searcher.rs @@ -300,7 +300,7 @@ impl LastSlotSearcher { Err(err) => match err.downcast_ref::() { Some(_) => slot += 1, None => return Err(err), - } + }, } } @@ -333,7 +333,7 @@ impl LastSlotSearcher { Err(err) => match err.downcast_ref::() { Some(_) => slot -= 1, None => return Err(err), - } + }, } } @@ -618,12 +618,14 @@ mod tests { finalized_slot + 2, ); - let last_submitted_block = last_slot_searcher.linear_search_backward( - finalized_slot + 1, - finalized_slot + 10, - &beacon_rpc_client, - ð_client_contract, - ).unwrap(); + let last_submitted_block = last_slot_searcher + .linear_search_backward( + finalized_slot + 1, + finalized_slot + 10, + &beacon_rpc_client, + ð_client_contract, + ) + .unwrap(); assert_eq!(last_submitted_block, finalized_slot + 2); send_execution_blocks( @@ -634,12 +636,14 @@ mod tests { config_for_test.slot_without_block - 1, ); - let last_submitted_block = last_slot_searcher.linear_search_backward( - finalized_slot + 1, - config_for_test.right_bound_in_slot_search, - &beacon_rpc_client, - ð_client_contract, - ).unwrap(); + let last_submitted_block = last_slot_searcher + .linear_search_backward( + finalized_slot + 1, + config_for_test.right_bound_in_slot_search, + &beacon_rpc_client, + ð_client_contract, + ) + .unwrap(); assert_eq!(last_submitted_block, config_for_test.slot_without_block); } @@ -669,15 +673,17 @@ mod tests { config_for_test.slot_without_block - 2, ); - let last_block_on_near = last_slot_searcher.linear_search_forward( - eth_client_contract - .get_finalized_beacon_block_slot() - .unwrap() - + 1, - config_for_test.right_bound_in_slot_search, - &beacon_rpc_client, - ð_client_contract, - ).unwrap(); + let last_block_on_near = last_slot_searcher + .linear_search_forward( + eth_client_contract + .get_finalized_beacon_block_slot() + .unwrap() + + 1, + config_for_test.right_bound_in_slot_search, + &beacon_rpc_client, + ð_client_contract, + ) + .unwrap(); assert_eq!(last_block_on_near, config_for_test.slot_without_block - 2); @@ -689,15 +695,17 @@ mod tests { config_for_test.slot_without_block - 1, ); - let last_block_on_near = last_slot_searcher.linear_search_forward( - eth_client_contract - .get_finalized_beacon_block_slot() - .unwrap() - + 1, - config_for_test.right_bound_in_slot_search, - &beacon_rpc_client, - ð_client_contract, - ).unwrap(); + let last_block_on_near = last_slot_searcher + .linear_search_forward( + eth_client_contract + .get_finalized_beacon_block_slot() + .unwrap() + + 1, + config_for_test.right_bound_in_slot_search, + &beacon_rpc_client, + ð_client_contract, + ) + .unwrap(); assert_eq!(last_block_on_near, config_for_test.slot_without_block); } diff --git a/eth2near/eth2near-block-relay-rs/src/lib.rs b/eth2near/eth2near-block-relay-rs/src/lib.rs index 7a8684822..4bf4bb5a9 100644 --- a/eth2near/eth2near-block-relay-rs/src/lib.rs +++ b/eth2near/eth2near-block-relay-rs/src/lib.rs @@ -1,5 +1,3 @@ -extern crate core; - pub mod beacon_block_body_merkle_tree; pub mod beacon_rpc_client; pub mod config; diff --git a/eth2near/eth2near-block-relay-rs/src/test_utils.rs b/eth2near/eth2near-block-relay-rs/src/test_utils.rs index c0a00978c..3bcfdd836 100644 --- a/eth2near/eth2near-block-relay-rs/src/test_utils.rs +++ b/eth2near/eth2near-block-relay-rs/src/test_utils.rs @@ -214,7 +214,9 @@ pub fn get_client_contract( match from_file { true => test_utils::init_contract_from_files(&mut eth_client_contract, config_for_test), - false => init_contract::init_contract(&config, &mut eth_client_contract, "".to_string()).unwrap(), + false => { + init_contract::init_contract(&config, &mut eth_client_contract, "".to_string()).unwrap() + } }; Box::new(eth_client_contract)