use schemars::JsonSchema;
use serde::{Deserialize, Serialize};
use std::cmp::Ordering;
use std::convert::TryFrom;
use std::convert::TryInto;
use sha2::{Digest, Sha256};
use cosmwasm_std::Binary;
#[derive(Serialize, Deserialize, Clone, PartialEq, Eq, JsonSchema, Debug)]
pub struct Validator {
pub address: Binary,
pub power: u64,
}
#[derive(Serialize, Deserialize, Clone, PartialEq, Eq, JsonSchema, Debug)]
pub struct ValidatorUpdate {
pub pubkey: Pubkey,
pub power: u64,
}
#[derive(Serialize, Deserialize, Clone, PartialEq, Eq, JsonSchema, Debug)]
pub struct ValidatorVote {
pub address: Binary,
pub power: u64,
pub voted: bool,
}
#[non_exhaustive]
#[derive(Serialize, Deserialize, Clone, JsonSchema, Debug, PartialEq, Eq)]
#[serde(rename_all = "snake_case")]
pub enum Pubkey {
Ed25519(Binary),
Secp256k1(Binary),
Sr25519(Binary),
}
impl PartialOrd for Pubkey {
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
Some(self.cmp(other))
}
}
impl Ord for Pubkey {
fn cmp(&self, other: &Self) -> Ordering {
match (self, other) {
(Pubkey::Ed25519(a), Pubkey::Ed25519(b)) => a.0.cmp(&b.0),
(Pubkey::Ed25519(_), Pubkey::Secp256k1(_)) => Ordering::Less,
(Pubkey::Ed25519(_), Pubkey::Sr25519(_)) => Ordering::Less,
(Pubkey::Secp256k1(_), Pubkey::Ed25519(_)) => Ordering::Greater,
(Pubkey::Secp256k1(a), Pubkey::Secp256k1(b)) => a.0.cmp(&b.0),
(Pubkey::Secp256k1(_), Pubkey::Sr25519(_)) => Ordering::Less,
(Pubkey::Sr25519(_), Pubkey::Ed25519(_)) => Ordering::Greater,
(Pubkey::Sr25519(_), Pubkey::Secp256k1(_)) => Ordering::Greater,
(Pubkey::Sr25519(a), Pubkey::Sr25519(b)) => a.0.cmp(&b.0),
}
}
}
#[derive(Serialize, Deserialize, Clone, Debug, JsonSchema, PartialEq, Eq)]
pub struct Ed25519Pubkey([u8; 32]);
impl Ed25519Pubkey {
pub fn to_vec(&self) -> Vec<u8> {
self.0.to_vec()
}
pub fn to_base64(&self) -> String {
base64::encode(self.0)
}
}
impl ToAddress for Ed25519Pubkey {
fn to_address(&self) -> [u8; 20] {
let hash = Sha256::digest(&self.0);
hash[0..20].try_into().unwrap()
}
}
pub trait ToAddress {
fn to_address(&self) -> [u8; 20];
}
impl From<Ed25519Pubkey> for Pubkey {
fn from(ed: Ed25519Pubkey) -> Self {
Pubkey::Ed25519(ed.0.into())
}
}
#[derive(Debug)]
pub enum Ed25519PubkeyConversionError {
WrongType,
InvalidDataLength,
}
impl<'a> TryFrom<&'a Pubkey> for Ed25519Pubkey {
type Error = Ed25519PubkeyConversionError;
fn try_from(pubkey: &'a Pubkey) -> Result<Self, Self::Error> {
match pubkey {
Pubkey::Ed25519(data) => {
let data: [u8; 32] = data
.as_slice()
.try_into()
.map_err(|_| Ed25519PubkeyConversionError::InvalidDataLength)?;
Ok(Ed25519Pubkey(data))
}
_ => Err(Ed25519PubkeyConversionError::WrongType),
}
}
}
impl TryFrom<Pubkey> for Ed25519Pubkey {
type Error = Ed25519PubkeyConversionError;
fn try_from(pubkey: Pubkey) -> Result<Self, Self::Error> {
Ed25519Pubkey::try_from(&pubkey)
}
}
#[cfg(test)]
mod tests {
use super::*;
use hex_literal::hex;
#[test]
fn pubkey_implements_ord() {
let ed_a = Pubkey::Ed25519(b"abc".into());
let ed_b = Pubkey::Ed25519(b"bcd".into());
let se_a = Pubkey::Secp256k1(b"abc".into());
let se_b = Pubkey::Secp256k1(b"bcd".into());
let sr_a = Pubkey::Sr25519(b"abc".into());
let sr_b = Pubkey::Sr25519(b"bcd".into());
assert!(ed_a < ed_b);
assert!(se_a < se_b);
assert!(sr_a < sr_b);
assert!(ed_a < se_a);
assert!(se_a < sr_a);
assert!(ed_a < sr_a);
}
#[test]
fn ed25519pubkey_address() {
let pubkey = Ed25519Pubkey(hex!(
"14253D61EF42D166D02E68D540D07FDF8D65A9AF0ACAA46302688E788A8521E2"
));
let address = pubkey.to_address();
assert_eq!(address, hex!("0CDA3F47EF3C4906693B170EF650EB968C5F4B2C"))
}
}