Skip to content

About

A decentralized fact-verification primitive for the GenLayer blockchain.

Resources

Stars

1 star

Watchers

0 watching

Forks

Latest commit

 

History

3 Commits

Folders and files

Repository files navigation

CrossSourceFactVerifier

A decentralized fact-verification primitive for the GenLayer blockchain. It cross-references multiple independent web sources to determine whether a given statement is TRUE, FALSE, or UNVERIFIABLE -- powered by AI consensus among decentralized validator nodes.

Why CrossSourceFactVerifier?

Traditional fact-checking is centralized: a single entity decides what is true. CrossSourceFactVerifier distributes this process across a network of independent AI validators, each fetching sources and reasoning independently. The result is a trustless, censorship-resistant verification record stored on-chain.

Key differentiator: Requires a minimum of 2 independent source URLs, enforcing genuine cross-verification rather than single-source reliance.


Public API

Write Methods

verify_fact(statement: str, source_urls: str) -> None

Verify a factual statement against multiple sources.

Parameter Type Description
statement str The claim to verify (must not be empty)
source_urls str Comma-separated URLs (min 2, max 10, each must start with http:// or https://)

Raises:

  • UserError("statement must not be empty") -- empty or whitespace-only statement
  • UserError("no valid source URLs provided") -- no URLs start with http/https
  • UserError("at least 2 source URLs required for cross-verification") -- only 1 valid URL

View Methods

get_verification(record_id: str) -> str

Returns a single verification record as JSON.

{
  "id": "0",
  "statement": "Tesla delivered 500000 vehicles in Q3 2025",
  "sources": "https://reuters.com/article1,https://bbc.com/article2",
  "verdict": "TRUE",
  "agreement_ratio": 85,
  "conflicting_sources": "None",
  "verifier": "0xabc123..."
}

Raises: UserError("record not found") if record_id does not exist.

get_all_verifications() -> str

Returns all verification records as a JSON array.

get_stats() -> str

Returns aggregate statistics:

{
  "total_verified": 10,
  "true_count": 6,
  "false_count": 2,
  "unverifiable_count": 2
}

How Consensus Works

CrossSourceFactVerifier uses gl.vm.run_nondet_unsafe(leader_fn, validator_fn) -- the most powerful consensus pattern in GenLayer, where you write your own validator logic.

Leader Phase

  1. The leader validator fetches content from each source URL using gl.nondet.web.render(url, mode="text").
  2. Source content is truncated (3000 chars per source, 8000 total) and assembled into labeled sections.
  3. The leader calls gl.nondet.exec_prompt() with a structured fact-checking prompt, requesting JSON output with verdict, agreement_ratio, and conflicting_sources.
  4. Results are normalized (verdict mapped to TRUE/FALSE/UNVERIFIABLE, ratio clamped 0-100).

Validator Phase

Each validator independently:

  1. Re-runs the entire leader logic -- fetching sources and querying their own LLM.
  2. Compares semantics, not exact text:
    • Verdict must match (both say TRUE, or both say FALSE, etc.) after normalization
    • Agreement ratio must fall in the same band:
      • Band 0 (LOW): 0-35%
      • Band 1 (MID): 36-70%
      • Band 2 (HIGH): 71-100%
    • conflicting_sources text is not compared (different LLMs may list sources differently)

This band-based comparison allows different LLMs to reach the same semantic conclusion without requiring identical numeric outputs.

Why This Matters

  • Not a format check: Validators verify the meaning of the result, not just JSON structure.
  • Robust to LLM variance: Different models can word things differently but still agree on the core verdict and confidence level.
  • Genuine cross-source analysis: Each validator independently fetches and analyzes the sources.

Use Cases

Use Case Description
News Verification Verify breaking news claims before sharing on decentralized social media
Research Claims Check scientific claims against multiple journal/news sources
Due Diligence Verify company information from independent sources before investing
Prediction Markets Resolve event outcomes using multiple independent news sources
Content Platforms Label user-submitted articles as "Verified" or "Disputed"
Insurance Claims Cross-reference claim details against public records and news
Supply Chain Verify product origin and certification claims from multiple registries

Usage Examples

Verify a News Claim

Method: verify_fact
Args:
  statement: "SpaceX successfully launched Starship on June 15 2025"
  source_urls: "https://reuters.com/space/spacex-starship,https://bbc.com/news/science-spacex,https://cnbc.com/spacex-launch"

Check the Result

Method: get_verification
Args:
  record_id: "0"

View Statistics

Method: get_stats
Args: (none)

State Design

VerificationRecord (on-chain struct):
  - statement: str
  - sources: str (comma-separated URLs)
  - verdict: str (TRUE | FALSE | UNVERIFIABLE)
  - agreement_ratio: bigint (0-100)
  - conflicting_sources: str (URLs or "None")
  - verifier: str (caller address as hex)

Contract state:
  - records: TreeMap[str, VerificationRecord]
  - next_id: bigint
  - total_verified: bigint
  - true_count: bigint
  - false_count: bigint
  - unverifiable_count: bigint

Edge Case Handling

Scenario Behavior
Empty statement UserError("statement must not be empty")
No valid URLs UserError("no valid source URLs provided")
Only 1 valid URL UserError("at least 2 source URLs required...")
All sources unreachable Verdict = UNVERIFIABLE, ratio = 0
Some sources fail Analyzes reachable sources only
Only 1 source reachable Analyzes it, notes "Insufficient reachable sources"
LLM returns bad JSON Fallback to UNVERIFIABLE, ratio = 0
Ratio out of range Clamped to 0-100
More than 10 URLs Only first 10 are used
Same statement verified twice Allowed (information may change over time)

Live Deployment on Studionet

The contract is actively deployed on the GenLayer test network (studionet):

  • Contract Address: 0x4afC08645cC7cd2074A8774e03C2fD162a5ee43f
  • Network: studionet

Worked Example

Below is a realistic, worked example demonstrating how the primitive processes a claim.

1. Execute verification (Write Method)

Call verify_fact with a statement and at least two source URLs:

  • Statement: "GenLayer is a blockchain Layer-1 that integrates AI at the consensus level."
  • Source URLs: "https://genlayer.com,https://github.com/genlayer"

2. Query the result (View Method)

Call get_verification("0"). It returns the following verification record JSON:

{
  "id": "0",
  "statement": "GenLayer is a blockchain Layer-1 that integrates AI at the consensus level.",
  "sources": "https://genlayer.com,https://github.com/genlayer",
  "verdict": "TRUE",
  "agreement_ratio": 100,
  "conflicting_sources": "None",
  "verifier": "0x58f3a56e32a9637e8bcd44ccaeae794508b9b25e"
}

Deploy on GenLayer Studio

  1. Open GenLayer Studio.
  2. Click "New Contract" or use the file explorer.
  3. Paste the contents of contracts/CrossSourceFactVerifier.py into the editor.
  4. Select network Studionet.
  5. Click "Deploy".
  6. Wait for deployment confirmation -- you should see the contract address.
  7. Test via the Studio UI:
    • Call verify_fact with a statement and comma-separated URLs.
    • Call get_verification with record_id = "0" to see the result.
    • Call get_stats to see aggregate counts.

Running Tests Locally

Prerequisites

  • Python 3.11+
  • genlayer-test package (gltest)

Install

pip install genlayer-test

Run

cd cross-source-fact-verifier
pytest tests/test_cross_source_fact_verifier.py -v

Test Coverage

  • Happy paths: TRUE, FALSE, UNVERIFIABLE verdicts
  • Edge cases: Empty statement, no URLs, single URL, nonexistent record
  • Stats tracking: Counters increment correctly across multiple verifications
  • Multiple verifications: Re-verifying updates stats properly

Submit to GenLayer Builder Portal

  1. Go to the GenLayer Builder Portal.
  2. Navigate to the Builder track, Intelligent Contracts category.
  3. Fill in the submission form:
    • Title: CrossSourceFactVerifier
    • Description: A decentralized fact-verification primitive that cross-references multiple independent web sources using AI consensus to determine statement truthfulness.
    • Repository: Link to your repo or upload the project files.
    • Contract file: contracts/CrossSourceFactVerifier.py
    • Test file: tests/test_cross_source_fact_verifier.py
  4. Submit and wait for review.

Project Structure

cross-source-fact-verifier/
  contracts/
    CrossSourceFactVerifier.py   # The intelligent contract
  tests/
    test_cross_source_fact_verifier.py  # Test suite with mocks
  README.md                      # This file

License

MIT

About

A decentralized fact-verification primitive for the GenLayer blockchain.

Resources

Stars

1 star

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages