1#[cfg(feature = "bls-experimental")]
19use crate::ecdsa_bls_crypto;
20use crate::{
21 ecdsa_crypto, AuthorityIdBound, BeefySignatureHasher, Commitment, DoubleVotingProof,
22 ForkVotingProof, FutureBlockVotingProof, Payload, ValidatorSetId, VoteMessage,
23};
24use sp_application_crypto::{AppCrypto, AppPair, RuntimeAppPublic, Wraps};
25use sp_core::{ecdsa, Pair};
26use sp_runtime::traits::{BlockNumber, Hash, Header as HeaderT};
27
28use codec::Encode;
29use std::{collections::HashMap, marker::PhantomData, sync::LazyLock};
30use strum::IntoEnumIterator;
31
32#[allow(missing_docs)]
34#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, strum::Display, strum::EnumIter)]
35pub enum Keyring<AuthorityId> {
36 Alice,
37 Bob,
38 Charlie,
39 Dave,
40 Eve,
41 Ferdie,
42 One,
43 Two,
44 _Marker(PhantomData<AuthorityId>),
45}
46
47pub trait BeefySignerAuthority<MsgHash: Hash>: AppPair {
51 fn sign_with_hasher(&self, message: &[u8]) -> <Self as AppCrypto>::Signature;
53}
54
55impl<MsgHash> BeefySignerAuthority<MsgHash> for <ecdsa_crypto::AuthorityId as AppCrypto>::Pair
56where
57 MsgHash: Hash,
58 <MsgHash as Hash>::Output: Into<[u8; 32]>,
59{
60 fn sign_with_hasher(&self, message: &[u8]) -> <Self as AppCrypto>::Signature {
61 let hashed_message = <MsgHash as Hash>::hash(message).into();
62 self.as_inner_ref().sign_prehashed(&hashed_message).into()
63 }
64}
65
66#[cfg(feature = "bls-experimental")]
67impl<MsgHash> BeefySignerAuthority<MsgHash> for <ecdsa_bls_crypto::AuthorityId as AppCrypto>::Pair
68where
69 MsgHash: Hash,
70 <MsgHash as Hash>::Output: Into<[u8; 32]>,
71{
72 fn sign_with_hasher(&self, message: &[u8]) -> <Self as AppCrypto>::Signature {
73 self.as_inner_ref().sign_with_hasher::<MsgHash>(&message).into()
74 }
75}
76
77impl<AuthorityId> Keyring<AuthorityId>
79where
80 AuthorityId: AuthorityIdBound + From<<<AuthorityId as AppCrypto>::Pair as AppCrypto>::Public>,
81 <AuthorityId as AppCrypto>::Pair: BeefySignerAuthority<BeefySignatureHasher>,
82 <AuthorityId as RuntimeAppPublic>::Signature:
83 Send + Sync + From<<<AuthorityId as AppCrypto>::Pair as AppCrypto>::Signature>,
84{
85 pub fn sign(&self, msg: &[u8]) -> <AuthorityId as RuntimeAppPublic>::Signature {
87 let key_pair: <AuthorityId as AppCrypto>::Pair = self.pair();
88 key_pair.sign_with_hasher(&msg).into()
89 }
90
91 pub fn pair(&self) -> <AuthorityId as AppCrypto>::Pair {
93 <AuthorityId as AppCrypto>::Pair::from_string(self.to_seed().as_str(), None)
94 .unwrap()
95 .into()
96 }
97
98 pub fn public(&self) -> AuthorityId {
100 self.pair().public().into()
101 }
102
103 pub fn to_seed(&self) -> String {
105 format!("//{}", self)
106 }
107
108 pub fn from_public(who: &AuthorityId) -> Option<Keyring<AuthorityId>> {
110 Self::iter().find(|k| k.public() == *who)
111 }
112}
113
114static PRIVATE_KEYS: LazyLock<HashMap<Keyring<ecdsa_crypto::AuthorityId>, ecdsa_crypto::Pair>> =
115 LazyLock::new(|| Keyring::iter().map(|i| (i.clone(), i.pair())).collect());
116static PUBLIC_KEYS: LazyLock<HashMap<Keyring<ecdsa_crypto::AuthorityId>, ecdsa_crypto::Public>> =
117 LazyLock::new(|| {
118 PRIVATE_KEYS
119 .iter()
120 .map(|(name, pair)| (name.clone(), sp_application_crypto::Pair::public(pair)))
121 .collect()
122 });
123
124impl From<Keyring<ecdsa_crypto::AuthorityId>> for ecdsa_crypto::Pair {
125 fn from(k: Keyring<ecdsa_crypto::AuthorityId>) -> Self {
126 k.pair()
127 }
128}
129
130impl From<Keyring<ecdsa_crypto::AuthorityId>> for ecdsa::Pair {
131 fn from(k: Keyring<ecdsa_crypto::AuthorityId>) -> Self {
132 k.pair().into()
133 }
134}
135
136impl From<Keyring<ecdsa_crypto::AuthorityId>> for ecdsa_crypto::Public {
137 fn from(k: Keyring<ecdsa_crypto::AuthorityId>) -> Self {
138 (*PUBLIC_KEYS).get(&k).cloned().unwrap()
139 }
140}
141
142pub fn signed_vote<Number: BlockNumber>(
144 block_number: Number,
145 payload: Payload,
146 validator_set_id: ValidatorSetId,
147 keyring: &Keyring<ecdsa_crypto::AuthorityId>,
148) -> VoteMessage<Number, ecdsa_crypto::Public, ecdsa_crypto::Signature> {
149 let commitment = Commitment { validator_set_id, block_number, payload };
150 let signature = keyring.sign(&commitment.encode());
151 VoteMessage { commitment, id: keyring.public(), signature }
152}
153
154pub fn generate_double_voting_proof(
156 vote1: (u64, Payload, ValidatorSetId, &Keyring<ecdsa_crypto::AuthorityId>),
157 vote2: (u64, Payload, ValidatorSetId, &Keyring<ecdsa_crypto::AuthorityId>),
158) -> DoubleVotingProof<u64, ecdsa_crypto::Public, ecdsa_crypto::Signature> {
159 let first = signed_vote(vote1.0, vote1.1, vote1.2, vote1.3);
160 let second = signed_vote(vote2.0, vote2.1, vote2.2, vote2.3);
161 DoubleVotingProof { first, second }
162}
163
164pub fn generate_fork_voting_proof<Header: HeaderT<Number = u64>, AncestryProof>(
166 vote: (u64, Payload, ValidatorSetId, &Keyring<ecdsa_crypto::AuthorityId>),
167 ancestry_proof: AncestryProof,
168 header: Header,
169) -> ForkVotingProof<Header, ecdsa_crypto::Public, AncestryProof> {
170 let signed_vote = signed_vote(vote.0, vote.1, vote.2, vote.3);
171 ForkVotingProof { vote: signed_vote, ancestry_proof, header }
172}
173
174pub fn generate_future_block_voting_proof(
176 vote: (u64, Payload, ValidatorSetId, &Keyring<ecdsa_crypto::AuthorityId>),
177) -> FutureBlockVotingProof<u64, ecdsa_crypto::Public> {
178 let signed_vote = signed_vote(vote.0, vote.1, vote.2, vote.3);
179 FutureBlockVotingProof { vote: signed_vote }
180}