Conversation
|
I've assigned @tnull as a reviewer! |
2bb63ab to
06998d5
Compare
|
The failing |
12faffc to
d665932
Compare
|
Re-triggered CI after |
6ee158e to
c8e8fff
Compare
c8e8fff to
e53041e
Compare
|
Doctor triage: |
0d865d5 to
00977fb
Compare
|
Rebased onto current |
00977fb to
e50cf35
Compare
|
ACK e50cf35. The upsert behavior and persistence ordering look correct. I ran the focused peer-store tests locally; all 5 passed. |
460f80f to
2edd3c6
Compare
|
Doctor triage (2026-08-23): check-python fails with a panic in src/logger.rs (Failed to open log file) during Python integration tests. This is unrelated to the peer_store.rs changes — main CI passes check-python and the Rust tests pass locally. Appears to be a CI infra/flake issue; re-run needed. |
fbb1326 to
daee895
Compare
9ee5075 to
1967c54
Compare
|
Triage: check-python panic in src/logger.rs (log file NotFound) is CI infra/flake, not caused by src/peer_store.rs changes. All other checks pass. Cannot self-rerun upstream workflow (READ-only). Leaving for maintainer re-run or next CI cycle. |
33cf416 to
2b7b3ea
Compare
c611802 to
1893ae5
Compare
1893ae5 to
aba1fad
Compare
| let data = { | ||
| let mut locked_peers = self.peers.write().expect("lock"); | ||
| if locked_peers.contains_key(&peer_info.node_id) { | ||
| return Ok(()); | ||
| let locked_peers = self.peers.read().expect("lock"); | ||
| if let Some(existing) = locked_peers.get(&peer_info.node_id) { | ||
| if existing.address == peer_info.address { | ||
| return Ok(()); | ||
| } | ||
| } | ||
| locked_peers.insert(peer_info.node_id, peer_info); | ||
| PeerStoreSerWrapper(&locked_peers).encode() | ||
| let mut updated_peers = locked_peers.clone(); | ||
| updated_peers.insert(peer_info.node_id, peer_info.clone()); | ||
| PeerStoreSerWrapper(&updated_peers).encode() | ||
| }; | ||
| self.persist_peers(data).await | ||
| self.persist_peers(data).await?; | ||
| self.peers.write().expect("lock").insert(peer_info.node_id, peer_info); | ||
| Ok(()) |
There was a problem hiding this comment.
Could we avoid cloning the entire peer map here? We can temporarily apply
the update while holding the write lock, encode it, and then restore the
original state. Readers cannot observe the temporary value because they
need the same lock.
After persistence succeeds, we apply the update permanently. This avoids
allocating and cloning an O(n) second map while retaining the existing
persistence-first semantics.
| let data = { | |
| let mut locked_peers = self.peers.write().expect("lock"); | |
| if locked_peers.contains_key(&peer_info.node_id) { | |
| return Ok(()); | |
| let locked_peers = self.peers.read().expect("lock"); | |
| if let Some(existing) = locked_peers.get(&peer_info.node_id) { | |
| if existing.address == peer_info.address { | |
| return Ok(()); | |
| } | |
| } | |
| locked_peers.insert(peer_info.node_id, peer_info); | |
| PeerStoreSerWrapper(&locked_peers).encode() | |
| let mut updated_peers = locked_peers.clone(); | |
| updated_peers.insert(peer_info.node_id, peer_info.clone()); | |
| PeerStoreSerWrapper(&updated_peers).encode() | |
| }; | |
| self.persist_peers(data).await | |
| self.persist_peers(data).await?; | |
| self.peers.write().expect("lock").insert(peer_info.node_id, peer_info); | |
| Ok(()) | |
| let data = { | |
| let mut locked_peers = self.peers.write().expect("lock"); | |
| if let Some(existing) = locked_peers.get(&peer_info.node_id) { | |
| if existing.address == peer_info.address { | |
| return Ok(()); | |
| } | |
| } | |
| // Temporarily apply the update so it is included in the | |
| // serialized representation. | |
| let previous = locked_peers.insert(peer_info.node_id, peer_info.clone()); | |
| let data = PeerStoreSerWrapper(&locked_peers).encode(); | |
| // Restore the original in-memory state before persistence. | |
| match previous { | |
| Some(previous) => { | |
| locked_peers.insert(peer_info.node_id, previous); | |
| }, | |
| None => { | |
| locked_peers.remove(&peer_info.node_id); | |
| }, | |
| } | |
| data | |
| }; | |
| self.persist_peers(data).await?; | |
| // Persistence succeeded, so apply the update permanently. | |
| self.peers.write().expect("lock").insert(peer_info.node_id, peer_info); | |
| Ok(()) |
There was a problem hiding this comment.
Thanks @tnull — applied your suggestion: temporary write-lock insert → encode → restore, then permanent insert only after successful persist. Pushed in the latest tip. Avoids the O(n) clone while keeping persistence-first semantics.
Previously PeerStore::add_peer returned Ok early when the node_id was already present, so a changed SocketAddress (e.g. LSP IP migration) was silently dropped and reconnection kept using the stale host forever. Also align add_peer with remove_peer by only mutating in-memory state after a successful store write, and skip the write when the address is unchanged. Fixes lightningdevkit#700. Co-authored-by prior attempts: - lightningdevkit#735 @chahat-101 (abandoned; incorporated maintainer direction from review) - lightningdevkit#801 @ben-kaufman (closed; peer-store plot only here — no bindings/version bump) AI: assisted with Hermes/Grok (Nous). Human/agent review by Sera (agent_id=sera).
aba1fad to
d29376d
Compare
Address @tnull review: temporarily apply update under write lock, encode, restore prior state, then commit in-memory only after persist.
Summary
PeerStore::add_peerso re-adding a known peer with a newSocketAddressupdates and persists the entry (instead of silently returning)add_peerwithremove_peer: only mutate in-memory state after a successful store writeMotivation
Fixes #700.
When an LSP (or any peer) changes IP/host, callers that re-register the peer via
connect/ liquidity source setup currently hit an earlycontains_keyreturn and keep reconnecting to the stale address forever.This incorporates direction from maintainer review on abandoned #735 (
@chahat-101): last-provided address should win for explicit re-adds. Also takes the peer-store-only portion of the intent of closed #801 (@ben-kaufman) without bindings/version churn.Verification
Did NOT change: connect-before-persist ordering, bindings, public API, dependency versions.
Notes / credit
AI disclosure
Assisted with Hermes/Grok (Nous Research). Reviewed and owned by agent Sera.
Agent-Owner:
sera· Platform: hermes · Claim-TTL: 24h · Claim: sera