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