Skip to content

Commit

Permalink
Merge branch 'tomas/fix-validator-raw-hash' (#326)
Browse files Browse the repository at this point in the history
* tomas/fix-validator-raw-hash:
  update wasm checksums
  client/utils: switch off validator's p2p addr strict mode in localhost
  test/e2e: add test for double signing slashing
  shell: fix slashing log msg
  ledger/shell: fix validator look-up from tm raw hash
  tests/PoS: fix the validator's raw hash to correspond to consensus key
  PoS: fix the validator's raw hash to correspond to consensus key
  tendermint: fix address written to TM to correspond to consensus key
  • Loading branch information
tzemanovic committed Aug 21, 2022
2 parents 40b3091 + 23e1334 commit 0cadb8f
Show file tree
Hide file tree
Showing 12 changed files with 509 additions and 112 deletions.
8 changes: 2 additions & 6 deletions apps/src/lib/client/tx.rs
Original file line number Diff line number Diff line change
Expand Up @@ -353,15 +353,11 @@ pub async fn submit_init_validator(
};
// add validator address and keys to the wallet
ctx.wallet
.add_validator_data(validator_address.clone(), validator_keys);
.add_validator_data(validator_address, validator_keys);
ctx.wallet.save().unwrap_or_else(|err| eprintln!("{}", err));

let tendermint_home = ctx.config.ledger.tendermint_dir();
tendermint_node::write_validator_key(
&tendermint_home,
&validator_address,
&consensus_key,
);
tendermint_node::write_validator_key(&tendermint_home, &consensus_key);
tendermint_node::write_validator_state(tendermint_home);

println!();
Expand Down
11 changes: 4 additions & 7 deletions apps/src/lib/client/utils.rs
Original file line number Diff line number Diff line change
Expand Up @@ -282,7 +282,6 @@ pub async fn join_network(
// Write consensus key to tendermint home
tendermint_node::write_validator_key(
&tm_home_dir,
&address,
&*pre_genesis_wallet.consensus_key,
);

Expand Down Expand Up @@ -547,11 +546,7 @@ pub fn init_network(
);

// Write consensus key for Tendermint
tendermint_node::write_validator_key(
&tm_home_dir,
&address,
&keypair,
);
tendermint_node::write_validator_key(&tm_home_dir, &keypair);

keypair.ref_to()
});
Expand Down Expand Up @@ -887,6 +882,7 @@ pub fn init_network(
consensus_timeout_commit;
config.ledger.tendermint.p2p_allow_duplicate_ip =
allow_duplicate_ip;
config.ledger.tendermint.p2p_addr_book_strict = !localhost;
// Clear the net address from the config and use it to set ports
let net_address = validator_config.net_address.take().unwrap();
let first_port = SocketAddr::from_str(&net_address).unwrap().port();
Expand Down Expand Up @@ -1163,7 +1159,8 @@ fn network_configs_url_prefix(chain_id: &ChainId) -> String {
})
}

