Skip to content
This repository was archived by the owner on Nov 15, 2023. It is now read-only.
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
Show all changes
47 commits
Select commit Hold shift + click to select a range
7d74264
client/beefy: simplify self_vote logic
acatangiu Dec 21, 2022
c366330
client/beefy: migrate to new state version
acatangiu Dec 21, 2022
a9f067e
client/beefy: detect equivocated votes
acatangiu Dec 22, 2022
4becc37
fix typos
acatangiu Jan 4, 2023
6db1632
sp-beefy: add equivocation primitives
acatangiu Jan 4, 2023
e8f50ac
client/beefy: refactor vote processing
acatangiu Jan 4, 2023
fc35fd5
fix version migration for new rounds struct
acatangiu Jan 5, 2023
800c1d9
client/beefy: track equivocations and create proofs
acatangiu Jan 5, 2023
bbc786a
client/beefy: adjust tests for new voting logic
acatangiu Jan 5, 2023
d6f6c18
sp-beefy: fix commitment ordering and equality
acatangiu Jan 5, 2023
4958928
client/beefy: simplify handle_vote() a bit
acatangiu Jan 5, 2023
acfcb1f
client/beefy: add simple equivocation test
acatangiu Jan 6, 2023
8c0d67b
client/beefy: submit equivocation proof - WIP
acatangiu Jan 9, 2023
7114074
frame/beefy: add equivocation report runtime api - part 1
acatangiu Jan 9, 2023
3219c2f
frame/beefy: report equivocation logic - part 2
acatangiu Jan 10, 2023
9278bf0
frame/beefy: add pluggable Equivocation handler - part 3
acatangiu Jan 10, 2023
db11585
frame/beefy: impl ValidateUnsigned for equivocations reporting
acatangiu Jan 10, 2023
57d6897
client/beefy: submit report equivocation unsigned extrinsic
acatangiu Jan 10, 2023
8a344cc
primitives/beefy: fix tests
acatangiu Jan 10, 2023
f6aa2e0
frame/beefy: add default weights
acatangiu Jan 10, 2023
5cf2560
frame/beefy: fix tests
acatangiu Jan 10, 2023
2c2c5d6
client/beefy: fix tests
acatangiu Jan 10, 2023
93ba33d
Merge branch 'master' of github.com:paritytech/substrate into beefy-e…
acatangiu Jan 16, 2023
9349350
frame/beefy-mmr: fix tests
acatangiu Jan 16, 2023
b5e2c21
frame/beefy: cross-check session index with equivocation report
acatangiu Jan 16, 2023
1eca5b2
sp-beefy: make test Keyring useable in pallet
acatangiu Jan 17, 2023
fccf5c7
frame/beefy: add basic equivocation test
acatangiu Jan 17, 2023
9d68c1d
frame/beefy: test verify equivocation results in slashing
acatangiu Jan 17, 2023
a08b319
frame/beefy: test report_equivocation_old_set
acatangiu Jan 17, 2023
64114b4
frame/beefy: add more equivocation tests
acatangiu Jan 18, 2023
5634805
sp-beefy: fix docs
acatangiu Jan 18, 2023
d8898a5
beefy: simplify equivocations and fix tests
acatangiu Jan 19, 2023
7388c55
client/beefy: address review comments
acatangiu Jan 19, 2023
1f52f4c
Merge remote-tracking branch 'origin/master' into beefy-equivocations
Jan 19, 2023
6ff53e5
frame/beefy: add ValidateUnsigned to test/mock runtime
acatangiu Jan 20, 2023
8f29cdb
Merge branch 'master' of github.com:paritytech/substrate into beefy-e…
acatangiu Jan 24, 2023
ab11674
client/beefy: fixes after merge master
acatangiu Jan 24, 2023
cb2bb8b
Merge branch 'master' of github.com:paritytech/substrate into beefy-e…
acatangiu Feb 6, 2023
711832b
fix missed merge damage
acatangiu Feb 6, 2023
7d62d22
Merge branch 'master' of github.com:paritytech/substrate into beefy-e…
acatangiu Feb 13, 2023
ab975f4
client/beefy: add test for reporting equivocations
acatangiu Feb 13, 2023
f6bfc81
sp-beefy: move test utils to their own file
acatangiu Feb 13, 2023
02e166e
client/beefy: add negative test for equivocation reports
acatangiu Feb 13, 2023
42ef521
sp-beefy: move back MmrRootProvider - used in polkadot-service
acatangiu Feb 13, 2023
282d18f
impl review suggestions
acatangiu Feb 16, 2023
900547f
Merge branch 'master' of github.com:paritytech/substrate into beefy-e…
acatangiu Feb 16, 2023
f070f63
client/beefy: add equivocation metrics
acatangiu Feb 16, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
beefy: simplify equivocations and fix tests
  • Loading branch information
