2021-01-07 18:19:31 +11:00
|
|
|
// Copyright 2020 Sigma Prime Pty Ltd.
|
|
|
|
//
|
|
|
|
// Permission is hereby granted, free of charge, to any person obtaining a
|
|
|
|
// copy of this software and associated documentation files (the "Software"),
|
|
|
|
// to deal in the Software without restriction, including without limitation
|
|
|
|
// the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
|
|
|
// and/or sell copies of the Software, and to permit persons to whom the
|
|
|
|
// Software is furnished to do so, subject to the following conditions:
|
|
|
|
//
|
|
|
|
// The above copyright notice and this permission notice shall be included in
|
|
|
|
// all copies or substantial portions of the Software.
|
|
|
|
//
|
|
|
|
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
|
|
|
|
// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
|
|
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
|
|
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
|
|
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
|
|
|
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
|
|
|
// DEALINGS IN THE SOFTWARE.
|
|
|
|
|
|
|
|
use crate::error::ValidationError;
|
|
|
|
use crate::peer_score::RejectReason;
|
|
|
|
use crate::MessageId;
|
|
|
|
use libp2p_core::PeerId;
|
|
|
|
use log::debug;
|
|
|
|
use std::collections::HashMap;
|
2022-02-14 21:24:58 +11:00
|
|
|
use wasm_timer::Instant;
|
2021-01-07 18:19:31 +11:00
|
|
|
|
protocols/gossipsub: Improve bandwidth (#2327)
This PR adds some bandwidth improvements to gossipsub.
After a bit of inspection on live networks a number of improvements have been
made that can help reduce unnecessary bandwidth on gossipsub networks. This PR
introduces the following:
- A 1:1 tracking of all in-flight IWANT requests. This not only ensures that all
IWANT requests are answered and peers penalized accordingly, but gossipsub
will no no longer create multiple IWANT requests for multiple peers.
Previously, gossipsub sampled the in-flight IWANT requests in order to
penalize peers for not responding with a high probability that we would detect
non-responsive nodes. Futher, it was possible to re-request IWANT messages
that are already being requested causing added duplication in messages and
wasted unnecessary IWANT control messages. This PR shifts this logic to only
request message ids that we are not currently requesting from peers.
- Triangle routing naturally gives rise to unnecessary duplicates. Consider a
mesh of 4 peers that are interconnected. Peer 1 sends a new message to 2,3,4.
2 propagates to 3,4 and 3 propagates to 2,4 and 4 propagates to 2,3. In this
case 3 has received the message 3 times. If we keep track of peers that send
us messages, when publishing or forwarding we no longer send to peers that
have sent us a duplicate, we can eliminate one of the sends in the scenario
above. This only occurs when message validation is async however. This PR adds
this logic to remove some elements of triangle-routing duplicates.
Co-authored-by: Divma <26765164+divagant-martian@users.noreply.github.com>
Co-authored-by: Max Inden <mail@max-inden.de>
Co-authored-by: Diva M <divma@protonmail.com>
2021-12-21 22:09:15 +11:00
|
|
|
/// Tracks recently sent `IWANT` messages and checks if peers respond to them.
|
2021-01-07 18:19:31 +11:00
|
|
|
#[derive(Default)]
|
|
|
|
pub(crate) struct GossipPromises {
|
|
|
|
/// Stores for each tracked message id and peer the instant when this promise expires.
|
|
|
|
///
|
|
|
|
/// If the peer didn't respond until then we consider the promise as broken and penalize the
|
|
|
|
/// peer.
|
|
|
|
promises: HashMap<MessageId, HashMap<PeerId, Instant>>,
|
|
|
|
}
|
|
|
|
|
|
|
|
impl GossipPromises {
|
protocols/gossipsub: Improve bandwidth (#2327)
This PR adds some bandwidth improvements to gossipsub.
After a bit of inspection on live networks a number of improvements have been
made that can help reduce unnecessary bandwidth on gossipsub networks. This PR
introduces the following:
- A 1:1 tracking of all in-flight IWANT requests. This not only ensures that all
IWANT requests are answered and peers penalized accordingly, but gossipsub
will no no longer create multiple IWANT requests for multiple peers.
Previously, gossipsub sampled the in-flight IWANT requests in order to
penalize peers for not responding with a high probability that we would detect
non-responsive nodes. Futher, it was possible to re-request IWANT messages
that are already being requested causing added duplication in messages and
wasted unnecessary IWANT control messages. This PR shifts this logic to only
request message ids that we are not currently requesting from peers.
- Triangle routing naturally gives rise to unnecessary duplicates. Consider a
mesh of 4 peers that are interconnected. Peer 1 sends a new message to 2,3,4.
2 propagates to 3,4 and 3 propagates to 2,4 and 4 propagates to 2,3. In this
case 3 has received the message 3 times. If we keep track of peers that send
us messages, when publishing or forwarding we no longer send to peers that
have sent us a duplicate, we can eliminate one of the sends in the scenario
above. This only occurs when message validation is async however. This PR adds
this logic to remove some elements of triangle-routing duplicates.
Co-authored-by: Divma <26765164+divagant-martian@users.noreply.github.com>
Co-authored-by: Max Inden <mail@max-inden.de>
Co-authored-by: Diva M <divma@protonmail.com>
2021-12-21 22:09:15 +11:00
|
|
|
/// Returns true if the message id exists in the promises.
|
|
|
|
pub fn contains(&self, message: &MessageId) -> bool {
|
|
|
|
self.promises.contains_key(message)
|
|
|
|
}
|
|
|
|
|
2021-01-07 18:19:31 +11:00
|
|
|
/// Track a promise to deliver a message from a list of [`MessageId`]s we are requesting.
|
|
|
|
pub fn add_promise(&mut self, peer: PeerId, messages: &[MessageId], expires: Instant) {
|
protocols/gossipsub: Improve bandwidth (#2327)
This PR adds some bandwidth improvements to gossipsub.
After a bit of inspection on live networks a number of improvements have been
made that can help reduce unnecessary bandwidth on gossipsub networks. This PR
introduces the following:
- A 1:1 tracking of all in-flight IWANT requests. This not only ensures that all
IWANT requests are answered and peers penalized accordingly, but gossipsub
will no no longer create multiple IWANT requests for multiple peers.
Previously, gossipsub sampled the in-flight IWANT requests in order to
penalize peers for not responding with a high probability that we would detect
non-responsive nodes. Futher, it was possible to re-request IWANT messages
that are already being requested causing added duplication in messages and
wasted unnecessary IWANT control messages. This PR shifts this logic to only
request message ids that we are not currently requesting from peers.
- Triangle routing naturally gives rise to unnecessary duplicates. Consider a
mesh of 4 peers that are interconnected. Peer 1 sends a new message to 2,3,4.
2 propagates to 3,4 and 3 propagates to 2,4 and 4 propagates to 2,3. In this
case 3 has received the message 3 times. If we keep track of peers that send
us messages, when publishing or forwarding we no longer send to peers that
have sent us a duplicate, we can eliminate one of the sends in the scenario
above. This only occurs when message validation is async however. This PR adds
this logic to remove some elements of triangle-routing duplicates.
Co-authored-by: Divma <26765164+divagant-martian@users.noreply.github.com>
Co-authored-by: Max Inden <mail@max-inden.de>
Co-authored-by: Diva M <divma@protonmail.com>
2021-12-21 22:09:15 +11:00
|
|
|
for message_id in messages {
|
|
|
|
// If a promise for this message id and peer already exists we don't update the expiry!
|
2021-01-07 18:19:31 +11:00
|
|
|
self.promises
|
|
|
|
.entry(message_id.clone())
|
|
|
|
.or_insert_with(HashMap::new)
|
|
|
|
.entry(peer)
|
|
|
|
.or_insert(expires);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn message_delivered(&mut self, message_id: &MessageId) {
|
|
|
|
// Someone delivered a message, we can stop tracking all promises for it.
|
|
|
|
self.promises.remove(message_id);
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn reject_message(&mut self, message_id: &MessageId, reason: &RejectReason) {
|
|
|
|
// A message got rejected, so we can stop tracking promises and let the score penalty apply
|
|
|
|
// from invalid message delivery.
|
|
|
|
// We do take exception and apply promise penalty regardless in the following cases, where
|
|
|
|
// the peer delivered an obviously invalid message.
|
|
|
|
match reason {
|
|
|
|
RejectReason::ValidationError(ValidationError::InvalidSignature) => (),
|
|
|
|
RejectReason::SelfOrigin => (),
|
|
|
|
_ => {
|
|
|
|
self.promises.remove(message_id);
|
|
|
|
}
|
|
|
|
};
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Returns the number of broken promises for each peer who didn't follow up on an IWANT
|
|
|
|
/// request.
|
|
|
|
/// This should be called not too often relative to the expire times, since it iterates over
|
|
|
|
/// the whole stored data.
|
|
|
|
pub fn get_broken_promises(&mut self) -> HashMap<PeerId, usize> {
|
|
|
|
let now = Instant::now();
|
|
|
|
let mut result = HashMap::new();
|
|
|
|
self.promises.retain(|msg, peers| {
|
|
|
|
peers.retain(|peer_id, expires| {
|
|
|
|
if *expires < now {
|
2021-02-15 11:59:51 +01:00
|
|
|
let count = result.entry(*peer_id).or_insert(0);
|
2021-01-07 18:19:31 +11:00
|
|
|
*count += 1;
|
|
|
|
debug!(
|
protocols/gossipsub: Improve bandwidth (#2327)
This PR adds some bandwidth improvements to gossipsub.
After a bit of inspection on live networks a number of improvements have been
made that can help reduce unnecessary bandwidth on gossipsub networks. This PR
introduces the following:
- A 1:1 tracking of all in-flight IWANT requests. This not only ensures that all
IWANT requests are answered and peers penalized accordingly, but gossipsub
will no no longer create multiple IWANT requests for multiple peers.
Previously, gossipsub sampled the in-flight IWANT requests in order to
penalize peers for not responding with a high probability that we would detect
non-responsive nodes. Futher, it was possible to re-request IWANT messages
that are already being requested causing added duplication in messages and
wasted unnecessary IWANT control messages. This PR shifts this logic to only
request message ids that we are not currently requesting from peers.
- Triangle routing naturally gives rise to unnecessary duplicates. Consider a
mesh of 4 peers that are interconnected. Peer 1 sends a new message to 2,3,4.
2 propagates to 3,4 and 3 propagates to 2,4 and 4 propagates to 2,3. In this
case 3 has received the message 3 times. If we keep track of peers that send
us messages, when publishing or forwarding we no longer send to peers that
have sent us a duplicate, we can eliminate one of the sends in the scenario
above. This only occurs when message validation is async however. This PR adds
this logic to remove some elements of triangle-routing duplicates.
Co-authored-by: Divma <26765164+divagant-martian@users.noreply.github.com>
Co-authored-by: Max Inden <mail@max-inden.de>
Co-authored-by: Diva M <divma@protonmail.com>
2021-12-21 22:09:15 +11:00
|
|
|
"[Penalty] The peer {} broke the promise to deliver message {} in time!",
|
2021-01-07 18:19:31 +11:00
|
|
|
peer_id, msg
|
|
|
|
);
|
|
|
|
false
|
|
|
|
} else {
|
|
|
|
true
|
|
|
|
}
|
|
|
|
});
|
|
|
|
!peers.is_empty()
|
|
|
|
});
|
|
|
|
result
|
|
|
|
}
|
|
|
|
}
|