Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ edition = "2021"
# the ROOT manifest (`[workspace.package].version`), so it MUST be set here for a
# release to fire (§3.6). The library crates (dig-node-core/dig-runtime/dig-wallet)
# keep their own independent versions — only the released binary tracks the workspace version.
version = "0.75.3"
version = "0.75.4"

# Release hardening, matching digstore: keep integer-overflow checks ON in release.
# The node parses untrusted serialized input and does offset/length arithmetic over
Expand Down
62 changes: 62 additions & 0 deletions crates/dig-node-core/src/seams/dig_peer/dht.rs
Original file line number Diff line number Diff line change
Expand Up @@ -816,6 +816,68 @@ mod tests {
assert_eq!(to_withdraw.len(), 2, "store + its capsule both withdrawn");
}

// -- sync_inventory (active retract on loss) -----------------------------------------------

/// **Verifies:** `sync_inventory` on evicted capsules calls `retract_own_provider` (active
/// retract), NOT the passive `withdraw_provider`. Active retract deletes the local provider record
/// immediately, so a reader's `find_providers` query does NOT see this node as a provider anymore;
/// passive withdraw leaves the record until TTL, causing wasted dials to a node that can no longer
/// serve (#1962).
///
/// **Catches:** accidental revert to `withdraw_provider` in the loss branch.
#[tokio::test]
async fn evicted_capsule_is_actively_retracted_from_local_providers() {
let transport = Arc::new(test_transport("sync-inventory-1962"));
let service = Arc::new(DhtService::new(
PeerId::from_bytes([0x11; 32]),
vec![],
dig_dht::DhtConfig::default(),
transport,
));
let dht = DhtHandle::new(service.clone(), vec![]);

// Step 1: Announce a capsule by calling reconcile_inventory with it present.
let s = "bb".repeat(32);
let r = "cc".repeat(32);
let cached = [cap(&s, &r)];
let delta = dht.reconcile_inventory(&cached).await;
assert!(
!delta.gained.is_empty(),
"capsule announced on first reconcile"
);
let announced_ids = delta.gained.clone();

// Step 2: Evict the capsule (empty inventory) and trigger the active-retract branch.
let delta_loss = dht.reconcile_inventory(&[]).await;
assert_eq!(
delta_loss.lost.len(),
announced_ids.len(),
"all announced ids retracted on eviction"
);
assert!(
announced_ids.iter().all(|id| delta_loss.lost.contains(id)),
"the lost set contains exactly the ids we had announced"
);

// Step 3: Verify active retract via find_providers: the local provider record for the
// evicted capsule is GONE, not just "waiting for TTL". A passive withdraw would leave it
// in the local table. We query find_providers without adding peers to the routing table,
// so it can only return local records or those already in the table (none in this case).
// The assertion: `find_providers` does not return self (our PeerId) for the evicted id.
// If retract_own_provider was used, the local record is deleted and find_providers returns
// an empty list. If withdraw_provider was used, the record stays and find_providers returns
// self (because the record is still there locally even if we stopped announcing it).
for evicted_id in &announced_ids {
let providers = service.find_providers(evicted_id).await.unwrap_or_default();
assert!(
providers.is_empty(),
"after active retract, find_providers for {evicted_id:?} does not return self; \
if it does, the code reverted to passive withdraw_provider instead of active \
retract_own_provider"
);
}
}

// -- is_dht_request (inbound classification) -----------------------------------------------

#[test]
Expand Down
Loading