{"id":50673009,"url":"https://github.com/oasisprotocol/rofl-header-oracle","last_synced_at":"2026-06-08T13:02:47.935Z","repository":{"id":332332539,"uuid":"1055155680","full_name":"oasisprotocol/rofl-header-oracle","owner":"oasisprotocol","description":"Oracle running in Oasis ROFL that reports block headers from other chains to Oasis Sapphire.","archived":false,"fork":false,"pushed_at":"2026-02-23T12:23:29.000Z","size":289,"stargazers_count":0,"open_issues_count":9,"forks_count":0,"subscribers_count":0,"default_branch":"master","last_synced_at":"2026-02-23T20:50:09.441Z","etag":null,"topics":["block-header","oasis","oracle","python","rofl","sapphire","solidity"],"latest_commit_sha":null,"homepage":"https://explorer.oasis.io/mainnet/sapphire/rofl/app/rofl1qz5h592w87uyftlrht388g3rkf58s5z7n53w5xh0","language":"Python","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/oasisprotocol.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2025-09-11T21:14:41.000Z","updated_at":"2026-02-04T11:45:14.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/oasisprotocol/rofl-header-oracle","commit_stats":null,"previous_names":["oasisprotocol/rofl-header-oracle"],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/oasisprotocol/rofl-header-oracle","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/oasisprotocol%2Frofl-header-oracle","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/oasisprotocol%2Frofl-header-oracle/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/oasisprotocol%2Frofl-header-oracle/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/oasisprotocol%2Frofl-header-oracle/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/oasisprotocol","download_url":"https://codeload.github.com/oasisprotocol/rofl-header-oracle/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/oasisprotocol%2Frofl-header-oracle/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":34063159,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-05-26T15:22:16.424Z","status":"online","status_checked_at":"2026-06-08T02:00:07.615Z","response_time":111,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["block-header","oasis","oracle","python","rofl","sapphire","solidity"],"created_at":"2026-06-08T13:02:47.145Z","updated_at":"2026-06-08T13:02:47.917Z","avatar_url":"https://github.com/oasisprotocol.png","language":"Python","funding_links":[],"categories":[],"sub_categories":[],"readme":"# ROFL Header Oracle\n\nA Python-based Oasis ROFL (Runtime OFf-chain Logic) oracle that fetches block\nheaders from source chains and submits them to the ROFLAdapter contract on\nOasis Sapphire for cross-chain bridge verification.\n\n## Overview\n\nThis oracle listens for `BlockHeaderRequested` events from a source chain\ncontract and responds by fetching the requested block headers and submitting\nthem to the Oasis Sapphire network through the ROFL runtime. It's designed to\nwork as part of a Hashi-based cross-chain bridge system.\n\n## Architecture\n\n- **Source Chain**: Listens for events on any EVM-compatible blockchain\n- **Target Chain**: Submits block headers to Oasis Sapphire via ROFL\n- **ROFL Runtime**: Uses Oasis confidential compute for secure oracle operations\n- **Event-Driven**: Processes `BlockHeaderRequested` events in real-time\n\n## Oracle Modes\n\nThe oracle supports four operating modes, configured via `ORACLE_MODE`:\n\n| Mode | Use When | How It Works |\n|------|----------|-------------|\n| `event_listener` | A `BlockHeaderRequester` contract exists on the source chain and emits requests for specific block headers | Polls for `BlockHeaderRequested` events and submits only the requested headers |\n| `push` | You need continuous, unconditional block header availability on Sapphire (e.g., for a bridge that may need any recent header) | Pushes the latest block headers at a fixed interval, regardless of demand |\n| `watcher` | You want headers only for blocks where specific addresses have on-chain activity (transactions to/from) | Scans blocks for interactions with watched addresses and submits only those block headers. Supports optional internal transaction detection via `debug_traceTransaction` |\n| `token_watcher` | You want headers only for blocks containing ERC-20 transfers to specific recipients (e.g., bridge deposit addresses) | Monitors `Transfer` events on configured token contracts filtered by recipient addresses, and submits headers for blocks with matching transfers |\n\nThe `watcher` and `token_watcher` modes include a **heartbeat\nmechanism** that periodically stores a checkpoint block header even\nwhen no activity is detected, bounding sync time on oracle restart.\n\n## Requirements\n\n- Docker and Docker Compose\n- Access to a ROFL-enabled Oasis Network environment\n- Source chain RPC endpoint\n- Deployed contracts:\n  - `BlockHeaderRequester` on source chain\n  - `ROFLAdapter` on Oasis Sapphire\n\n## Configuration\n\nThe oracle is configured through environment variables defined in `compose.yaml`:\n\n### Environment Variables\n\nThe oracle supports four modes: **event_listener**, **push**, **watcher**,\nand **token_watcher**. Some environment variables are required for all\nmodes, while others are specific to a mode.\n\n#### **Common Variables (All Modes)**\n\n| Variable               | Description                                               | Default                              | Required |\n|------------------------|----------------------------------------------------------|--------------------------------------|----------|\n| `PYTHONUNBUFFERED`     | Disable Python output buffering for immediate logs       | `1`                                  | No       |\n| `SOURCE_RPC_URL`       | RPC endpoint for the source chain                        | `https://ethereum.publicnode.com`    | No       |\n| `TARGET_RPC_URL`       | RPC endpoint for the target chain                        | `https://testnet.sapphire.oasis.io`  | No       |\n| `ROFL_ADAPTER_ADDRESS` | Address of the ROFLAdapter contract on Oasis Sapphire    | -                                    | **Yes**  |\n| `REQUEST_TIMEOUT`      | HTTP request timeout (seconds)                           | `30`                                 | No       |\n| `RETRY_COUNT`          | Number of retry attempts for operations                  | `3`                                  | No       |\n| `ORACLE_MODE`          | Operating mode (see [Oracle Modes](#oracle-modes))       | `event_listener`                     | No       |\n| `LOG_LEVEL`            | Logging level: DEBUG, INFO, WARNING, ERROR, CRITICAL     | `INFO`                               | No       |\n| `JSON_LOGS`            | Enable JSON-formatted structured logging                 | `false`                              | No       |\n| `MIN_REPORTER_BALANCE` | Minimum reporter balance in native tokens before startup | `0.001`                              | No       |\n\n---\n\n#### **Event Listener Mode (`ORACLE_MODE=event_listener`)**\n\n| Variable                   | Description                                                        | Default | Required |\n|----------------------------|--------------------------------------------------------------------|---------|----------|\n| `SOURCE_CONTRACT_ADDRESS`  | Address of the BlockHeaderRequester contract on source chain       | -       | **Yes**  |\n| `POLLING_INTERVAL`         | Seconds between event checks                                       | `12`    | No       |\n| `LOOKBACK_BLOCKS`          | Number of blocks to look back on startup                           | `100`   | No       |\n\n---\n\n#### **Push Mode (`ORACLE_MODE=push`)**\n\n| Variable           | Description                                   | Default | Required |\n|--------------------|-----------------------------------------------|---------|----------|\n| `PUSH_INTERVAL`    | Seconds between block pushes                  | `60`    | No       |\n| `PUSH_BATCH_SIZE`  | Max blocks to push per iteration              | `20`    | No       |\n\n---\n\n#### **Watcher Mode (`ORACLE_MODE=watcher`)**\n\n| Variable                        | Description                                         | Default | Required |\n|---------------------------------|-----------------------------------------------------|---------|----------|\n| `WATCH_ADDRESSES`               | Comma-separated list of addresses to watch          | -       | **Yes**  |\n| `SCAN_INTERVAL`                 | Seconds between scanning for interactions           | `60`    | No       |\n| `WATCHER_BATCH_SIZE`            | Max blocks to scan per iteration                    | `50`    | No       |\n| `LOOKBACK_BLOCKS`               | Number of blocks to look back on startup            | `100`   | No       |\n| `ENABLE_INTERNAL_TX_DETECTION`  | Enable internal transaction detection               | `false` | No       |\n| `HEARTBEAT_INTERVAL_SECONDS`    | Seconds between heartbeat checkpoint submissions    | `3600`  | No       |\n\n**Internal Transaction Detection:**\n\nWhen `ENABLE_INTERNAL_TX_DETECTION=true`, the watcher will also detect interactions\nthat occur via internal transactions (contract-to-contract calls). This feature:\n\n- **Requires:** Archive node with `debug_traceTransaction` API support\n- **Performance:** Significantly slower due to tracing overhead (trace each\n  transaction)\n- **Use case:** Critical when watched addresses primarily interact via smart\n  contracts\n- **Recommended:** Only enable if you have access to archive nodes and need\n  comprehensive tracking\n\nWithout this feature, only direct (external) transactions to/from watched\naddresses are detected.\n\n---\n\n#### **Token Watcher Mode (`ORACLE_MODE=token_watcher`)**\n\n| Variable                     | Description                                              | Default | Required |\n|------------------------------|----------------------------------------------------------|---------|----------|\n| `TOKEN_ADDRESSES`            | Comma-separated list of ERC-20 token contract addresses  | -       | **Yes**  |\n| `RECIPIENT_ADDRESSES`        | Comma-separated list of recipient addresses to watch     | -       | **Yes**  |\n| `SCAN_INTERVAL`              | Seconds between scanning for token transfers             | `5`     | No       |\n| `MAX_BLOCKS_PER_SCAN`        | Max blocks to scan per iteration                         | `10`    | No       |\n| `HEARTBEAT_INTERVAL_SECONDS` | Seconds between heartbeat checkpoint submissions         | `3600`  | No       |\n\n---\n\n#### **Local Mode (Testing Only)**\n\n| Variable            | Description                                | Default | Required           |\n|---------------------|--------------------------------------------|---------|--------------------|\n| `LOCAL_PRIVATE_KEY` | Private key for local testing mode         | -       | **Yes (Local Mode)** |\n\n---\n\n**Note:**\n\n- All addresses must be valid EVM addresses (checksummed).\n- `LOCAL_PRIVATE_KEY` is only required for local mode/testing.\n- If a required variable is missing for the selected mode, the oracle will\n  fail to start with a clear error.\n\n---\n\n#### Important Notes\n\n- **`PYTHONUNBUFFERED=1`**: Essential for real-time log visibility in\ncontainerized environments. Without this, log output may be buffered and not\nappear immediately, making the oracle appear \"stuck\" when it's actually running normally.\n- **`LOCAL_PRIVATE_KEY`**: Required only when running in local mode for testing\nwithout ROFL utilities. Should be a hex-encoded private key.\n- **`ENABLE_INTERNAL_TX_DETECTION`**: When enabled in watcher mode, uses\n`debug_traceTransaction` to detect internal contract calls. This requires:\n  - Archive node access (full nodes won't work)\n  - Debug API enabled on the RPC endpoint\n  - May require premium RPC provider plans\n  - Significantly increases processing time (10-100x slower)\n  - Only use if absolutely necessary for your use case\n\n## Usage\n\n### 1. Set Environment Variables\n\nCreate a `.env` file or set environment variables:\n\n```bash\n# Required for all modes\nexport ROFL_ADAPTER_ADDRESS=0xYourROFLAdapterAddress\nexport SOURCE_RPC_URL=https://your-source-chain-rpc.com\nexport ORACLE_MODE=event_listener\n\n# Required for event_listener mode\nexport SOURCE_CONTRACT_ADDRESS=0xYourBlockHeaderRequesterAddress\n\n# Optional: configure other settings\nexport POLLING_INTERVAL=12\nexport LOOKBACK_BLOCKS=100\n```\n\n### 2. Run with Docker Compose\n\n```bash\ndocker-compose up --build\n```\n\n### 3. Monitor Logs\n\nThe oracle will display:\n\n- Initialization progress\n- ROFL connection status\n- Block range being monitored\n- Event processing status\n- Periodic heartbeat messages\n\n## Local Mode (Testing)\n\nFor testing and development without ROFL infrastructure, the oracle supports a\nlocal mode that simulates transaction submissions and skips ROFL utilities.\n\n### Local Mode Features\n\n- **No ROFL Dependencies**: Skips ROFL utility initialization and socket connections\n- **Transaction Simulation**: Logs transaction details instead of actual submission\n- **Event Listening**: Full WebSocket and polling event listening functionality\n- **Local Private Key**: Uses a local private key for contract interaction testing\n\n### Running in Local Mode\n\nUse the dedicated local testing Docker Compose configuration:\n\n```bash\n# Run with local testing configuration\ndocker compose -f compose.local.yaml up --build\n```\n\n### Local Mode Environment Variables\n\nIn addition to the standard variables, local mode requires:\n\n```bash\n# Required for local mode - add this to your .env file\nLOCAL_PRIVATE_KEY=0x1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef\n```\n\n## Operation\n\n1. **Initialization**: Connects to ROFL runtime and source chain\n2. **Event Monitoring**: Polls for `BlockHeaderRequested` events\n3. **Block Fetching**: Retrieves requested block headers from source chain\n4. **Header Submission**: Submits headers to Sapphire via ROFL\n5. **Continuous Operation**: Runs in an infinite loop with configurable intervals\n\n## Monitoring \u0026 Health Checks\n\nThe oracle includes built-in health check endpoints for container orchestration\nand monitoring:\n\n### Health Endpoints\n\n- **`/health`** - Overall system health with component status\n- **`/health/live`** - Liveness probe (is the service running)\n- **`/health/ready`** - Readiness probe (is the service ready to handle work)\n\nHealth endpoints are exposed on port 8080 by default.\n\n### Example Health Check\n\n```bash\n# Check overall health\ncurl http://localhost:8080/health\n\n# Liveness probe (for Kubernetes/Docker)\ncurl http://localhost:8080/health/live\n\n# Readiness probe\ncurl http://localhost:8080/health/ready\n```\n\n### Error Handling \u0026 Resilience\n\nThe oracle includes production-grade error handling:\n\n- **Exponential Backoff**: Automatic retry with exponential backoff for\n  transient failures\n- **Circuit Breakers**: Prevents cascading failures when RPCs are down\n- **Retry Logic**: Configurable retry attempts (via `RETRY_COUNT`) for all\n  critical operations\n- **Graceful Degradation**: Continues operating even with degraded connectivity\n\n### Structured Logging\n\nEnable JSON-formatted structured logging for production environments:\n\n```bash\nexport JSON_LOGS=true\n```\n\nThis outputs logs in JSON format for easier parsing by log aggregation systems\n(ELK, Splunk, DataDog, etc.).\n\n## Development\n\n### Dependencies\n\n- Python 3.10+\n- oasis-sapphire-py\n- web3.py\n- httpx\n- cbor2\n- aiohttp\n\n### Local Development\n\n```bash\n# Install dependencies\nmake sync\n\n# Run tests\nmake test\n\n# Run tests with coverage\nmake test-cov\n\n# Format code\nmake format\n\n# Lint code\nmake lint\n\n# Fix linting issues\nmake lint-fix\n\n# Run all checks (format, lint, test)\nmake pre-commit\n\n# Run the application (via Docker Compose)\ndocker compose -f compose.local.yaml up --build\n```\n\n## Architecture Integration\n\nThis oracle is designed to work with:\n\n- Hashi cross-chain message verification system\n- Oasis ROFL confidential compute runtime\n- EVM-compatible source chains\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Foasisprotocol%2Frofl-header-oracle","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Foasisprotocol%2Frofl-header-oracle","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Foasisprotocol%2Frofl-header-oracle/lists"}