-
Notifications
You must be signed in to change notification settings - Fork 72
Expand file tree
/
Copy pathlib.rs
More file actions
123 lines (111 loc) · 4.75 KB
/
Copy pathlib.rs
File metadata and controls
123 lines (111 loc) · 4.75 KB
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
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
use nimiq_blockchain_proxy::BlockchainProxy;
use nimiq_keys::{Address, KeyPair};
use nimiq_network_interface::{
network::Network as NetworkInterface, validator_record::ValidatorRecord,
};
use nimiq_network_libp2p::{
dht::{DhtRecord, DhtVerifierError, Verifier as DhtVerifier},
discovery::peer_contacts::{ValidatorInfoError, ValidatorRecordVerifier},
libp2p::kad::Record,
Network, PeerId,
};
use nimiq_serde::Deserialize;
use nimiq_utils::tagged_signing::{TaggedSignable, TaggedSigned};
pub struct Verifier {
blockchain: BlockchainProxy,
}
impl Verifier {
pub fn new(blockchain: BlockchainProxy) -> Self {
Self { blockchain }
}
}
impl ValidatorRecordVerifier for Verifier {
fn verify_validator_record(
&self,
signed_record: &TaggedSigned<
ValidatorRecord<<Network as NetworkInterface>::PeerId>,
KeyPair,
>,
) -> Result<(), ValidatorInfoError> {
// Acquire blockchain read access. For now exclude Light clients.
let blockchain = match self.blockchain {
BlockchainProxy::Full(ref blockchain) => blockchain,
BlockchainProxy::Light(_) => return Err(ValidatorInfoError::StateIncomplete),
};
let blockchain_read = blockchain.read();
// Get the staking contract to retrieve the public key for verification.
let staking_contract = blockchain_read
.get_staking_contract_if_complete(None)
.ok_or(ValidatorInfoError::StateIncomplete)?;
// Get the public key needed for verification.
let data_store = blockchain_read.get_staking_contract_store();
let txn = blockchain_read.read_transaction();
let public_key = staking_contract
.get_validator(
&data_store.read(&txn),
&signed_record.record.validator_address,
)
.ok_or(ValidatorInfoError::UnknownValidator(
signed_record.record.validator_address.clone(),
))?
.signing_key;
// Verify the record.
signed_record
.verify(&public_key)
.then_some(())
.ok_or(ValidatorInfoError::InvalidSignature)
}
}
impl DhtVerifier for Verifier {
fn verify(&self, record: &Record) -> Result<DhtRecord, DhtVerifierError> {
// Peek the tag to know what kind of record this is.
let Some(tag) = TaggedSigned::<ValidatorRecord<PeerId>, KeyPair>::peek_tag(&record.value)
else {
log::warn!(?record, "DHT Tag not peekable.");
return Err(DhtVerifierError::MalformedTag);
};
// Depending on tag perform the verification.
match tag {
ValidatorRecord::<PeerId>::TAG => {
// Deserialize the value of the record, which is a ValidatorRecord. If it fails return an error.
let validator_record =
TaggedSigned::<ValidatorRecord<PeerId>, KeyPair>::deserialize_from_vec(
&record.value,
)
.map_err(DhtVerifierError::MalformedValue)?;
// Make sure the peer who published the record is also the one signed into the record.
if record.publisher.ok_or(DhtVerifierError::MissingPublisher)?
!= validator_record.record.peer_id
{
return Err(DhtVerifierError::PublisherMismatch(
record.publisher.unwrap(),
validator_record.record.peer_id,
));
}
// Deserialize the key of the record which is an Address. If it fails return an error.
let validator_address = Address::deserialize_from_vec(record.key.as_ref())
.map_err(DhtVerifierError::MalformedKey)?;
// Make sure the address used as key is also the one signed into the record.
if validator_address != validator_record.record.validator_address {
return Err(DhtVerifierError::AddressMismatch(
validator_address,
validator_record.record.validator_address,
));
}
self.verify_validator_record(&validator_record)
.map_err(|_| DhtVerifierError::ValidatorInfoError)
.map(|_| {
DhtRecord::Validator(
validator_record.record.peer_id,
validator_record.record,
record.clone(),
)
})
}
_ => {
log::error!(tag, "DHT invalid record tag received");
Err(DhtVerifierError::UnknownTag)
}
}
}
}