Skip to content

Add Oracle (OracleSet + OracleDelete) transaction workloads#57

Open
manasip-prog wants to merge 3 commits into
mainfrom
manasip/oracle-workload
Open

Add Oracle (OracleSet + OracleDelete) transaction workloads#57
manasip-prog wants to merge 3 commits into
mainfrom
manasip/oracle-workload

Conversation

@manasip-prog
Copy link
Copy Markdown
Collaborator

@manasip-prog manasip-prog commented May 14, 2026

Summary

  • Adds full Antithesis workload coverage for Price Oracles (XLS-47)OracleSet and OracleDelete transaction types with valid paths, fault injection, state tracking, and protocol-invariant assertions.
  • No setup phase required — Oracle objects are created implicitly by OracleSet and the empty-state case is handled by early return in handlers.

New files

File Purpose
transactions/oracle.py OracleSet + OracleDelete handlers (valid + faulty paths)
parallel_driver_oracle_set_random.sh Antithesis driver script for OracleSet
parallel_driver_oracle_delete_random.sh Antithesis driver script for OracleDelete

Modified files

File Change
models.py Added Oracle dataclass (account, document_id, provider, asset_class)
params.py Added 10 Oracle parameter generators (document_id, provider, asset_class, base/quote assets, asset_price, scale, price_data_count, last_update_time)
app.py Added self.oracles = [] to Workload state
transactions/__init__.py Added _on_oracle_set / _on_oracle_delete state updaters + registry entries
assertions.py Added OracleSet / OracleDelete to _META_EXPECTATIONS table + OracleDocumentID to _OBJECT_ID_FIELDS
transactions/tickets.py Added OracleSet to _TICKET_BUILDERS + OracleDelete to _TICKET_EXCLUDED
scripts/check-imports Added oracle_set, oracle_delete, Oracle imports
scripts/check-endpoints Added /oracle/set/random, /oracle/delete/random

Coverage

Valid paths

  • OracleSet: 60% create new oracle (random doc_id, provider, asset_class, timestamp, 1–5 PriceData entries with unique base/quote pairs). 40% update existing oracle (reuses stored provider/asset_class, fresh timestamp + price data).
  • OracleDelete: Picks a tracked Oracle from w.oracles and deletes it. Returns silently if none exist.

Faulty paths — OracleSet (4 mutations)

Mutation Expected result
non_owner_submission tefBAD_AUTH
invalid_flags (0x80000000) temINVALID_FLAG
invalid_update_time (epoch + 1) tecINVALID_UPDATE_TIME
provider_mismatch Provider conflict on existing oracle

Faulty paths — OracleDelete (3 mutations)

Mutation Expected result
delete_nonexistent tecNO_ENTRY
non_owner_submission tefBAD_AUTH
invalid_flags (0x80000000) temINVALID_FLAG

Assertions (Always-invariants)

  • _META_EXPECTATIONS["OracleSet"] = ("Created", "Modified", "Oracle") — on tesSUCCESS, metadata must contain an Oracle CreatedNode or ModifiedNode
  • _META_EXPECTATIONS["OracleDelete"] = ("Deleted", "Oracle") — on tesSUCCESS, metadata must contain an Oracle DeletedNode

State tracking

  • _on_oracle_set: Idempotent — updates existing oracle (by account + document_id) or appends new Oracle to w.oracles
  • _on_oracle_delete: Removes oracle matching account + document_id from w.oracles

Design decisions

  1. PriceData unique pairs_random_price_data_series() deduplicates base/quote pairs within a single series and guarantees at least one entry, matching the spec requirement.
  2. invalid_update_time uses epoch + 1 — xrpl-py blocks values before the XRPL epoch (946684800), so we use a value just after the epoch (~year 2000) which passes client validation but triggers tecINVALID_UPDATE_TIME server-side (>300s from ledger close).
  3. No setup phase — Oracles don't require pre-existing ledger objects, avoiding additions to the setup dependency chain.
  4. Ticket coverageOracleSet is stateless (can create new oracle with any doc_id) so it's in _TICKET_BUILDERS. OracleDelete requires a pre-existing oracle so it's in _TICKET_EXCLUDED.
  5. Hex-encoded Provider/AssetClass — xrpl-py calls bytes.fromhex() on these Blob fields, so generators return uppercase hex strings (e.g. "chainlink_123""636861696E6C696E6B5F313233").

Test plan

  • scripts/check-imports passes
  • scripts/check-endpoints passes (65 endpoints, 29 expected)
  • ruff check passes
  • ruff format --check passes
  • Antithesis run (#1217) — all assertions passed:
    • workload::success : OracleSet ✅ reached
    • workload::success : OracleDelete ✅ reached
    • workload::failure : OracleSet ✅ reached (faulty paths exercised)
    • workload::seen : OracleSet ✅ reached
    • workload::endpoint_exception ✅ resolved (hex-encoding fix)
    • No existing assertions regressed

Known xrpl-py limitations

The following scenarios are blocked by xrpl-py client-side validation before reaching rippled:

Scenario Ledger error Why blocked
Empty PriceDataSeries temARRAY_EMPTY xrpl-py requires len(price_data_series) > 0
>10 PriceData entries temARRAY_TOO_LARGE / tecARRAY_TOO_LARGE xrpl-py enforces len <= 10
LastUpdateTime before XRPL epoch temMALFORMED xrpl-py enforces >= 946684800

References


Pull Request opened by Augment Code with guidance from the PR author

@manasip-prog manasip-prog requested a review from vvysokikh1 May 18, 2026 17:51
@manasip-prog manasip-prog marked this pull request as ready for review May 26, 2026 17:55
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