-
Notifications
You must be signed in to change notification settings - Fork 0
Oracle System Oracle Architecture
- Introduction
- Project Structure
- Core Components
- Architecture Overview
- Detailed Component Analysis
- Dependency Analysis
- Performance Considerations
- Troubleshooting Guide
- Conclusion
- Appendices
This document describes the Oracle Architecture for the Countersig Network. It explains how the off-chain oracle computes and writes reputation scores, how it interacts with on-chain contracts, and how HTTP endpoints expose administrative and preview capabilities. It also documents the modular design separating HTTP endpoints, chain event processing, and scoring logic, along with containerization, orchestration, and operational guidance for oracle operators.
The repository organizes the oracle implementation under the oracle/ directory, with supporting contracts under src/, documentation under docs/, and a TypeScript SDK under packages/sdk/. The top-level docker-compose.oracle.yml defines the service orchestration for the oracle.
graph TB
subgraph "Repository Root"
A["README.md"]
B["docker-compose.oracle.yml"]
end
subgraph "Oracle Service"
C["oracle/Dockerfile"]
D["oracle/package.json"]
E["oracle/index.js"]
F["oracle/chain.js"]
G["oracle/scoring.js"]
H["oracle/scoring.test.js"]
end
subgraph "Contracts"
I["src/CountersigReputation.sol"]
J["src/CountersigIdentity.sol"]
K["src/CountersigStaking.sol"]
end
subgraph "Documentation"
L["docs/reputation-model.md"]
M["docs/quickstart.md"]
end
subgraph "SDK"
N["packages/sdk/src/index.ts"]
O["packages/sdk/src/types.ts"]
P["packages/sdk/package.json"]
end
A --> E
B --> C
E --> F
E --> G
F --> I
F --> J
F --> K
L --> G
M --> E
N --> I
N --> J
N --> K
Diagram sources
- README.md:1-415
- docker-compose.oracle.yml:1-11
- oracle/Dockerfile:1-11
- oracle/package.json:1-19
- oracle/index.js:1-178
- oracle/chain.js:1-85
- oracle/scoring.js:1-50
- oracle/scoring.test.js:1-109
- src/CountersigReputation.sol:1-181
- src/CountersigIdentity.sol:1-227
- src/CountersigStaking.sol:1-331
- docs/reputation-model.md:1-156
- docs/quickstart.md:1-183
- packages/sdk/src/index.ts:1-36
- packages/sdk/src/types.ts:1-66
- packages/sdk/package.json:1-34
Section sources
- README.md:1-415
- docker-compose.oracle.yml:1-11
- HTTP API server: Provides health, manual epoch triggering, attestation ingestion, flag submission, and score preview endpoints.
- Chain integration: Connects to an RPC endpoint, initializes contracts, scans for AgentRegistered events, reads identity info, and writes reputation.
- Scoring engine: Computes the 6-factor reputation score from in-memory state and on-chain agent metadata.
- Containerization: Node.js runtime with production-ready Docker image and compose orchestration.
Key responsibilities and separation of concerns:
- HTTP endpoints: Administrative and preview functions; no state persistence.
- Chain integration: Event scanning, identity lookup, and on-chain writes.
- Scoring logic: Deterministic, pure functions for each factor; total capped at 100.
Section sources
- oracle/index.js:1-178
- oracle/chain.js:1-85
- oracle/scoring.js:1-50
- oracle/Dockerfile:1-11
- oracle/package.json:1-19
The oracle operates as a periodic job that:
- Scans for newly registered agents via on-chain events.
- Collects per-agent metrics (attestations, flags) from HTTP endpoints.
- Computes the 6-factor score and writes it on-chain.
- Exposes administrative endpoints for manual control and previews.
graph TB
subgraph "Oracle Service"
A["HTTP API<br/>index.js"]
B["Chain Adapter<br/>chain.js"]
C["Scoring Engine<br/>scoring.js"]
end
subgraph "On-Chain Contracts"
D["CountersigIdentity<br/>Identity registry"]
E["CountersigReputation<br/>Score store"]
F["CountersigStaking<br/>Slash lifecycle"]
end
subgraph "External Inputs"
G["CounterAudit / Users<br/>Submit attestations"]
H["Operators<br/>Manual triggers"]
end
G --> A
H --> A
A --> B
B --> D
B --> E
B --> F
B --> C
C --> B
Diagram sources
- oracle/index.js:1-178
- oracle/chain.js:1-85
- oracle/scoring.js:1-50
- src/CountersigReputation.sol:1-181
- src/CountersigIdentity.sol:1-227
- src/CountersigStaking.sol:1-331
Responsibilities:
- Health check endpoint.
- Manual epoch trigger for testing.
- Attestation ingestion endpoint (authorized).
- Flag submission endpoint (authorized).
- Score preview endpoint (no on-chain write).
Security and validation:
- Optional bearer token authorization for sensitive endpoints.
- Request body size limit and JSON parsing with error handling.
- Path validation and method routing.
Operational behavior:
- Starts an HTTP server and schedules periodic epochs.
- Logs epoch start/end and per-agent updates.
sequenceDiagram
participant Client as "Client"
participant API as "HTTP API (index.js)"
participant Chain as "Chain Adapter (chain.js)"
participant Score as "Scoring (scoring.js)"
participant Rep as "CountersigReputation"
Client->>API : POST /attest {didHash, success}
API->>API : authorize + parse body
API->>API : update in-memory attestations
API-->>Client : 200 OK
Client->>API : POST /epoch
API->>API : runEpoch()
API->>Chain : getRegisteredAgents()
Chain-->>API : agent list
loop for each agent
API->>Chain : getAgentInfo(didHash)
Chain-->>API : {registeredAt, status}
API->>Score : computeScore(...)
Score-->>API : {scores}
API->>Chain : writeReputation(didHash, scores)
Chain->>Rep : updateReputation(...)
Rep-->>Chain : tx receipt
Chain-->>API : tx hash
end
API-->>Client : 202 Accepted
Diagram sources
- oracle/index.js:78-178
- oracle/chain.js:32-82
- oracle/scoring.js:32-47
- src/CountersigReputation.sol:100-129
Section sources
- oracle/index.js:78-178
Responsibilities:
- Initialize provider, wallet, and contract instances.
- Scan for AgentRegistered events in chunks to respect RPC limits.
- Cache known agents and rescan history incrementally.
- Fetch agent identity (registration time and status).
- Write reputation data to CountersigReputation.
Key behaviors:
- Incremental scan using last scanned block marker.
- Sleep between chunks to avoid rate limits.
- Writes use a wallet with ORACLE_ROLE to update scores.
flowchart TD
Start(["getRegisteredAgents()"]) --> CheckRange["Compute from..to range"]
CheckRange --> HasRange{"Range valid?"}
HasRange --> |No| ReturnList["Return cached list"]
HasRange --> |Yes| LoopChunks["Iterate chunk windows"]
LoopChunks --> Query["queryFilter(Chunk)"]
Query --> ForEach["For each event"]
ForEach --> Cache["Store in knownAgents map"]
Cache --> Sleep["Sleep between chunks"]
Sleep --> NextChunk{"More chunks?"}
NextChunk --> |Yes| LoopChunks
NextChunk --> |No| UpdateMarker["Update lastScannedBlock"]
UpdateMarker --> ReturnList
Diagram sources
- oracle/chain.js:32-60
Section sources
- oracle/chain.js:1-85
Responsibilities:
- Compute six factors: Fee Activity, Success Rate, Age, External Trust, Community, Propagation.
- Return a normalized total capped at 100.
- Stubbed External Trust and Propagation for Phase 2.
Factor details:
- Fee Activity: Points per 10 attestations, capped at 30.
- Success Rate: Percentage of successful attestations, capped at 25.
- Age: Logarithmic growth reaching 20 after ~31 days.
- External Trust: Placeholder for SAID/Gitcoin integrations.
- Community: Deducted per unresolved flag; max 5.
- Propagation: Placeholder for trust graph; max 5.
flowchart TD
In(["Inputs: registeredAt, attestations, flags"]) --> FS["feeScore(total)"]
In --> SS["successScore(successful,total)"]
In --> AS["ageScore(registeredAt)"]
In --> ES["externalScore (stub)"]
In --> CS["communityScore(flags)"]
In --> PS["propagationScore (stub)"]
FS --> Sum["Sum factors"]
SS --> Sum
AS --> Sum
ES --> Sum
CS --> Sum
PS --> Sum
Sum --> Clamp["Clamp to ≤ 100"]
Clamp --> Out(["Scores + total"])
Diagram sources
- oracle/scoring.js:9-47
- docs/reputation-model.md:7-82
Section sources
- oracle/scoring.js:1-50
- docs/reputation-model.md:1-156
- CountersigReputation: Accepts oracle-written scores and validates per-factor caps. Emits updates and supports threshold checks.
- CountersigIdentity: Stores operator, agent address, Ed25519 public key, and status. Supports key rotation and status transitions.
- CountersigStaking: Manages CSIG stakes, slash lifecycle, and zeroing of reputation upon execution.
sequenceDiagram
participant Oracle as "Oracle"
participant Rep as "CountersigReputation"
participant Id as "CountersigIdentity"
participant St as "CountersigStaking"
Oracle->>Rep : updateReputation(didHash, scores)
Rep-->>Oracle : emits ReputationUpdated
St->>Id : updateStatus(didHash, Suspended)
Note over St,Id : Challenge window starts
alt Operator disputes
Oracle->>Id : updateStatus(didHash, Active)
else After window
Oracle->>St : executeSlash(didHash)
St->>Id : updateStatus(didHash, Slashed)
St->>Rep : zeroReputation(didHash)
end
Diagram sources
- src/CountersigReputation.sol:100-146
- src/CountersigIdentity.sol:143-179
- src/CountersigStaking.sol:205-293
Section sources
- src/CountersigReputation.sol:1-181
- src/CountersigIdentity.sol:1-227
- src/CountersigStaking.sol:1-331
- Docker image: Node.js 20 Alpine, installs production dependencies, copies runtime files, and runs the main script.
- Compose service: Builds from oracle/ directory, sets restart policy, mounts environment file, and binds port 3030.
Operational notes:
- Environment variables are loaded via dotenv in the process.
- The service listens on localhost:3030 by default.
Section sources
- oracle/Dockerfile:1-11
- docker-compose.oracle.yml:1-11
- oracle/package.json:1-19
Internal dependencies:
- index.js depends on chain.js and scoring.js.
- chain.js depends on ethers and uses ABI constants for contracts.
- scoring.js is a pure module with no external runtime dependencies.
External dependencies:
- Node.js runtime and npm packages (dotenv, ethers).
- SDK types and interfaces for on-chain consumption.
graph LR
IDX["index.js"] --> CHAIN["chain.js"]
IDX --> SCORE["scoring.js"]
CHAIN --> ETH["ethers"]
SCORE --> |pure math| SCORE
Diagram sources
- oracle/index.js:1-10
- oracle/chain.js:1-5
- oracle/scoring.js:1-5
- oracle/package.json:10-13
Section sources
- oracle/index.js:1-10
- oracle/chain.js:1-5
- oracle/scoring.js:1-5
- oracle/package.json:1-19
- Epoch cadence: Controlled by EPOCH_HOURS; default aligns with testnet guidance.
- RPC chunking: chain.js scans logs in chunks and sleeps between requests to respect free-tier limits.
- Memory state: In-memory maps for attestations and flags; recomputation occurs on restart.
- Throughput: Depends on RPC throughput, event volume, and compute cost of scoring.
Recommendations:
- Scale horizontally by running multiple oracle instances behind a load balancer (not currently defined in the provided compose).
- Persist state externally (PostgreSQL/SQLite) for production to avoid recomputation on restart.
- Monitor RPC rate limits and adjust chunk sizes accordingly.
[No sources needed since this section provides general guidance]
Common issues and remedies:
- Missing environment variables: The process exits early if required variables are missing.
- Unauthorized access: POST /attest and POST /flag require a valid bearer token when configured.
- Request body errors: Bodies exceeding the size limit or invalid JSON cause 400 responses.
- Chain errors: Failures in fetching agents or writing reputation are logged; inspect RPC connectivity and account permissions.
- Slashed agents: Skipped during epoch computation; reputation zeroed on-chain by Staking.
Operational checks:
- Use GET /health to confirm service availability and epoch configuration.
- Use POST /epoch to trigger an immediate run for diagnostics.
- Use GET /score/:didHash to preview scores without writing.
Section sources
- oracle/index.js:23-26
- oracle/index.js:105-109
- oracle/index.js:87-103
- oracle/index.js:46-51
- oracle/chain.js:17-18
The Countersig Oracle is a modular, deterministic system that periodically computes and writes reputation scores to the blockchain. Its HTTP API enables operator control and previews, while chain integration ensures secure, auditable updates. The design cleanly separates concerns across HTTP endpoints, chain processing, and scoring logic, and the containerization strategy supports straightforward deployment and operation.
[No sources needed since this section summarizes without analyzing specific files]
- GET /health: Returns service health and epoch configuration.
- POST /epoch: Triggers a manual epoch run.
- POST /attest: Ingests an attestation for a didHash (authorized).
- POST /flag: Submits a community flag for a didHash (authorized).
- GET /score/:didHash: Returns computed scores and state without writing.
Section sources
- oracle/index.js:111-171
- Environment variables: RPC_URL, ORACLE_PRIVATE_KEY, IDENTITY_ADDRESS, REPUTATION_ADDRESS, EPOCH_HOURS, PORT, FROM_BLOCK, LOG_CHUNK_SIZE, ORACLE_ADMIN_TOKEN.
- Docker build and run: Use docker-compose.oracle.yml to build and start the service.
- Test coverage: scoring tests validate factor computations.
Section sources
- oracle/index.js:11-21
- docker-compose.oracle.yml:1-11
- oracle/scoring.test.js:1-109
- ORACLE_ROLE: Allowed to write reputation.
- STAKING_CORE_ROLE: Allowed to zero reputation and manage status.
- UPGRADER_ROLE: Allowed to upgrade contracts.
Section sources
- src/CountersigReputation.sol:29-36
- src/CountersigIdentity.sol:23-27
- src/CountersigStaking.sol:40-44
Start Here
Core Concepts
Smart Contracts
Oracle System
Agent SDK
Integration Guides
Economic Model
Deployment & Ops
Advanced Topics