Skip to content

Commit

Permalink
grin v5.3 (0040) inefficient locking on recv of peers lists can resul…
Browse files Browse the repository at this point in the history
…t in failure to get peers lock (mimblewimble#3566) (mimblewimble#3570)

* fix for: inefficient locking of peers lists can result in failure to get peers lock
* dont hold the peers Vec lock while writing to the peers lmdb
  • Loading branch information
bayk committed Jun 11, 2024
1 parent 6628433 commit 259a823
Show file tree
Hide file tree
Showing 2 changed files with 42 additions and 22 deletions.
55 changes: 33 additions & 22 deletions p2p/src/peers.rs
Original file line number Diff line number Diff line change
Expand Up @@ -67,27 +67,29 @@ impl Peers {
/// Adds the peer to our internal peer mapping. Note that the peer is still
/// returned so the server can run it.
pub fn add_connected(&self, peer: Arc<Peer>) -> Result<(), Error> {
let mut peers = self.peers.try_write_for(LOCK_TIMEOUT).ok_or_else(|| {
error!("add_connected: failed to get peers lock");
Error::Timeout
})?;

if self.is_banned(peer.info.addr.clone()) {
return Err(Error::Banned);
let peer_data: PeerData;
{
// Scope for peers vector lock - dont hold the peers lock while adding to lmdb
let mut peers = self.peers.try_write_for(LOCK_TIMEOUT).ok_or_else(|| {
error!("add_connected: failed to get peers lock");
Error::Timeout
})?;
peer_data = PeerData {
addr: peer.info.addr,
capabilities: peer.info.capabilities,
user_agent: peer.info.user_agent.clone(),
flags: State::Healthy,
last_banned: 0,
ban_reason: ReasonForBan::None,
last_connected: Utc::now().timestamp(),
};
debug!("Adding newly connected peer {}.", peer_data.addr);
peers.insert(peer_data.addr, peer);
}
let peer_data = PeerData {
addr: peer.info.addr.clone(),
capabilities: peer.info.capabilities,
user_agent: peer.info.user_agent.clone(),
flags: State::Healthy,
last_banned: 0,
ban_reason: ReasonForBan::None,
last_connected: Utc::now().timestamp(),
};
debug!("Saving newly connected peer {}.", peer_data.addr);
self.save_peer(&peer_data)?;
peers.insert(peer_data.addr, peer);

if let Err(e) = self.save_peer(&peer_data) {
error!("Could not save connected peer address: {:?}", e);
}
Ok(())
}

Expand Down Expand Up @@ -151,8 +153,10 @@ impl Peers {
}
/// Ban a peer, disconnecting it if we're currently connected
pub fn ban_peer(&self, peer_addr: PeerAddr, ban_reason: ReasonForBan) -> Result<(), Error> {
// Update the peer in peers db
self.update_state(peer_addr.clone(), State::Banned)?;

// Update the peer in the peers Vec
match self.get_connected_peer(peer_addr.clone()) {
Some(peer) => {
info!("Banning peer {}, ban_reason {:?}", peer_addr, ban_reason);
Expand Down Expand Up @@ -310,6 +314,11 @@ impl Peers {
self.store.save_peer(p).map_err(From::from)
}

/// Saves updated information about mulitple peers in batch
pub fn save_peers(&self, p: Vec<PeerData>) -> Result<(), Error> {
self.store.save_peers(p).map_err(From::from)
}

/// Updates the state of a peer in store
pub fn update_state(&self, peer_addr: PeerAddr, new_state: State) -> Result<(), Error> {
self.store
Expand Down Expand Up @@ -677,6 +686,7 @@ impl NetAdapter for Peers {
/// A list of peers has been received from one of our peers.
fn peer_addrs_received(&self, peer_addrs: Vec<PeerAddr>) {
trace!("Received {} peer addrs, saving.", peer_addrs.len());
let mut to_save: Vec<PeerData> = Vec::new();
for pa in peer_addrs {
if let Ok(e) = self.exists_peer(pa.clone()) {
if e {
Expand All @@ -692,9 +702,10 @@ impl NetAdapter for Peers {
ban_reason: ReasonForBan::None,
last_connected: Utc::now().timestamp(),
};
if let Err(e) = self.save_peer(&peer) {
error!("Could not save received peer address: {:?}", e);
}
to_save.push(peer);
}
if let Err(e) = self.save_peers(to_save) {
error!("Could not save received peer addresses: {:?}", e);
}
}

Expand Down
9 changes: 9 additions & 0 deletions p2p/src/store.rs
Original file line number Diff line number Diff line change
Expand Up @@ -139,6 +139,15 @@ impl PeerStore {
batch.commit()
}

pub fn save_peers(&self, p: Vec<PeerData>) -> Result<(), Error> {
let batch = self.db.batch()?;
for pd in p {
debug!("save_peers: {:?} marked {:?}", pd.addr, pd.flags);
batch.put_ser(&peer_key(pd.addr)[..], &pd)?;
}
batch.commit()
}

pub fn get_peer(&self, peer_addr: PeerAddr) -> Result<PeerData, Error> {
option_to_not_found(self.db.get_ser(&peer_key(peer_addr.clone())[..]), || {
format!("Peer at address: {}", peer_addr)
Expand Down

0 comments on commit 259a823

Please sign in to comment.