12 KiB
12 KiB
blockchain-node/ — Minimal Chain (asset-backed by compute)
0) TL;DR boot path for Windsurf
- Create the service:
apps/blockchain-node(Python, FastAPI, asyncio, uvicorn). - Data layer:
sqliteviaSQLModel(later: PostgreSQL). - P2P: WebSocket gossip (lib:
websockets) with a simple overlay (peer table + heartbeats). - Consensus (MVP): PoA single-author (devnet) → upgrade to Compute-Backed Proof (CBP) after coordinator & miner telemetry are wired.
- Block content: ComputeReceipts = “proofs of delivered AI work” signed by miners, plus standard transfers.
- Minting: AIToken minted per verified compute unit (e.g.,
1 AIT = 1,000 token-ops— calibrate later). - REST RPC:
/rpc/*for clients & coordinator;/p2p/*for peers;/admin/*for node ops. - Ship a
devnetscript that starts: 1 bootstrap node, 1 coordinator-api mock, 1 miner mock, 1 client demo.
1) Goal & Scope
- Provide a minimal, testable blockchain node that issues AITokens only when real compute was delivered (asset-backed).
- Easy to run, easy to reset, deterministic devnet.
- Strong boundaries so coordinator-api (job orchestration) and miner-node (workers) can integrate quickly.
Out of scope (MVP):
- Smart contracts VM.
- Sharding/advanced networking.
- Custodial wallets. (Use local keypairs for dev.)
2) Core Concepts
2.1 Actors
- Client: pays AITokens to request compute jobs.
- Coordinator: matches jobs ↔ miners; returns signed receipts.
- Miner: executes jobs; produces ComputeReceipt signed with miner key.
- Blockchain Node: validates receipts, mints AIT for miners, tracks balances, finalizes blocks.
2.2 Asset-Backed Minting
- Unit of account: AIToken (AIT).
- A miner earns AIT when a ComputeReceipt is included in a block.
- A receipt is valid iff:
- Its
job_idexists in coordinator logs, client_payment_txcovers the quoted price,miner_sigover(job_id, hash(output_meta), compute_units, price, nonce)is valid,- Not previously claimed (
receipt_idunique).
- Its
3) Minimal Architecture
blockchain-node/
├─ src/
│ ├─ main.py # FastAPI entry
│ ├─ p2p.py # WS gossip, peer table, block relay
│ ├─ consensus.py # PoA/CBP state machine
│ ├─ types.py # dataclasses / pydantic models
│ ├─ state.py # DB access (SQLModel), UTXO/Account
│ ├─ mempool.py # tx pool (transfers + receipts)
│ ├─ crypto.py # ed25519 keys, signatures, hashing
│ ├─ receipts.py # receipt validation (with coordinator)
│ ├─ blocks.py # block build/verify, difficulty stub
│ ├─ rpc.py # REST/RPC routes for clients & ops
│ └─ settings.py # env config
├─ tests/
│ └─ ... # unit & integration tests
├─ scripts/
│ ├─ devnet_up.sh # run bootstrap node + mocks
│ └─ keygen.py # create node/miner/client keys
├─ README.md
└─ requirements.txt
4) Data Model (SQLModel)
4.1 Tables
blocks(id, parent_id, height, timestamp, proposer, tx_count, hash, state_root, sig)tx(id, block_id, type, payload_json, sender, nonce, fee, sig, hash, status)accounts(address, balance, nonce, pubkey)receipts(receipt_id, job_id, client_addr, miner_addr, compute_units, price, output_hash, miner_sig, status)peers(node_id, addr, last_seen, score)params(key, value)— chain config (mint ratios, fee rate, etc.)
4.2 TX Types
TRANSFER: move AIT from A → BRECEIPT_CLAIM: include a ComputeReceipt; mints to miner and settles client escrowSTAKE/UNSTAKE(later)PARAM_UPDATE(PoA only, gated by admin key for devnet)
5) Block Format (JSON)
{
"parent": "<block_hash>",
"height": 123,
"timestamp": 1699999999,
"proposer": "<node_address>",
"txs": ["<tx_hash>", "..."],
"stateRoot": "<merkle_root_after_block>",
"sig": "<proposer_signature_over_header>"
}
Header sign bytes = hash(parent|height|timestamp|proposer|stateRoot)
6) Consensus
6.1 MVP: PoA (Single Author)
- One configured
PROPOSER_KEYcreates blocks at fixed interval (e.g., 2s). - Honest mode only for devnet; finality by canonical longest/height rule.
6.2 Upgrade: Compute-Backed Proof (CBP)
- Each block’s work score = total
compute_unitsin included receipts. - Proposer election = weighted round-robin by recent work score and stake (later).
- Slashing: submitting invalid receipts reduces score; repeated offenses → temp ban.
7) Receipt Validation (Coordinator Check)
receipts.py performs:
- Coordinator attestation (HTTP call to coordinator-api):
/attest/receiptwithjob_id,client,miner,price,compute_units,output_hash.- Returns
{exists: bool, paid: bool, not_double_spent: bool, quote: {...}}.
- Signature check: verify
miner_sigwith miner’spubkey. - Economic checks: ensure
client_payment_txexists & coversprice + fee.
For devnet without live coordinator, ship a mock that returns deterministic attestation for known
job_idranges.
8) Fees & Minting
- Fee model (MVP):
fee = base_fee + k * payload_size. - Minting:
- Miner gets:
mint = compute_units * MINT_PER_UNIT. - Coordinator gets:
coord_cut = mint * COORDINATOR_RATIO. - Chain treasury (optional): small %, configurable in
params.
- Miner gets:
9) RPC Surface (FastAPI)
9.1 Public
POST /rpc/sendTx→{txHash}GET /rpc/getTx/{txHash}→{status, receipt}GET /rpc/getBlock/{heightOrHash}GET /rpc/getHead→{height, hash}GET /rpc/getBalance/{address}→{balance, nonce}POST /rpc/estimateFee→{fee}
9.2 Coordinator-facing
POST /rpc/submitReceipt(alias ofsendTxwith typeRECEIPT_CLAIM)POST /rpc/attest(devnet mock only)
9.3 Admin (devnet)
POST /admin/paramSet(PoA only)POST /admin/peers/add{addr}POST /admin/mintFaucet{address, amount}(devnet)
9.4 P2P (WS)
GET /p2p/peers→ listWS /p2p/ws→ subscribe to gossip:{"type":"block"|"tx"|"peer","data":...}
10) Keys & Crypto
- ed25519 for account & node keys.
- Address =
bech32(hrp="ait", sha256(pubkey)[0:20]). - Sign bytes:
- TX:
hash(type|sender|nonce|fee|payload_json_canonical) - Block: header hash as above.
- TX:
Ship scripts/keygen.py for dev use.
11) Mempool Rules
- Accept if:
sigvalid,nonce == account.nonce + 1,fee >= minFee,- For
RECEIPT_CLAIM: passesreceipts.validate()optimistically (soft-accept), then revalidate at block time.
Replacement: higher-fee replaces same (sender, nonce).
12) Node Lifecycle
Start:
- Load config, open DB, ensure genesis.
- Connect to bootstrap peers (if any).
- Start RPC (FastAPI) + P2P WS server.
- Start block proposer (if PoA key present).
- Start peer heartbeats + gossip loops.
Shutdown:
- Graceful: flush mempool snapshot, close DB.
13) Genesis
genesis.json:chain_id,timestamp,accounts(faucet),params(mint ratios, base fee),authorities(PoA keys).
Provide scripts/make_genesis.py.
14) Devnet: End-to-End Demo
14.1 Components
- blockchain-node (this repo)
- coordinator-api (mock):
/attest/receiptreturns valid forjob_idin[1..1_000_000] - miner-node (mock): posts
RECEIPT_CLAIMfor synthetic jobs - client-web (demo): sends
TRANSFER& displays balances
14.2 Flow
- Client pays
priceto escrow address (coordinator). - Miner executes job; coordinator verifies output.
- Miner submits ComputeReceipt → included in next block.
- Mint AIT to miner; escrow settles; client charged.
15) Testing Strategy
15.1 Unit
crypto: keygen, sign/verify, address derivationstate: balances, nonce, persistencereceipts: signature + coordinator mockblocks: header hash, stateRoot
15.2 Integration
- Single node PoA: produce N blocks; submit transfers/receipts; assert balances.
- Two nodes P2P: block/tx relay; head convergence.
15.3 Property tests
- Nonce monotonicity; no double-spend; unique receipts.
16) Observability
- Structured logs (JSON) with
component,event,height,latency_ms. /rpc/metrics(Prometheus format) — block time, mempool size, peers.
17) Configuration (ENV)
CHAIN_ID=ait-devnetDB_PATH=./data/chain.dbP2P_BIND=0.0.0.0:7070RPC_BIND=0.0.0.0:8080BOOTSTRAP_PEERS=ws://host:7070,...PROPOSER_KEY=...(optional for non-authors)MINT_PER_UNIT=1000COORDINATOR_RATIO=0.05
Provide .env.example.
18) Minimal API Payloads
18.1 TRANSFER
{
"type": "TRANSFER",
"sender": "ait1...",
"nonce": 1,
"fee": 10,
"payload": {"to":"ait1...","amount":12345},
"sig": "<ed25519>"
}
18.2 RECEIPT_CLAIM
{
"type": "RECEIPT_CLAIM",
"sender": "ait1miner...",
"nonce": 7,
"fee": 50,
"payload": {
"receipt_id": "rcpt_7f3a...",
"job_id": "job_42",
"client_addr": "ait1client...",
"miner_addr": "ait1miner...",
"compute_units": 2500,
"price": 50000,
"output_hash": "sha256:abcd...",
"miner_sig": "<sig_over_core_fields>"
},
"sig": "<miner_account_sig>"
}
19) Security Notes (MVP)
- Devnet PoA means trust in proposer; do not expose to internet without firewall.
- Enforce coordinator host allowlist for attest calls.
- Rate-limit
/rpc/sendTx.
20) Roadmap
- ✅ PoA devnet with receipts.
- 🔜 CBP proposer selection from rolling work score.
- 🔜 Stake & slashing.
- 🔜 Replace SQLite with PostgreSQL.
- 🔜 Snapshots & fast-sync.
- 🔜 Light client (SPV of receipts & balances).
21) Developer Tasks (Windsurf Order)
-
Scaffold project &
requirements.txt:fastapi,uvicorn[standard],sqlmodel,pydantic,websockets,pyyaml,python-dotenv,ed25519,orjson.
-
Implement:
crypto.py,types.py,state.py.rpc.py(public routes).mempool.py.blocks.py(build/validate).consensus.py(PoA tick).p2p.py(WS server + simple gossip).receipts.py(mock coordinator).
-
Wire
main.py:- Start RPC, P2P, PoA loops.
-
Scripts:
scripts/keygen.py,scripts/make_genesis.py,scripts/devnet_up.sh.
-
Tests:
- Add unit + an integration test that mints on a receipt.
-
Docs:
- Update
README.mdwith curl examples.
- Update
22) Curl Snippets (Dev)
- Faucet (dev only):
curl -sX POST localhost:8080/admin/mintFaucet -H 'content-type: application/json' \
-d '{"address":"ait1client...","amount":1000000}'
- Transfer:
curl -sX POST localhost:8080/rpc/sendTx -H 'content-type: application/json' \
-d @transfer.json
- Submit Receipt:
curl -sX POST localhost:8080/rpc/submitReceipt -H 'content-type: application/json' \
-d @receipt_claim.json
23) Definition of Done (MVP)
- Node produces blocks on PoA.
- Can transfer AIT between accounts.
- Can submit a valid ComputeReceipt → miner balance increases; escrow decreases.
- Two nodes converge on same head via P2P.
- Basic metrics exposed.
24) Next Files to Create
src/main.pysrc/crypto.pysrc/types.pysrc/state.pysrc/mempool.pysrc/blocks.pysrc/consensus.pysrc/p2p.pysrc/receipts.pysrc/rpc.pyscripts/keygen.py,scripts/devnet_up.sh.env.example,README.md,requirements.txt