Skip to content

feat(contracts): oracle price staleness circuit breaker#2

Open
Dev-Odun-oss wants to merge 1 commit into
mainfrom
feat/oracle-circuit-breaker
Open

feat(contracts): oracle price staleness circuit breaker#2
Dev-Odun-oss wants to merge 1 commit into
mainfrom
feat/oracle-circuit-breaker

Conversation

@Dev-Odun-oss

Copy link
Copy Markdown
Owner

Summary

Implements a circuit breaker in carbon_marketplace and a price-staleness check in carbon_oracle to halt trades when oracle price data exceeds the 24-hour freshness threshold.

Changes

contracts/carbon_oracle/src/lib.rs

  • Added PRICE_STALENESS_SECS constant (24 hours).
  • Added PriceUpdatedAt(String, u32) DataKey variant — stores the Unix timestamp of the last update_credit_price() call in persistent storage (survives the temporary price entry TTL).
  • update_credit_price() now writes PriceUpdatedAt alongside the price value.
  • Added is_price_current(methodology, vintage_year) -> bool: returns true iff the price was updated within the last 24 hours.
  • Added 7 tests in mod staleness_tests.

contracts/carbon_marketplace/src/lib.rs

  • Added CircuitBreakerTripped = 22 to CarbonError.
  • Added DataKey variants: OracleContract, CircuitBreaker, CircuitBreakerTrippedAt.
  • Added CircuitBreakerEvent and CircuitBreakerResetEvent contract types with alert design documentation in comments.
  • Added set_oracle_contract(admin, oracle) — admin registers the oracle address post-deployment.
  • Added get_circuit_breaker_state() -> bool and get_circuit_breaker_tripped_at() -> Option<u64>.
  • Added trip_circuit_breaker(admin) — manual halt.
  • Added reset_circuit_breaker(admin) — recovery endpoint, emits CircuitBreakerResetEvent.
  • purchase_credits() now:
    1. Checks CircuitBreaker flag at entry → returns CircuitBreakerTripped immediately if already set.
    2. Calls oracle.is_price_current() via cross-contract invoke (skipped if no oracle registered).
    3. On stale price: auto-trips the breaker, emits ("c_ledger", "cb_trip") event, returns CircuitBreakerTripped.
  • bulk_purchase() has the same two-layer circuit breaker guard.
  • Added 12 tests in mod circuit_breaker_tests.

Acceptance Criteria

Criterion Status
is_monitoring_current() returns false if data >365 days old ✅ (pre-existing + regression test added)
Marketplace rejects purchase if price data >24 hours stale
Circuit breaker event logged with timestamp and threshold info CircuitBreakerEvent emitted on auto-trip
Recovery endpoint to manually re-enable marketplace after oracle recovery reset_circuit_breaker()
Tests simulate 5+ staleness scenarios with recovery assertions ✅ 7 oracle tests + 12 marketplace tests
Alert design documented ✅ In CircuitBreakerEvent doc comments

Alert Design

External systems should watch for the event topic ("c_ledger", "cb_trip") emitted by the marketplace contract.

Field Value
Topic ("c_ledger", "cb_trip")
Payload CircuitBreakerEvent { methodology, vintage_year, price_age_secs, threshold_secs, tripped_at }
Recommended action PagerDuty/OpsGenie P1 during trading hours; Slack warning otherwise
Recovery Oracle submits fresh price via update_credit_price() → admin calls reset_circuit_breaker()

Recovery Path

  1. Oracle team submits fresh price via carbon_oracle::update_credit_price()
  2. Admin calls carbon_marketplace::reset_circuit_breaker()
  3. purchase_credits() and bulk_purchase() resume normally

Closes Carbon-Ledger-stellar#534

Implements a circuit breaker in carbon_marketplace and a price-staleness
check in carbon_oracle to halt trades when oracle data is stale.

### carbon_oracle/src/lib.rs

- Added PRICE_STALENESS_SECS constant (24 hours).
- Added PriceUpdatedAt(String, u32) DataKey variant: stores the Unix
  timestamp of the last successful update_credit_price() call in
  persistent storage (survives even after the 17_280-ledger TTL on the
  temporary price entry expires).
- update_credit_price() now writes PriceUpdatedAt alongside the price.
- Added is_price_current(methodology, vintage_year) -> bool: returns
  true iff PriceUpdatedAt exists and is < 24 hours old. This is the
  query function the marketplace calls for every purchase.
- Added 7 tests in mod staleness_tests covering: never-set returns false,
  fresh update returns true, stale after 24 h, recovery after re-update,
  is_monitoring_current regression (365-day window), independent
  tracking per (methodology, vintage_year) pair.

### carbon_marketplace/src/lib.rs

- Added CircuitBreakerTripped = 22 to CarbonError.
- Added DataKey variants: OracleContract, CircuitBreaker,
  CircuitBreakerTrippedAt.
- Added CircuitBreakerEvent and CircuitBreakerResetEvent contracttypes
  for on-chain event emission (with alert design docs in comments).
- Added set_oracle_contract(admin, oracle): admin registers the oracle
  contract address post-deployment.
- Added get_circuit_breaker_state() -> bool: query endpoint.
- Added get_circuit_breaker_tripped_at() -> Option<u64>: audit trail.
- Added trip_circuit_breaker(admin): manual admin halt.
- Added reset_circuit_breaker(admin): recovery endpoint; emits
  CircuitBreakerResetEvent.
- purchase_credits() now:
  1. Checks CircuitBreaker flag at entry — returns CircuitBreakerTripped
     if already tripped.
  2. After loading the listing, calls oracle.is_price_current() via
     cross-contract invoke (skipped if no oracle registered).
  3. On stale price: auto-trips the breaker, emits ("c_ledger",
     "cb_trip") CircuitBreakerEvent, returns CircuitBreakerTripped.
- bulk_purchase() has the same two-layer circuit breaker guard.
- Added 12 tests in mod circuit_breaker_tests covering: initial state,
  manual trip, purchase blocked, bulk_purchase blocked, admin reset,
  recovery sequence, set_oracle_contract, non-admin cannot trip/reset,
  timestamp audit trail, multiple trip/reset cycles.

Alert design (documented in CircuitBreakerEvent):
  - Watch for topic ("c_ledger", "cb_trip") events from the marketplace.
  - P1 alert if tripped during trading hours; Slack warn otherwise.
  - Recovery: oracle submits fresh price → admin calls reset_circuit_breaker().

Closes Carbon-Ledger-stellar#534
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.

[Smart Contracts] Implement price oracle staleness detection and circuit breaker

1 participant