Validate eth1 chain id (#1877)
## Issue Addressed Resolves #1815 ## Proposed Changes Adds extra validation for eth1 chain id apart from the existing check for eth1 network id.
This commit is contained in:
parent
4d732a1f1d
commit
280334b1b0
@ -32,8 +32,9 @@ pub const DEPOSIT_COUNT_RESPONSE_BYTES: usize = 96;
|
|||||||
/// Number of bytes in deposit contract deposit root (value only).
|
/// Number of bytes in deposit contract deposit root (value only).
|
||||||
pub const DEPOSIT_ROOT_BYTES: usize = 32;
|
pub const DEPOSIT_ROOT_BYTES: usize = 32;
|
||||||
|
|
||||||
|
/// Represents an eth1 chain/network id.
|
||||||
#[derive(Debug, PartialEq, Clone, Serialize, Deserialize)]
|
#[derive(Debug, PartialEq, Clone, Serialize, Deserialize)]
|
||||||
pub enum Eth1NetworkId {
|
pub enum Eth1Id {
|
||||||
Goerli,
|
Goerli,
|
||||||
Mainnet,
|
Mainnet,
|
||||||
Custom(u64),
|
Custom(u64),
|
||||||
@ -46,28 +47,28 @@ pub enum BlockQuery {
|
|||||||
Latest,
|
Latest,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Into<u64> for Eth1NetworkId {
|
impl Into<u64> for Eth1Id {
|
||||||
fn into(self) -> u64 {
|
fn into(self) -> u64 {
|
||||||
match self {
|
match self {
|
||||||
Eth1NetworkId::Mainnet => 1,
|
Eth1Id::Mainnet => 1,
|
||||||
Eth1NetworkId::Goerli => 5,
|
Eth1Id::Goerli => 5,
|
||||||
Eth1NetworkId::Custom(id) => id,
|
Eth1Id::Custom(id) => id,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<u64> for Eth1NetworkId {
|
impl From<u64> for Eth1Id {
|
||||||
fn from(id: u64) -> Self {
|
fn from(id: u64) -> Self {
|
||||||
let into = |x: Eth1NetworkId| -> u64 { x.into() };
|
let into = |x: Eth1Id| -> u64 { x.into() };
|
||||||
match id {
|
match id {
|
||||||
id if id == into(Eth1NetworkId::Mainnet) => Eth1NetworkId::Mainnet,
|
id if id == into(Eth1Id::Mainnet) => Eth1Id::Mainnet,
|
||||||
id if id == into(Eth1NetworkId::Goerli) => Eth1NetworkId::Goerli,
|
id if id == into(Eth1Id::Goerli) => Eth1Id::Goerli,
|
||||||
id => Eth1NetworkId::Custom(id),
|
id => Eth1Id::Custom(id),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl FromStr for Eth1NetworkId {
|
impl FromStr for Eth1Id {
|
||||||
type Err = String;
|
type Err = String;
|
||||||
|
|
||||||
fn from_str(s: &str) -> Result<Self, Self::Err> {
|
fn from_str(s: &str) -> Result<Self, Self::Err> {
|
||||||
@ -78,16 +79,28 @@ impl FromStr for Eth1NetworkId {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Get the eth1 network id of the given endpoint.
|
/// Get the eth1 network id of the given endpoint.
|
||||||
pub async fn get_network_id(endpoint: &str, timeout: Duration) -> Result<Eth1NetworkId, String> {
|
pub async fn get_network_id(endpoint: &str, timeout: Duration) -> Result<Eth1Id, String> {
|
||||||
let response_body = send_rpc_request(endpoint, "net_version", json!([]), timeout).await?;
|
let response_body = send_rpc_request(endpoint, "net_version", json!([]), timeout).await?;
|
||||||
Eth1NetworkId::from_str(
|
Eth1Id::from_str(
|
||||||
response_result(&response_body)?
|
response_result(&response_body)?
|
||||||
.ok_or_else(|| "No result was returned for block number".to_string())?
|
.ok_or_else(|| "No result was returned for network id".to_string())?
|
||||||
.as_str()
|
.as_str()
|
||||||
.ok_or_else(|| "Data was not string")?,
|
.ok_or_else(|| "Data was not string")?,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Get the eth1 chain id of the given endpoint.
|
||||||
|
pub async fn get_chain_id(endpoint: &str, timeout: Duration) -> Result<Eth1Id, String> {
|
||||||
|
let response_body = send_rpc_request(endpoint, "eth_chainId", json!([]), timeout).await?;
|
||||||
|
hex_to_u64_be(
|
||||||
|
response_result(&response_body)?
|
||||||
|
.ok_or_else(|| "No result was returned for chain id".to_string())?
|
||||||
|
.as_str()
|
||||||
|
.ok_or_else(|| "Data was not string")?,
|
||||||
|
)
|
||||||
|
.map(Into::into)
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Debug, PartialEq, Clone)]
|
#[derive(Debug, PartialEq, Clone)]
|
||||||
pub struct Block {
|
pub struct Block {
|
||||||
pub hash: Hash256,
|
pub hash: Hash256,
|
||||||
|
@ -3,8 +3,8 @@ use crate::{
|
|||||||
block_cache::{BlockCache, Error as BlockCacheError, Eth1Block},
|
block_cache::{BlockCache, Error as BlockCacheError, Eth1Block},
|
||||||
deposit_cache::Error as DepositCacheError,
|
deposit_cache::Error as DepositCacheError,
|
||||||
http::{
|
http::{
|
||||||
get_block, get_block_number, get_deposit_logs_in_range, get_network_id, BlockQuery,
|
get_block, get_block_number, get_chain_id, get_deposit_logs_in_range, get_network_id,
|
||||||
Eth1NetworkId, Log,
|
BlockQuery, Eth1Id, Log,
|
||||||
},
|
},
|
||||||
inner::{DepositUpdater, Inner},
|
inner::{DepositUpdater, Inner},
|
||||||
};
|
};
|
||||||
@ -18,8 +18,10 @@ use std::time::{SystemTime, UNIX_EPOCH};
|
|||||||
use tokio::time::{interval_at, Duration, Instant};
|
use tokio::time::{interval_at, Duration, Instant};
|
||||||
use types::ChainSpec;
|
use types::ChainSpec;
|
||||||
|
|
||||||
/// Indicates the default eth1 network we use for the deposit contract.
|
/// Indicates the default eth1 network id we use for the deposit contract.
|
||||||
pub const DEFAULT_NETWORK_ID: Eth1NetworkId = Eth1NetworkId::Goerli;
|
pub const DEFAULT_NETWORK_ID: Eth1Id = Eth1Id::Goerli;
|
||||||
|
/// Indicates the default eth1 chain id we use for the deposit contract.
|
||||||
|
pub const DEFAULT_CHAIN_ID: Eth1Id = Eth1Id::Goerli;
|
||||||
|
|
||||||
const STANDARD_TIMEOUT_MILLIS: u64 = 15_000;
|
const STANDARD_TIMEOUT_MILLIS: u64 = 15_000;
|
||||||
|
|
||||||
@ -84,7 +86,9 @@ pub struct Config {
|
|||||||
/// The address the `BlockCache` and `DepositCache` should assume is the canonical deposit contract.
|
/// The address the `BlockCache` and `DepositCache` should assume is the canonical deposit contract.
|
||||||
pub deposit_contract_address: String,
|
pub deposit_contract_address: String,
|
||||||
/// The eth1 network id where the deposit contract is deployed (Goerli/Mainnet).
|
/// The eth1 network id where the deposit contract is deployed (Goerli/Mainnet).
|
||||||
pub network_id: Eth1NetworkId,
|
pub network_id: Eth1Id,
|
||||||
|
/// The eth1 chain id where the deposit contract is deployed (Goerli/Mainnet).
|
||||||
|
pub chain_id: Eth1Id,
|
||||||
/// Defines the first block that the `DepositCache` will start searching for deposit logs.
|
/// Defines the first block that the `DepositCache` will start searching for deposit logs.
|
||||||
///
|
///
|
||||||
/// Setting too high can result in missed logs. Setting too low will result in unnecessary
|
/// Setting too high can result in missed logs. Setting too low will result in unnecessary
|
||||||
@ -115,6 +119,7 @@ impl Default for Config {
|
|||||||
endpoint: "http://localhost:8545".into(),
|
endpoint: "http://localhost:8545".into(),
|
||||||
deposit_contract_address: "0x0000000000000000000000000000000000000000".into(),
|
deposit_contract_address: "0x0000000000000000000000000000000000000000".into(),
|
||||||
network_id: DEFAULT_NETWORK_ID,
|
network_id: DEFAULT_NETWORK_ID,
|
||||||
|
chain_id: DEFAULT_CHAIN_ID,
|
||||||
deposit_contract_deploy_block: 1,
|
deposit_contract_deploy_block: 1,
|
||||||
lowest_cached_block_number: 1,
|
lowest_cached_block_number: 1,
|
||||||
follow_distance: 128,
|
follow_distance: 128,
|
||||||
@ -387,23 +392,36 @@ impl Service {
|
|||||||
|
|
||||||
async fn do_update(&self, update_interval: Duration) -> Result<(), ()> {
|
async fn do_update(&self, update_interval: Duration) -> Result<(), ()> {
|
||||||
let endpoint = self.config().endpoint.clone();
|
let endpoint = self.config().endpoint.clone();
|
||||||
let config_network = self.config().network_id.clone();
|
let config_network_id = self.config().network_id.clone();
|
||||||
let result =
|
let config_chain_id = self.config().chain_id.clone();
|
||||||
|
let network_id_result =
|
||||||
get_network_id(&endpoint, Duration::from_millis(STANDARD_TIMEOUT_MILLIS)).await;
|
get_network_id(&endpoint, Duration::from_millis(STANDARD_TIMEOUT_MILLIS)).await;
|
||||||
match result {
|
let chain_id_result =
|
||||||
Ok(network_id) => {
|
get_chain_id(&endpoint, Duration::from_millis(STANDARD_TIMEOUT_MILLIS)).await;
|
||||||
if network_id != config_network {
|
match (network_id_result, chain_id_result) {
|
||||||
|
(Ok(network_id), Ok(chain_id)) => {
|
||||||
|
if network_id != config_network_id {
|
||||||
crit!(
|
crit!(
|
||||||
self.log,
|
self.log,
|
||||||
"Invalid eth1 network. Please switch to correct network";
|
"Invalid eth1 network id. Please switch to correct network id";
|
||||||
"expected" => format!("{:?}",config_network),
|
"expected" => format!("{:?}",config_network_id),
|
||||||
"received" => format!("{:?}",network_id),
|
"received" => format!("{:?}",network_id),
|
||||||
"warning" => WARNING_MSG,
|
"warning" => WARNING_MSG,
|
||||||
);
|
);
|
||||||
return Ok(());
|
return Ok(());
|
||||||
}
|
}
|
||||||
|
if chain_id != config_chain_id {
|
||||||
|
crit!(
|
||||||
|
self.log,
|
||||||
|
"Invalid eth1 chain id. Please switch to correct chain id";
|
||||||
|
"expected" => format!("{:?}",config_chain_id),
|
||||||
|
"received" => format!("{:?}", chain_id),
|
||||||
|
"warning" => WARNING_MSG,
|
||||||
|
);
|
||||||
|
return Ok(());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
Err(_) => {
|
_ => {
|
||||||
crit!(
|
crit!(
|
||||||
self.log,
|
self.log,
|
||||||
"Error connecting to eth1 node. Please ensure that you have an eth1 http server running locally on http://localhost:8545 or \
|
"Error connecting to eth1 node. Please ensure that you have an eth1 http server running locally on http://localhost:8545 or \
|
||||||
|
@ -258,6 +258,7 @@ pub fn get_config<E: EthSpec>(
|
|||||||
client_config.eth1.deposit_contract_deploy_block;
|
client_config.eth1.deposit_contract_deploy_block;
|
||||||
client_config.eth1.follow_distance = spec.eth1_follow_distance;
|
client_config.eth1.follow_distance = spec.eth1_follow_distance;
|
||||||
client_config.eth1.network_id = spec.deposit_network_id.into();
|
client_config.eth1.network_id = spec.deposit_network_id.into();
|
||||||
|
client_config.eth1.chain_id = spec.deposit_chain_id.into();
|
||||||
|
|
||||||
if let Some(mut boot_nodes) = eth2_testnet_config.boot_enr {
|
if let Some(mut boot_nodes) = eth2_testnet_config.boot_enr {
|
||||||
client_config.network.boot_nodes_enr.append(&mut boot_nodes)
|
client_config.network.boot_nodes_enr.append(&mut boot_nodes)
|
||||||
|
@ -15,6 +15,7 @@ use web3::{
|
|||||||
const GANACHE_STARTUP_TIMEOUT_MILLIS: u64 = 10_000;
|
const GANACHE_STARTUP_TIMEOUT_MILLIS: u64 = 10_000;
|
||||||
|
|
||||||
const NETWORK_ID: u64 = 42;
|
const NETWORK_ID: u64 = 42;
|
||||||
|
const CHAIN_ID: u64 = 42;
|
||||||
|
|
||||||
/// Provides a dedicated `ganachi-cli` instance with a connected `Web3` instance.
|
/// Provides a dedicated `ganachi-cli` instance with a connected `Web3` instance.
|
||||||
///
|
///
|
||||||
@ -46,6 +47,8 @@ impl GanacheInstance {
|
|||||||
.arg("\"vast thought differ pull jewel broom cook wrist tribe word before omit\"")
|
.arg("\"vast thought differ pull jewel broom cook wrist tribe word before omit\"")
|
||||||
.arg("--networkId")
|
.arg("--networkId")
|
||||||
.arg(format!("{}", NETWORK_ID))
|
.arg(format!("{}", NETWORK_ID))
|
||||||
|
.arg("--chainId")
|
||||||
|
.arg(format!("{}", CHAIN_ID))
|
||||||
.spawn()
|
.spawn()
|
||||||
.map_err(|e| {
|
.map_err(|e| {
|
||||||
format!(
|
format!(
|
||||||
@ -106,6 +109,11 @@ impl GanacheInstance {
|
|||||||
NETWORK_ID
|
NETWORK_ID
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Returns the chain id of the ganache instance
|
||||||
|
pub fn chain_id(&self) -> u64 {
|
||||||
|
CHAIN_ID
|
||||||
|
}
|
||||||
|
|
||||||
/// Increase the timestamp on future blocks by `increase_by` seconds.
|
/// Increase the timestamp on future blocks by `increase_by` seconds.
|
||||||
pub async fn increase_time(&self, increase_by: u64) -> Result<(), String> {
|
pub async fn increase_time(&self, increase_by: u64) -> Result<(), String> {
|
||||||
self.web3
|
self.web3
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
use crate::{checks, LocalNetwork, E};
|
use crate::{checks, LocalNetwork, E};
|
||||||
use clap::ArgMatches;
|
use clap::ArgMatches;
|
||||||
use eth1::http::Eth1NetworkId;
|
use eth1::http::Eth1Id;
|
||||||
use eth1_test_rig::GanacheEth1Instance;
|
use eth1_test_rig::GanacheEth1Instance;
|
||||||
use futures::prelude::*;
|
use futures::prelude::*;
|
||||||
use node_test_rig::{
|
use node_test_rig::{
|
||||||
@ -76,6 +76,7 @@ pub fn run_eth1_sim(matches: &ArgMatches) -> Result<(), String> {
|
|||||||
let ganache_eth1_instance = GanacheEth1Instance::new().await?;
|
let ganache_eth1_instance = GanacheEth1Instance::new().await?;
|
||||||
let deposit_contract = ganache_eth1_instance.deposit_contract;
|
let deposit_contract = ganache_eth1_instance.deposit_contract;
|
||||||
let network_id = ganache_eth1_instance.ganache.network_id();
|
let network_id = ganache_eth1_instance.ganache.network_id();
|
||||||
|
let chain_id = ganache_eth1_instance.ganache.chain_id();
|
||||||
let ganache = ganache_eth1_instance.ganache;
|
let ganache = ganache_eth1_instance.ganache;
|
||||||
let eth1_endpoint = ganache.endpoint();
|
let eth1_endpoint = ganache.endpoint();
|
||||||
let deposit_contract_address = deposit_contract.address();
|
let deposit_contract_address = deposit_contract.address();
|
||||||
@ -108,7 +109,8 @@ pub fn run_eth1_sim(matches: &ArgMatches) -> Result<(), String> {
|
|||||||
beacon_config.eth1.follow_distance = 1;
|
beacon_config.eth1.follow_distance = 1;
|
||||||
beacon_config.dummy_eth1_backend = false;
|
beacon_config.dummy_eth1_backend = false;
|
||||||
beacon_config.sync_eth1_chain = true;
|
beacon_config.sync_eth1_chain = true;
|
||||||
beacon_config.eth1.network_id = Eth1NetworkId::Custom(network_id);
|
beacon_config.eth1.network_id = Eth1Id::Custom(network_id);
|
||||||
|
beacon_config.eth1.chain_id = Eth1Id::Custom(chain_id);
|
||||||
|
|
||||||
beacon_config.network.enr_address = Some(IpAddr::V4(Ipv4Addr::new(127, 0, 0, 1)));
|
beacon_config.network.enr_address = Some(IpAddr::V4(Ipv4Addr::new(127, 0, 0, 1)));
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user