Skip to content

Commit

Permalink
node: validate chain ID of a finalize config
Browse files Browse the repository at this point in the history
  • Loading branch information
tzemanovic committed Sep 25, 2024
1 parent d269374 commit 112c930
Show file tree
Hide file tree
Showing 3 changed files with 78 additions and 6 deletions.
73 changes: 69 additions & 4 deletions crates/apps_lib/src/config/genesis/chain.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ use std::str::FromStr;

use borsh::{BorshDeserialize, BorshSerialize};
use borsh_ext::BorshSerializeExt;
use eyre::eyre;
use namada_macros::BorshDeserializer;
#[cfg(feature = "migrations")]
use namada_migrations::*;
Expand Down Expand Up @@ -106,6 +107,8 @@ impl Finalized {

/// Try to read all genesis and the chain metadata TOML files from the given
/// directory.
///
/// The consistency of the files is checked with [`Finalized::is_valid`].
pub fn read_toml_files(input_dir: &Path) -> eyre::Result<Self> {
let vps_file = input_dir.join(templates::VPS_FILE_NAME);
let tokens_file = input_dir.join(templates::TOKENS_FILE_NAME);
Expand All @@ -121,14 +124,20 @@ impl Finalized {
let parameters = read_toml(&parameters_file, "Parameters")?;
let transactions = read_toml(&transactions_file, "Transactions")?;
let metadata = read_toml(&metadata_file, "Chain metadata")?;
Ok(Self {
let genesis = Self {
vps,
tokens,
balances,
parameters,
transactions,
metadata,
})
};

if !genesis.is_valid() {
return Err(eyre!("Invalid genesis files"));
}

Ok(genesis)
}

/// Find the address of the configured native token
Expand Down Expand Up @@ -485,6 +494,54 @@ impl Finalized {
pub fn get_token_address(&self, alias: &Alias) -> Option<&Address> {
self.tokens.token.get(alias).map(|token| &token.address)
}

// Validate the chain ID against the genesis contents
pub fn is_valid(&self) -> bool {
let Self {
vps,
tokens,
balances,
parameters,
transactions,
metadata,
} = self.clone();
let Metadata {
chain_id,
genesis_time,
consensus_timeout_commit,
address_gen,
} = metadata.clone();

let Some(chain_id_prefix) = chain_id.prefix() else {
tracing::warn!(
"Invalid Chain ID \"{chain_id}\" - unable to find a prefix"
);
return false;
};
let metadata = Metadata {
chain_id: chain_id_prefix.clone(),
genesis_time,
consensus_timeout_commit,
address_gen,
};
let to_finalize = ToFinalize {
vps,
tokens,
balances,
parameters,
transactions,
metadata,
};
let derived_chain_id = derive_chain_id(chain_id_prefix, &to_finalize);
let is_valid = derived_chain_id == chain_id;
if !is_valid {
tracing::warn!(
"Invalid chain ID. This indicates that something in the \
genesis files might have been modified."
);
}
is_valid
}
}

/// Create the [`Finalized`] chain configuration. Derives the chain ID from the
Expand Down Expand Up @@ -541,8 +598,7 @@ pub fn finalize(
parameters,
transactions,
};
let to_finalize_bytes = to_finalize.serialize_to_vec();
let chain_id = ChainId::from_genesis(chain_id_prefix, to_finalize_bytes);
let chain_id = derive_chain_id(chain_id_prefix, &to_finalize);

// Construct the `Finalized` chain
let ToFinalize {
Expand Down Expand Up @@ -575,6 +631,15 @@ pub fn finalize(
}
}

/// Derive a chain ID from genesis contents
pub fn derive_chain_id(
chain_id_prefix: ChainIdPrefix,
to_finalize: &ToFinalize,
) -> ChainId {
let to_finalize_bytes = to_finalize.serialize_to_vec();
ChainId::from_genesis(chain_id_prefix, to_finalize_bytes)
}

/// Chain genesis config to be finalized. This struct is used to derive the
/// chain ID to construct a [`Finalized`] chain genesis config.
#[derive(
Expand Down
7 changes: 7 additions & 0 deletions crates/core/src/chain.rs
Original file line number Diff line number Diff line change
Expand Up @@ -109,6 +109,13 @@ impl ChainId {
}
errors
}

/// Find the prefix of a valid ChainId.
pub fn prefix(&self) -> Option<ChainIdPrefix> {
let ChainId(chain_id) = self;
let (prefix, _) = chain_id.rsplit_once(CHAIN_ID_PREFIX_SEP)?;
Some(ChainIdPrefix(prefix.to_string()))
}
}

/// Height of a block, i.e. the level. The `default` is the
Expand Down
4 changes: 2 additions & 2 deletions crates/node/src/shell/init_chain.rs
Original file line number Diff line number Diff line change
Expand Up @@ -133,14 +133,14 @@ where
let genesis = {
let chain_dir = self.base_dir.join(chain_id);
genesis::chain::Finalized::read_toml_files(&chain_dir)
.expect("Missing genesis files")
.expect("Missing or invalid genesis files")
};
#[cfg(any(test, fuzzing, feature = "benches"))]
let genesis = {
let chain_dir = self.base_dir.join(chain_id);
if chain_dir.join(genesis::chain::METADATA_FILE_NAME).exists() {
genesis::chain::Finalized::read_toml_files(&chain_dir)
.expect("Missing genesis files")
.expect("Missing or invalid genesis files")
} else {
genesis::make_dev_genesis(num_validators, &chain_dir)
}
Expand Down

0 comments on commit 112c930

Please sign in to comment.