Small Node.js scripts for deriving a v3 Merkle root from a secret file and building anchored binary Merkle trees for local debugging.
RemotePlayWorld is expected to carry many agents and many values; those values are contrasted across agents for comparison and monitoring. Merkle trees support flexible visibility (address and prove subsets of the world) and delta-oriented replication: peers can sync only what is missing or new along the tree instead of the full dataset, then merge updates into local world state on each client. The v3 anchor (buffer.txt → .root) plus player-chain digests bind that structure to one deployment root. For the full rationale, see node-validation.md (section World architecture: RemotePlayWorld and why Merkle trees).
Each run of tool.js, create-merkle-tree.js, and validate-merkle-node.js writes a timestamped file under logs/ with a short header describing the operation. Diagnostic lines are copied there from stderr; the tree builder also stores the JSON shape in the log file. Stderr ends with [operation log: …]. logs/*.log is gitignored (the logs/ folder is kept via .gitkeep).
- Node.js (uses built-in
crypto; no npm install required)
All commands below assume you run them from this directory:
cd /path/to/play-toolsWrites a short banner to stdout, then a single line of 64 lowercase hex characters (the derived root). The script always reads buffer.txt next to tool.js, not from your shell’s current working directory.
node tool.jsExample (last line is the root you typically save as your anchor id):
Merkle root (v3): scrypt(dkLen=32) over buffer.txt bytes; salt=SHA-256(domain label). See file header comment for full spec.
a1b2c3d4e5f6789012345678901234567890abcdef1234567890abcdef123456
Redirect only the hex line if you need it in a file:
node tool.js | tail -n 1 > .rootEnsure buffer.txt exists and is non-empty before running.
Reads an anchor id (non-empty text, usually 64 hex chars) from a file, builds a binary Merkle subtree of N leaves under that anchor, writes leaf credentials to agent-play-debug.passw, prints debug views on stderr, and prints the tree shape as JSON on stdout.
node create-merkle-tree.js [--count N] [--root-file PATH] [--buffer PATH] [--validate]
| Option | Default | Meaning |
|---|---|---|
--count N |
2 |
Number of leaf nodes (non-negative integer). |
--root-file PATH |
See note below | File whose trimmed contents are the anchor id. |
--buffer PATH |
./buffer.txt (next to script) |
Secret bytes used only with --validate. |
--validate |
off | Check that buffer.txt derives the same root as the anchor id in --root-file; does not build a tree. |
-h, --help |
Print usage and exit. |
Default --root-file: the script ships with a hard-coded path to a .root file on the maintainer’s machine. On your machine, pass an explicit path (for example the file you created with tool.js):
node create-merkle-tree.js --root-file ./.root --count 4node create-merkle-tree.js --root-file ./.root --count 4- Stdout: indented JSON tree shape (safe to pipe or save).
- Stderr: ASCII tree diagram and flat merge-level debug output, plus a line like
Wrote N entries to .../agent-play-debug.passw.
node create-merkle-tree.js --root-file ./.root --count 2 2>merkle-debug.log | tee tree-shape.jsonChecks that scrypt-v3 derivation from the buffer matches the anchor id (exit 0 if match, 1 if not):
node create-merkle-tree.js --root-file ./.root --validateCustom buffer path:
node create-merkle-tree.js --root-file ./.root --buffer ./buffer.txt --validatenode create-merkle-tree.js --root-file ./.root --count 0Produces an anchor-only tree (no binary subtree); stderr explains that the merge ladder is omitted.
Checks whether a node id is consistent with the cryptography you expect. Exit code 0 means valid, 1 means not valid (or usage error).
The secret file must be the same raw bytes used for Merkle root v3 (buffer.txt). The node id must be exactly the 64-character lowercase hex root derived from that file (same as tool.js output). This is the check described in node-validation.md for the trust anchor.
node validate-merkle-node.js --node-id "$(node tool.js | tail -n 1)" --buffer ./buffer.txtOr put the id in a file:
node validate-merkle-node.js --node-id-file ./.root --buffer ./buffer.txtDefault --buffer is buffer.txt next to the script.
A leaf id is not determined by the buffer alone; it is digestLeaf(\${anchor}:${index}:${password}`). Use --leafplus the anchor string (your.rootline), the leaf index, and the password fromagent-play-debug.passw`:
node validate-merkle-node.js --leaf \
--node-id '<64-hex from node-id:... line>' \
--anchor "$(cat ./.root)" \
--index 0 \
--password '<hex after passw:>'--anchor-file ./.root is equivalent to passing the anchor on the command line.
| File | Role |
|---|---|
merkle-tree-node.js |
MerkleTreeNode, tree builders, prettyPrintMerkleTree, serializeShape. |
agent-play-merkle.js |
digestLeaf, digestPair, buildMerkleRootHex, prettyPrintDigestLevels. |
merkle-root-v3.js |
Same v3 scrypt derivation as tool.js (for reuse in other scripts). |
See node-validation.md for how the pieces fit together and how MerkleTreeNode.validate ties the anchor to buffer.txt. The anchor check in validate-merkle-node.js matches that behavior.