More cards
This commit is contained in:
+18
-20
@@ -1,9 +1,22 @@
|
||||
# Native RandomX engine
|
||||
|
||||
This is the CPU proof engine used by the Wikideck testnet node and explicit opt-in
|
||||
native miner. Browser mining has been removed from the active application. The
|
||||
Docker image builds this pinned implementation and runs its known-vector test.
|
||||
There is no GPU path, simulated hash, or production fallback hash.
|
||||
native miner. Mining runs only when the operator starts the native CLI; the browser
|
||||
does not mine or launch native programs. The Docker image builds this pinned
|
||||
implementation and runs its known-vector test. There is no GPU path, simulated hash,
|
||||
or production fallback hash.
|
||||
|
||||
This document covers building the executable, its memory modes, its line protocol,
|
||||
and the TypeScript adapter. For the user-facing install and run instructions, start
|
||||
with the [README](../README.md).
|
||||
|
||||
## Contents
|
||||
|
||||
- [Source and build](#source-and-build)
|
||||
- [Modes and resource use](#modes-and-resource-use)
|
||||
- [Line protocol](#line-protocol)
|
||||
- [Node API](#node-api)
|
||||
- [Real upstream known-vector check](#real-upstream-known-vector-check)
|
||||
|
||||
## Source and build
|
||||
|
||||
@@ -47,8 +60,8 @@ must permit the script; do not bypass a managed policy. POSIX customization:
|
||||
CMake environment or a manual configuration. Don't switch generators in an
|
||||
existing build directory.
|
||||
|
||||
All generators place the executable directly under [native/build](../native/build)
|
||||
(with `.exe` on Windows), including Release builds with multi-config generators.
|
||||
All generators place the executable directly under `native/build` (with `.exe` on
|
||||
Windows), including Release builds with multi-config generators.
|
||||
Upstream tests/benchmark/codegen are excluded from the default build: v1.2.1 does
|
||||
not provide a tests-disable option. No benchmark or dataset-heavy fast-mode test
|
||||
runs automatically.
|
||||
@@ -177,18 +190,3 @@ ctest --test-dir native/build -C Release --output-on-failure
|
||||
This test is OFF by default and is separate from the application's tests. Without
|
||||
a built native binary, no native engine or native test is run by the application.
|
||||
|
||||
## Validation record
|
||||
|
||||
Verified on Windows x64 with CMake 3.26.4, MinGW GCC 13.1.0 and Node 24.22.0:
|
||||
|
||||
- Release native build with two compiler jobs; opt-in CTest upstream vector passed.
|
||||
- Production TypeScript/application build passed.
|
||||
- Ad-hoc actual-native light-mode checks passed: FIFO hashes, same-key reuse,
|
||||
key changes and restoration, mining success/exhaustion, target equality and
|
||||
big-endian comparison, LE8 nonce handling, 8192-byte blob, strict invalid-input
|
||||
rejection, native uint64 nonce output, missing binary, queue bounds, crash
|
||||
rejection, idempotent close, and stdin EOF.
|
||||
- Both build scripts passed syntax checks.
|
||||
|
||||
Fast-mode allocation/runtime and Linux/macOS/MSVC builds were not run. The memory
|
||||
and initialization cost of the full dataset remains an explicit opt-in.
|
||||
|
||||
+28
-12
@@ -2,24 +2,39 @@
|
||||
|
||||
Implementation reference for the current tree, **not a public-mainnet specification or security certification**. See [README](../README.md) for setup/wallet commands and [native-engine details](randomx-native.md) for RandomX tooling. Consensus code: [shared serialization](../shared/testnet.ts), [validation](../server/testnet/consensus.ts), [DAG/persistence](../server/testnet/ledger.ts), [peer transport](../server/testnet/peers.ts), [HTTP](../server/testnet/http.ts), [miner](../server/testnet/miner.ts).
|
||||
|
||||
## Network, genesis and catalog
|
||||
This document is for operators and developers who need the exact current protocol
|
||||
rules. It is not a quick-start guide: consensus serialization and constants are
|
||||
implementation-specific, and changing them can create a different chain.
|
||||
|
||||
- Network: `wikideck-randomx-testnet-2`, block version **2**. Genesis has no blocks, NFTs or work; first mined height is 1. No privileged issuance/admin mint key.
|
||||
## Contents
|
||||
|
||||
- [Network, genesis and article selection](#network-genesis-and-article-selection)
|
||||
- [Header, work and three distinct identities](#header-work-and-three-distinct-identities)
|
||||
- [Targets, timestamps and epoch boundaries](#targets-timestamps-and-epoch-boundaries)
|
||||
- [Native NFT transition and commitments](#native-nft-transition-and-commitments)
|
||||
- [Fork choice, reorgs and storage](#fork-choice-reorgs-and-storage)
|
||||
- [Fixed peers and HTTP surface](#fixed-peers-and-http-surface)
|
||||
|
||||
## Network, genesis and article selection
|
||||
|
||||
- Network: `wikideck-randomx-testnet-4`, block version **4**. Genesis has no blocks, NFTs or work; first mined height is 1. No privileged issuance/admin mint key. Version 4 has a new chain identity; prior-version ledger files and wallet backups are not compatible.
|
||||
- `GENESIS_TIME = 1792411200` (Unix seconds). Let `S(x)` mean lowercase hex SHA-256 of UTF-8 `x`, and `J(x)` mean compact JavaScript `JSON.stringify(x)`; field order below is consensus-critical.
|
||||
- `MAX_TARGET` is `0fff` followed by 60 `f` digits. `CHAIN_ID = S(J([NETWORK, CONSENSUS, GENESIS_TIME, MAX_TARGET, STARTER_ARTICLES.map(articleTuple)]))`, using the constants object's insertion order in the implementation.
|
||||
- `MAX_TARGET` is `0fff` followed by 60 `f` digits. `CHAIN_ID = S(J([NETWORK, CONSENSUS, GENESIS_TIME, MAX_TARGET]))`, using the constants object's insertion order in the implementation. `CONSENSUS` identifies the random Wikipedia source and mint-statistics snapshot format.
|
||||
- `GENESIS_HASH = S(NETWORK + ':genesis:' + CHAIN_ID)`; `INITIAL_KEY = S(NETWORK + ':initial-key:' + CHAIN_ID)`. Nodes independently derive the same manifest and reject other network/chain IDs.
|
||||
- The [catalog](../shared/catalog.ts) contains four fixed **original summaries**: Albert Einstein (736), Moon (19331), Octopus (22780), Periodic table (23053). No live Wikipedia request determines consensus metadata. `articleTuple = [pageId, revisionId, title, extract, image-or-empty-string, url, source, category]`.
|
||||
- The next catalog index is the big-endian integer `S(CHAIN_ID + ':article:' + previousHash)` modulo 4. Validation requires the exact selected tuple. NFT state stores that article's same `pageId`. Changing the catalog/constants currently changes genesis: coordinate a new chain, not a live catalog expansion or demo-asset migration.
|
||||
- [Starter samples](../shared/catalog.ts) remain only as interface previews; they are not eligible for minting. Each mining-template request asks the fixed English Wikipedia API endpoint for up to ten random namespace-0 pages, with a plain-text extract and thumbnail. It makes at most three requests and returns a page with a usable extract and an HTTPS image on `upload.wikimedia.org` or `thumb.wikimedia.org`. A page may be minted repeatedly. There is no static fallback: if no pictured article or its statistics are available, template creation fails and the miner can retry.
|
||||
- The selected `Article` snapshot and `statsSnapshot` are copied into the block header and covered by the miner's block signature and block ID. `articleTuple = [pageId, revisionId, title, extract, image-or-empty-string, url, source, category]`. The at-mint statistics contain capture time, metadata revision, page bytes, language-link count/truncation, six-month pageviews when available, and the derived Attention/Depth/Reach scores. Missing pageviews are represented as unavailable, never invented zeroes. The node forces a fresh enrichment request for this snapshot; it is captured when the mining template is prepared, since changing it after work begins would invalidate the proof. Current UI statistics are fetched separately and may reflect later edits.
|
||||
- A repeated page still creates a distinct NFT: token identity includes the parent block, height, and owner. Validators check article/image and stats schemas, the page URL, Wikimedia HTTPS host, pageview summaries, derived scores, and block commitments, but do not constrain repeated page IDs.
|
||||
- Validators do **not** contact Wikipedia during consensus validation. They verify the committed snapshot's structure and internal metric summaries, not the API provenance or ongoing existence of the page/image. A miner can construct a syntactically valid snapshot itself; this experimental design avoids making block acceptance dependent on an external service being online. The node's template endpoint fetches the article and fresh statistics for ordinary mining clients.
|
||||
|
||||
## Header, work and three distinct identities
|
||||
|
||||
`headerMessage(h)` is `J([NETWORK, version, chainId, height, previousHash, createdAt, articleTuple(article), owner, publicKey, target, key, transactionsRoot, stateRoot])`. It excludes the nonce. Hash its UTF-8 bytes with SHA-256 to obtain **32 raw bytes**, then append the nonce encoded as **8 unsigned little-endian bytes**. The resulting **40-byte mining blob** has nonce offset **32** (not a 32-bit nonce). Node's numeric interface restricts nonces to nonnegative safe integers; the native line protocol supports uint64.
|
||||
`headerMessage(h)` is `J([NETWORK, version, chainId, height, previousHash, createdAt, articleTuple(article), statsSnapshotTuple, owner, publicKey, target, key, transactionsRoot, stateRoot])`. `statsSnapshotTuple` commits capture time, revision, size/language counts, ordered monthly views and summary values, plus the three derived scores. It excludes the nonce. Hash its UTF-8 bytes with SHA-256 to obtain **32 raw bytes**, then append the nonce encoded as **8 unsigned little-endian bytes**. The resulting **40-byte mining blob** has nonce offset **32** (not a 32-bit nonce). Node's numeric interface restricts nonces to nonnegative safe integers; the native line protocol supports uint64.
|
||||
|
||||
| Identifier | Exact construction / meaning |
|
||||
| --- | --- |
|
||||
| Block ID (`hash`) | SHA-256 of the raw mining blob, lowercase hex. Does not include ECDSA signature bytes or the separate `powHash` field. |
|
||||
| RandomX proof (`powHash`) | Native RandomX of the mining blob using the 32-byte epoch key. Determines work eligibility and game rarity/stats, not the NFT ID. |
|
||||
| NFT ID (`tokenId`) | `S(J([NETWORK, CHAIN_ID, 'mint', previousHash, height, owner, article.pageId]))`. Independent of nonce/proof/signature, avoiding a circular dependency through state commitment. |
|
||||
| NFT ID (`tokenId`) | `S(J([NETWORK, CHAIN_ID, 'mint', previousHash, height, owner, article.pageId, statsSnapshotTuple]))`. The capture time and page statistics help distinguish repeated mints of the same page. Independent of nonce/proof/signature, avoiding a circular dependency through state commitment. |
|
||||
|
||||
Interpret RandomX output and target as **unsigned big-endian** integers; accept `powHash <= target` including equality. This differs from Monero's target convention. The initial/easiest threshold accepts exactly **1/16** of uniformly distributed hashes (expected 16 attempts). No fake or browser PoW is accepted by the production node.
|
||||
|
||||
@@ -48,7 +63,7 @@ Per-block work is `floor(2^256 / (target + 1))`; accumulate from genesis work ze
|
||||
|
||||
On reorg, reconstruct ownership from the winning branch. Orphan mints disappear from canonical ownership; disconnected transfers are reconsidered before existing pending entries, in order, only if still valid and not already committed. Conflicting, immature or orphan-issuance transfers are discarded. No checkpoints/finality or rollback protection beyond observed work; an isolated node has no peer-backed security.
|
||||
|
||||
The [ledger](../server/testnet/ledger.ts) stores the entire DAG and pending pool in [the testnet ledger](../data/testnet/ledger.json), under `WIKIDECK_DATA_DIR`'s testnet subdirectory. Defaults use project data; Docker uses /app/data. Disk caps: **128 MiB, 10,000 total blocks including side branches**; blocks: **64 KiB and 64 transfers**. Each in-memory DAG node stores a full NFT-state snapshot: potentially **quadratic memory growth**, plus full-file rewrite cost. These are experimental stop limits, not scalable storage or a public DoS defense.
|
||||
The [ledger](../server/testnet/ledger.ts) stores the entire DAG and pending pool in `data/testnet/ledger.json`, under the `WIKIDECK_DATA_DIR` testnet subdirectory. The file is created when the node first writes ledger data. Defaults use project data; Docker uses `/app/data`. Disk caps: **128 MiB, 10,000 total blocks including side branches**; blocks: **64 KiB and 64 transfers**. Each in-memory DAG node stores a full NFT-state snapshot: potentially **quadratic memory growth**, plus full-file rewrite cost. These are experimental stop limits, not scalable storage or a public DoS defense.
|
||||
|
||||
Mutations are serialized (queue cap 256); persist via a synchronized temporary file and atomic rename before exposing new state. Restart independently revalidates every saved proof and transaction; malformed, oversized or mismatched files fail closed without automatic reset. HTTP startup exclusively creates a data-directory lock named testnet-node.lock. It is removed on normal shutdown, **not automatically after a crash**: stop and verify all owning processes have exited before manual stale-lock removal. Never bypass a live lock or share a writer directory. Back up stopped-node volumes/files and wallet exports separately; destructive volume reset cannot recover assets from a wallet alone.
|
||||
|
||||
@@ -61,10 +76,11 @@ Sync polls every **5 seconds**, checks network/chain ID, imports at most **32**
|
||||
| Route | Purpose |
|
||||
| --- | --- |
|
||||
| `GET /healthz` | Process health/network, not sync or consensus security. |
|
||||
| `GET /api/state`, `/api/chain` | Canonical blocks, mined/pending transfers, tip/work and next article. |
|
||||
| `GET /api/nfts/:id`, `/api/peers` | Canonical NFT owner/sequence/confirmations/metadata; configured peer status. |
|
||||
| `GET /api/wikipedia/:pageId` | Optional cached live enrichment for catalog IDs: categories, views, size, languages and display-only scores. Never a consensus input. |
|
||||
| `POST /api/mining/template`, `/api/blocks` | Public miner identity to template; independently validated signed block submission. |
|
||||
| `GET /api/state`, `/api/chain` | Canonical blocks, mined/pending transfers, tip/work and peer count. |
|
||||
| `GET /api/nfts/:id`, `/api/peers` | Canonical NFT owner/sequence/confirmations, article and at-mint statistics; configured peer status. |
|
||||
| `GET /api/wikipedia/:pageId` | Cached current enrichment for positive English Wikipedia page IDs: categories, views, size, languages and display-only scores. Never a consensus input. |
|
||||
| `POST /api/mining/template` | Rate-limited public miner identity; fetches a random article with a picture plus fresh at-mint statistics. Returns 503 when either cannot be fetched. |
|
||||
| `POST /api/blocks` | Independently validates a signed block, proof, article snapshot, required Wikimedia image URL, and statistics snapshot consistency. Repeated page IDs are accepted. |
|
||||
| `POST /api/transfer` | Signed transfer admission; 202 means pending. |
|
||||
| `GET /p2p/status`, `/p2p/blocks?offset=0`, `/p2p/mempool` | Manifest/size/tip, 32-block inventory pages, pending transactions. |
|
||||
| `POST /p2p/block`, `/p2p/transaction` | Same validation as local block/transfer submission. |
|
||||
|
||||
Reference in New Issue
Block a user