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:
Pawan Dhananjay
2020-11-16 23:10:42 +00:00
parent 4d732a1f1d
commit 280334b1b0
5 changed files with 71 additions and 29 deletions

View File

@@ -32,8 +32,9 @@ pub const DEPOSIT_COUNT_RESPONSE_BYTES: usize = 96;
/// Number of bytes in deposit contract deposit root (value only).
pub const DEPOSIT_ROOT_BYTES: usize = 32;
/// Represents an eth1 chain/network id.
#[derive(Debug, PartialEq, Clone, Serialize, Deserialize)]
pub enum Eth1NetworkId {
pub enum Eth1Id {
Goerli,
Mainnet,
Custom(u64),
@@ -46,28 +47,28 @@ pub enum BlockQuery {
Latest,
}
impl Into<u64> for Eth1NetworkId {
impl Into<u64> for Eth1Id {
fn into(self) -> u64 {
match self {
Eth1NetworkId::Mainnet => 1,
Eth1NetworkId::Goerli => 5,
Eth1NetworkId::Custom(id) => id,
Eth1Id::Mainnet => 1,
Eth1Id::Goerli => 5,
Eth1Id::Custom(id) => id,
}
}
}
impl From<u64> for Eth1NetworkId {
impl From<u64> for Eth1Id {
fn from(id: u64) -> Self {
let into = |x: Eth1NetworkId| -> u64 { x.into() };
let into = |x: Eth1Id| -> u64 { x.into() };
match id {
id if id == into(Eth1NetworkId::Mainnet) => Eth1NetworkId::Mainnet,
id if id == into(Eth1NetworkId::Goerli) => Eth1NetworkId::Goerli,
id => Eth1NetworkId::Custom(id),
id if id == into(Eth1Id::Mainnet) => Eth1Id::Mainnet,
id if id == into(Eth1Id::Goerli) => Eth1Id::Goerli,
id => Eth1Id::Custom(id),
}
}
}
impl FromStr for Eth1NetworkId {
impl FromStr for Eth1Id {
type Err = String;
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.
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?;
Eth1NetworkId::from_str(
Eth1Id::from_str(
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()
.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)]
pub struct Block {
pub hash: Hash256,

View File

@@ -3,8 +3,8 @@ use crate::{
block_cache::{BlockCache, Error as BlockCacheError, Eth1Block},
deposit_cache::Error as DepositCacheError,
http::{
get_block, get_block_number, get_deposit_logs_in_range, get_network_id, BlockQuery,
Eth1NetworkId, Log,
get_block, get_block_number, get_chain_id, get_deposit_logs_in_range, get_network_id,
BlockQuery, Eth1Id, Log,
},
inner::{DepositUpdater, Inner},
};
@@ -18,8 +18,10 @@ use std::time::{SystemTime, UNIX_EPOCH};
use tokio::time::{interval_at, Duration, Instant};
use types::ChainSpec;
/// Indicates the default eth1 network we use for the deposit contract.
pub const DEFAULT_NETWORK_ID: Eth1NetworkId = Eth1NetworkId::Goerli;
/// Indicates the default eth1 network id we use for the deposit contract.
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;
@@ -84,7 +86,9 @@ pub struct Config {
/// The address the `BlockCache` and `DepositCache` should assume is the canonical deposit contract.
pub deposit_contract_address: String,
/// 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.
///
/// 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(),
deposit_contract_address: "0x0000000000000000000000000000000000000000".into(),
network_id: DEFAULT_NETWORK_ID,
chain_id: DEFAULT_CHAIN_ID,
deposit_contract_deploy_block: 1,
lowest_cached_block_number: 1,
follow_distance: 128,
@@ -387,23 +392,36 @@ impl Service {
async fn do_update(&self, update_interval: Duration) -> Result<(), ()> {
let endpoint = self.config().endpoint.clone();
let config_network = self.config().network_id.clone();
let result =
let config_network_id = self.config().network_id.clone();
let config_chain_id = self.config().chain_id.clone();
let network_id_result =
get_network_id(&endpoint, Duration::from_millis(STANDARD_TIMEOUT_MILLIS)).await;
match result {
Ok(network_id) => {
if network_id != config_network {
let chain_id_result =
get_chain_id(&endpoint, Duration::from_millis(STANDARD_TIMEOUT_MILLIS)).await;
match (network_id_result, chain_id_result) {
(Ok(network_id), Ok(chain_id)) => {
if network_id != config_network_id {
crit!(
self.log,
"Invalid eth1 network. Please switch to correct network";
"expected" => format!("{:?}",config_network),
"Invalid eth1 network id. Please switch to correct network id";
"expected" => format!("{:?}",config_network_id),
"received" => format!("{:?}",network_id),
"warning" => WARNING_MSG,
);
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!(
self.log,
"Error connecting to eth1 node. Please ensure that you have an eth1 http server running locally on http://localhost:8545 or \