Skip to content
This repository has been archived by the owner on Nov 15, 2023. It is now read-only.

Commit

Permalink
Merge remote-tracking branch 'origin/master' into rgafiyatullin-subst…
Browse files Browse the repository at this point in the history
…rate-8103
  • Loading branch information
RGafiyatullin committed May 4, 2022
2 parents 5eae200 + 636ffa4 commit 443c10f
Show file tree
Hide file tree
Showing 13 changed files with 556 additions and 163 deletions.
38 changes: 34 additions & 4 deletions bin/node/runtime/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1832,8 +1832,12 @@ impl_runtime_apis! {
fn generate_proof(leaf_index: pallet_mmr::primitives::LeafIndex)
-> Result<(mmr::EncodableOpaqueLeaf, mmr::Proof<mmr::Hash>), mmr::Error>
{
Mmr::generate_proof(leaf_index)
.map(|(leaf, proof)| (mmr::EncodableOpaqueLeaf::from_leaf(&leaf), proof))
Mmr::generate_batch_proof(vec![leaf_index]).and_then(|(leaves, proof)|
Ok((
mmr::EncodableOpaqueLeaf::from_leaf(&leaves[0]),
mmr::BatchProof::into_single_leaf_proof(proof)?
))
)
}

fn verify_proof(leaf: mmr::EncodableOpaqueLeaf, proof: mmr::Proof<mmr::Hash>)
Expand All @@ -1843,7 +1847,7 @@ impl_runtime_apis! {
.into_opaque_leaf()
.try_decode()
.ok_or(mmr::Error::Verify)?;
Mmr::verify_leaf(leaf, proof)
Mmr::verify_leaves(vec![leaf], mmr::Proof::into_batch_proof(proof))
}

fn verify_proof_stateless(
Expand All @@ -1852,12 +1856,38 @@ impl_runtime_apis! {
proof: mmr::Proof<mmr::Hash>
) -> Result<(), mmr::Error> {
let node = mmr::DataOrHash::Data(leaf.into_opaque_leaf());
pallet_mmr::verify_leaf_proof::<mmr::Hashing, _>(root, node, proof)
pallet_mmr::verify_leaves_proof::<mmr::Hashing, _>(root, vec![node], mmr::Proof::into_batch_proof(proof))
}

fn mmr_root() -> Result<mmr::Hash, mmr::Error> {
Ok(Mmr::mmr_root())
}

fn generate_batch_proof(leaf_indices: Vec<pallet_mmr::primitives::LeafIndex>)
-> Result<(Vec<mmr::EncodableOpaqueLeaf>, mmr::BatchProof<mmr::Hash>), mmr::Error>
{
Mmr::generate_batch_proof(leaf_indices)
.map(|(leaves, proof)| (leaves.into_iter().map(|leaf| mmr::EncodableOpaqueLeaf::from_leaf(&leaf)).collect(), proof))
}

fn verify_batch_proof(leaves: Vec<mmr::EncodableOpaqueLeaf>, proof: mmr::BatchProof<mmr::Hash>)
-> Result<(), mmr::Error>
{
let leaves = leaves.into_iter().map(|leaf|
leaf.into_opaque_leaf()
.try_decode()
.ok_or(mmr::Error::Verify)).collect::<Result<Vec<mmr::Leaf>, mmr::Error>>()?;
Mmr::verify_leaves(leaves, proof)
}

fn verify_batch_proof_stateless(
root: mmr::Hash,
leaves: Vec<mmr::EncodableOpaqueLeaf>,
proof: mmr::BatchProof<mmr::Hash>
) -> Result<(), mmr::Error> {
let nodes = leaves.into_iter().map(|leaf|mmr::DataOrHash::Data(leaf.into_opaque_leaf())).collect();
pallet_mmr::verify_leaves_proof::<mmr::Hashing, _>(root, nodes, proof)
}
}

impl sp_session::SessionKeys<Block> for Runtime {
Expand Down
52 changes: 14 additions & 38 deletions client/beefy/src/round.rs
Original file line number Diff line number Diff line change
Expand Up @@ -73,26 +73,15 @@ pub(crate) struct Rounds<Payload, B: Block> {
best_done: Option<NumberFor<B>>,
session_start: NumberFor<B>,
validator_set: ValidatorSet<Public>,
prev_validator_set: ValidatorSet<Public>,
}

impl<P, B> Rounds<P, B>
where
P: Ord + Hash + Clone,
B: Block,
{
pub(crate) fn new(
session_start: NumberFor<B>,
validator_set: ValidatorSet<Public>,
prev_validator_set: ValidatorSet<Public>,
) -> Self {
Rounds {
rounds: BTreeMap::new(),
best_done: None,
session_start,
validator_set,
prev_validator_set,
}
pub(crate) fn new(session_start: NumberFor<B>, validator_set: ValidatorSet<Public>) -> Self {
Rounds { rounds: BTreeMap::new(), best_done: None, session_start, validator_set }
}
}

Expand All @@ -101,24 +90,12 @@ where
P: Ord + Hash + Clone,
B: Block,
{
pub(crate) fn validator_set_id_for(&self, block_number: NumberFor<B>) -> ValidatorSetId {
if block_number > self.session_start {
self.validator_set.id()
} else {
self.prev_validator_set.id()
}
}

pub(crate) fn validators_for(&self, block_number: NumberFor<B>) -> &[Public] {
if block_number > self.session_start {
self.validator_set.validators()
} else {
self.prev_validator_set.validators()
}
pub(crate) fn validator_set_id(&self) -> ValidatorSetId {
self.validator_set.id()
}

pub(crate) fn validator_set(&self) -> &ValidatorSet<Public> {
&self.validator_set
pub(crate) fn validators(&self) -> &[Public] {
self.validator_set.validators()
}

pub(crate) fn session_start(&self) -> &NumberFor<B> {
Expand All @@ -143,7 +120,7 @@ where
round.1
);
false
} else if !self.validator_set.validators().iter().any(|id| vote.0 == *id) {
} else if !self.validators().iter().any(|id| vote.0 == *id) {
debug!(
target: "beefy",
"🥩 received vote {:?} from validator that is not in the validator set, ignoring",
Expand All @@ -170,12 +147,11 @@ where
// remove this and older (now stale) rounds
let signatures = self.rounds.remove(round)?.votes;
self.rounds.retain(|&(_, number), _| number > round.1);
self.best_done = self.best_done.clone().max(Some(round.1.clone()));
self.best_done = self.best_done.max(Some(round.1));
debug!(target: "beefy", "🥩 Concluded round #{}", round.1);

Some(
self.validator_set
.validators()
self.validators()
.iter()
.map(|authority_id| signatures.get(authority_id).cloned())
.collect(),
Expand Down Expand Up @@ -247,13 +223,13 @@ mod tests {
.unwrap();

let session_start = 1u64.into();
let rounds = Rounds::<H256, Block>::new(session_start, validators.clone(), validators);
let rounds = Rounds::<H256, Block>::new(session_start, validators);

assert_eq!(42, rounds.validator_set_id_for(session_start));
assert_eq!(42, rounds.validator_set_id());
assert_eq!(1, *rounds.session_start());
assert_eq!(
&vec![Keyring::Alice.public(), Keyring::Bob.public(), Keyring::Charlie.public()],
rounds.validators_for(session_start)
rounds.validators()
);
}

Expand All @@ -274,7 +250,7 @@ mod tests {
let round = (H256::from_low_u64_le(1), 1);

let session_start = 1u64.into();
let mut rounds = Rounds::<H256, Block>::new(session_start, validators.clone(), validators);
let mut rounds = Rounds::<H256, Block>::new(session_start, validators);

// no self vote yet, should self vote
assert!(rounds.should_self_vote(&round));
Expand Down Expand Up @@ -347,7 +323,7 @@ mod tests {
.unwrap();

let session_start = 1u64.into();
let mut rounds = Rounds::<H256, Block>::new(session_start, validators.clone(), validators);
let mut rounds = Rounds::<H256, Block>::new(session_start, validators);

// round 1
assert!(rounds.add_vote(
Expand Down
52 changes: 45 additions & 7 deletions client/beefy/src/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,9 @@ use beefy_primitives::{
crypto::AuthorityId, BeefyApi, ConsensusLog, MmrRootHash, ValidatorSet, BEEFY_ENGINE_ID,
KEY_TYPE as BeefyKeyType,
};
use sp_mmr_primitives::{EncodableOpaqueLeaf, Error as MmrError, LeafIndex, MmrApi, Proof};
use sp_mmr_primitives::{
BatchProof, EncodableOpaqueLeaf, Error as MmrError, LeafIndex, MmrApi, Proof,
};

use sp_api::{ApiRef, ProvideRuntimeApi};
use sp_consensus::BlockOrigin;
Expand Down Expand Up @@ -259,6 +261,22 @@ macro_rules! create_test_api {
fn mmr_root() -> Result<MmrRootHash, MmrError> {
Ok($mmr_root)
}

fn generate_batch_proof(_leaf_indices: Vec<LeafIndex>) -> Result<(Vec<EncodableOpaqueLeaf>, BatchProof<MmrRootHash>), MmrError> {
unimplemented!()
}

fn verify_batch_proof(_leaves: Vec<EncodableOpaqueLeaf>, _proof: BatchProof<MmrRootHash>) -> Result<(), MmrError> {
unimplemented!()
}

fn verify_batch_proof_stateless(
_root: MmrRootHash,
_leaves: Vec<EncodableOpaqueLeaf>,
_proof: BatchProof<MmrRootHash>
) -> Result<(), MmrError> {
unimplemented!()
}
}
}
}
Expand Down Expand Up @@ -469,8 +487,8 @@ fn finalize_block_and_wait_for_beefy(
}

if expected_beefy.is_empty() {
// run for 1 second then verify no new best beefy block available
let timeout = Some(Duration::from_millis(500));
// run for quarter second then verify no new best beefy block available
let timeout = Some(Duration::from_millis(250));
streams_empty_after_timeout(best_blocks, &net, runtime, timeout);
streams_empty_after_timeout(signed_commitments, &net, runtime, None);
} else {
Expand Down Expand Up @@ -535,8 +553,8 @@ fn lagging_validators() {
let beefy_peers = peers.iter().enumerate().map(|(id, key)| (id, key, api.clone())).collect();
runtime.spawn(initialize_beefy(&mut net, beefy_peers, min_block_delta));

// push 42 blocks including `AuthorityChange` digests every 30 blocks.
net.generate_blocks(42, session_len, &validator_set, true);
// push 62 blocks including `AuthorityChange` digests every 30 blocks.
net.generate_blocks(62, session_len, &validator_set, true);
net.block_until_sync();

let net = Arc::new(Mutex::new(net));
Expand All @@ -550,7 +568,7 @@ fn lagging_validators() {
let (best_blocks, signed_commitments) = get_beefy_streams(&mut *net.lock(), peers);
net.lock().peer(0).client().as_client().finalize_block(finalize, None).unwrap();
// verify nothing gets finalized by BEEFY
let timeout = Some(Duration::from_millis(500));
let timeout = Some(Duration::from_millis(250));
streams_empty_after_timeout(best_blocks, &net, &mut runtime, timeout);
streams_empty_after_timeout(signed_commitments, &net, &mut runtime, None);

Expand All @@ -563,6 +581,26 @@ fn lagging_validators() {

// Both finalize #30 (mandatory session) and #32 -> BEEFY finalize #30 (mandatory), #31, #32
finalize_block_and_wait_for_beefy(&net, peers, &mut runtime, &[30, 32], &[30, 31, 32]);

// Verify that session-boundary votes get buffered by client and only processed once
// session-boundary block is GRANDPA-finalized (this guarantees authenticity for the new session
// validator set).

// Alice finalizes session-boundary mandatory block #60, Bob lags behind
let (best_blocks, signed_commitments) = get_beefy_streams(&mut *net.lock(), peers);
let finalize = BlockId::number(60);
net.lock().peer(0).client().as_client().finalize_block(finalize, None).unwrap();
// verify nothing gets finalized by BEEFY
let timeout = Some(Duration::from_millis(250));
streams_empty_after_timeout(best_blocks, &net, &mut runtime, timeout);
streams_empty_after_timeout(signed_commitments, &net, &mut runtime, None);

// Bob catches up and also finalizes #60 (and should have buffered Alice's vote on #60)
let (best_blocks, signed_commitments) = get_beefy_streams(&mut *net.lock(), peers);
net.lock().peer(1).client().as_client().finalize_block(finalize, None).unwrap();
// verify beefy skips intermediary votes, and successfully finalizes mandatory block #40
wait_for_best_beefy_blocks(best_blocks, &net, &mut runtime, &[60]);
wait_for_beefy_signed_commitments(signed_commitments, &net, &mut runtime, &[60]);
}

#[test]
Expand Down Expand Up @@ -624,7 +662,7 @@ fn correct_beefy_payload() {
.unwrap();

// verify consensus is _not_ reached
let timeout = Some(Duration::from_millis(500));
let timeout = Some(Duration::from_millis(250));
streams_empty_after_timeout(best_blocks, &net, &mut runtime, timeout);
streams_empty_after_timeout(signed_commitments, &net, &mut runtime, None);

Expand Down
Loading

0 comments on commit 443c10f

Please sign in to comment.