fn write_tendermint_node_key(
/// Write the node key into tendermint config dir.
pub fn write_tendermint_node_key(
tm_home_dir: &Path,
node_sk: common::SecretKey,
) -> common::PublicKey {
Expand Down
19 changes: 4 additions & 15 deletions apps/src/lib/node/ledger/shell/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -398,6 +398,7 @@ where
let pos_params = self.storage.read_pos_params();
let current_epoch = self.storage.block.epoch;
for evidence in byzantine_validators {
tracing::info!("Processing evidence {evidence:?}.");
let evidence_height = match u64::try_from(evidence.height) {
Ok(height) => height,
Err(err) => {
Expand Down Expand Up @@ -455,19 +456,7 @@ where
}
};
let validator_raw_hash = match evidence.validator {
Some(validator) => {
match String::from_utf8(validator.address) {
Ok(raw_hash) => raw_hash,
Err(err) => {
tracing::error!(
"Evidence failed to decode validator \
address from utf-8 with {}",
err
);
continue;
}
}
}
Some(validator) => tm_raw_hash_to_string(validator.address),
None => {
tracing::error!(
"Evidence without a validator {:#?}",
Expand All @@ -491,9 +480,9 @@ where
};
tracing::info!(
"Slashing {} for {} in epoch {}, block height {}",
evidence_epoch,
slash_type,
validator,
slash_type,
evidence_epoch,
evidence_height
);
if let Err(err) = self.storage.slash(
Expand Down
79 changes: 24 additions & 55 deletions apps/src/lib/node/ledger/tendermint_node.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@ use std::process::Stdio;
use std::str::FromStr;

use borsh::BorshSerialize;
use namada::types::address::Address;
use namada::types::chain::ChainId;
use namada::types::key::*;
use namada::types::time::DateTimeUtc;
Expand Down Expand Up @@ -95,23 +94,10 @@ pub async fn run(

#[cfg(feature = "dev")]
{
let genesis = &crate::config::genesis::genesis();
let consensus_key = crate::wallet::defaults::validator_keypair();
// write the validator key file if it didn't already exist
if !has_validator_key {
write_validator_key_async(
&home_dir,
&genesis
.validators
.first()
.expect(
"There should be one genesis validator in \"dev\" mode",
)
.pos_data
.address,
&consensus_key,
)
.await;
write_validator_key_async(&home_dir, &consensus_key).await;
}
}
write_tm_genesis(&home_dir, chain_id, genesis_time, &config).await;
Expand Down Expand Up @@ -198,49 +184,33 @@ pub fn reset(tendermint_dir: impl AsRef<Path>) -> Result<()> {

/// Convert a common signing scheme validator key into JSON for
/// Tendermint
fn validator_key_to_json(
address: &Address,
sk: &common::SecretKey,
fn validator_key_to_json<SK: SecretKey>(
sk: &SK,
) -> std::result::Result<serde_json::Value, ParseSecretKeyError> {
let address = address.raw_hash().unwrap();

let (id_str, pk_arr, kp_arr) = match sk {
common::SecretKey::Ed25519(_) => {
let sk_ed: ed25519::SecretKey = sk.try_to_sk().unwrap();
let keypair = [
sk_ed.try_to_vec().unwrap(),
sk_ed.ref_to().try_to_vec().unwrap(),
]
.concat();
("Ed25519", sk_ed.ref_to().try_to_vec().unwrap(), keypair)
}
common::SecretKey::Secp256k1(_) => {
let sk_sec: secp256k1::SecretKey = sk.try_to_sk().unwrap();
(
"Secp256k1",
sk_sec.ref_to().try_to_vec().unwrap(),
sk_sec.try_to_vec().unwrap(),
)
}
};

Ok(json!({
"address": address,
"pub_key": {
"type": format!("tendermint/PubKey{}",id_str),
"value": base64::encode(pk_arr),
},
"priv_key": {
"type": format!("tendermint/PrivKey{}",id_str),
"value": base64::encode(kp_arr),
}
}))
ed25519::SecretKey::try_from_sk(sk).map(|sk| {
let pk: ed25519::PublicKey = sk.ref_to();
let pk_common = common::PublicKey::try_from_pk(&pk)
.expect("must be able to convert ed25519 to common");
let raw_hash = tm_consensus_key_raw_hash(&pk_common);
let ck_arr =
[sk.try_to_vec().unwrap(), pk.try_to_vec().unwrap()].concat();
json!({
"address": raw_hash,
"pub_key": {
"type": "tendermint/PubKeyEd25519",
"value": base64::encode(pk.try_to_vec().unwrap()),
},
"priv_key": {
"type": "tendermint/PrivKeyEd25519",
"value": base64::encode(ck_arr),
}
})
})
}

/// Initialize validator private key for Tendermint
pub async fn write_validator_key_async(
home_dir: impl AsRef<Path>,
address: &Address,
consensus_key: &common::SecretKey,
) {
let home_dir = home_dir.as_ref();
Expand All @@ -257,7 +227,7 @@ pub async fn write_validator_key_async(
.open(&path)
.await
.expect("Couldn't create private validator key file");
let key = validator_key_to_json(address, consensus_key).unwrap();
let key = validator_key_to_json(consensus_key).unwrap();
let data = serde_json::to_vec_pretty(&key)
.expect("Couldn't encode private validator key file");
file.write_all(&data[..])
Expand All @@ -268,7 +238,6 @@ pub async fn write_validator_key_async(
/// Initialize validator private key for Tendermint
pub fn write_validator_key(
home_dir: impl AsRef<Path>,
address: &Address,
consensus_key: &common::SecretKey,
) {
let home_dir = home_dir.as_ref();
Expand All @@ -283,7 +252,7 @@ pub fn write_validator_key(
.truncate(true)
.open(&path)
.expect("Couldn't create private validator key file");
let key = validator_key_to_json(address, consensus_key).unwrap();
let key = validator_key_to_json(consensus_key).unwrap();
serde_json::to_writer_pretty(file, &key)
.expect("Couldn't write private validator key file");
}
Expand Down
23 changes: 17 additions & 6 deletions proof_of_stake/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -180,10 +180,11 @@ pub trait PosActions: PosReadOnly {
&mut self,
params: &PosParams,
) -> Result<(), Self::Error>;
/// Write PoS validator's raw hash its address.
/// Write PoS validator's raw hash of its consensus key.
fn write_validator_address_raw_hash(
&mut self,
address: &Self::Address,
consensus_key: &Self::PublicKey,
) -> Result<(), Self::Error>;
/// Write PoS validator's staking reward address, into which staking rewards
/// will be credited.
Expand Down Expand Up @@ -283,6 +284,7 @@ pub trait PosActions: PosReadOnly {
),
)?;
}
let consensus_key_clone = consensus_key.clone();
let BecomeValidatorData {
consensus_key,
state,
Expand All @@ -302,7 +304,7 @@ pub trait PosActions: PosReadOnly {
self.write_validator_consensus_key(address, consensus_key)?;
self.write_validator_state(address, state)?;
self.write_validator_set(validator_set)?;
self.write_validator_address_raw_hash(address)?;
self.write_validator_address_raw_hash(address, &consensus_key_clone)?;
self.write_validator_total_deltas(address, total_deltas)?;
self.write_validator_voting_power(address, voting_power)?;
Ok(())
Expand Down Expand Up @@ -583,7 +585,7 @@ pub trait PosBase {

/// Read PoS parameters.
fn read_pos_params(&self) -> PosParams;
/// Read PoS raw hash of validator's address.
/// Read PoS raw hash of validator's consensus key.
fn read_validator_address_raw_hash(
&self,
raw_hash: impl AsRef<str>,
Expand Down Expand Up @@ -618,8 +620,12 @@ pub trait PosBase {

/// Write PoS parameters.
fn write_pos_params(&mut self, params: &PosParams);
/// Write PoS validator's raw hash its address.
fn write_validator_address_raw_hash(&mut self, address: &Self::Address);
/// Write PoS validator's raw hash of its consensus key.
fn write_validator_address_raw_hash(
&mut self,
address: &Self::Address,
consensus_key: &Self::PublicKey,
);
/// Write PoS validator's staking reward address, into which staking rewards
/// will be credited.
fn write_validator_staking_reward_address(
Expand Down Expand Up @@ -729,7 +735,12 @@ pub trait PosBase {
voting_power,
bond: (bond_id, bond),
} = res?;
self.write_validator_address_raw_hash(address);
self.write_validator_address_raw_hash(
address,
consensus_key
.get(current_epoch)
.expect("Consensus key must be set"),
);
self.write_validator_staking_reward_address(
address,
&staking_reward_address,
Expand Down
8 changes: 6 additions & 2 deletions shared/src/ledger/pos/storage.rs
Original file line number Diff line number Diff line change
Expand Up @@ -454,8 +454,12 @@ where
self.write(&params_key(), encode(params)).unwrap();
}

fn write_validator_address_raw_hash(&mut self, address: &Self::Address) {
let raw_hash = address.raw_hash().unwrap();
fn write_validator_address_raw_hash(
&mut self,
address: &Self::Address,
consensus_key: &Self::PublicKey,
) {
let raw_hash = key::tm_consensus_key_raw_hash(consensus_key);
self.write(&validator_address_raw_hash_key(raw_hash), encode(address))
.unwrap();
}
Expand Down
20 changes: 20 additions & 0 deletions shared/src/types/key/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -351,6 +351,26 @@ impl<PK: PublicKey> From<&PK> for PublicKeyHash {
}
}

/// Convert validator's consensus key into address raw hash that is compatible
/// with Tendermint
pub fn tm_consensus_key_raw_hash(pk: &common::PublicKey) -> String {
match pk {
common::PublicKey::Ed25519(pk) => {
let pkh = PublicKeyHash::from(pk);
pkh.0
}
common::PublicKey::Secp256k1(pk) => {
let pkh = PublicKeyHash::from(pk);
pkh.0
}
}
}

/// Convert Tendermint validator's raw hash bytes to Anoma raw hash string
pub fn tm_raw_hash_to_string(raw_hash: impl AsRef<[u8]>) -> String {
hex::encode_upper(raw_hash)
}

/// Helpers for testing with keys.
#[cfg(any(test, feature = "testing"))]
pub mod testing {
Expand Down
Loading

0 comments on commit 0cadb8f

Please sign in to comment.