Skip to content

feat: add /unregister_beacon route to deregister a beacon from the BeaconRegistry#83

Merged
koko1123 merged 3 commits into
mainfrom
koko/beaconator-unregister-beacon
Jul 14, 2026
Merged

feat: add /unregister_beacon route to deregister a beacon from the BeaconRegistry#83
koko1123 merged 3 commits into
mainfrom
koko/beaconator-unregister-beacon

Conversation

@koko1123

@koko1123 koko1123 commented Jul 14, 2026

Copy link
Copy Markdown
Collaborator

What

Adds POST /unregister_beacon to the-beaconator — removes a beacon from the on-chain BeaconRegistry. The service previously had register_beacon but no way to deregister.

Why

We're decommissioning most mainnet censorship (OONI) markets and need to deregister the retired beacons from the registry (deleting the market_metadata row and stopping updates are separate, already-supported steps). No deregister route existed, so this adds one.

How

Mirrors the existing register_beacon_with_registry path exactly, with an inverted pre-check:

  • New UnregistrationOutcome enum (AlreadyUnregistered / SafeProposed / OnChainConfirmed) — kept separate from RegistrationOutcome so the register route's exhaustive match is untouched.
  • unregister_beacon_with_registry() in services/beacon/core.rs: if the beacon is not registered it's a no-op success; if a Safe is configured (both live networks) it proposes a Safe multisig transaction; otherwise (local/non-Safe) it executes directly with a pool wallet and confirms the receipt with an on-chain fallback.
  • POST /unregister_beacon route (ApiToken-guarded). Request { beacon_address, registry_address? }registry_address is optional and defaults to the server-configured registry.
  • Uses the IBeaconRegistry::unregisterBeacon(address) binding that already exists in the inline sol! interface (src/routes/mod.rs) — no ABI refresh.

Deployed-contract verification

the-beaconator pins beacons=v0.0.1 / perpcity-contracts=v0.1.0 (.contracts-versions) — the tags actually deployed on Arbitrum One / Sepolia. Confirmed BeaconRegistry.unregisterBeacon(IBeacon) external onlyOwner exists at beacons@v0.0.1 (d61aca0), selector unregisterBeacon(address) — matches the binding, so the call hits real deployed code.

Drift note: at v0.0.1 the emit is BeaconUnregistered(beacon, beacon.index()) un-guarded; the try/catch around index() is a post-v0.0.1 addition on beacons main and is NOT in the deployed contract. Practical impact: the deployed unregisterBeacon reverts only if the target's index() reverts — a non-issue for the live, healthy beacons we're removing.

Live-network behavior

On mainnet the registry owner is a Safe multisig, so this route proposes the removal — it takes effect only once signers execute the Safe tx. This is the identical mechanism that registered all current beacons, so it's a proven path.

Tests

  • 11 new unit tests (tests/unit_tests/unregister_beacon_route_tests.rs) — address validation, optional-registry defaulting, serde, and the no-op-on-unknown-status behavior. These run in the unit-tests CI job.
  • Integration tests (tests/integration_tests/unregister_beacon_integration_tests.rs) mirror the register integration tests and are #[ignore]d for the same reason (the shared Anvil harness doesn't deploy the factories).
  • make quality green locally (fmt-check, clippy -D warnings, unit suite 200 passed, Redis tests).

Notes

  • No source/logs/commit emojis.
  • Deploying this to the Railway beaconators + the actual mainnet deregister run are follow-up ops steps, not part of this PR.

Summary by CodeRabbit

  • New Features
    • Added a POST /unregister_beacon endpoint to deregister a beacon from its registry.
    • Supports an optional registry address (defaults to the server-configured registry when omitted).
    • Provides distinct responses for already-unregistered beacons, Safe-proposed transactions, and on-chain confirmations, and is included in the generated OpenAPI specification.
  • Bug Fixes
    • Improved failure handling: provider issues now return 500 InternalServerError instead of behaving like a no-op.
  • Tests
    • Added unit tests for request validation/serde and provider-failure behavior, plus ignored integration tests for unregistering and idempotency.

@coderabbitai

coderabbitai Bot commented Jul 14, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 41fe6015-fe95-46a2-ba4c-38d6eeddac74

📥 Commits

Reviewing files that changed from the base of the PR and between 4b304af and 603b2fd.

📒 Files selected for processing (1)
  • tests/integration_tests/unregister_beacon_integration_tests.rs
🚧 Files skipped from review as they are similar to previous changes (1)
  • tests/integration_tests/unregister_beacon_integration_tests.rs

📝 Walkthrough

Walkthrough

Changes

Adds a beacon unregistration request model, service flow, POST /unregister_beacon route, OpenAPI registration, and unit/integration tests covering validation, registry fallback, no-op behavior, transaction outcomes, and idempotency.

Beacon unregistration

