1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
use exonum::{blockchain::BlockProof, crypto::PublicKey, helpers::ValidatorId, messages::Message};
use std::collections::HashSet;
#[derive(Debug, Clone)]
pub struct TrustAnchor {
validators: Vec<PublicKey>,
}
#[derive(Debug, Clone, PartialEq, Eq, Hash, Fail)]
pub enum BlockVerifyError {
#[fail(display = "invalid validator id encountered")]
InvalidValidatorId,
#[fail(display = "duplicate `Precommit`s authored by the same validator")]
DuplicateValidators,
#[fail(display = "no sufficient validator quorum")]
NoQuorum,
#[fail(display = "invalid validator signature")]
InvalidSignature,
}
impl TrustAnchor {
pub fn new<I>(consensus_keys: I) -> Self
where
I: IntoIterator<Item = PublicKey>,
{
TrustAnchor {
validators: consensus_keys.into_iter().collect(),
}
}
pub fn verify_block_proof(&self, block_proof: &BlockProof) -> Result<(), BlockVerifyError> {
let validators: Result<Vec<_>, _> = block_proof
.precommits
.iter()
.map(|precommit| precommit.validator())
.map(|ValidatorId(id)| {
self.validators
.get(id as usize)
.ok_or(BlockVerifyError::InvalidValidatorId)
})
.collect();
let validators = validators?;
if validators.iter().collect::<HashSet<_>>().len() != validators.len() {
return Err(BlockVerifyError::DuplicateValidators);
}
if validators.len() < 2 * self.validators.len() / 3 + 1 {
return Err(BlockVerifyError::NoQuorum);
}
let all_signatures_are_valid = block_proof
.precommits
.iter()
.zip(validators)
.all(|(precommit, pk)| precommit.verify_signature(pk));
if !all_signatures_are_valid {
return Err(BlockVerifyError::InvalidSignature);
}
Ok(())
}
}