-
Notifications
You must be signed in to change notification settings - Fork 2.7k
Babe VRF Signing in keystore #6225
Changes from 13 commits
6a6b33f
363bb02
45c7582
4fcf607
3c148b7
3ca49f6
f292623
df6063d
76bcb2c
81e31c5
1d64e56
95a7b93
f62b1d7
04ec073
6c6f380
c572d13
b5415f6
e4db9bf
b581c6c
022b706
0c23a48
c3f17de
a691f24
a5821f0
b5322c3
53bed39
43596d7
61e3b8d
383bf44
2508594
1fd6936
b45a1ca
df7dd65
67b1c03
e46467b
ecd7cf1
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -16,18 +16,19 @@ | |
|
|
||
| //! BABE authority selection and slot claiming. | ||
|
|
||
| use sp_application_crypto::AppKey; | ||
| use sp_consensus_babe::{ | ||
| make_transcript, AuthorityId, BabeAuthorityWeight, BABE_VRF_PREFIX, | ||
| SlotNumber, AuthorityPair, | ||
| BABE_ENGINE_ID, BABE_VRF_PREFIX, | ||
| AuthorityId, BabeAuthorityWeight, | ||
| SlotNumber, | ||
| }; | ||
| use sp_consensus_babe::digests::{ | ||
| PreDigest, PrimaryPreDigest, SecondaryPlainPreDigest, SecondaryVRFPreDigest, | ||
| }; | ||
| use sp_consensus_vrf::schnorrkel::{VRFOutput, VRFProof}; | ||
| use sp_core::{U256, blake2_256}; | ||
| use sp_core::{U256, blake2_256, traits::BareCryptoStore}; | ||
| use codec::Encode; | ||
| use schnorrkel::vrf::VRFInOut; | ||
| use sp_core::Pair; | ||
| use sc_keystore::KeyStorePtr; | ||
| use super::Epoch; | ||
|
|
||
|
|
@@ -124,7 +125,8 @@ pub(super) fn secondary_slot_author( | |
| fn claim_secondary_slot( | ||
| slot_number: SlotNumber, | ||
| epoch: &Epoch, | ||
| key_pairs: &[(AuthorityPair, usize)], | ||
| keys: &[(AuthorityId, usize)], | ||
| keystore: &KeyStorePtr, | ||
| author_secondary_vrf: bool, | ||
| ) -> Option<(PreDigest, AuthorityId)> { | ||
| let Epoch { authorities, randomness, epoch_index, .. } = epoch; | ||
|
|
@@ -139,31 +141,42 @@ fn claim_secondary_slot( | |
| *randomness, | ||
| )?; | ||
|
|
||
| for (pair, authority_index) in key_pairs { | ||
| if pair.public() == *expected_author { | ||
| for (authority_id, authority_index) in keys { | ||
| if authority_id == expected_author { | ||
| let pre_digest = if author_secondary_vrf { | ||
| let transcript = super::authorship::make_transcript( | ||
| let result = keystore.read().vrf_sign( | ||
|
||
| AuthorityId::ID, | ||
| authority_id.as_ref(), | ||
| &BABE_ENGINE_ID, | ||
| BABE_VRF_PREFIX, | ||
| randomness, | ||
| slot_number, | ||
| *epoch_index, | ||
| u128::MAX, | ||
| ); | ||
|
|
||
| let s = get_keypair(&pair).vrf_sign(transcript); | ||
|
|
||
| PreDigest::SecondaryVRF(SecondaryVRFPreDigest { | ||
| slot_number, | ||
| vrf_output: VRFOutput(s.0.to_output()), | ||
| vrf_proof: VRFProof(s.1), | ||
| authority_index: *authority_index as u32, | ||
| }) | ||
| if let Ok(Some((output, proof))) = result { | ||
| let proof = schnorrkel::vrf::VRFProof::from_bytes(&proof).ok()?; | ||
| let output = schnorrkel::vrf::VRFOutput::from_bytes(&output).ok()?; | ||
|
|
||
| Some(PreDigest::SecondaryVRF(SecondaryVRFPreDigest { | ||
| slot_number, | ||
| vrf_output: VRFOutput(output), | ||
| vrf_proof: VRFProof(proof), | ||
| authority_index: *authority_index as u32, | ||
| })) | ||
| } else { | ||
| None | ||
| } | ||
| } else { | ||
| PreDigest::SecondaryPlain(SecondaryPlainPreDigest { | ||
| Some(PreDigest::SecondaryPlain(SecondaryPlainPreDigest { | ||
| slot_number, | ||
| authority_index: *authority_index as u32, | ||
| }) | ||
| })) | ||
| }; | ||
|
|
||
| return Some((pre_digest, pair.public())); | ||
| if let Some(pre_digest) = pre_digest { | ||
| return Some((pre_digest, authority_id.clone())); | ||
| } | ||
| } | ||
| } | ||
|
|
||
|
|
@@ -179,34 +192,31 @@ pub fn claim_slot( | |
| epoch: &Epoch, | ||
| keystore: &KeyStorePtr, | ||
| ) -> Option<(PreDigest, AuthorityId)> { | ||
| let key_pairs = { | ||
| let keystore = keystore.read(); | ||
| epoch.authorities.iter() | ||
| .enumerate() | ||
| .flat_map(|(i, a)| { | ||
| keystore.key_pair::<AuthorityPair>(&a.0).ok().map(|kp| (kp, i)) | ||
| }) | ||
| .collect::<Vec<_>>() | ||
| }; | ||
| claim_slot_using_key_pairs(slot_number, epoch, &key_pairs) | ||
| let authorities = epoch.authorities.iter() | ||
| .enumerate() | ||
| .map(|(index, a)| (a.0.clone(), index)) | ||
| .collect::<Vec<_>>(); | ||
| claim_slot_using_keys(slot_number, epoch, keystore, &authorities) | ||
| } | ||
|
|
||
| /// Like `claim_slot`, but allows passing an explicit set of key pairs. Useful if we intend | ||
| /// to make repeated calls for different slots using the same key pairs. | ||
| pub fn claim_slot_using_key_pairs( | ||
| pub fn claim_slot_using_keys( | ||
| slot_number: SlotNumber, | ||
| epoch: &Epoch, | ||
| key_pairs: &[(AuthorityPair, usize)], | ||
| keystore: &KeyStorePtr, | ||
| keys: &[(AuthorityId, usize)], | ||
| ) -> Option<(PreDigest, AuthorityId)> { | ||
| claim_primary_slot(slot_number, epoch, epoch.config.c, &key_pairs) | ||
| claim_primary_slot(slot_number, epoch, epoch.config.c, keystore, &keys) | ||
| .or_else(|| { | ||
| if epoch.config.allowed_slots.is_secondary_plain_slots_allowed() || | ||
| epoch.config.allowed_slots.is_secondary_vrf_slots_allowed() | ||
| { | ||
| claim_secondary_slot( | ||
| slot_number, | ||
| &epoch, | ||
| &key_pairs, | ||
| keys, | ||
| keystore, | ||
| epoch.config.allowed_slots.is_secondary_vrf_slots_allowed(), | ||
| ) | ||
| } else { | ||
|
|
@@ -215,11 +225,6 @@ pub fn claim_slot_using_key_pairs( | |
| }) | ||
| } | ||
|
|
||
| fn get_keypair(q: &AuthorityPair) -> &schnorrkel::Keypair { | ||
| use sp_core::crypto::IsWrappedBy; | ||
| sp_core::sr25519::Pair::from_ref(q).as_ref() | ||
| } | ||
|
|
||
| /// Claim a primary slot if it is our turn. Returns `None` if it is not our turn. | ||
| /// This hashes the slot number, epoch, genesis hash, and chain randomness into | ||
| /// the VRF. If the VRF produces a value less than `threshold`, it is our turn, | ||
|
|
@@ -228,33 +233,40 @@ fn claim_primary_slot( | |
| slot_number: SlotNumber, | ||
| epoch: &Epoch, | ||
| c: (u64, u64), | ||
| key_pairs: &[(AuthorityPair, usize)], | ||
| keystore: &KeyStorePtr, | ||
| keys: &[(AuthorityId, usize)], | ||
| ) -> Option<(PreDigest, AuthorityId)> { | ||
| let Epoch { authorities, randomness, epoch_index, .. } = epoch; | ||
|
|
||
| for (pair, authority_index) in key_pairs { | ||
| let transcript = super::authorship::make_transcript(randomness, slot_number, *epoch_index); | ||
|
|
||
| for (authority_id, authority_index) in keys { | ||
| // Compute the threshold we will use. | ||
| // | ||
| // We already checked that authorities contains `key.public()`, so it can't | ||
| // be empty. Therefore, this division in `calculate_threshold` is safe. | ||
| let threshold = super::authorship::calculate_primary_threshold(c, authorities, *authority_index); | ||
|
|
||
| let pre_digest = get_keypair(pair) | ||
| .vrf_sign_after_check(transcript, |inout| super::authorship::check_primary_threshold(inout, threshold)) | ||
| .map(|s| { | ||
| PreDigest::Primary(PrimaryPreDigest { | ||
| slot_number, | ||
| vrf_output: VRFOutput(s.0.to_output()), | ||
| vrf_proof: VRFProof(s.1), | ||
| authority_index: *authority_index as u32, | ||
| }) | ||
| let result = keystore.read().vrf_sign( | ||
| AuthorityId::ID, | ||
| authority_id.as_ref(), | ||
| &BABE_ENGINE_ID, | ||
| BABE_VRF_PREFIX, | ||
| randomness, | ||
| slot_number, | ||
| *epoch_index, | ||
| threshold, | ||
| ); | ||
| if let Ok(Some((output, proof))) = result { | ||
| let proof = schnorrkel::vrf::VRFProof::from_bytes(&proof).ok()?; | ||
| let output = schnorrkel::vrf::VRFOutput::from_bytes(&output).ok()?; | ||
|
|
||
| let pre_digest = PreDigest::Primary(PrimaryPreDigest { | ||
| slot_number, | ||
| vrf_output: VRFOutput(output), | ||
| vrf_proof: VRFProof(proof), | ||
| authority_index: *authority_index as u32, | ||
| }); | ||
|
|
||
| // early exit on first successful claim | ||
| if let Some(pre_digest) = pre_digest { | ||
| return Some((pre_digest, pair.public())); | ||
| return Some((pre_digest, authority_id.clone())); | ||
| } | ||
| } | ||
|
|
||
|
|
||
Uh oh!
There was an error while loading. Please reload this page.