Skip to content

Banned contract keeps emitting outbound SUBSCRIBE renewals while node holds an active subscription #4373

Description

@sanity

Problem

A contract that is banned while this node already holds an active subscription is not torn down by the ban path, so the node keeps emitting outbound SUBSCRIBE renewal wire requests for it until the ban TTL expires.

Ring::apply_ban_decisions (crates/core/src/ring.rs ~L800) only calls ban_list.ban() / ban_list.unban() on a BanTriggered / BanLifted decision. It does not clear the contract's entry from active_subscriptions / local interest, so the contract remains in the renewal set.

The subscription-renewal loop (crates/core/src/ring.rs ~L1255, spawning crate::operations::subscribe::run_renewal_subscribe at ~L1323) iterates contracts_needing_renewal and, for each, spawns a renewal driver that emits an outbound SUBSCRIBE request using the same machinery as a client-initiated SUBSCRIBE. This renewal path does not pass through operations::reject_if_contract_banned — that egress gate (#4300) lives only at the four start_client_* originator entry points, not at the connection-maintenance renewal scheduler. So a banned-but-still-subscribed contract keeps sending outbound SUBSCRIBE renewals on every maintenance cycle until the ban's TTL lifts.

Scope / severity

This is genuine outbound network egress for a banned contract, so it is adjacent to #4300. It is out of #4300's named scope for two reasons:

So this is a lower-severity, bounded egress leak rather than a hole in the state-egress block, which is why it's a follow-up rather than part of #4371.

Proposed fix

Either:

  1. Gate the renewal loop on the ban list — skip run_renewal_subscribe for any contract currently in ContractBanList (e.g. add an is_banned check alongside the existing can_request_subscription spam check at ~L1277), or
  2. Actively unsubscribe / drop interest for a contract when it is banned — have apply_ban_decisions clear the contract from active_subscriptions / local interest (and ideally send an Unsubscribe) on BanTriggered, so it leaves the renewal set entirely.

Option 2 is the more thorough fix (it also stops the node from holding a subscription it has decided is harmful); option 1 is the smaller, more contained change.

References #4300 and #4371.

[AI-assisted - Claude]

Metadata

Metadata

Assignees

Labels

A-contractsArea: Contract runtime, SDK, and executionA-networkingArea: Networking, ring protocol, peer discoveryE-mediumExperience needed to fix/implement: Medium / intermediateP-mediumMedium priorityT-bugType: Something is broken

Type

No type
No fields configured for issues without a type.

Projects

Status
Done

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions