Skip to content

Kheshie1/solana-job-queue

Repository files navigation

Solana Job Queue

An on-chain job queue built as a Solana program using Anchor, demonstrating how a traditional backend job/task queue can be redesigned using Solana's account model with escrow-based payments.

Superteam Bounty Submission: Rebuild production backend systems as on-chain Rust programs

How This Works in Web2

A traditional backend job queue (think Bull, Celery, AWS SQS + Lambda) follows this architecture:

┌──────────┐     ┌──────────┐     ┌──────────┐     ┌──────────┐
│  Client   │────▶│  Queue   │────▶│  Worker  │────▶│ Database │
│  (API)    │     │ (Redis)  │     │ (Process)│     │ (Postgres)│
└──────────┘     └──────────┘     └──────────┘     └──────────┘

Components:

  • Message broker (Redis, RabbitMQ) holds jobs in FIFO order
  • Workers poll the queue, claim jobs via atomic pop
  • Database stores job state (pending, processing, completed, failed)
  • Escrow/payment handled by a separate billing service (Stripe, PayPal)
  • Dispute resolution requires manual human intervention + customer support

Weaknesses:

  • Payment and job execution are separate systems → trust required
  • State lives across 3+ services → consistency is hard
  • Worker identity is internal → no public accountability
  • Dispute resolution is off-chain and opaque

How This Works on Solana

The on-chain version collapses queue, database, escrow, and dispute resolution into a single Solana program:

┌──────────┐     ┌─────────────────────────────────┐     ┌──────────┐
│  Client   │────▶│     Solana Program (Job Queue)  │◀────│  Worker  │
│  Wallet   │     │                                 │     │  Wallet  │
└──────────┘     │  ┌─────────┐  ┌──────────────┐  │     └──────────┘
                 │  │ Counter │  │ Job PDA #0   │  │
                 │  │  PDA    │  │ (escrow +    │  │
                 │  │         │  │  state)      │  │
                 │  └─────────┘  ├──────────────┤  │
                 │               │ Job PDA #1   │  │
                 │               ├──────────────┤  │
                 │               │ Job PDA #N   │  │
                 │               └──────────────┘  │
                 └─────────────────────────────────┘

Key design decisions:

Account Model

  • JobCounter PDA (seeds = ["counter"]): Global singleton tracking total/open/completed counts. Auto-incrementing job IDs.
  • Job PDAs (seeds = ["job", job_id]): One account per job, storing all state + acting as the escrow vault.

Escrow Pattern

When a client creates a job, SOL is transferred directly into the Job PDA via CPI to the System Program. The PDA itself holds the reward funds. On approval, lamports are moved from the PDA to the worker. On cancel/dispute/expire, lamports return to the client.

This is an account-as-escrow pattern — no separate vault program needed.

State Machine

Open ──┬──▶ InProgress ──▶ PendingApproval ──┬──▶ Completed
       │                                     └──▶ Disputed
       └──▶ Cancelled
       
InProgress ──▶ Expired (if deadline passes)

Each transition is enforced by on-chain require!() checks. Only valid state transitions are permitted.

Tradeoffs & Constraints

Aspect Web2 Queue Solana Queue
Payment trust Requires external escrow service Built-in: SOL locked in PDA
Ordering FIFO guaranteed by broker No ordering — workers claim any open job
Throughput 100K+ jobs/sec (Redis) ~400 TPS (Solana block limit)
Cost per job ~$0 (infrastructure) ~0.003 SOL rent + tx fees
Privacy Job details are private All data is public on-chain
Dispute Manual customer support On-chain, auditable, instant refund
Worker identity Internal service accounts Public keys with on-chain history
Scalability Horizontal (add workers) Constrained by Solana account limits

When the on-chain version wins:

  • Cross-organization job markets (no trusted middleman)
  • Payment-critical workflows (escrow is atomic)
  • Audit/compliance (immutable execution log)
  • Agent-to-agent economies (both parties are programs)

When Web2 wins:

  • High-throughput internal queues
  • Jobs with private/sensitive data
  • Sub-second latency requirements

Architecture

Instructions (7 total)

  1. initialize_counter — One-time setup for the global job counter PDA
  2. create_job — Client posts a job with title, description, reward (SOL), and deadline. Reward is escrowed in the Job PDA.
  3. claim_job — Worker claims an open job before the deadline
  4. submit_result — Worker submits a result URI (link to deliverable)
  5. approve_result — Client approves, releasing escrowed SOL to worker
  6. cancel_job — Client cancels an unclaimed job, getting a refund
  7. dispute_result — Client disputes a submitted result, getting a refund
  8. expire_job — Client reclaims funds from an expired in-progress job

Events

All state transitions emit events (JobCreated, JobClaimed, ResultSubmitted, JobCompleted, JobCancelled, JobDisputed, JobExpired) for off-chain indexing.

Error Handling

Custom error codes for every invalid state transition, with descriptive messages.

Project Structure

solana-job-queue/
├── programs/solana-job-queue/src/
│   └── lib.rs              # Anchor program (instructions, accounts, state, events, errors)
├── tests/
│   └── solana-job-queue.ts  # Integration tests (7 test cases)
├── cli/
│   └── job-queue.ts         # TypeScript CLI client
├── .github/workflows/
│   └── ci.yml               # GitHub Actions CI (build + test)
├── Anchor.toml
└── README.md

Getting Started

Prerequisites

  • Rust & Cargo
  • Solana CLI (v1.18+)
  • Anchor CLI (v0.30+)
  • Node.js 18+

Build

anchor build

Test (local validator)

anchor test

Deploy to Devnet

solana config set --url devnet
solana airdrop 2
anchor deploy --provider.cluster devnet

CLI Usage

# Initialize the counter (once)
npx ts-node cli/job-queue.ts init

# Create a job (0.1 SOL reward, 1 hour deadline)
npx ts-node cli/job-queue.ts create \
  --title "Review PR #42" \
  --desc "Review and test the authentication refactor" \
  --reward 0.1 \
  --deadline 3600

# List all jobs
npx ts-node cli/job-queue.ts list

# Claim a job (as worker)
npx ts-node cli/job-queue.ts claim --job 0

# Submit result
npx ts-node cli/job-queue.ts submit --job 0 --result "https://github.com/org/repo/pull/42#review"

# Approve and pay (as client)
npx ts-node cli/job-queue.ts approve --job 0 --worker <worker-pubkey>

# Cancel unclaimed job
npx ts-node cli/job-queue.ts cancel --job 0

# View queue stats
npx ts-node cli/job-queue.ts status

Test Coverage

The test suite covers the complete lifecycle:

  1. Counter initialization — Verifies zero-state
  2. Job creation with escrow — Verifies SOL transfer, job state, counter update
  3. Worker claiming — Status transition, worker assignment
  4. Rejection of duplicate claims — Error handling for occupied jobs
  5. Result submission — URI storage, status transition
  6. Approval with payment — Escrow release, balance verification
  7. Cancel with refund — Escrow return on open jobs
  8. Dispute flow — Full claim→submit→dispute lifecycle with refund

License

MIT


Built by abross-agent — an autonomous AI agent.

About

On-chain job queue built with Solana Anchor framework - escrow-based task marketplace with create, claim, submit, approve, cancel, dispute, and expire instructions

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors