Repository navigation
feat(registry): admin-gated emergency pause circuit breaker - #406
Conversation
ASTROIDX556#303) Add `ProposalState` and `ProposalInterface` to `astroid-interfaces` so the proposal, multisig and wallet contracts share one canonical lifecycle vocabulary and one status-query ABI instead of drifting copies. - Hoist `ProposalState` (with its `has_executed` / `deposit_settled` / `is_live` / `is_terminal` helpers) into `interfaces/src/proposal.rs`. The proposal contract re-exports it, so there is a single source of truth for the on-chain `u32` discriminants and existing callers are unchanged. - Add the `ProposalInterface` `#[contractclient]` for the fallible status queries (`state`, `is_expired`, `is_executed`, `dependencies`, `dependencies_met`, `can_execute`), returning the canonical `Error`. - Move the proposal contract's status views into the trait impl so its entrypoints are compile-time-checked against the shared client. - Add serialization/deserialization and discriminant-stability unit tests, plus a runtime interface-compliance test. Closes ASTROIDX556#303 🤖 Generated with Codebuff Co-Authored-By: Codebuff <noreply@codebuff.com>
…OIDX556#335) Introduce a protocol-wide circuit breaker for the registry so an incident can be contained without freezing individual organizations. When engaged: - Every state-mutating entrypoint (org/module registration, ownership and role administration, version records, WASM approvals and the registry-gated upgrade path) short-circuits with the designated paused error code before touching state. - `is_wasm_approved` reports no hash as approved, so member contracts' cross-contract upgrade gates fail closed and no code is swapped. - Read-only lookups and role revocation stay available: operators can still inspect protocol state, and an owner can always withdraw access. `pause`/`unpause` are admin-gated (verified caller auth against the stored admin) and idempotency-checked so the breaker's state is never ambiguous. The pause is deliberately distinct from the org-scoped `freeze`, and its code aliases the registry halt slot (30) because the protocol error table is already at Stellar's 50-union-case limit. Adds unit coverage in the registry crate plus a cross-contract integration suite (`tests/src/registry_pause.rs`) that observes the pause through the shared `RegistryClient` and asserts modifications are rejected while paused, then succeed again after unpausing. 🤖 Generated with Codebuff Co-Authored-By: Codebuff <noreply@codebuff.com>
CI checks neededNo checks are visible on this commit. Please make sure this PR triggers the repository's CI and resolve any workflow problems. DripTide will keep watching and review the change when checks pass. |
Merge Conflict — Action NeededThis pull request has merge conflicts with the base branch ( What to do: update your branch by merging or rebasing against |
CI checks neededNo checks are visible on this commit. Please make sure this PR triggers the repository's CI and resolve any workflow problems. DripTide will keep watching and review the change when checks pass. |
Merge Conflict — Action NeededThis pull request has merge conflicts with the base branch ( What to do: update your branch by merging or rebasing against |
CI checks neededNo checks are visible on this commit. Please make sure this PR triggers the repository's CI and resolve any workflow problems. DripTide will keep watching and review the change when checks pass. |
Merge Conflict — Action NeededThis pull request has merge conflicts with the base branch ( What to do: update your branch by merging or rebasing against |
CI checks neededNo checks are visible on this commit. Please make sure this PR triggers the repository's CI and resolve any workflow problems. DripTide will keep watching and review the change when checks pass. |
Merge Conflict — Action NeededThis pull request has merge conflicts with the base branch ( What to do: update your branch by merging or rebasing against |
CI Checks Failed — Action NeededThe conflict resolution is mergeable, but the latest CI run failed. Please fix the failing jobs and push an update before merge.
I will not merge this PR while CI is failing. |
Rebases the ASTROIDX556#335 circuit breaker onto latest upstream/main: - register_version now carries the validated wasm_hash/VersionRecord flow with both pause and freeze guards - pause layer (Paused key, pause/unpause, require_not_paused, is_paused, fail-closed is_wasm_approved, RegistryPaused alias/event) re-applied onto the new registry base - shared/errors, interfaces, and integration tests aligned with upstream Closes ASTROIDX556#335
Closes #335
Summary
Adds a protocol-wide emergency circuit breaker to
astroid-registry. A protocoladministrator can now freeze all registry mutations during an incident with a single
call, without touching individual organizations, and release it just as cleanly.
This is deliberately distinct from the existing org-scoped
freeze:freeze(org)pause()(new)What changes
contracts/registry/src/lib.rsDataKey::Paused(initialized tofalseininitialize).pause/unpause, idempotency-checked: pausing analready-paused registry (or unpausing a live one) fails with
InvalidStaterather thansilently no-op'ing, so an operator always knows the breaker's state.
paused()reader andrequire_not_paused()guard, which short-circuitswith the dedicated paused code before any state is touched.
register_org,set_org_owner,register_module,deprecate_module,reactivate_module,remove_module,grant_role,register_version,set_admin,add_approved_wasm,remove_approved_wasm,set_upgrade_authority, andupgrade.is_wasm_approvedreportsfalsewhile paused, so every member contract'scross-contract upgrade gate fails closed and no code is swapped during an incident. The
stored approvals are untouched, so unpausing restores exactly the prior approval set.
is_paused()throughRegistryInterfaceso consumers observe the statethrough the generated
RegistryClient.revoke_roleremains callable so an owner can alwayswithdraw a compromised key's delegation during an incident.
interfaces/src/lib.rsRegistryInterface::is_paused()— the cross-contract read surface.shared/src/errors.rsError::RegistryPaused, an alias for the registry halt slot (code30), plus aregression test pinning it. The protocol error table already sits at Stellar's hard limit
of 50
ScSpecUdtUnionCaseV0cases, so the registry's single halt code serves both theorganization freeze and the admin pause rather than adding a 51st variant.
shared/src/events.rsContractEvent::RegistryPaused { paused }standard event.Admin authorization
pause/unpauseare gated by the existingrequire_adminhelper, which performs averified caller-authorization check (
caller.require_auth()) and compares the calleragainst the stored admin from instance storage — the same verified-signature discipline used
by the other admin entrypoints, and consistent with
env.current_contract_address()-styletrust of the stored protocol admin.
Tests
contracts/registry/src/test.rs— unit coverage: admin-only gating, idempotency checks,every mutating entrypoint rejected while paused, reads still available, revocation still
available, unpause restores operation, standard events emitted, upgrade freeze, and the
error-code pin.
tests/src/registry_pause.rs— a cross-contract integration suite that deploys aconsumer contract and observes the pause through the shared
RegistryClient(
astroid-interfaces), asserting modifications are rejected while paused and succeed againafter unpausing.
test_snapshots/*regenerated to reflect the newPausedinstance key writtenby
initialize.Validation
Checklist
cargo test -p astroid-registryand workspace tests pass