Skip to content

Commit 8970a54

Browse files
author
techartdev
committed
fix: community browse fetches members from network, not local DHT
dht_find_value_iterative short-circuited on the local CommunityMembers entry which only contained the local node. The relay's merged list (with all members) was never queried, so remote shares never appeared. - Extract dht_find_value_from_network (skips local cache, always queries peers) - browse_community uses network lookup to get the relay's merged member list - Filter own address from DHT-discovered members to avoid self-queries - Local participant label changed from IP to 'this node'
1 parent c7122f2 commit 8970a54

10 files changed

Lines changed: 54 additions & 21 deletions

File tree

Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ resolver = "2"
1111
[workspace.package]
1212
edition = "2024"
1313
license = "MPL-2.0"
14-
version = "0.3.1"
14+
version = "0.3.2"
1515
repository = "https://github.com/techartdev/scp2p"
1616

1717
[workspace.dependencies]

app/package-lock.json

Lines changed: 2 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

app/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
{
22
"name": "scp2p-app",
33
"private": true,
4-
"version": "0.3.1",
4+
"version": "0.3.2",
55
"type": "module",
66
"scripts": {
77
"dev": "vite",

app/src-tauri/tauri.conf.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
{
22
"$schema": "https://raw.githubusercontent.com/nicegui/nicegui/main/nicegui/static/tauri/schemas/tauri-conf-v2.json",
33
"productName": "SCP2P",
4-
"version": "0.3.1",
4+
"version": "0.3.2",
55
"identifier": "com.scp2p.desktop",
66
"build": {
77
"frontendDist": "../dist",

crates/scp2p-cli/Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ clap = { workspace = true, features = ["env"] }
1515
ed25519-dalek.workspace = true
1616
hex.workspace = true
1717
rand.workspace = true
18-
scp2p-core = { path = "../scp2p-core", version = "0.3.1" }
18+
scp2p-core = { path = "../scp2p-core", version = "0.3.2" }
1919
tokio.workspace = true
2020
inquire = "0.7"
2121
indicatif = "0.17"

crates/scp2p-core/src/api/node_dht.rs

Lines changed: 21 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -225,6 +225,25 @@ impl NodeHandle {
225225
return Ok(Some(value));
226226
}
227227

228+
self.dht_find_value_from_network(transport, key, seed_peers)
229+
.await
230+
}
231+
232+
/// Like [`Self::dht_find_value_iterative`], but always queries the
233+
/// network even when a local copy exists. The remote result is
234+
/// stored locally before being returned.
235+
///
236+
/// Use this for values where the relay's copy is the authoritative
237+
/// merged superset (e.g. `CommunityMembers`).
238+
pub async fn dht_find_value_from_network<T: RequestTransport + ?Sized>(
239+
&self,
240+
transport: &T,
241+
key: [u8; 32],
242+
seed_peers: &[PeerAddr],
243+
) -> anyhow::Result<Option<DhtValue>> {
244+
let key_hex = hex::encode(&key[..8]);
245+
debug!(key = %key_hex, "dht_find_value_from_network: starting");
246+
228247
let mut target = [0u8; 20];
229248
target.copy_from_slice(&key[..20]);
230249
let mut peers = self
@@ -264,7 +283,7 @@ impl NodeHandle {
264283
remote.ttl_secs.max(DEFAULT_TTL_SECS),
265284
now,
266285
)?;
267-
debug!(key = %key_hex, "dht_find_value_iterative: found remotely");
286+
debug!(key = %key_hex, "dht_find_value_from_network: found remotely");
268287
return Ok(state.dht.find_value(key, now));
269288
}
270289
discovered |= merge_peer_list(&mut peers, result.closer_peers);
@@ -274,7 +293,7 @@ impl NodeHandle {
274293
}
275294
}
276295

277-
debug!(key = %key_hex, queried = queried.len(), "dht_find_value_iterative: not found");
296+
debug!(key = %key_hex, queried = queried.len(), "dht_find_value_from_network: not found");
278297
Ok(None)
279298
}
280299

crates/scp2p-core/src/api/tests.rs

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4979,7 +4979,11 @@ async fn community_members_dht_merge_on_store() {
49794979
let found = handle.dht_find_value(key).await.expect("find").unwrap();
49804980
let merged: crate::wire::CommunityMembers =
49814981
crate::cbor::from_slice(&found.value).expect("decode");
4982-
assert_eq!(merged.members.len(), 2, "should have both members after merge");
4982+
assert_eq!(
4983+
merged.members.len(),
4984+
2,
4985+
"should have both members after merge"
4986+
);
49834987
assert!(merged.members.contains(&addr_a));
49844988
assert!(merged.members.contains(&addr_b));
49854989
assert_eq!(merged.updated_at, 200, "updated_at should be max of both");
@@ -5007,8 +5011,7 @@ async fn upsert_community_member_roundtrip() {
50075011

50085012
let key = crate::dht_keys::community_info_key(&community_share_id);
50095013
let found = handle.dht_find_value(key).await.expect("find").unwrap();
5010-
let cm: crate::wire::CommunityMembers =
5011-
crate::cbor::from_slice(&found.value).expect("decode");
5014+
let cm: crate::wire::CommunityMembers = crate::cbor::from_slice(&found.value).expect("decode");
50125015
assert_eq!(cm.members.len(), 1);
50135016
assert_eq!(cm.members[0], addr);
50145017

crates/scp2p-desktop/Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,6 @@ hex.workspace = true
1212
rand.workspace = true
1313
serde.workspace = true
1414
ciborium.workspace = true
15-
scp2p-core = { path = "../scp2p-core", version = "0.3.1" }
15+
scp2p-core = { path = "../scp2p-core", version = "0.3.2" }
1616
tokio.workspace = true
1717
tracing.workspace = true

crates/scp2p-desktop/src/app_state.rs

Lines changed: 19 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -675,15 +675,25 @@ impl DesktopAppState {
675675
// announced themselves as community members. This is essential
676676
// because the bootstrap relay typically has NOT joined the
677677
// community, so without DHT discovery we'd return 0 participants.
678+
//
679+
// Use `dht_find_value_from_network` (not `_iterative`) because
680+
// the local DHT copy only contains *this* node; the relay's
681+
// copy is the merged superset of all members.
678682
let community_key =
679683
scp2p_core::community_info_key(&scp2p_core::ShareId(community.share_id));
684+
let self_addr = self.resolve_self_addr(&node).await.ok();
680685
if let Ok(Some(dht_value)) = node
681-
.dht_find_value_iterative(&transport, community_key, &peers)
686+
.dht_find_value_from_network(&transport, community_key, &peers)
682687
.await
683688
&& let Ok(cm) =
684689
scp2p_core::cbor::from_slice::<scp2p_core::wire::CommunityMembers>(&dht_value.value)
685690
{
686691
for member in cm.members {
692+
// Skip our own address — we already handle local shares
693+
// separately below.
694+
if self_addr.as_ref().is_some_and(|sa| member == *sa) {
695+
continue;
696+
}
687697
if !peers.iter().any(|p| p == &member) {
688698
peers.push(member);
689699
}
@@ -719,21 +729,17 @@ impl DesktopAppState {
719729
)
720730
.await
721731
.unwrap_or_default();
732+
let local_label = "this node".to_string();
722733
if !local_shares.is_empty() {
723-
let self_addr_label = if let Ok(sa) = self.resolve_self_addr(&node).await {
724-
format!("{}:{}", sa.ip, sa.port)
725-
} else {
726-
"local".to_string()
727-
};
728734
participants.push(CommunityParticipantView {
729735
community_share_id_hex: hex::encode(community.share_id),
730-
peer_addr: self_addr_label.clone(),
736+
peer_addr: local_label.clone(),
731737
transport: "local".to_string(),
732738
});
733739
for share in local_shares {
734740
if seen_shares.insert(share.share_id) {
735741
public_shares.push(PublicShareView {
736-
source_peer_addr: self_addr_label.clone(),
742+
source_peer_addr: local_label.clone(),
737743
share_id_hex: hex::encode(share.share_id),
738744
share_pubkey_hex: hex::encode(share.share_pubkey),
739745
latest_seq: share.latest_seq,
@@ -746,6 +752,11 @@ impl DesktopAppState {
746752
}
747753

748754
for peer in peers {
755+
// Skip querying ourselves — local shares are already
756+
// included above.
757+
if self_addr.as_ref().is_some_and(|sa| peer == *sa) {
758+
continue;
759+
}
749760
match node
750761
.fetch_community_status_from_peer(
751762
&transport,

crates/scp2p-relay/Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ name = "scp2p-relay"
1414
path = "src/main.rs"
1515

1616
[dependencies]
17-
scp2p-core = { path = "../scp2p-core", version = "0.3.1" }
17+
scp2p-core = { path = "../scp2p-core", version = "0.3.2" }
1818

1919
anyhow = { workspace = true }
2020
async-trait = { workspace = true }

0 commit comments

Comments
 (0)