VitoCoin — Complete Technical Disclosure
Full Architecture
1.1 Frontend
Framework: None. The entire frontend is a single vanilla JavaScript file — /app.html (≈3,100 lines). No React, Vue, Angular, or bundler.
- Language: Vanilla HTML/CSS/JavaScript (ES2020+, no transpiler)
- Entry point:
/home/user/app/app.html— served directly by Vercel as a static file - State management: Module-level JS variables +
localStoragefor session persistence (wallets, active address, cached balance) - Routing:
history.pushState— path-based page switching, no SPA framework - Rendering: DOM manipulation via
innerHTMLandgetElementById— no virtual DOM - Real-time:
EventSource(SSE) connected to/api/node/events; fallback polling every 30 s - Auth: Supabase JS SDK (
@supabase/supabase-js) via CDN script tag - PWA:
/manifest.json+/sw.jsservice worker, offline page, install banner
1.2 Backend / Node Server
Framework: Python standard library http.server.BaseHTTPRequestHandler. No Flask, FastAPI, or Django.
- Language: Python 3.10+
- API server:
api.py—ThreadingHTTPServer, one thread per request - P2P network:
network.py— asyncio event loop + raw TCP sockets, port 6334 - Miner:
miner.py— Pythonthreading.Threadper CPU core, SHA-256d in Pythonhashlib - Blockchain core:
blockchain.py,block.py,transaction.py,script.py,utxo.py - Storage:
store.py— SQLite via Pythonsqlite3 - Deployment:
systemdservice (vitocoin.service,Restart=always), one service per VPS
1.3 Blockchain
- Type: Custom clean-room implementation — not a fork of Bitcoin Core, Litecoin, or any existing chain
- Architecture: UTXO (Unspent Transaction Output) — identical model to Bitcoin
- Consensus: SHA-256d Proof-of-Work, heaviest cumulative chain work rule
- Smart contracts: None — basic P2PKH (Pay-to-Public-Key-Hash) scripts only
- Core logic files:
blockchain.py(chain),block.py(structure + PoW),transaction.py(UTXO logic),utxo.py(UTXO set),network.py(P2P),miner.py(mining),api.py(REST + SSE)
1.4 Vercel Proxy Layer
- Platform: Vercel (static + serverless proxy)
- Project:
vito-coin-v2 - Frontend: Static files served from
/home/user/app/(GitHub repo root) - Proxy routes:
/api/node/*→ Node1 (195.114.193.73:6333),/api/node2/*→ Node2 (213.139.77.18:6333),/api/node3/*→ Node3 (84.201.20.90:6333)
1.5 Folder Structure (important files)
/home/user/app/ ← Vercel deploy root app.html ← Entire frontend (~3,100 lines, vanilla JS) whitepaper.html ← Investor whitepaper api-docs.html ← Interactive API documentation tech-disclosure.html ← This document manifest.json ← PWA manifest sw.js ← Service worker (caching + offline) vercel.json ← Routing rules + proxy config features-p1.js / features-p2.js ← Lazy-loaded feature modules (charts, etc.) /opt/vitocoin/vitocoin/ ← On each VPS node main.py ← Entry point (CLI args, service init) blockchain.py ← Chain state, tip tracking, block acceptance block.py ← Block structure, header serialisation, PoW validation transaction.py ← TX parsing, validation, coinbase check utxo.py ← UTXO set management, balance queries network.py ← P2P TCP, peer handshake, sync protocol miner.py ← CPU mining threads, nonce iteration api.py ← HTTP REST API + SSE /events endpoint store.py ← SQLite persistence layer script.py ← P2PKH script execution wallet.py ← Key derivation (BIP-44), address encoding /opt/vitocoin/vitocoin/chaindata/ chainstore.db ← SQLite database (blocks, UTXOs, metadata)
Blockchain Engine
2.1 Block Creation
Blocks are created by the miner process on each node. When the miner finds a valid nonce, it assembles the block from the candidate template and calls chain.accept_block(block). The process:
- Collect pending transactions from the mempool (currently always empty → coinbase only)
- Build a coinbase transaction paying 50 VITO to the configured wallet address
- Compute Merkle root of all transaction TXIDs (single-element tree = coinbase TXID)
- Assemble 80-byte block header:
version ∥ prev_hash ∥ merkle_root ∥ timestamp ∥ bits ∥ nonce - Iterate nonce 0–4,294,967,295 until
SHA256d(header) < target - On valid nonce: persist block to SQLite, update UTXO set, relay to all peers via P2P
2.2 Mining Algorithm — SHA-256d
Identical to Bitcoin's Proof-of-Work algorithm:
block_hash = SHA256( SHA256( version[4] ∥ prev_hash[32] ∥ merkle_root[32]
∥ timestamp[4] ∥ bits[4] ∥ nonce[4] ) )
# All fields little-endian (Bitcoin byte order)
# valid when: int.from_bytes(block_hash, 'big') < target
2.3 Target Derivation from bits
The compact bits field encodes the target in Bitcoin's standard format:
bits = 0x1d00ffff (genesis difficulty, also current difficulty)
exponent = (bits >> 24) & 0xFF = 0x1d = 29
mantissa = bits & 0x00FFFFFF = 0x00ffff
target = mantissa × 2^(8 × (exponent − 3))
= 0x00ffff × 2^(8 × 26)
= 0x00000000ffff0000000000000000000000000000000000000000000000000000
# In decimal:
target = 26959535291011309493156476344723991336010898738574164086137773096960
2.4 Difficulty Formula
Difficulty retargets every 2,016 blocks (~2 weeks at 10-min target). No retarget has occurred yet (chain is at height 10):
expected_time = 600 × 2016 = 1,209,600 seconds actual_time = block[2016].ts − block[0].ts # Anti-manipulation clamp: actual_time = max(expected_time / 4, min(actual_time, expected_time × 4)) new_target = old_target × (actual_time / expected_time) new_target = min(new_target, genesis_target) # floor — difficulty never drops below 1.0 current_difficulty = genesis_target / current_target
Current: difficulty = 1.0, bits = 0x1d00ffff (genesis minimum — no retarget yet)
2.5 Validation Logic Location
All validation happens in blockchain.py → accept_block() and block.py → validate():
block.validate_pow()— SHA256d(header) < target from bitsblock.validate_merkle()— recompute Merkle root, compare to header fieldblockchain.py— height continuity, coinbase reward check, UTXO input validationutxo.py— every non-coinbase input must reference an existing unspent outputscript.py— input script must satisfy output script (P2PKH signature check)
2.6 Sample Block JSON — Block #10 (most recent)
{
"hash": "00000000e060cafcd66eb2a4425a5e52a1490fbf6eec4af8ebf1fd94a77528de",
"height": 10,
"header": {
"version": 2,
"prev_hash": "000000003c218be4e1c22268a5ef00ecc468d56313126ba94240c795c4bd62cb",
"merkle_root": "0f30bb164cbfc0db676d47cef352992ab543e8c349fd00fa1d566d7c1e121e9e",
"timestamp": 1775706303,
"bits": 486604799,
"bits_hex": "1d00ffff",
"nonce": 3242755474,
"difficulty": 1.0
},
"tx_count": 1,
"size": 177,
"work": "4295032833",
"transactions": [
{
"txid": "0f30bb164cbfc0db676d47cef352992ab543e8c349fd00fa1d566d7c1e121e9e",
"version": 2,
"locktime": 0,
"is_coinbase": true,
"inputs": [
{"prev_txid": "0000000000000000000000000000000000000000000000000000000000000000",
"prev_index": 4294967295}
],
"outputs": [
{"value": 5000000000, "value_vito": 50.0,
"script_pubkey": "76a914e75a382381dfe9049ce8bce1f5842058d096f03388ac"}
],
"size": 97
}
]
}
2.7 PoW Verification — 3 Consecutive Blocks
Verification method: Python hashlib.sha256(hashlib.sha256(header_bytes).digest()).digest() with header fields serialised as little-endian uint32 (Bitcoin byte order). All three blocks independently confirmed valid.
Node System
3.1 Node Inventory (live at time of report)
All 3 nodes confirmed identical: height=10, chain_work=47245361163, best_hash=00000000e060cafcd66e… — verified live via direct HTTP at time of writing.
3.2 Node Sync Protocol
Sync follows Bitcoin's headers-first protocol over TCP (port 6334), with JSON-encoded messages instead of Bitcoin's binary wire format:
- Connection: TCP connect to peer IP:6334. Magic bytes:
0x56 0x49 0x54 0x4F("VITO") prefix each message frame. - Handshake:
versionmessage (includes node height, user-agent, timestamp) → peer replies withversion+verack→ sender repliesverack - Sync: If peer reports higher height in version message, send
getheaders(with current tip hash) → peer replies with up to 2,000 block headers → sender validates each header's PoW → sendsgetdatafor each missing block → peer sends full blocks - Accept: Each received block passes full validation in
accept_block(). On success: persisted, UTXO set updated, relayed to other peers. - Transaction relay:
invmessage announces TX hash → peer sendsgetdataif unseen → TX sent → validated and added to mempool - Periodic resync: Every 10 seconds the node requests headers from all peers reporting a higher height (fallback for missed events)
3.3 Conflict Resolution (Fork Handling)
Fork resolution uses Bitcoin's canonical heaviest cumulative chain work rule, not longest chain:
canonical_chain = chain with max( sum(difficulty) for all blocks from genesis )
- If a peer presents a chain with higher cumulative work: switch to that chain (reorganise)
- Reorganisation: walk back to common ancestor, undo UTXOs for orphaned blocks, apply UTXOs for new chain blocks
- Orphaned transactions re-enter the mempool
- Currently no reorg has occurred (single-chain history, all nodes mining to same canonical chain)
3.4 Peer Discovery
- Hardcoded seeds: Each node has the other two nodes' IPs hardcoded in
network.py → SEED_NODES - Address exchange:
getaddr/addrmessages — nodes share up to 1,000 known peer addresses - Reconnect: Outbound reconnect with exponential backoff on disconnect
Mining System
Mining is REAL. SHA-256d double-hashing runs on actual server CPU threads. The nonces in mined blocks are genuinely computed, not generated randomly or simulated. All 11 blocks (0–10) were found through real PoW computation, verified independently in this report.
4.1 Where Hashing Happens
| Location | Status | Details |
|---|---|---|
| Browser (WebWorker) | NOT USED | No browser-side mining. The frontend app has a "Mining" page for UX, but it displays server-side stats from the API — it does not perform SHA-256d computation. |
| Server (VPS CPU threads) | REAL | Python miner.py runs N threads per node, each iterating nonces. Uses Python hashlib.sha256 (C extension — not pure Python). |
| Pool (Stratum) | NOT IMPLEMENTED | No mining pool or Stratum protocol. Planned Phase 2. Currently all 3 nodes mine independently as solo miners to the same wallet address. |
4.2 Mining Architecture
- Thread model: Each node spawns N independent Python threads (Node 1: 8, Nodes 2 & 3: 4)
- Nonce space partitioning: Each thread works a different starting nonce offset to avoid duplicate work
- Timestamp updates: Template refreshed every ~30 seconds and on each new block from network
- Candidate block: Pre-built header template refreshed on each
accept_block()call; each thread hashes the template with varying nonce - Extra nonce: Field present but currently
extra_nonce=0— not incremented (nonce space of 4.3 billion is sufficient at current low difficulty) - Block relay on find: Immediately calls
accept_block()then broadcasts to all connected peers via P2P - Wallet: All three nodes mine to
Sovereign Founder Wallet — re-keyed Apr 12 2026 (see §3b transparency report)(admin wallet)
4.3 Live Hashrate at Time of Report
| Node | Threads | Hashrate | Total Hashes (session) |
|---|---|---|---|
| Node 1 (Frankfurt) | 8 | ~184 KH/s | 130,159,246 |
| Node 2 (Moscow) | 4 | ~388 KH/s | 276,421,811 |
| Node 3 (Moscow) | 4 | ~330 KH/s | 78,890,777 |
| Combined | 16 | ~902 KH/s | — |
At current difficulty (1.0) and combined hashrate (~900 KH/s), the expected time per block is:
expected_hashes_per_block = 2^32 / 1.0 ≈ 4,294,967,296 time_per_block ≈ 4,294,967,296 / 902,000 ≈ 4,762 seconds (~79 minutes) # Note: blocks 0–10 were mined at difficulty 1.0 # Target block time is 600 seconds (10 minutes) # Current hashrate is insufficient to hit 10-min targets — addressed in Known Limitations
4.4 Shares / Pool
No pool protocol exists. Each node is a solo miner. When any node finds a block, it broadcasts to peers who verify and add to their chain. There is no share accounting, no pool fee, no vardiff.
Real-Time System (SSE)
5.1 Protocol
Protocol: Server-Sent Events (SSE) — HTTP 1.1 persistent connection with Content-Type: text/event-stream. Not WebSocket.
- Transport: HTTP/1.1 chunked transfer encoding, persistent keep-alive
- Direction: Server → client only (one-way push)
- Reconnect: Browser/client auto-reconnects on disconnect via
EventSourceAPI; frontend adds exponential backoff (2s → 4s → 8s → max 30s)
5.2 SSE Endpoint
# Direct node access: http://195.114.193.73:6333/events http://213.139.77.18:6333/events http://84.201.20.90:6333/events # Via Vercel proxy (HTTPS, production): https://vitocoin.com/api/node/events # Terminal test: curl -N https://vitocoin.com/api/node/events
5.3 Event Types
| Event name | Frequency | Description |
|---|---|---|
block | ~1 second | Full chain state snapshot. When height increments vs previous event, a new block was mined. |
mempool | On change | Fires when unconfirmed transaction count changes. Payload same as block event. |
ping | ~1 second | Heartbeat to prevent proxy/browser timeouts. Payload same as block event. |
Note: There is no new_transaction or balance_update event type. The block event carries full chain state; clients must diff height to detect new blocks, and re-query /balance/:addr on new block to update balances.
5.4 Live Event Payload (captured from production)
event: block
data: {"height":10,"best_hash":"00000000e060cafcd66eb2a4425a5e52a1490fbf6eec4af8ebf1fd94a77528de",
"difficulty":1.0,"peers":4,"mempool":0,"supply_vito":550.0,"block_reward":50.0,
"next_halving":209990,"miner":{"mining":true,"hashrate":"184.81 KH/s",
"hashrate_hps":184814.72,"blocks_found":0},"ts":1775728380}
event: ping
data: {"height":10,"best_hash":"00000000e060cafcd66eb2a4425a5e52a1490fbf6eec4af8ebf1fd94a77528de",
"difficulty":1.0,"peers":4,"mempool":0,"supply_vito":550.0,"block_reward":50.0,
"next_halving":209990,"miner":{"mining":true,"hashrate":"186.29 KH/s",
"hashrate_hps":186293.33,"blocks_found":0},"ts":1775728381}
5.5 Frontend Integration
// app.html — SSE engine
const es = new EventSource('https://vitocoin.com/api/node/events');
es.addEventListener('block', (e) => {
const d = JSON.parse(e.data);
if (d.height > _sseLastHeight) {
_sseLastHeight = d.height;
refreshBalances(); // re-query /balance/:addr
loadOverviewTxs(); // reload transaction history
addNotification('success', `Block #${d.height} mined`);
}
// Update status bar: height, peers, difficulty, hashrate
});
es.onerror = () => {
es.close();
_sseRetryDelay = Math.min(_sseRetryDelay * 2, 30000);
setTimeout(_connectSSE, _sseRetryDelay);
};
Database
6.1 Blockchain Database
Type: SQLite via Python sqlite3. File: /opt/vitocoin/vitocoin/chaindata/chainstore.db. Current size: ~28 KB (11 blocks).
Schema: a single key-value table with binary keys and values:
CREATE TABLE kv (
key BLOB PRIMARY KEY,
value BLOB
);
Data is stored via key prefix convention:
| Key prefix | What is stored | Example |
|---|---|---|
B: | Block by height → serialised block object | B:10 → full Block #10 |
b: | Block header by hash → block height | b:00000000e060… → 10 |
T: | Transaction by TXID → block height + index | T:0f30bb… → (10, 0) |
u: | UTXO set — key: txid+vout index → value: amount, script, height, coinbase | u:0f30bb…:0 → 5000000000 sats |
x: | Address → list of UTXO references (for fast balance lookup) | x:VNSvE8rH… → [(txid,idx), …] |
m: | Metadata scalars | m:tip_hash, m:height, m:chain_work |
6.2 What is Stored
- Blocks: Full block objects (header + all transactions) stored in
B:andb:namespaces - Transactions: Indexed by TXID in
T:for fast lookup by explorer - UTXOs (balances): Every unspent output is in
u:. Balance = sum ofvaluefields for UTXOs with script matching address. No separate balance table. - Address index:
x:maps each address to its UTXO references (built on-the-fly as blocks accepted) - Metadata:
m:tip_hash,m:height,m:chain_work— loaded at startup to restore chain state
6.3 Auth Database (separate)
Type: Supabase (PostgreSQL). URL: https://pjhhurgivuptqeulsqty.supabase.co
Stores only user authentication data and wallet metadata — NOT blockchain data:
| Table | Columns | Purpose |
|---|---|---|
auth.users | id, email, encrypted_password, … | Managed by Supabase Auth — email/password users |
wallets | id, user_id, address, label (JSON) | Maps Supabase user ↔ VITO wallet addresses. Balances NOT stored here — queried live from blockchain node. |
6.4 Blockchain ↔ Database Sync
There is no sync to maintain. They are two independent systems:
- Blockchain balances are always queried live from
/balance/:addresswhich reads the UTXO set directly - Supabase only stores which address belongs to which user — never cached balances
- There is no risk of stale balance data; every balance shown in the UI is a real-time query to the node
Auth System
7.1 Auth Provider
Provider: Supabase Auth (managed PostgreSQL + JWT). Not a custom auth system.
- Method: Email + password
- Token type: JWT (RS256 signed by Supabase)
- Session storage:
localStorage— Supabase SDK persists the access token and refresh token automatically - Session refresh: Supabase SDK auto-refreshes JWT before expiry in background
- Anon key: Public key used in frontend for read-only Supabase table access — not a secret
7.2 Session Handling Flow
// 1. App opens
init() {
loadWallets(); // Read wallets from localStorage (instant, no network)
showPage('home'); // Render UI immediately from cached state
// 2. Auth check runs IN BACKGROUND after UI is visible
checkAuth() {
const session = await supabase.auth.getSession(); // reads localStorage JWT
if (!session) { showLoginModal(); return false; }
// Validate JWT against Supabase (single HTTP call, ~200ms)
// On success: fetch user's wallet addresses from 'wallets' table
// Cache wallet data in localStorage
return true;
}
// 3. SSE starts after auth resolves
_connectSSE();
}
7.3 Why "Loading…" Appeared (historical)
Previously, the init function called checkAuth() before showPage(). The 200–400ms JWT validation round-trip caused the UI to show "Loading…" until auth resolved. This was fixed: the UI now renders from localStorage cache immediately, and auth runs in the background with a 4-second timeout fallback. The "Loading…" state no longer blocks interaction.
7.4 Auth Does NOT Affect Blockchain
Auth is purely a frontend gate for the web app. The node APIs (/api/node/*) have no authentication — they are fully public. Any blockchain data (blocks, transactions, balances) can be queried without a user account.
Transaction System
8.1 Model: UTXO (Unspent Transaction Output)
VitoCoin uses the UTXO model — identical to Bitcoin. There is no account model, no global balance counter, and no smart contract state.
- Every transaction consumes one or more UTXOs (inputs) and creates one or more new UTXOs (outputs)
- Balance of an address = sum of all unspent outputs locked to that address's public key hash
- Change outputs: if input value exceeds payment amount, sender creates a change output back to themselves
- Currently only coinbase transactions exist on-chain (mining rewards). No user-to-user transfers have been executed yet.
8.2 Double-Spend Prevention
Two layers of protection:
- Mempool check: When a new transaction arrives at a node, all input UTXOs are checked against (a) the confirmed UTXO set and (b) the mempool. A UTXO already spent in any mempool transaction is rejected (
"double spend detected"). - Block validation check: When a block is proposed,
accept_block()re-validates every input UTXO against the current confirmed UTXO set. Any input referencing an already-spent output causes the entire block to be rejected.
The canonical UTXO set (stored in u: keys) is the authoritative source. An output is spent when it is consumed by a confirmed transaction in a confirmed block — not when it enters the mempool.
8.3 Confirmation Tracking
confirmations = chain.height - tx_block_height + 1 # Example: TX in block #10, current chain height = 10 confirmations = 10 - 10 + 1 = 1 # A TX in block #8: confirmations = 10 - 8 + 1 = 3
- Coinbase maturity: Coinbase outputs (mining rewards) require 100 confirmations before they can be spent. This is hardcoded:
COINBASE_MATURITY = 100. At current height 10, no coinbase output is yet mature. - Standard confirmation recommendation: 6 confirmations for user transactions (same as Bitcoin)
- The explorer shows
confirmationsfor each transaction in the block detail view
8.4 Transaction Broadcast
# POST /tx/send
{"raw_tx": "<hex-encoded signed transaction>"}
# Response (accepted):
{"txid": "abc123...", "status": "accepted"}
# Response (rejected):
{"error": "double spend detected", "code": 400}
On acceptance, the node adds the TX to its mempool and relays to all peers via P2P inv/getdata exchange.
8.5 Script System
Only P2PKH (Pay-to-Public-Key-Hash) scripts are implemented:
# Output (locking) script: OP_DUP OP_HASH160 <pubKeyHash> OP_EQUALVERIFY OP_CHECKSIG # Hex: 76a914 <20-byte-hash> 88ac # Input (unlocking) script: <signature> <pubKey>
Script execution is in script.py. No SegWit, no Taproot, no multisig, no P2SH in the current version.
8.6 USDT Buy/Cash-Out (Web App Feature)
SIMULATED — not real blockchain transactions. The "Buy VITO" and "Cash Out to USDT" features in the web app are test-mode UI. They do not interact with any real USDT contract, DEX, or exchange. A visible amber warning banner reads: "TEST MODE — Simulated transactions. No real USDT is processed." Real exchange integration is planned for Phase 2 (Q3 2026).
API Endpoints
Base URL: https://vitocoin.com/api/node/ (Vercel proxy → Node 1). All return JSON. All GET endpoints are public — no authentication required.
| Method | Endpoint | Description | Status |
|---|---|---|---|
| GET | /status | Full node state: height, best_hash, difficulty, mempool, peers, miner stats, supply, version | LIVE |
| GET | /supply | Circulating supply (satoshi + VITO), max supply, current subsidy, next halving blocks | LIVE |
| GET | /market | Price (fixed $0.01), market cap, circulating supply, volume (0 — DEX pending), block reward, next halving | LIVE |
| GET | /market/price | Lightweight: {"price_usd": 0.01, "symbol": "VITO", "ts": ...} | LIVE |
| GET | /market/volume | {"volume_24h_usd": 0, "note": "DEX integration pending"} | LIVE |
| GET | /blocks | Paginated block list. Params: limit (default 10, max 100), offset | LIVE |
| GET | /block/:id | Single block by height (integer) or full hash (hex). Returns header + all transactions. | LIVE |
| GET | /tx/:txid | Transaction by TXID. Returns version, inputs, outputs, coinbase flag, size. | LIVE |
| GET | /mempool | Unconfirmed transactions. Currently always {"count": 0, "transactions": []} | LIVE |
| POST | /tx/send | Broadcast raw signed transaction. Body: {"raw_tx": "<hex>"} | LIVE |
| GET | /balance/:address | Address balance in satoshi and VITO, UTXO count. Queried live from UTXO set. | LIVE |
| GET | /address/:address | Full address history: balance + all transactions + UTXO list | LIVE |
| GET | /utxo/:address | Unspent outputs for address: txid, index, value, height, coinbase flag | LIVE |
| GET | /peers | Connected P2P peers: id, version, height, ban_score, uptime, in/outbound | LIVE |
| GET | /mining/status | Miner stats: threads, hashrate_hps, hashrate_str, total_hashes, blocks_found, wallet, uptime | LIVE |
| GET | /events | SSE stream (text/event-stream). Events: block, mempool, ping. Interval ~1s. | LIVE |
Additional node aliases: /api/node2/ → Node 2 (213.139.77.18), /api/node3/ → Node 3 (84.201.20.90). All nodes expose the same endpoint set.
Known Limitations — Mandatory Disclosure
This section discloses all known weaknesses, simulated components, and production gaps as of 2026-04-09. No omissions.
10.1 Synchronisation Issues
| # | Issue | Impact | Current Mitigation |
|---|---|---|---|
| S1 | Handshake race condition in P2P sync: _on_verack fires before _on_version sets peer.start_height for outbound connections, so _request_headers is not triggered automatically at connection time. |
Node may not request missing blocks immediately upon connecting to a peer. Can result in temporary divergence after restart. | A 2-second delayed re-check thread in _on_verack plus a 10-second _periodic_sync_loop catch all cases. Max 10-second lag before resync. |
| S2 | Peer height field in /peers API: Outbound connections show "height": 0 because start_height from the version message is not always captured before the handshake completes. |
Cosmetic only — actual chain height on all nodes is 10. Does not affect sync correctness. | Inbound connections show correct height. Known cosmetic bug, not yet fixed. |
| S3 | Node sync relies on periodic loop (10s) rather than pure event-driven sync. | Up to 10 seconds of delay before a node detects and requests a block found by another node — beyond the natural P2P propagation. Acceptable at current block times (~79 min), not acceptable for fast blocks. | 10-second loop. Will be replaced with proper real-time event-driven sync when refactoring P2P layer. |
| S4 | SQLite WAL mode: SQLite uses Write-Ahead Logging. If the process is stopped uncleanly, the WAL file must be checkpointed on next start. The current code does not run PRAGMA wal_checkpoint on startup. |
Risk of data inconsistency if WAL is not flushed before DB copy or after crash. Mitigated by systemd Restart=always. |
Manual checkpoint required for DB backup/migration. Startup checkpoint not yet automatic. |
10.2 Performance Issues
| # | Issue | Impact |
|---|---|---|
| P1 | Mining is Python-only (no C extension, no ASIC, no GPU). Combined hashrate ~900 KH/s across 3 nodes. | At difficulty 1.0, expected block time is ~79 minutes, not the target 10 minutes. Actual blocks 0–10 show timestamps confirming this (~4,700 s average inter-block time). Difficulty will never retarget upward at this hashrate within the 2,016-block window without external miners joining. |
| P2 | Single-threaded Python HTTP server (ThreadingHTTPServer). Thread-per-request model — not async. |
Under high concurrent load (e.g. many SSE connections + API calls), Python GIL and thread overhead will limit throughput. Not production-grade under load. Acceptable at current traffic level. |
| P3 | No caching layer. Every /balance/:addr, /blocks, /status call recomputes from SQLite. |
Response times are <10ms at current chain size (11 blocks, 12 UTXOs). Will degrade as chain grows. |
| P4 | Node 2 has a ban_score of 30 on its inbound connection from Node 1. | Node 1 recorded 30 ban points for Node 2 (likely from duplicate/invalid messages during early sync). Not yet at ban threshold (100). Cosmetic; nodes are fully synced. |
10.3 Simulated / Non-Production Components
| Component | Status | Detail |
|---|---|---|
| USDT Buy / Cash Out | SIMULATED | No real USDT contract interaction. No real exchange or DEX liquidity. Clearly labelled in the UI with amber "TEST MODE" banner. Planned Phase 2. |
| Price ($0.01 USD) | FIXED RATE | Price is hardcoded at $0.01 — not derived from any market or order book. Labelled "price_source": "fixed_initial_rate" in API. Will become market-determined once listed on a DEX/CEX. |
| Volume ($0) | ZERO | No trades have occurred. Volume is correctly reported as 0. API labels this "volume_note": "DEX integration pending (Phase 2)". |
| Market Cap ($5.50) | DERIVED | Market cap = 550 VITO × $0.01 = $5.50. Mathematically correct given the fixed price. Not based on real market activity. |
| Mining pool (Stratum) | NOT IMPLEMENTED | No pool protocol. All three nodes are solo miners. External miners cannot connect. Planned Phase 2. |
| Web browser mining | NOT IMPLEMENTED | The "Mining" page in the frontend displays server-side stats. No WebWorker SHA-256d computation in browser. The displayed hashrate is the server-side miner's hashrate. |
| User-to-user transactions | INFRASTRUCTURE READY | POST /tx/send accepts raw signed transactions. Wallet derivation (BIP-44), key signing (secp256k1), and UTXO construction exist. However, no coinbase outputs are yet mature (require 100 confirmations). Zero user-to-user transfers have occurred on mainnet. Will become fully functional once blocks reach height ≥ 101. |
| DEX / exchange integration | NOT IMPLEMENTED | No DEX smart contract, no bridge, no CEX listing. Planned Q3 2026 (Phase 2). |
| Geographic distribution | LIMITED | Node 1 is in Frankfurt (Hetzner). Nodes 2 and 3 are both in Moscow (Yandex Cloud) — two of three nodes in the same datacenter region. Not yet globally distributed. Whitepaper states "Frankfurt / NY / Singapore" as target; current reality is Frankfurt + Moscow × 2. |
| Script system | P2PKH ONLY | Only Pay-to-Public-Key-Hash scripts. No multisig, no P2SH, no SegWit, no Taproot, no smart contracts. Sufficient for basic transfers and mining rewards. |
| Transaction fees | NO FEE MARKET | Fees are accepted by the miner but there is no fee market, no mempool fee sorting, and no minimum relay fee. At current stage (all blocks contain only coinbase TXs), fees are effectively zero. |
| SPV / light clients | NOT IMPLEMENTED | No bloom filter, no SPV proof, no light client protocol. External wallets must run a full node or trust the public API. |
| GitHub source code | PRIVATE REPO | Source code is in a private GitHub repository (united-vito-com/VitoCoin-v2). Not yet open-source. CMC/exchange listings may require public source availability. |
10.4 Security Posture
| Risk | Severity | Detail |
|---|---|---|
| 51% attack | HIGH (expected) | Combined network hashrate is ~900 KH/s. Any consumer GPU can exceed this. A single attacker with a $50/month cloud GPU could rewrite recent chain history. This is expected and disclosed in the whitepaper (Section 8.2). Risk reduces as external miners join. |
| Node availability | MEDIUM | Only 3 nodes exist. Loss of any 2 stops block production. The chain continues to validate but no new blocks are mined. Not censorship-resistant at this scale. |
| API exposure | LOW | All node APIs (6333) are publicly accessible with no rate limiting. Susceptible to DoS via excessive requests. No CDN or rate-limit middleware in front of direct node IPs. Mitigated partially by Vercel proxy for web app traffic. |
This technical disclosure was compiled on 2026-04-09 from live production data queried directly from all three VitoCoin mainnet nodes. Block heights, hashes, nonces, and hashrates reflect node state at time of writing. PoW verification was performed independently using Python hashlib double-SHA256 against the serialised block headers. All limitations in Section 10 are disclosed in full without omission.