use serde::{de::Error as _, Deserialize, Deserializer, Serialize};
use subtle_encoding::base64;
use crate::{account, hash::Hash, merkle, vote, Error, Kind, PublicKey, Signature};
use std::convert::{TryFrom, TryInto};
use tendermint_proto::types::SimpleValidator as RawSimpleValidator;
use tendermint_proto::types::Validator as RawValidator;
use tendermint_proto::types::ValidatorSet as RawValidatorSet;
use tendermint_proto::Protobuf;
#[derive(Serialize, Deserialize, Clone, Debug, PartialEq)]
pub struct Set {
validators: Vec<Info>,
proposer: Option<Info>,
total_voting_power: vote::Power,
}
impl Protobuf<RawValidatorSet> for Set {}
impl TryFrom<RawValidatorSet> for Set {
type Error = Error;
fn try_from(value: RawValidatorSet) -> Result<Self, Self::Error> {
let validators = value
.validators
.into_iter()
.map(TryInto::try_into)
.collect::<Result<Vec<_>, _>>()?;
let proposer = value.proposer.map(TryInto::try_into).transpose()?;
let validator_set = Self::new(validators, proposer);
let raw_voting_power = value.total_voting_power.try_into()?;
if raw_voting_power != validator_set.total_voting_power() {
return Err(Kind::RawVotingPowerMismatch {
raw: raw_voting_power,
computed: validator_set.total_voting_power(),
}
.into());
}
Ok(validator_set)
}
}
impl From<Set> for RawValidatorSet {
fn from(value: Set) -> Self {
RawValidatorSet {
validators: value.validators.into_iter().map(Into::into).collect(),
proposer: value.proposer.map(Into::into),
total_voting_power: value.total_voting_power.into(),
}
}
}
impl Set {
pub fn new(mut validators: Vec<Info>, proposer: Option<Info>) -> Set {
Self::sort_validators(&mut validators);
let total_voting_power = validators
.iter()
.map(|v| v.voting_power.value())
.sum::<u64>()
.try_into()
.unwrap();
Set {
validators,
proposer,
total_voting_power,
}
}
pub fn without_proposer(validators: Vec<Info>) -> Set {
Self::new(validators, None)
}
pub fn with_proposer(
validators: Vec<Info>,
proposer_address: account::Id,
) -> Result<Self, Error> {
let proposer = validators
.iter()
.find(|v| v.address == proposer_address)
.cloned()
.ok_or(Kind::ProposerNotFound(proposer_address))?;
Ok(Self::new(validators, Some(proposer)))
}
pub fn validators(&self) -> &Vec<Info> {
&self.validators
}
pub fn proposer(&self) -> &Option<Info> {
&self.proposer
}
pub fn total_voting_power(&self) -> vote::Power {
self.total_voting_power
}
fn sort_validators(vals: &mut Vec<Info>) {
vals.sort_by_key(|v| (std::cmp::Reverse(v.voting_power), v.address));
}
pub fn validator(&self, val_id: account::Id) -> Option<Info> {
self.validators
.iter()
.find(|val| val.address == val_id)
.cloned()
}
pub fn hash(&self) -> Hash {
let validator_bytes: Vec<Vec<u8>> = self
.validators()
.iter()
.map(|validator| validator.hash_bytes())
.collect();
Hash::Sha256(merkle::simple_hash_from_byte_vectors(validator_bytes))
}
}
#[derive(Clone, Copy, Debug, PartialEq, Serialize, Deserialize, Eq)]
pub struct Info {
pub address: account::Id,
pub pub_key: PublicKey,
#[serde(alias = "power", alias = "total_voting_power")]
pub voting_power: vote::Power,
#[serde(skip)]
pub proposer_priority: ProposerPriority,
}
impl TryFrom<RawValidator> for Info {
type Error = Error;
fn try_from(value: RawValidator) -> Result<Self, Self::Error> {
Ok(Info {
address: value.address.try_into()?,
pub_key: value.pub_key.ok_or(Kind::MissingPublicKey)?.try_into()?,
voting_power: value.voting_power.try_into()?,
proposer_priority: value.proposer_priority.try_into()?,
})
}
}
impl From<Info> for RawValidator {
fn from(value: Info) -> Self {
RawValidator {
address: value.address.into(),
pub_key: Some(value.pub_key.into()),
voting_power: value.voting_power.into(),
proposer_priority: value.proposer_priority.into(),
}
}
}
impl Info {
pub fn power(&self) -> u64 {
self.voting_power.value()
}
pub fn verify_signature(&self, sign_bytes: &[u8], signature: &Signature) -> Result<(), Error> {
self.pub_key.verify(sign_bytes, signature)
}
}
impl From<PublicKey> for account::Id {
fn from(pub_key: PublicKey) -> account::Id {
match pub_key {
PublicKey::Ed25519(pk) => account::Id::from(pk),
#[cfg(feature = "secp256k1")]
PublicKey::Secp256k1(pk) => account::Id::from(pk),
}
}
}
impl Info {
pub fn new(pk: PublicKey, vp: vote::Power) -> Info {
Info {
address: account::Id::from(pk),
pub_key: pk,
voting_power: vp,
proposer_priority: ProposerPriority::default(),
}
}
}
#[derive(Clone, PartialEq)]
pub struct SimpleValidator {
pub pub_key: Option<tendermint_proto::crypto::PublicKey>,
pub voting_power: vote::Power,
}
impl Protobuf<RawSimpleValidator> for SimpleValidator {}
impl TryFrom<RawSimpleValidator> for SimpleValidator {
type Error = Error;
fn try_from(value: RawSimpleValidator) -> Result<Self, Self::Error> {
Ok(SimpleValidator {
pub_key: value.pub_key,
voting_power: value.voting_power.try_into()?,
})
}
}
impl From<SimpleValidator> for RawSimpleValidator {
fn from(value: SimpleValidator) -> Self {
RawSimpleValidator {
pub_key: value.pub_key,
voting_power: value.voting_power.into(),
}
}
}
impl From<&Info> for SimpleValidator {
fn from(info: &Info) -> SimpleValidator {
let sum = match &info.pub_key {
PublicKey::Ed25519(pk) => Some(tendermint_proto::crypto::public_key::Sum::Ed25519(
pk.as_bytes().to_vec(),
)),
#[cfg(feature = "secp256k1")]
PublicKey::Secp256k1(pk) => Some(tendermint_proto::crypto::public_key::Sum::Secp256k1(
pk.as_bytes().to_vec(),
)),
};
SimpleValidator {
pub_key: Some(tendermint_proto::crypto::PublicKey { sum }),
voting_power: info.voting_power,
}
}
}
impl Info {
pub fn hash_bytes(&self) -> Vec<u8> {
SimpleValidator::from(self).encode_vec().unwrap()
}
}
#[derive(Copy, Clone, Debug, Eq, PartialEq, PartialOrd, Ord, Default)]
pub struct ProposerPriority(i64);
impl From<i64> for ProposerPriority {
fn from(value: i64) -> Self {
ProposerPriority(value)
}
}
impl From<ProposerPriority> for i64 {
fn from(priority: ProposerPriority) -> i64 {
priority.value()
}
}
impl ProposerPriority {
pub fn value(self) -> i64 {
self.0
}
}
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
pub struct Update {
#[serde(deserialize_with = "deserialize_public_key")]
pub pub_key: PublicKey,
#[serde(default)]
pub power: vote::Power,
}
#[derive(Serialize, Deserialize)]
#[serde(tag = "type", content = "data")]
enum Pk {
#[serde(rename = "ed25519")]
Ed25519(String),
}
fn deserialize_public_key<'de, D>(deserializer: D) -> Result<PublicKey, D::Error>
where
D: Deserializer<'de>,
{
match &Pk::deserialize(deserializer)? {
Pk::Ed25519(base64_value) => {
let bytes =
base64::decode(base64_value).map_err(|e| D::Error::custom(format!("{}", e)))?;
PublicKey::from_raw_ed25519(&bytes)
.ok_or_else(|| D::Error::custom("error parsing Ed25519 key"))
}
}
}
#[cfg(test)]
mod tests {
use super::*;
fn make_validator(pk: Vec<u8>, vp: u64) -> Info {
let pk = PublicKey::from_raw_ed25519(&pk).unwrap();
Info::new(pk, vote::Power::try_from(vp).unwrap())
}
#[test]
fn test_validator_set() {
let v1 = make_validator(
vec![
48, 163, 55, 132, 231, 147, 230, 163, 56, 158, 127, 218, 179, 139, 212, 103, 218,
89, 122, 126, 229, 88, 84, 48, 32, 0, 185, 174, 63, 72, 203, 52,
],
148_151_478_422_287_875,
);
let v2 = make_validator(
vec![
54, 253, 174, 153, 121, 74, 145, 180, 111, 16, 214, 48, 193, 109, 104, 134, 55,
162, 151, 16, 182, 114, 125, 135, 32, 195, 236, 248, 64, 112, 74, 101,
],
158_095_448_483_785_107,
);
let v3 = make_validator(
vec![
182, 205, 13, 86, 147, 27, 65, 49, 160, 118, 11, 180, 117, 35, 206, 35, 68, 19, 27,
173, 69, 92, 204, 224, 200, 51, 249, 81, 105, 128, 112, 244,
],
770_561_664_770_006_272,
);
let hash_expect = vec![
11, 64, 107, 4, 234, 81, 232, 75, 204, 199, 160, 114, 229, 97, 243, 95, 118, 213, 17,
22, 57, 84, 71, 122, 200, 169, 192, 252, 41, 148, 223, 180,
];
let val_set = Set::without_proposer(vec![v1, v2, v3]);
let hash = val_set.hash();
assert_eq!(hash_expect, hash.as_bytes().to_vec());
let not_in_set = make_validator(
vec![
110, 147, 87, 120, 27, 218, 66, 209, 81, 4, 169, 153, 64, 163, 137, 89, 168, 97,
219, 233, 42, 119, 24, 61, 47, 59, 76, 31, 182, 60, 13, 4,
],
10_000_000_000_000_000,
);
assert_eq!(val_set.validator(v1.address).unwrap(), v1);
assert_eq!(val_set.validator(v2.address).unwrap(), v2);
assert_eq!(val_set.validator(v3.address).unwrap(), v3);
assert_eq!(val_set.validator(not_in_set.address), None);
assert_eq!(
val_set.total_voting_power().value(),
148_151_478_422_287_875 + 158_095_448_483_785_107 + 770_561_664_770_006_272
);
}
}