Layer / File(s) Summary
Request contract and route registration
src/models/requests.rs, src/models/mod.rs, src/lib.rs
Defines and exports UnregisterBeaconRequest, then registers the unregistration endpoint with Rocket and OpenAPI.
Unregistration service flow
src/services/beacon/core.rs
Adds strict and lenient registration checks, outcome types, Safe proposals, direct transactions, receipt confirmation, and reverted-transaction errors.
HTTP handler and response mapping
src/routes/beacon.rs
Validates addresses, resolves the optional registry override, invokes the service, and maps outcomes to HTTP responses.
Validation and integration coverage
tests/unit_tests/*, tests/integration_tests/*
Tests request serialization, address validation, provider failures, successful removal, no-op behavior, and repeated unregistration.

Estimated code review effort: 4 (Complex) | ~45 minutes

Sequence Diagram(s)

sequenceDiagram
  participant Client
  participant Rocket
  participant BeaconService
  participant Registry
  participant SafeOrWallet
  Client->>Rocket: POST /unregister_beacon
  Rocket->>BeaconService: unregister_beacon_with_registry
  BeaconService->>Registry: check_beacon_registered
  alt Not registered
    Registry-->>BeaconService: AlreadyUnregistered
  else Registered
    BeaconService->>SafeOrWallet: Propose or send unregisterBeacon
    SafeOrWallet-->>BeaconService: Transaction hash
    BeaconService->>Registry: Confirm transaction
    Registry-->>BeaconService: Receipt status
  end
  BeaconService-->>Rocket: UnregistrationOutcome
  Rocket-->>Client: JSON response
Loading
🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately reflects the main change: adding the /unregister_beacon route to deregister beacons from the BeaconRegistry.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch koko/beaconator-unregister-beacon

Comment @coderabbitai help to get the list of available commands.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 3

🧹 Nitpick comments (1)
tests/integration_tests/unregister_beacon_integration_tests.rs (1)

29-37: 📐 Maintainability & Code Quality | 🔵 Trivial | 🏗️ Heavy lift

Provide a seeded local fixture before claiming integration coverage. The tests are all ignored due to hanging real-RPC calls; two also convert fixture failure into a passing return. Seed beacon factories in the isolated Anvil setup, make setup failures assert, and remove #[ignore].

  • tests/integration_tests/unregister_beacon_integration_tests.rs#L29-L37: execute the register/unregister flow against the seeded fixture and fail if beacon creation fails.
  • tests/integration_tests/unregister_beacon_integration_tests.rs#L74-L76: execute the no-op flow in CI against the same hermetic fixture.
  • tests/integration_tests/unregister_beacon_integration_tests.rs#L99-L107: execute idempotency coverage and replace the successful early return with a setup assertion.

As per coding guidelines, “Mock providers with wallets in tests so setup is consistent and network calls fail gracefully in the test environment.”

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@tests/integration_tests/unregister_beacon_integration_tests.rs` around lines
29 - 37, The unregister beacon integration tests currently remain ignored and
may pass silently when fixture setup fails. In
tests/integration_tests/unregister_beacon_integration_tests.rs#29-37, `#74-76`,
and `#99-107`, seed beacon factories in the isolated Anvil setup, use hermetic
wallet-backed mock providers, remove #[ignore], and assert beacon creation/setup
succeeds instead of returning early; preserve the register/unregister, no-op,
and idempotency flows respectively.

Source: Coding guidelines

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@src/services/beacon/core.rs`:
- Around line 500-508: Update the unregistration flow around
is_beacon_registered so RPC or contract-call failures are propagated instead of
being converted into false; use a strict lookup variant if available, and return
AlreadyUnregistered only when the registry successfully confirms the beacon is
absent.
- Around line 463-472: Update the transaction confirmation path around
is_transaction_confirmed so Ok(Ok(None)) performs the same progressive receipt
polling used by the registration flow before returning an error. Keep the
existing timeout and successful receipt handling, but allow pending transactions
to be observed before declaring the transaction missing and failing the request.

In `@tests/unit_tests/unregister_beacon_route_tests.rs`:
- Around line 109-145: Update test_unregister_beacon_unknown_status_is_noop_ok
and test_unregister_beacon_defaults_registry_when_absent so provider failures
are not converted into successful no-ops. Configure the mock provider to return
“not registered” for the relevant registry, especially
app_state.contracts.perpcity_registry when registry_address is None, or assert
that an unavailable provider produces InternalServerError instead.

---

Nitpick comments:
In `@tests/integration_tests/unregister_beacon_integration_tests.rs`:
- Around line 29-37: The unregister beacon integration tests currently remain
ignored and may pass silently when fixture setup fails. In
tests/integration_tests/unregister_beacon_integration_tests.rs#29-37, `#74-76`,
and `#99-107`, seed beacon factories in the isolated Anvil setup, use hermetic
wallet-backed mock providers, remove #[ignore], and assert beacon creation/setup
succeeds instead of returning early; preserve the register/unregister, no-op,
and idempotency flows respectively.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 69ed8249-f7f7-4682-bf72-ab561a2a7851

📥 Commits

Reviewing files that changed from the base of the PR and between f22d381 and 6b3a0ee.

📒 Files selected for processing (9)
  • src/lib.rs
  • src/models/mod.rs
  • src/models/requests.rs
  • src/routes/beacon.rs
  • src/services/beacon/core.rs
  • tests/integration_tests/mod.rs
  • tests/integration_tests/unregister_beacon_integration_tests.rs
  • tests/unit_tests/mod.rs
  • tests/unit_tests/unregister_beacon_route_tests.rs

Comment thread src/services/beacon/core.rs Outdated
Comment thread src/services/beacon/core.rs Outdated
Comment thread tests/unit_tests/unregister_beacon_route_tests.rs Outdated
@koko1123
koko1123 merged commit d98b2d0 into main Jul 14, 2026
13 checks passed
@koko1123
koko1123 deleted the koko/beaconator-unregister-beacon branch July 14, 2026 22:16
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant