More cards
This commit is contained in:
@@ -1,12 +1,12 @@
|
||||
# Wikideck
|
||||
|
||||
**Mine knowledge. Collect the extraordinary.** An independent, experimental **RandomX testnet** with native NFTs, independently validating nodes, and recoverable P-256 wallets. Built with React, TypeScript, Express, Web Crypto, and a pinned native RandomX engine.
|
||||
Wikideck is an experimental, self-hosted RandomX testnet where each mined block creates a native NFT from a random English Wikipedia article. A page may be minted more than once; each NFT commits its own article and mint-time statistics snapshot, including a Wikimedia-hosted picture. It includes a React interface, a validating node, local P-256 wallets, transfers, and current off-chain Wikipedia statistics.
|
||||
|
||||
**Not a public mainnet.** No public bootnodes or deployed public network are supplied. Test assets have no promised value; launch with no funds. This is not Monero mining, an Ethereum/ERC-721 NFT, an ASIC-proof claim, or an audited security product. Old browser-mined demo assets and wallets are separate: there is no migration.
|
||||
**This is a local test network, not a public mainnet or an investment product.** No public bootnodes or hosted network are provided. Test NFTs have no promised value. Do not use funds or valuable assets. This project is not affiliated with Wikipedia or the Wikimedia Foundation.
|
||||
|
||||
## Quick start: three local validators
|
||||
## Run the three-node testnet (Docker)
|
||||
|
||||
Install Docker Desktop with Linux containers and Compose v2. From the repository root:
|
||||
Install Docker Desktop with Linux containers and Docker Compose v2. From the repository root, start three connected nodes:
|
||||
|
||||
```sh
|
||||
docker compose -f compose.testnet.yaml up --build -d
|
||||
@@ -14,106 +14,93 @@ docker compose -f compose.testnet.yaml ps
|
||||
docker compose -f compose.testnet.yaml logs -f node-a
|
||||
```
|
||||
|
||||
Open **http://127.0.0.1:3101** (node-a); node-b and node-c are at **3102** and **3103**. Each independently validates blocks and has its own named volume: `testnet-a`, `testnet-b`, `testnet-c` (Compose prefixes actual volume names). **No miner starts automatically.** A healthy node is not proof of connected peers; inspect the UI peer count or `/api/peers`.
|
||||
Open **http://127.0.0.1:3101**. The other nodes are at **http://127.0.0.1:3102** and **http://127.0.0.1:3103**. Each node validates blocks independently and stores its ledger in a separate Docker volume. Mining does not start automatically. A healthy node is not necessarily connected to its peers; check the peer status in the interface or request `/api/peers`. Nodes need outbound access to Wikipedia when generating mining templates and capturing mint-time statistics. If that data is unavailable, the node returns an error and mining can be retried.
|
||||
|
||||
Stop with `docker compose -f compose.testnet.yaml down`; restart with the first command. Volumes survive ordinary shutdown and rebuilds. **Adding `-v` deletes all three ledgers.** Stop nodes before making consistent volume backups; never share one writable data directory between nodes. Back up wallets separately.
|
||||
Stop the nodes with:
|
||||
|
||||
The default [compose.yaml](compose.yaml) instead runs one node at **http://127.0.0.1:3001**, with a different `wikideck-data` volume; it is not the three-node setup. Existing project-local demo data is excluded from the image and is not imported. Current nodes write a separate testnet ledger, not the old demo chain.
|
||||
```sh
|
||||
docker compose -f compose.testnet.yaml down
|
||||
```
|
||||
|
||||
## Host build: Windows or Linux
|
||||
The volumes persist across stops and rebuilds. **Do not add `-v` unless you intend to delete all three ledgers.** Back up wallets separately. Protocol v4 uses a new chain identity; earlier v2/v3 ledgers and encrypted backups are not compatible. To keep old Docker data intact while trying v4, use a separate Compose project name, for example `docker compose -p wikideck-v4 -f compose.testnet.yaml up --build -d`, and use the same `-p wikideck-v4` for subsequent Compose commands. The default `docker compose up --build -d` uses [compose.yaml](compose.yaml): it starts one isolated node on port 3001 with a different volume.
|
||||
|
||||
Use **Node.js 24 LTS**, npm, Git, CMake **3.24+**, and a compatible C/C++17 toolchain. Initial native configuration fetches pinned RandomX over HTTPS. On Windows, put CMake, Git, the MinGW compiler, make, and compiler runtime DLLs on PATH; use a consistent 64-bit toolchain. From a terminal in the repository root:
|
||||
For an existing host install, keep the old data directory intact and set `WIKIDECK_DATA_DIR` to a new empty directory before starting protocol v4. The node intentionally fails closed on an old ledger; it does not reset or migrate it.
|
||||
|
||||
```powershell
|
||||
## Run on your host
|
||||
|
||||
Requirements: Node.js 24, npm, Git, CMake 3.24+, and a C/C++17 toolchain. The first native-engine configuration downloads the pinned RandomX source over HTTPS. On Windows, install a compatible toolchain (for example, MinGW-w64 and make) and use the matching CMake generator. Do not change generators in an existing `native/build` directory; use a fresh build directory when switching toolchains.
|
||||
|
||||
Install dependencies and build the native RandomX engine:
|
||||
|
||||
```sh
|
||||
npm install
|
||||
npm run native:configure -- -G "MinGW Makefiles"
|
||||
npm run native:configure
|
||||
npm run native:build
|
||||
npm run test:native
|
||||
npm run build
|
||||
npm start
|
||||
```
|
||||
|
||||
Open **http://127.0.0.1:3001**. In PowerShell, use `npm.cmd` in place of `npm` if execution policy blocks the npm PowerShell shim. Do not bypass a managed policy. The optional [Windows script](scripts/build-randomx.ps1) also requires permission to run: `./scripts/build-randomx.ps1 -Generator 'MinGW Makefiles' -Test`. The npm commands above invoke CMake directly rather than that script. Do not switch generators inside an existing native build directory; use a fresh build directory when changing toolchains.
|
||||
On Windows with MinGW, configure with `npm run native:configure -- -G "MinGW Makefiles"`. If PowerShell blocks the `npm` shim, use `npm.cmd`; follow your organization's execution policy rather than bypassing it. The optional platform scripts are [scripts/build-randomx.ps1](scripts/build-randomx.ps1) and [scripts/build-randomx.sh](scripts/build-randomx.sh). See [native engine setup and protocol](docs/randomx-native.md) for toolchain details.
|
||||
|
||||
On Linux, install the distribution's C/C++ build tools, CMake and Git; run `npm install`, `sh scripts/build-randomx.sh --test`, `npm run build`, then `npm start`. MSVC requires a developer terminal with C++/MASM tooling; omit the MinGW generator and review upstream PowerShell build requirements. See [native build, memory, and line-protocol details](docs/randomx-native.md). The current node and CLI use that engine, with no fake production fallback.
|
||||
The node listens at **http://127.0.0.1:3001** by default. For development, `npm run dev` starts the API on port 3001 and Vite on **http://127.0.0.1:5173**. Keep both services on loopback; Vite proxies the browser's `/api` requests to the API. The native miner should connect directly to the API port, not Vite.
|
||||
|
||||
For development, `npm run dev` starts the loopback API on **3001** and Vite on **5173**; open **http://127.0.0.1:5173**. Build the native engine first. Never expose Vite publicly. Stop conflicting servers before reusing a port.
|
||||
## Wallets and backups
|
||||
|
||||
## Wallet backup and recovery
|
||||
The browser creates a local, recoverable P-256 wallet. Open the wallet panel and use **Wallet backup & recovery** to download an encrypted backup. Choose a unique password of at least 12 characters, keep the file outside the repository, and store the password separately. Test recovery in another browser profile before relying on the backup.
|
||||
|
||||
1. Open the wallet button, then **Wallet backup & recovery**. The browser creates an **exportable ECDSA P-256** key in IndexedDB; its address is SHA-256 of the canonical SPKI public key.
|
||||
2. Download the encrypted backup with a strong, unique password (12–1024 characters). Confirm the download actually saved; store the file **outside the repository/Docker build context**, separately from its password. Do not commit either.
|
||||
3. Test recovery in another browser profile: choose the backup, enter its password, confirm replacement of any active wallet, and recover. Check the receive address matches. Back up the replaced wallet first; reload other open tabs before signing.
|
||||
The password encrypts the downloaded backup; it does **not** encrypt the key stored in browser IndexedDB. Same-origin scripts and access to the browser profile may expose that key. Clearing site data without a usable backup loses access. Wallets are scoped to an origin (scheme, hostname, and port), so a backup must be restored at another origin to use the same identity there. A restored wallet controls the same address; it does not move assets between chains.
|
||||
|
||||
Portable backups use **AES-256-GCM** with authenticated headers, a fresh 16-byte salt and 12-byte IV, and **PBKDF2-SHA256, 600,000 iterations**. Export/import happens locally; this is control of a signing key, **not a server login**. No node endpoint accepts private keys, backups, or passwords. Public keys, addresses and signatures are shared normally.
|
||||
The current testnet wallet is separate from any wallet used by an older demo. There is no automatic migration. See [consensus, wallets, and operational limits](docs/testnet-consensus.md) and the in-app backup warnings for more detail.
|
||||
|
||||
**IndexedDB itself is not password-encrypted.** Same-origin scripts/XSS or browser-profile access may use or export the key. A backup password protects the portable file, not an unlocked browser or miner. Anyone with file and password controls the wallet. Lost passwords cannot be reset; clearing site data without a usable backup loses access.
|
||||
## Mine only by explicit choice
|
||||
|
||||
Use a consistent browser **scheme + hostname + port**. localhost, 127.0.0.1, 5173, 3001 and 3101–3103 are different origins with separate wallet storage. Restore the backup at another origin to use the same identity; recovery does not move assets between chains. The UI uses same-origin RPC (Vite proxies it in development), **trusts that node's reported state**, and is not an SPV or independently verifying browser client.
|
||||
|
||||
## Mine explicitly, outside the browser
|
||||
|
||||
After building the native engine, use the browser's encrypted backup in an **interactive terminal**:
|
||||
Mining uses the native CPU RandomX engine. The browser page never mines or launches a native program. First build the engine, download an encrypted wallet backup, then run the CLI from an interactive terminal and enter the password at its hidden prompt:
|
||||
|
||||
```sh
|
||||
npm run miner -- --wallet "path/to/encrypted-backup.json" --consent --node http://127.0.0.1:3101 --blocks 3
|
||||
```
|
||||
|
||||
Replace the quoted path with your saved file. Enter the backup password at the hidden local prompt: **never put passwords in environment variables or command-line arguments**. The backup/password are not sent to the node. `--consent` is required; defaults are one worker, light mode, one block, and node port 3001. Add `--fast` only after budgeting memory. **Ctrl+C stops mining; closing the browser does not.** The page never mines or launches native programs.
|
||||
Use port 3001 for the default single host/Docker node, or 3101–3103 for the three-node Docker testnet. The command above uses node-a. The miner defaults to one worker, light mode, and one block; `--blocks 3` requests up to three accepted blocks. Press **Ctrl+C** to stop it. Do not put the backup password in a command, environment variable, or repository file. The backup and password are decrypted locally and are not sent to the node.
|
||||
|
||||
- Light mode: **256 MiB cache**, about 2 MiB scratchpad, plus process overhead.
|
||||
- Fast mode: about **2080 MiB dataset plus the retained 256 MiB cache**, scratchpad and overhead: budget **over 2.3 GiB per miner process**. Each validating node also needs its own light-mode cache. CPU, heat, energy and initialization costs are real; the Compose nodes' 1 GiB limits are not fast-miner budgets.
|
||||
- Use HTTPS for remote miner endpoints. The CLI rejects non-loopback HTTP unless explicitly overridden; do not weaken this for public connections.
|
||||
Each template request asks English Wikipedia for up to ten random pages and retries at most three times to find one with an image and readable extract. The same page may be selected again. The node also captures page size, language-link count, revision, pageviews, and derived scores for the mint-time snapshot. If Wikipedia cannot supply the article or its metadata, template creation returns an error; there is no fixed-article fallback. Validators check and commit the included snapshot without contacting Wikipedia during consensus validation.
|
||||
|
||||
The Docker runtime image includes the native engine and can run the TypeScript miner directly with Node 24; it has no runtime tsx/development dependencies. Container mining is manual, needs an interactive TTY, a read-only mounted backup, and a container-reachable node URL. A host-run CLI as above avoids Windows host-networking pitfalls. Do not bake wallets into an image or start mining as a node service.
|
||||
Light mode needs a 256 MiB cache plus scratchpad and process overhead. `--fast` is optional and needs over 2.3 GiB per miner process. Mining consumes CPU, power, and time; RandomX is not a guarantee of ASIC resistance. Do not expose an HTTP miner endpoint remotely; use HTTPS. Detailed resource, native build, and line-protocol notes are in [docs/randomx-native.md](docs/randomx-native.md).
|
||||
|
||||
## Collect, transfer, and inspect
|
||||
## What the app shows
|
||||
|
||||
Each canonical block mints one **native NFT**; the same article may be minted repeatedly with different token IDs. Preview cards are not owned. Card details and the explorer distinguish NFT token ID, block ID and RandomX proof hash. Rarity/stats are proof-derived game values, not Wikipedia facts or a fair economic lottery.
|
||||
- **Discover** shows preview examples until the node has mined blocks; previews are not owned NFTs. Minted cards can reference the same page, but each carries its own captured stats snapshot.
|
||||
- **My collection** shows NFTs owned by the active local wallet on the connected node's canonical chain.
|
||||
- **Block explorer** distinguishes block IDs, NFT token IDs, and RandomX proof hashes. A submitted transfer is pending until a block confirms it. Reorganizations can change canonical ownership and confirmations.
|
||||
- Each minted card shows current Wikipedia statistics alongside its immutable at-mint snapshot: pageviews, article size, language links, revision, and derived scores. Current values may change; at-mint values are committed to the block. Missing pageview data stays unavailable, not zero.
|
||||
- The appearance selector offers Catppuccin Mocha, Macchiato, Frappé, and Latte themes.
|
||||
|
||||
Use another profile or a second wallet to receive a transfer. Signing submits it to the mempool: **HTTP 202 is pending, not changed ownership**. Ownership changes only after inclusion in the canonical chain. A mint at height `h` can first transfer in block `h+2`; the pool may accept it at tip `h+1` for next-block inclusion. Confirmations count the mint block itself. Reorganizations can remove mints, reverse ownership and change confirmations; there is no fixed finality or undo for a wrong address.
|
||||
The browser interface trusts the connected node's reported state. It does not independently verify the chain or provide an SPV client. Transfers are irreversible once confirmed; check the recipient address carefully.
|
||||
|
||||
Metadata is a **fixed four-article catalog of original starter summaries**, not a live Wikipedia API feed. The catalog is genesis-bound; expanding it currently requires a new genesis/chain. Page IDs agree across catalog and state. See [consensus, identifiers, peer RPC and limits](docs/testnet-consensus.md).
|
||||
## Tests and development checks
|
||||
|
||||
### Live Wikipedia card insights
|
||||
```sh
|
||||
npm test
|
||||
npm run build
|
||||
npm run test:native
|
||||
```
|
||||
|
||||
Cards also display **optional off-chain enrichment**, separate from the minted snapshot: human-readable description, visible Wikipedia categories (up to 50), article size in bytes, other-language links (up to 500, labeled as a lower bound if truncated), Wikidata ID, current revision, and six complete UTC months of Wikimedia page views. The details show the latest monthly count, daily average, six-month total, month-over-month change, and a readership chart. Counts use English Wikipedia, all access methods, and Analytics' `user` traffic classification; classified automated traffic is excluded. Article renames can affect title-based history. Missing/incomplete API data is shown as unavailable, never invented zeroes.
|
||||
`npm test` runs the application test suite, including fast test-only proof tests. `npm run test:native` runs the real upstream RandomX known-vector test and requires a native build configured with tests enabled; the documented `npm run native:configure` command enables them. The Docker build also builds RandomX and runs its native test.
|
||||
|
||||
Three **live scores** range from 0–100, rounded and capped: **Attention** = log₁₀(latest complete month's views + 1) / 6 × 100; **Depth** = log₁₀(article bytes + 1) / 6 × 100; **Reach** = log₁₀(language links + 1) / 3 × 100. Depth is a size proxy, not article quality. These scores may change; the original proof-derived Power/Defense/Knowledge, rarity, NFT ownership, and consensus do not. Live revision and retrieval time are shown explicitly, with Wikipedia/Wikimedia attribution.
|
||||
To explicitly test propagation and transfer behavior across the three local Docker nodes, first build the host native engine and start the three-node testnet, then run:
|
||||
|
||||
`GET /api/wikipedia/:pageId` only enriches current catalog IDs. The node contacts fixed Wikimedia HTTPS hosts with no redirects, bounded time/response sizes, four concurrent jobs, per-article request deduplication, and a bounded cache (up to six hours; shorter for partial failures). API outages do not block mining, validation, or transfers. No live enrichment is written into blocks, NFT state, or the genesis manifest; existing chains remain compatible. Rebuild the Docker image to serve this feature from containers.
|
||||
```sh
|
||||
node --experimental-strip-types scripts/testnet-smoke.ts --consent
|
||||
```
|
||||
|
||||
## Connect your own independent nodes
|
||||
This mines three real blocks using disposable identities. It changes the testnet, and is not run automatically.
|
||||
|
||||
Operators must provision their own nodes, separate storage and connectivity; multiple containers on one machine are not independent security domains. Configure `WIKIDECK_PEERS` as a comma-separated list of fixed peer **origins**, for example `https://peer-a.example.org,https://peer-b.example.org` after replacing these placeholders with actual operator-controlled endpoints. Default policy requires HTTPS and public IP/DNS answers; credentials, paths, queries, fragments and redirects are rejected. At most 16 peers; no bootnodes, DHT, discovery or peer-list expansion.
|
||||
## Network and safety limits
|
||||
|
||||
`WIKIDECK_ALLOW_PRIVATE_PEERS=1` explicitly permits private addresses and HTTP; the three-node Compose file uses this only for its private Docker test network. Do not carry that exception into public peer configuration. Peer URLs are operator settings, never accepted from remote peers.
|
||||
Nodes use only explicitly configured peers; there is no discovery service or public bootstrap network. The peer, storage, and HTTP configuration is documented in [docs/testnet-consensus.md](docs/testnet-consensus.md). The implementation is experimental: it has no fees or economic security, and remains vulnerable to resource exhaustion, isolation/eclipsing, censorship, majority-hashpower attacks, and reorganizations. Storage limits are stop limits rather than a scalable production design. HTTPS, container hardening, and passing tests do not constitute a security audit.
|
||||
|
||||
For a remote experiment, choose your own public domain and HTTPS origin, reverse proxy the intended node port, and set `PUBLIC_ORIGIN` to that exact frontend origin. Set `HOST` deliberately if not loopback, firewall backend ports and configure peers on each node. This describes required operator work, **not an already-deployed or production-ready public network**; HTTPS and origin checks do not provide consensus/economic security or authentication.
|
||||
Before considering any broader deployment, the protocol and cryptography would need independent audits, adversarial network testing, hardened abuse controls, and tested recovery procedures. Do not expose a public node or use valuable assets on this experimental network.
|
||||
|
||||
| Setting | Current behavior |
|
||||
| --- | --- |
|
||||
| `HOST`, `PORT` | Host defaults: 127.0.0.1, 3001; image binds 0.0.0.0:3001 inside container. |
|
||||
| `WIKIDECK_DATA_DIR` | Defaults to project data; image uses /app/data; testnet ledger lives in its testnet subdirectory. |
|
||||
| `RANDOMX_BINARY` | Optional trusted executable override; otherwise host native build output. Image sets its packaged binary. |
|
||||
| `PUBLIC_ORIGIN` | Additional exact allowed POST origin; not a browser RPC node selector or login. |
|
||||
| `WIKIDECK_PEERS`, `WIKIDECK_ALLOW_PRIVATE_PEERS` | Explicit outbound allowlist and opt-in private/HTTP permission; empty peers means isolated. |
|
||||
| `WIKIDECK_PORT` | Default Compose host-port interpolation only; does not change fixed 3101–3103 testnet mappings. |
|
||||
## Attribution
|
||||
|
||||
## Validation and operational limits
|
||||
|
||||
`npm run build` type-checks client/server and builds the UI. `npm test` uses a **test-only fake PoW** for fast fork/ledger tests, plus real native HTTP integration **when the executable exists** (otherwise that test skips). Production has no fake selector/fallback. `npm run test:native` runs the upstream known vector after native configuration with tests enabled; the Docker build also builds RandomX and runs CTest. These checks do not certify consensus safety or a successful deployment on every platform.
|
||||
|
||||
For an explicitly opted-in live check against the three local Docker nodes, run `node --experimental-strip-types scripts/testnet-smoke.ts --consent` after building the host native engine. This mines **three real testnet blocks** with disposable, non-recoverable test identities, submits and mines an NFT transfer, and asserts all nodes agree on work, tip, and ownership. It changes the test network; it is never run automatically. Docker restart durability has also been exercised on the three-node setup. Fork-choice/reorg tests use the labeled fast test engine; the HTTP and live-container tests use actual RandomX.
|
||||
|
||||
Storage is deliberately bounded: **128 MiB ledger, 10,000 total DAG blocks including forks, 256 pending transfers**. Every DAG node retains a complete NFT state; memory can grow quadratically despite disk caps. Whole-ledger atomic rewrites and full startup revalidation are unsuitable for a long-lived public chain. Corrupt/mismatched data fails closed rather than resetting. The HTTP process exclusively creates a data-directory lock; after a crash, **stop/verify all owning processes are gone before manually removing the stale lock**. There is no automatic stale-lock recovery.
|
||||
|
||||
The image runs nonroot; Compose uses loopback publishing, separate volumes, read-only roots, dropped capabilities, no-new-privileges and resource limits. There are no admin mint keys; ownership requires valid mint/transfer signatures, and private keys stay local. These measures are not a security audit. No fees or economic security exist; spam/DoS, eclipse and majority-hashpower (51%) attacks, censorship, rollback and reorgs remain material risks. Obtain independent protocol/cryptographic audits, adversarial network testing, hardened storage/abuse controls and recovery procedures before any broader launch. **No funds or valuable assets.**
|
||||
|
||||
Run `npm audit`, rebuild regularly, and scan the actual container/base OS and native dependencies for CVEs. Zero npm advisories is **not** an OS-image/native-code vulnerability guarantee; known-vector success is not an audit.
|
||||
|
||||
## Appearance and attribution
|
||||
|
||||
Official [Catppuccin](https://catppuccin.com/palette/) flavors: **Mocha** (default), **Macchiato**, **Frappé**, and light **Latte**. The top-bar selector saves the flavor locally, restores it before paint, and synchronizes same-origin tabs. With blocked storage it still switches for the page; themes never change wallets or chain state.
|
||||
|
||||
Independent experiment, not affiliated with Wikipedia or the Wikimedia Foundation. Current starter summaries are original, explicitly labeled, and link real articles. Wikipedia contributor text, where reused, is [CC BY-SA 4.0](https://creativecommons.org/licenses/by-sa/4.0/); Commons images have file-specific licenses and credits—open **Image & license** before reuse. Native NFT ownership grants no copyright or exclusive rights to article text/images. Linked Wikipedia content may be unsuitable for some audiences; no age filtering is provided.
|
||||
The four original starter summaries in the interface are preview examples only; they are not mintable. Mined cards contain short snapshots from Wikipedia contributors, licensed under [CC BY-SA 4.0](https://creativecommons.org/licenses/by-sa/4.0/), and a Wikimedia-hosted picture. Open each card's **Image & license** link and review the file-specific license and attribution before reuse. A native NFT does not grant copyright or exclusive rights to article text or images.
|
||||
|
||||
Reference in New Issue
Block a user