Skip to content
This repository has been archived by the owner on Jul 27, 2022. It is now read-only.

Problem (CRO-627) council node pubkey format different from tendermint #657

Merged
merged 1 commit into from
Dec 9, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
21 changes: 21 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

18 changes: 6 additions & 12 deletions chain-abci/tests/abci_app.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,7 @@ use chain_core::init::config::InitConfig;
use chain_core::init::config::InitNetworkParameters;
use chain_core::init::config::NetworkParameters;
use chain_core::init::config::{
JailingParameters, RewardsParameters, SlashRatio, SlashingParameters, ValidatorKeyType,
ValidatorPubkey,
JailingParameters, RewardsParameters, SlashRatio, SlashingParameters,
};
use chain_core::state::account::{
to_stake_key, CouncilNode, DepositBondTx, StakedState, StakedStateAddress,
Expand Down Expand Up @@ -254,19 +253,14 @@ fn init_chain_for(address: RedeemAddress) -> ChainNodeApp<MockClient> {
.collect();
let NetworkParameters::Genesis(params) = get_dummy_network_params();
let mut nodes = BTreeMap::new();
let pub_key_base64 = "MDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDA=";
let node_pubkey = (
"test".to_owned(),
None,
ValidatorPubkey {
consensus_pubkey_type: ValidatorKeyType::Ed25519,
consensus_pubkey_b64: pub_key_base64.to_string(),
},
);
let pub_key =
TendermintValidatorPubKey::from_base64(b"MDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDA=")
.unwrap();
let node_pubkey = ("test".to_owned(), None, pub_key.clone());
let validator = ValidatorUpdate {
pub_key: Some(PubKey {
field_type: "ed25519".to_owned(),
data: base64::decode(&pub_key_base64).unwrap(),
data: pub_key.as_bytes().to_vec(),
..Default::default()
})
.into(),
Expand Down
1 change: 1 addition & 0 deletions chain-core/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ static_assertions = { version = "1.1.0", default-features = false}
bech32 = { version = "0.7.1", optional = true }
aead = "0.2"
fixed = "0.4.6"
thiserror = { version = "1.0", default-features = false }

[dev-dependencies]
quickcheck = "0.9"
Expand Down
44 changes: 17 additions & 27 deletions chain-core/src/init/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -78,8 +78,14 @@ pub struct InitConfig {
// initial network parameters
pub network_params: InitNetworkParameters,
// initial validators
pub council_nodes:
BTreeMap<RedeemAddress, (ValidatorName, ValidatorSecurityContact, ValidatorPubkey)>,
pub council_nodes: BTreeMap<
RedeemAddress,
(
ValidatorName,
ValidatorSecurityContact,
TendermintValidatorPubKey,
),
>,
}

pub type GenesisState = (
Expand All @@ -95,7 +101,11 @@ impl InitConfig {
network_params: InitNetworkParameters,
council_nodes: BTreeMap<
RedeemAddress,
(ValidatorName, ValidatorSecurityContact, ValidatorPubkey),
(
ValidatorName,
ValidatorSecurityContact,
TendermintValidatorPubKey,
),
>,
) -> Self {
InitConfig {
Expand All @@ -114,25 +124,6 @@ impl InitConfig {
}
}

fn check_validator_key(
&self,
pubkey: &ValidatorPubkey,
) -> Result<TendermintValidatorPubKey, DistributionError> {
if let Ok(key) = base64::decode(&pubkey.consensus_pubkey_b64) {
let key_len = key.len();
match (key_len, &pubkey.consensus_pubkey_type) {
(32, ValidatorKeyType::Ed25519) => {
let mut out = [0u8; 32];
out.copy_from_slice(&key);
Ok(TendermintValidatorPubKey::Ed25519(out))
}
_ => Err(DistributionError::InvalidValidatorKey),
}
} else {
Err(DistributionError::InvalidValidatorKey)
}
}

/// returns the initial accounts
/// assumes one called [validate_config_get_genesis], otherwise it may panic
fn get_account(&self, genesis_time: Timespec) -> Vec<StakedState> {
Expand Down Expand Up @@ -166,15 +157,14 @@ impl InitConfig {

fn get_council_node(&self, address: &RedeemAddress) -> Result<CouncilNode, DistributionError> {
self.check_validator_address(address)?;
let (name, security_contact, key) = self
let (name, security_contact, pubkey) = self
.council_nodes
.get(address)
.ok_or(DistributionError::InvalidValidatorAccount)?;
let validator_key = self.check_validator_key(key)?;
Ok(CouncilNode::new_with_details(
name.clone(),
security_contact.clone(),
validator_key,
pubkey.clone(),
))
}

Expand All @@ -191,10 +181,10 @@ impl InitConfig {
return Err(DistributionError::NoValidators);
}
// check validator pubkey is duplicated or not
let pub_keys: HashSet<String> = self
let pub_keys: HashSet<_> = self
.council_nodes
.iter()
.map(|(_, details)| details.2.consensus_pubkey_b64.clone())
.map(|(_, details)| details.2.clone())
.collect();
if pub_keys.len() != self.council_nodes.len() {
return Err(DistributionError::DuplicateValidatorKey);
Expand Down
16 changes: 0 additions & 16 deletions chain-core/src/init/params.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,6 @@ use serde::{de, Deserialize, Deserializer, Serialize, Serializer};
use std::convert::TryFrom;
use std::fmt;
use std::ops::Mul;
use std::prelude::v1::String;
use std::str::FromStr;

const MAX_SLASH_RATIO: Milli = Milli::new(1, 0); // 1.0
Expand Down Expand Up @@ -292,18 +291,3 @@ impl fmt::Display for SlashRatioError {
}
}
}

#[derive(Debug, PartialEq, Eq, Clone)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
pub enum ValidatorKeyType {
Ed25519,
}

#[derive(Debug, PartialEq, Eq, Clone)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
pub struct ValidatorPubkey {
// Tendermint consensus public key type
pub consensus_pubkey_type: ValidatorKeyType,
// Tendermint consensus public key encoded in base64
pub consensus_pubkey_b64: String,
}
63 changes: 60 additions & 3 deletions chain-core/src/state/tendermint.rs
Original file line number Diff line number Diff line change
@@ -1,32 +1,65 @@
use parity_scale_codec::{Decode, Encode};
#[cfg(feature = "serde")]
use serde::{
de::{self, Visitor},
de::{self, Error as _, Visitor},
Deserialize, Deserializer, Serialize, Serializer,
};
use sha2::{Digest, Sha256};
use std::convert::TryFrom;
use std::fmt;
use std::prelude::v1::{String, ToString, Vec};
#[cfg(feature = "base64")]
use thiserror::Error;

/// Tendermint block height
/// TODO: u64?
pub type BlockHeight = i64;

/// ed25519 public key size
pub const PUBLIC_KEY_SIZE: usize = 32;

/// The protobuf structure currently has "String" to denote the type / length
/// and variable length byte array. In this internal representation,
/// it's desirable to keep it restricted and compact. (TM should be encoding using the compressed form.)
#[derive(Debug, PartialEq, Eq, Hash, PartialOrd, Ord, Clone, Encode, Decode)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[cfg_attr(feature = "serde", serde(tag = "type", content = "value"))]
pub enum TendermintValidatorPubKey {
Ed25519([u8; 32]),
#[cfg_attr(
feature = "serde",
serde(
rename = "tendermint/PubKeyEd25519",
serialize_with = "serialize_ed25519_base64",
deserialize_with = "deserialize_ed25519_base64"
)
)]
Ed25519([u8; PUBLIC_KEY_SIZE]),
// there's PubKeySecp256k1, but https://tendermint.com/docs/spec/abci/apps.html#validator-updates
// "The pub_key currently supports only one type:"
// "type = "ed25519" anddata = <raw 32-byte public key>`"
// there's also PubKeyMultisigThreshold, but that probably wouldn't be used for individual nodes / validators
// TODO: some other schemes when they are added in TM?
}

/// Serialize the bytes of an Ed25519 public key as Base64. Used for serializing JSON
#[cfg(feature = "base64")]
fn serialize_ed25519_base64<S>(pk: &[u8], serializer: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
base64::encode(pk).serialize(serializer)
}

#[cfg(feature = "base64")]
fn deserialize_ed25519_base64<'de, D>(deserializer: D) -> Result<[u8; PUBLIC_KEY_SIZE], D::Error>
where
D: Deserializer<'de>,
{
TendermintValidatorPubKey::from_base64(String::deserialize(deserializer)?.as_bytes())
.map(|key| *key.as_bytes())
.map_err(|e| D::Error::custom(format!("{}", e)))
}

#[cfg(feature = "hex")]
impl fmt::Display for TendermintValidatorPubKey {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
Expand All @@ -36,16 +69,40 @@ impl fmt::Display for TendermintValidatorPubKey {
}
}

#[cfg(feature = "base64")]
#[derive(Error, Debug)]
pub enum PubKeyDecodeError {
#[error("Base64 decode error")]
Base64(#[from] base64::DecodeError),
#[error("Size of publickey is invalid, expected: {PUBLIC_KEY_SIZE}, got: {0}")]
InvalidSize(usize),
}

impl TendermintValidatorPubKey {
#[cfg(feature = "base64")]
pub fn from_base64(input: &[u8]) -> Result<TendermintValidatorPubKey, PubKeyDecodeError> {
let bytes = base64::decode(input)?;
if bytes.len() != PUBLIC_KEY_SIZE {
return Err(PubKeyDecodeError::InvalidSize(bytes.len()));
}
let mut result = [0u8; PUBLIC_KEY_SIZE];
result.copy_from_slice(&bytes);
Ok(TendermintValidatorPubKey::Ed25519(result))
}
pub fn to_validator_update(&self) -> (String, Vec<u8>) {
match self {
TendermintValidatorPubKey::Ed25519(key) => {
let mut v = Vec::with_capacity(32);
let mut v = Vec::with_capacity(PUBLIC_KEY_SIZE);
v.extend_from_slice(&key[..]);
("ed25519".to_string(), v)
}
}
}
pub fn as_bytes(&self) -> &[u8; PUBLIC_KEY_SIZE] {
match self {
Self::Ed25519(ref bytes) => bytes,
}
}
}

#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Clone, Encode, Decode)]
Expand Down
10 changes: 5 additions & 5 deletions chain-core/tests/verify_config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,10 @@ use chain_core::init::address::RedeemAddress;
use chain_core::init::coin::Coin;
use chain_core::init::config::{
InitConfig, InitNetworkParameters, JailingParameters, RewardsParameters, SlashRatio,
SlashingParameters, ValidatorKeyType, ValidatorPubkey,
SlashingParameters,
};
use chain_core::state::account::StakedStateDestination;
use chain_core::state::tendermint::TendermintValidatorPubKey;
use chain_core::tx::fee::{LinearFee, Milli};
use serde::Deserialize;
use std::collections::BTreeMap;
Expand All @@ -29,10 +30,9 @@ fn test_verify_test_example_snapshot() {
let node_address = "0x2440ad2533c66d91eb97807a339be13556d04990"
.parse::<RedeemAddress>()
.unwrap();
let node_pubkey = ValidatorPubkey {
consensus_pubkey_type: ValidatorKeyType::Ed25519,
consensus_pubkey_b64: "EIosObgfONUsnWCBGRpFlRFq5lSxjGIChRlVrVWVkcE=".to_string(),
};
let node_pubkey =
TendermintValidatorPubKey::from_base64(b"EIosObgfONUsnWCBGRpFlRFq5lSxjGIChRlVrVWVkcE=")
.unwrap();
let mut nodes = BTreeMap::new();
nodes.insert(node_address, ("no-name".to_owned(), None, node_pubkey));

Expand Down
4 changes: 2 additions & 2 deletions client-common/src/tendermint/mock.rs
Original file line number Diff line number Diff line change
Expand Up @@ -81,8 +81,8 @@ const DEFAULT_GENESIS_JSON: &str = r#"{
"integration test",
"security@integration.test",
{
"consensus_pubkey_type": "Ed25519",
"consensus_pubkey_b64": "2H0sZxyy5iOU6q0/F+ZCQ3MyJJxg8odE5NMsGIyfFV0="
"type": "tendermint/PubKeyEd25519",
"value": "2H0sZxyy5iOU6q0/F+ZCQ3MyJJxg8odE5NMsGIyfFV0="
}
]
}
Expand Down
15 changes: 8 additions & 7 deletions dev-utils/example-dev-conf.json
Original file line number Diff line number Diff line change
Expand Up @@ -27,13 +27,14 @@
"per_byte_fee": "1.25"
},
"council_nodes": {
"0x3ae55c16800dc4bd0e3397a9d7806fb1f11639de": [
"test",
"security@example.com",
{
"consensus_pubkey_type": "Ed25519",
"consensus_pubkey_b64": "pPxJH5wUamXcCvSxgywzmANuO0UNR5x3nCbUzsrCeX8="
}]
"0x3ae55c16800dc4bd0e3397a9d7806fb1f11639de": [
"test",
"security@example.com",
{
"type": "tendermint/PubKeyEd25519",
"value": "pPxJH5wUamXcCvSxgywzmANuO0UNR5x3nCbUzsrCeX8="
}
]
},
"genesis_time": "2019-10-23T07:26:34.783271158Z"
}
15 changes: 10 additions & 5 deletions dev-utils/src/commands/genesis_dev_config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,10 @@ use serde::{Deserialize, Serialize};
use chain_core::init::{
address::RedeemAddress,
coin::Coin,
config::{
JailingParameters, RewardsParameters, SlashRatio, SlashingParameters, ValidatorPubkey,
},
config::{JailingParameters, RewardsParameters, SlashRatio, SlashingParameters},
};
use chain_core::state::account::{ValidatorName, ValidatorSecurityContact};
use chain_core::state::tendermint::TendermintValidatorPubKey;
use client_common::tendermint::types::Time;

#[derive(Deserialize, Debug)]
Expand All @@ -21,8 +20,14 @@ pub struct GenesisDevConfig {
pub slashing_config: SlashingParameters,
pub rewards_config: RewardsParameters,
pub initial_fee_policy: InitialFeePolicy,
pub council_nodes:
BTreeMap<RedeemAddress, (ValidatorName, ValidatorSecurityContact, ValidatorPubkey)>,
pub council_nodes: BTreeMap<
RedeemAddress,
(
ValidatorName,
ValidatorSecurityContact,
TendermintValidatorPubKey,
),
>,
pub genesis_time: Time,
}

Expand Down
Loading