Skip to content

Commit 48fcaec

Browse files
committed
fix(p2p): Validate every pubsub message in a batch before continuing. Cleanup code
1 parent f7384f5 commit 48fcaec

File tree

1 file changed

+81
-38
lines changed

1 file changed

+81
-38
lines changed

p2p/src/network/pubsub/pubsub_effectful/p2p_network_pubsub_effectful_effects.rs

Lines changed: 81 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,20 @@ use crate::{
1010

1111
use super::P2pNetworkPubsubEffectfulAction;
1212

13+
#[derive(Debug)]
14+
pub enum PubSubError {
15+
/// The message does not contain a signature.
16+
MissingSignature,
17+
/// The message does not contain a verifying key.
18+
MissingVerifyingKey,
19+
/// Failed to retrieve the originator's public key.
20+
OriginatorFailed,
21+
/// Serialization of the message without signature and key failed.
22+
SerializationError,
23+
/// The message's signature is invalid.
24+
InvalidSignature,
25+
}
26+
1327
impl P2pNetworkPubsubEffectfulAction {
1428
pub fn effects<Store, S>(self, _meta: &redux::ActionMeta, store: &mut Store)
1529
where
@@ -36,54 +50,83 @@ impl P2pNetworkPubsubEffectfulAction {
3650
addr,
3751
messages,
3852
} => {
53+
let mut valid_messages = Vec::with_capacity(messages.len());
54+
3955
for message in messages {
40-
let result = if let Some(signature) = message.signature.clone() {
41-
if let Ok(Some(pk)) = originator(&message) {
42-
// the message is mutable only in this function
43-
let mut message = message;
44-
let Ok(data) = encode_without_signature_and_key(&mut message) else {
45-
// should never happen;
46-
// we just decode this message, so it should encode without error
47-
bug_condition!("serialization error");
48-
return;
56+
match validate_message(message, store) {
57+
Ok(valid_msg) => valid_messages.push(valid_msg),
58+
Err(error) => {
59+
let error_msg = match error {
60+
PubSubError::MissingSignature => {
61+
"message doesn't contain signature"
62+
}
63+
PubSubError::MissingVerifyingKey => {
64+
"message doesn't contain verifying key"
65+
}
66+
PubSubError::OriginatorFailed => "originator function failed",
67+
PubSubError::InvalidSignature => "invalid signature",
68+
PubSubError::SerializationError => {
69+
// Should never happen;
70+
// We just decoded this message, so it should encode
71+
// without errors.
72+
bug_condition!("serialization error");
73+
"serialization error"
74+
}
4975
};
50-
// keep the binding immutable
51-
let message = message;
52-
53-
if store.service().verify_publication(&pk, &data, &signature) {
54-
store.dispatch(P2pNetworkPubsubAction::IncomingMessage {
55-
peer_id,
56-
message,
57-
seen_limit,
58-
});
59-
Ok(())
60-
} else {
61-
Err("invalid signature")
62-
}
63-
} else {
64-
Err("message doesn't contain verifying key")
76+
77+
store.dispatch(P2pNetworkSchedulerAction::Error {
78+
addr,
79+
error: P2pNetworkConnectionError::PubSubError(
80+
error_msg.to_string(),
81+
),
82+
});
83+
84+
return; // Early exit, no need to process the rest
6585
}
66-
} else {
67-
Err("message doesn't contain signature")
68-
};
69-
70-
if let Err(error) = result {
71-
store.dispatch(P2pNetworkSchedulerAction::Error {
72-
addr,
73-
error: P2pNetworkConnectionError::PubSubError(error.to_string()),
74-
});
75-
76-
// TODO: should this error short-circuit the whole batch?
77-
// if yes, shouldn't every message be verified first before
78-
// dispatching `P2pNetworkPubsubAction::IncomingMessage`?
79-
return;
8086
}
8187
}
88+
89+
// All good, we can continue with these validated messages
90+
for message in valid_messages {
91+
store.dispatch(P2pNetworkPubsubAction::IncomingMessage {
92+
peer_id,
93+
message,
94+
seen_limit,
95+
});
96+
}
8297
}
8398
}
8499
}
85100
}
86101

102+
fn validate_message<Store, S>(
103+
message: pb::Message,
104+
store: &mut Store,
105+
) -> Result<pb::Message, PubSubError>
106+
where
107+
Store: crate::P2pStore<S>,
108+
Store::Service: P2pCryptoService,
109+
{
110+
let signature = message
111+
.signature
112+
.clone()
113+
.ok_or(PubSubError::MissingSignature)?;
114+
115+
let pk = originator(&message)
116+
.map_err(|_| PubSubError::OriginatorFailed)?
117+
.ok_or(PubSubError::MissingVerifyingKey)?;
118+
119+
let mut message = message;
120+
let data = encode_without_signature_and_key(&mut message)
121+
.map_err(|_| PubSubError::SerializationError)?;
122+
123+
if store.service().verify_publication(&pk, &data, &signature) {
124+
Ok(message)
125+
} else {
126+
Err(PubSubError::InvalidSignature)
127+
}
128+
}
129+
87130
pub fn originator(message: &pb::Message) -> Result<Option<PublicKey>, DecodingError> {
88131
message
89132
.key

0 commit comments

Comments
 (0)