PoW-Aligned Bitcoin Preconfirmation Receipts with Cryptographic Commitments
HashPledge provides verifiable preconfirmation receipts for Bitcoin transactions before they are mined. A miner service produces a signed secp256k1 commitment to include a specific transaction within a validity window, anchored to observed chain state. The system demonstrates both success (fulfilled) and failure (violated + slashing) paths end-to-end on Bitcoin regtest.
- Docker & Docker Compose (v2+)
bash,curl,jq(for demo scripts)
make upThis starts:
| Service | URL |
|---|---|
| Bitcoin Core (regtest) | localhost:18443 |
| Backend API (FastAPI) | http://localhost:8000 |
| Frontend UI (React) | http://localhost:5173 |
| API Docs (Swagger) | http://localhost:8000/docs |
# Run both success and failure scenarios
make demo
# Or individually
make demo-success
make demo-failuremake downMILESTONE 1: Equivocation Detection
Detects when a miner issues multiple conflicting receipts (double-pledging). Uses UTXO fingerprinting (SHA256 of sorted input outpoints) to identify conflicts. Both conflicting receipts are marked EQUIVOCATED and bonds are slashed.
MILESTONE 2: Reorg Handling
Detects when a receipt's anchor block is orphaned due to chain reorganization. Validates anchor via getblockhash(anchor_height) comparison. If the anchor is reorged out, the receipt is marked ANCHOR_REORGED and the bond is neutralized (released, not slashed) — because this isn't the miner's fault.
MILESTONE 3: Bond Capacity
Models finite bonding capacity (e.g., 100k sats from Lightning channels or fidelity bonds). Tracks available = capacity - reserved - slashed. When capacity is exhausted, new receipt requests are refused with HTTP 409 INSUFFICIENT_BOND (machine-readable error).
5 Interactive Scenarios:
- Success: Receipt issued, TX mined in window → FULFILLED, bond released
- Failure: Receipt issued, TX not broadcast → VIOLATED, bond slashed
- Equivocation: Two receipts for conflicting TXs → EQUIVOCATED, both bonds slashed
- Reorg: Anchor block invalidated → ANCHOR_REORGED, bond neutralized
- Capacity: Issue receipts until exhaustion → HTTP 409 refusal
- User creates a transaction intent (unsigned raw tx)
- Miner issues a preconfirmation receipt — a signed commitment to include the tx within N blocks
- Miner broadcasts the tx; blocks are mined
- Receipt verification confirms FULFILLED — bond is released
- User creates an intent
- Miner issues a receipt but does not broadcast (simulated noncompliance)
- Blocks are mined past the validity window
- Receipt verification detects VIOLATED — miner bond is slashed
├── docker-compose.yml # Full stack orchestration
├── Makefile # Build/run/demo/test commands
├── scripts/ # Deterministic demo scripts
│ ├── demo_success.sh
│ ├── demo_failure.sh
│ └── demo_all.sh
├── docs/ # Protocol & architecture docs
│ ├── PROTOCOL.md
│ ├── THREAT_MODEL.md
│ ├── ARCHITECTURE.md
│ └── DEVPOST.md
├── backend/ # FastAPI Python backend
│ ├── Dockerfile
│ ├── pyproject.toml
│ └── app/
│ ├── main.py
│ ├── core/ # Config, logging
│ ├── db/ # SQLite models & session
│ ├── bitcoin/ # RPC client & wallet mgmt
│ ├── preconfirm/ # Crypto, encoding, service
│ └── api/ # Route modules
├── frontend/ # Vite + React + TypeScript
│ ├── Dockerfile
│ └── src/
│ ├── api/ # Typed fetch wrappers
│ ├── components/ # UI panels
│ └── models/ # TypeScript types
└── tests/ # Backend pytest suite
| Command | Description |
|---|---|
make up |
Build and start all services |
make down |
Stop and remove all containers + volumes |
make demo |
Run success + failure demo scripts |
make test |
Run ALL tests (TypeScript → Backend with Dockerized bitcoind → Playwright E2E) |
make lint |
Run ruff + black + mypy |
make logs |
Tail all service logs |
make proof MILESTONE=<name> |
Generate proof pack with test results and evidence |
# Runs full constitutional test suite:
# 1. TypeScript compilation (tsc --noEmit)
# 2. Backend tests with Dockerized bitcoind (pytest)
# 3. Frontend E2E tests via Playwright MCP wrapper
make testExpected output: tsc --noEmit → 0 errors, pytest → failed=0 skipped=0, Playwright → failed=0 skipped=0 retries=0
# Creates artifacts/proofpacks/<milestone>_YYYYMMDD_HHMMSS/ with:
# - Test results (JUnit XML + Playwright JSON + HTML reports)
# - Screenshots, videos, traces
# - MANIFEST.md with test statistics table
# - Integration harness evidence (bitcoind logs)
make proof MILESTONE=integration-zero-skip# Run enforcement gates (automatically run by make test):
bash scripts/ci/enforce_constitution.shEnforces 6 constitutional rules:
- Zero Skipped Tests - All tests run with Dockerized dependencies
- Zero Retries - Playwright retries disabled
- Data-TestID Only - No text-based selectors
- Playwright-Only Frontend Testing - No vitest/jest in gates
- Determinism Proven - Fixed clock produces identical outputs
- E2E on Vite Preview Only - Tests run against production builds
# Save a receipt to a file, then verify offline:
cd backend
python -m app.verify --receipt path/to/receipt.json| Issue | Fix |
|---|---|
| Services won't start | Run make down then make up |
| Bitcoin RPC not ready | Wait 10s; backend retries automatically |
| Port conflict | Change ports in docker-compose.yml |
| Demo script fails | Ensure jq is installed: apt install jq |
- Bitcoin Core 24 — regtest mode, JSON-RPC
- FastAPI (Python 3.11) — async API server
- SQLite — persistence for receipts, intents, miner ledger
- secp256k1 — ECDSA signatures via
coincurve - React 18 + TypeScript + Vite — frontend UI
- Docker Compose — full orchestration
MIT — Hackathon prototype. Not for production use with real funds.