acatangiu committed Jan 19, 2023
commit d8898a58430b3acbcda4d1dec5ebde77f3c1c5e7
6 changes: 4 additions & 2 deletions client/beefy/src/keystore.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,6 @@
use sp_application_crypto::RuntimeAppPublic;
use sp_core::keccak_256;
use sp_keystore::{SyncCryptoStore, SyncCryptoStorePtr};
use sp_runtime::traits::Keccak256;

use log::warn;

Expand All @@ -30,6 +29,9 @@ use beefy_primitives::{

use crate::error;

/// Hasher used for BEEFY signatures.
pub(crate) type BeefySignatureHasher = sp_runtime::traits::Keccak256;

/// A BEEFY specific keystore implemented as a `Newtype`. This is basically a
/// wrapper around [`sp_keystore::SyncCryptoStore`] and allows to customize
/// common cryptographic functionality.
Expand Down Expand Up @@ -99,7 +101,7 @@ impl BeefyKeystore {
///
/// Return `true` if the signature is authentic, `false` otherwise.
pub fn verify(public: &Public, sig: &Signature, message: &[u8]) -> bool {
BeefyAuthorityId::<Keccak256>::verify(public, sig, message)
BeefyAuthorityId::<BeefySignatureHasher>::verify(public, sig, message)
}
}

Expand Down
22 changes: 6 additions & 16 deletions client/beefy/src/round.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,7 @@

use beefy_primitives::{
crypto::{AuthorityId, Public, Signature},
Commitment, Equivocation, EquivocationProof, SignedCommitment, ValidatorSet, ValidatorSetId,
VoteMessage,
Commitment, EquivocationProof, SignedCommitment, ValidatorSet, ValidatorSetId, VoteMessage,
};
use codec::{Decode, Encode};
use log::debug;
Expand Down Expand Up @@ -164,14 +163,10 @@ where
target: "beefy", "🥩 detected equivocated vote: 1st: {:?}, 2nd: {:?}",
existing_vote, vote
);
let equivocation = Equivocation {
round_number: equivocation_key.1,
id: equivocation_key.0,
return VoteImportResult::Equivocation(EquivocationProof {
first: existing_vote.clone(),
second: vote,
};
let set_id = self.validator_set_id();
return VoteImportResult::Equivocation(EquivocationProof { set_id, equivocation })
})
}
} else {
// this is the first vote sent by `id` for `num`, all good
Expand Down Expand Up @@ -218,7 +213,7 @@ mod tests {
use sc_network_test::Block;

use beefy_primitives::{
crypto::Public, keyring::Keyring, known_payloads::MMR_ROOT_ID, Commitment, Equivocation,
crypto::Public, keyring::Keyring, known_payloads::MMR_ROOT_ID, Commitment,
EquivocationProof, Payload, SignedCommitment, ValidatorSet, VoteMessage,
};

Expand Down Expand Up @@ -501,13 +496,8 @@ mod tests {
alice_vote2.commitment = commitment2;

let expected_result = VoteImportResult::Equivocation(EquivocationProof {
set_id: validator_set_id,
equivocation: Equivocation {
id: Keyring::Alice.public(),
round_number: 1,
first: alice_vote1.clone(),
second: alice_vote2.clone(),
},
first: alice_vote1.clone(),
second: alice_vote2.clone(),
});

// vote on one payload - ok
Expand Down
21 changes: 11 additions & 10 deletions client/beefy/src/worker.rs
Original file line number Diff line number Diff line change
Expand Up @@ -23,13 +23,14 @@ use crate::{
},
error::Error,
justification::BeefyVersionedFinalityProof,
keystore::BeefyKeystore,
keystore::{BeefyKeystore, BeefySignatureHasher},
metric_inc, metric_set,
metrics::Metrics,
round::{Rounds, VoteImportResult},
BeefyVoterLinks,
};
use beefy_primitives::{
check_equivocation_proof,
crypto::{AuthorityId, Signature},
BeefyApi, Commitment, ConsensusLog, EquivocationProof, PayloadProvider, ValidatorSet,
VersionedFinalityProof, VoteMessage, BEEFY_ENGINE_ID,
Expand Down Expand Up @@ -914,18 +915,22 @@ where
let rounds =
self.persisted_state.voting_oracle.active_rounds().ok_or(Error::UninitSession)?;
let (validators, validator_set_id) = (rounds.validators(), rounds.validator_set_id());
let offender_id = proof.offender_id().clone();

if proof.set_id != validator_set_id {
debug!(target: "beefy", "🥩 Skip equivocation report for old set id: {:?}", proof.set_id);
if proof.set_id() != validator_set_id {
debug!(target: "beefy", "🥩 Skip equivocation report for old set id: {:?}", proof.set_id());
return Ok(())
} else if !check_equivocation_proof::<_, _, BeefySignatureHasher>(&proof) {
debug!(target: "beefy", "🥩 Skip report for bad equivocation {:?}", proof);
return Ok(())
} else if let Some(local_id) = self.key_store.authority_id(validators) {
if proof.equivocation.id == local_id {
if offender_id == local_id {
debug!(target: "beefy", "🥩 Skip equivocation report for own equivocation");
return Ok(())
}
}

let number = proof.equivocation.round_number;
let number = *proof.round_number();
let hash = self
.backend
.blockchain()
Expand All @@ -942,11 +947,7 @@ where
let runtime_api = self.runtime.runtime_api();
// generate key ownership proof at that block
let key_owner_proof = match runtime_api
.generate_key_ownership_proof(
&BlockId::Hash(hash),
validator_set_id,
proof.equivocation.id.clone(),
)
.generate_key_ownership_proof(&BlockId::Hash(hash), validator_set_id, offender_id)
.map_err(Error::RuntimeApi)?
{
Some(proof) => proof,
Expand Down
15 changes: 8 additions & 7 deletions frame/beefy/src/equivocation.rs
Original file line number Diff line number Diff line change
Expand Up @@ -239,9 +239,9 @@ impl<T: Config> Pallet<T> {
.priority(TransactionPriority::MAX)
// Only one equivocation report for the same offender at the same slot.
.and_provides((
equivocation_proof.equivocation.id.clone(),
equivocation_proof.set_id,
equivocation_proof.equivocation.round_number,
equivocation_proof.offender_id().clone(),
equivocation_proof.set_id(),
*equivocation_proof.round_number(),
))
.longevity(longevity)
// We don't propagate this. This can never be included on a remote node.
Expand Down Expand Up @@ -269,17 +269,18 @@ fn is_known_offence<T: Config>(
>,
key_owner_proof: &T::KeyOwnerProof,
) -> Result<(), TransactionValidityError> {
// check the membership proof to extract the offender's id
let key = (beefy_primitives::KEY_TYPE, equivocation_proof.equivocation.id.clone());
// check the membership proof to extract the offender's id,
// equivocation validity will be fully checked during the call.
let key = (beefy_primitives::KEY_TYPE, equivocation_proof.offender_id().clone());

let offender = T::KeyOwnerProofSystem::check_proof(key, key_owner_proof.clone())
.ok_or(InvalidTransaction::BadProof)?;

// check if the offence has already been reported,
// and if so then we can discard the report.
let time_slot = <T::HandleEquivocation as HandleEquivocation<T>>::Offence::new_time_slot(
equivocation_proof.set_id,
equivocation_proof.equivocation.round_number,
equivocation_proof.set_id(),
*equivocation_proof.round_number(),
);

let is_known_offence = T::HandleEquivocation::is_known_offence(&[offender], &time_slot);
Expand Down
8 changes: 4 additions & 4 deletions frame/beefy/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -347,9 +347,9 @@ impl<T: Config> Pallet<T> {
// associated session) and round. We also need to know the validator
// set count at the time of the offence since it is required to calculate
// the slash amount.
let set_id = equivocation_proof.set_id;
let round = equivocation_proof.equivocation.round_number;
let offender_id = equivocation_proof.equivocation.id.clone();
let set_id = equivocation_proof.set_id();
let round = *equivocation_proof.round_number();
let offender_id = equivocation_proof.offender_id().clone();
let session_index = key_owner_proof.session();
let validator_count = key_owner_proof.validator_count();

Expand All @@ -361,7 +361,7 @@ impl<T: Config> Pallet<T> {
.ok_or(Error::<T>::InvalidKeyOwnershipProof)?;

// validate equivocation proof (check votes are different and signatures are valid).
if !beefy_primitives::check_equivocation_proof(equivocation_proof) {
if !beefy_primitives::check_equivocation_proof(&equivocation_proof) {
return Err(Error::<T>::InvalidEquivocationProof.into())
}

Expand Down
31 changes: 10 additions & 21 deletions frame/beefy/src/mock.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,7 @@
use std::vec;

use beefy_primitives::{
keyring::Keyring as BeefyKeyring, Commitment, Equivocation, Payload, ValidatorSetId,
VoteMessage,
keyring::Keyring as BeefyKeyring, Commitment, Payload, ValidatorSetId, VoteMessage,
};
use codec::Encode;
use frame_election_provider_support::{onchain, SequentialPhragmen};
Expand Down Expand Up @@ -346,28 +345,18 @@ pub fn start_era(era_index: EraIndex) {
}

pub fn generate_equivocation_proof(
validator_set_id: ValidatorSetId,
reporter_public: BeefyId,
vote1: (u64, Payload, &BeefyKeyring),
vote2: (u64, Payload, &BeefyKeyring),
vote1: (u64, Payload, ValidatorSetId, &BeefyKeyring),
vote2: (u64, Payload, ValidatorSetId, &BeefyKeyring),
) -> EquivocationProof<u64, BeefyId, BeefySignature> {
let block_number = vote1.0;

let signed_vote = |block_number: u64, payload: Payload, keyring: &BeefyKeyring| {
let signed_vote = |block_number: u64,
payload: Payload,
validator_set_id: ValidatorSetId,
keyring: &BeefyKeyring| {
let commitment = Commitment { validator_set_id, block_number, payload };
let signature = keyring.sign(&commitment.encode());
VoteMessage { commitment, id: keyring.public(), signature }
};

let first = signed_vote(vote1.0, vote1.1, vote1.2);
let second = signed_vote(vote2.0, vote2.1, vote2.2);
EquivocationProof {
set_id: validator_set_id,
equivocation: Equivocation {
round_number: block_number,
id: reporter_public,
first,
second,
},
}
let first = signed_vote(vote1.0, vote1.1, vote1.2, vote1.3);
let second = signed_vote(vote2.0, vote2.1, vote2.2, vote2.3);
EquivocationProof { first, second }
}
Loading