sc-consensus-beefy: add peer reputation cost/benefit changes (#13881)

* add cost/benefit to gossip messages
* report BEEFY gossip peer reputation changes
* drop WorkerParams helper struct
* add reputation costs to tests
* add peer reputation cost/benefit to on-demand-requests protocol
* include amount of signatures checked in invalid proof reputation cost

Signed-off-by: Adrian Catangiu <adrian@parity.io>
This commit is contained in:
Adrian Catangiu
2023-04-12 14:09:50 +03:00
committed by GitHub
parent 84c9e2f63a
commit 4253ecbc62
12 changed files with 430 additions and 225 deletions
@@ -42,9 +42,9 @@ pub(crate) fn decode_and_verify_finality_proof<Block: BlockT>(
encoded: &[u8],
target_number: NumberFor<Block>,
validator_set: &ValidatorSet<AuthorityId>,
) -> Result<BeefyVersionedFinalityProof<Block>, ConsensusError> {
) -> Result<BeefyVersionedFinalityProof<Block>, (ConsensusError, u32)> {
let proof = <BeefyVersionedFinalityProof<Block>>::decode(&mut &*encoded)
.map_err(|_| ConsensusError::InvalidJustification)?;
.map_err(|_| (ConsensusError::InvalidJustification, 0))?;
verify_with_validator_set::<Block>(target_number, validator_set, &proof).map(|_| proof)
}
@@ -53,14 +53,15 @@ pub(crate) fn verify_with_validator_set<Block: BlockT>(
target_number: NumberFor<Block>,
validator_set: &ValidatorSet<AuthorityId>,
proof: &BeefyVersionedFinalityProof<Block>,
) -> Result<(), ConsensusError> {
) -> Result<(), (ConsensusError, u32)> {
let mut signatures_checked = 0u32;
match proof {
VersionedFinalityProof::V1(signed_commitment) => {
if signed_commitment.signatures.len() != validator_set.len() ||
signed_commitment.commitment.validator_set_id != validator_set.id() ||
signed_commitment.commitment.block_number != target_number
{
return Err(ConsensusError::InvalidJustification)
return Err((ConsensusError::InvalidJustification, 0))
}
// Arrangement of signatures in the commitment should be in the same order
@@ -73,14 +74,17 @@ pub(crate) fn verify_with_validator_set<Block: BlockT>(
.filter(|(id, signature)| {
signature
.as_ref()
.map(|sig| BeefyKeystore::verify(id, sig, &message[..]))
.map(|sig| {
signatures_checked += 1;
BeefyKeystore::verify(id, sig, &message[..])
})
.unwrap_or(false)
})
.count();
if valid_signatures >= crate::round::threshold(validator_set.len()) {
Ok(())
} else {
Err(ConsensusError::InvalidJustification)
Err((ConsensusError::InvalidJustification, signatures_checked))
}
},
}
@@ -127,16 +131,16 @@ pub(crate) mod tests {
// wrong block number -> should fail verification
let good_proof = proof.clone().into();
match verify_with_validator_set::<Block>(block_num + 1, &validator_set, &good_proof) {
Err(ConsensusError::InvalidJustification) => (),
_ => assert!(false, "Expected Err(ConsensusError::InvalidJustification)"),
Err((ConsensusError::InvalidJustification, 0)) => (),
e => assert!(false, "Got unexpected {:?}", e),
};
// wrong validator set id -> should fail verification
let good_proof = proof.clone().into();
let other = ValidatorSet::new(make_beefy_ids(keys), 1).unwrap();
match verify_with_validator_set::<Block>(block_num, &other, &good_proof) {
Err(ConsensusError::InvalidJustification) => (),
_ => assert!(false, "Expected Err(ConsensusError::InvalidJustification)"),
Err((ConsensusError::InvalidJustification, 0)) => (),
e => assert!(false, "Got unexpected {:?}", e),
};
// wrong signatures length -> should fail verification
@@ -147,8 +151,8 @@ pub(crate) mod tests {
};
bad_signed_commitment.signatures.pop().flatten().unwrap();
match verify_with_validator_set::<Block>(block_num + 1, &validator_set, &bad_proof.into()) {
Err(ConsensusError::InvalidJustification) => (),
_ => assert!(false, "Expected Err(ConsensusError::InvalidJustification)"),
Err((ConsensusError::InvalidJustification, 0)) => (),
e => assert!(false, "Got unexpected {:?}", e),
};
// not enough signatures -> should fail verification
@@ -158,9 +162,9 @@ pub(crate) mod tests {
};
// remove a signature (but same length)
*bad_signed_commitment.signatures.first_mut().unwrap() = None;
match verify_with_validator_set::<Block>(block_num + 1, &validator_set, &bad_proof.into()) {
Err(ConsensusError::InvalidJustification) => (),
_ => assert!(false, "Expected Err(ConsensusError::InvalidJustification)"),
match verify_with_validator_set::<Block>(block_num, &validator_set, &bad_proof.into()) {
Err((ConsensusError::InvalidJustification, 2)) => (),
e => assert!(false, "Got unexpected {:?}", e),
};
// not enough _correct_ signatures -> should fail verification
@@ -171,9 +175,9 @@ pub(crate) mod tests {
// change a signature to a different key
*bad_signed_commitment.signatures.first_mut().unwrap() =
Some(Keyring::Dave.sign(&bad_signed_commitment.commitment.encode()));
match verify_with_validator_set::<Block>(block_num + 1, &validator_set, &bad_proof.into()) {
Err(ConsensusError::InvalidJustification) => (),
_ => assert!(false, "Expected Err(ConsensusError::InvalidJustification)"),
match verify_with_validator_set::<Block>(block_num, &validator_set, &bad_proof.into()) {
Err((ConsensusError::InvalidJustification, 3)) => (),
e => assert!(false, "Got unexpected {:?}", e),
};
}