1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
use crate::crypto::key::Identifier;
use chain_crypto::{bech32::Bech32 as _, Ed25519, PublicKey};
use chain_impl_mockchain::{
    config::ConfigParam,
    key::{BftLeaderId, BftVerificationAlg},
};
use serde::{Deserialize, Deserializer, Serialize, Serializer};
use std::fmt;

#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub struct ConsensusLeaderId(BftLeaderId);

impl From<ConsensusLeaderId> for ConfigParam {
    fn from(consensus_leader_id: ConsensusLeaderId) -> Self {
        ConfigParam::AddBftLeader(consensus_leader_id.0)
    }
}

impl From<Identifier<Ed25519>> for ConsensusLeaderId {
    fn from(identifier: Identifier<Ed25519>) -> Self {
        ConsensusLeaderId(BftLeaderId::from(identifier.into_public_key()))
    }
}

impl From<PublicKey<Ed25519>> for ConsensusLeaderId {
    fn from(public_key: PublicKey<Ed25519>) -> Self {
        ConsensusLeaderId(BftLeaderId::from(public_key))
    }
}

impl From<BftLeaderId> for ConsensusLeaderId {
    fn from(leader_id: BftLeaderId) -> Self {
        Self(leader_id)
    }
}

impl From<ConsensusLeaderId> for BftLeaderId {
    fn from(leader_id: ConsensusLeaderId) -> Self {
        leader_id.0
    }
}

impl Serialize for ConsensusLeaderId {
    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
    where
        S: Serializer,
    {
        self.0.as_public_key().to_bech32_str().serialize(serializer)
    }
}

impl<'de> Deserialize<'de> for ConsensusLeaderId {
    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
    where
        D: Deserializer<'de>,
    {
        use serde::de::{self, Visitor};
        struct ConsensusLeaderIdVisitor;
        impl<'de> Visitor<'de> for ConsensusLeaderIdVisitor {
            type Value = ConsensusLeaderId;
            fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
                use chain_crypto::AsymmetricPublicKey as _;
                write!(
                    formatter,
                    "bech32 encoding of the leader id's public key ({})",
                    Ed25519::PUBLIC_BECH32_HRP
                )
            }

            fn visit_str<E>(self, s: &str) -> Result<Self::Value, E>
            where
                E: de::Error,
            {
                PublicKey::try_from_bech32_str(s)
                    .map(|pk: chain_crypto::PublicKey<BftVerificationAlg>| {
                        ConsensusLeaderId(pk.into())
                    })
                    .map_err(E::custom)
            }
        }

        deserializer.deserialize_str(ConsensusLeaderIdVisitor)
    }
}

#[cfg(test)]
mod test {
    use super::*;
    use quickcheck::{Arbitrary, Gen};

    impl Arbitrary for ConsensusLeaderId {
        fn arbitrary<G: Gen>(g: &mut G) -> Self {
            use crate::crypto::key::KeyPair;

            let kp: KeyPair<Ed25519> = KeyPair::arbitrary(g);
            let public_key = kp.identifier().into_public_key();
            ConsensusLeaderId(BftLeaderId::from(public_key))
        }
    }

    #[test]
    fn deserialize_from_str() {
        const STR: &str =
            "---\n\"ed25519_pk1evu9kfx9tztez708nac569hcp0xwkvekxpwc7m8ztxu44tmq4gws3yayej\"";

        let _: ConsensusLeaderId = serde_yaml::from_str(STR).unwrap();
    }

    quickcheck! {
        fn serde_encode_decode(consensus_leader_id: ConsensusLeaderId) -> bool {
            let s = serde_yaml::to_string(&consensus_leader_id).unwrap();
            let consensus_leader_id_dec: ConsensusLeaderId = serde_yaml::from_str(&s).unwrap();

            consensus_leader_id == consensus_leader_id_dec
        }
    }
}