StoryCoin is a collaborative storytelling experiment built around a pair of blockchains:
- an outer blockchain that stores the accepted sequence of words in the story, and
- an inner vote chain that tracks proof-of-work votes for each proposed next word.
Participants open the web UI, propose words, and use their browser to mine votes. The Rust node accepts the strongest vote chain for each candidate word and can advance the story by appending the most-voted word as the next block.
StoryCoin is split across three runtime pieces plus a small browser client:
-
Rust blockchain node (
src/server.rs)- Maintains the authoritative
Blockchainand in-memory vote state. - Accepts JSON commands such as
get_story,get_blocks,get_votes,set_blocks,set_votes, andchoose_next_word. - Stores one block per accepted story word.
- Validates vote chains with a proof-of-work rule before accepting them.
- Maintains the authoritative
-
Python web server (
webserver.py)- Serves the Bottle application and the browser UI from
static/index.html. - Accepts WebSocket connections at
/websocket/<name>. - Relays messages between browsers and the Rust node through Redis queues.
- Serves the Bottle application and the browser UI from
-
Python mesh-network wrapper (
network.py)- Starts the Rust node as a subprocess.
- Connects to the
mesh-networkinglibrary so nodes can exchange messages over UDP. - Uses
RedisProgramto bridge network messages into Redis-backed queues.
-
Browser client (
static/index.htmlandstatic/js/)- Displays the current story and proposed words.
- Mines votes in the browser using JavaScript hashing.
- Sends vote updates and story requests over a WebSocket.
Block(src/blockchain.rs): stores a story word vote chain, a block id, and the previous block hash.Blockchain(src/blockchain.rs): the ordered list of story blocks. The longest valid chain wins.Vote(src/wordvote.rs): one proof-of-work vote for a candidate word.VoteChain(src/wordvote.rs): the chain of votes for a specific word. The longest valid vote chain wins for that word.
Browser UI
-> WebSocket
Python Bottle server
-> Redis lists (node-recv / node-send)
Rust blockchain node
-> optional UDP mesh propagation via network.py
Other peers
src/lib.rs- Rust library rootsrc/server.rs- Rust node executablesrc/blockchain.rs- story blockchain logicsrc/wordvote.rs- vote-chain logic and proof-of-work checkssrc/hash_utils.rs- SHA-512 helperssrc/io_queue.rs- Redis queue helperswebserver.py- Bottle + WebSocket servernetwork.py- mesh-network entry pointstatic/- HTML, JS, and CSS assetstests/tests.rs- Rust tests for hashing and blockchain behavior
You need the following installed locally:
- Rust and Cargo for the blockchain node
- Python plus the packages in
requirements.txt - Redis running locally on
127.0.0.1:6379
The current code assumes Redis is reachable at redis://127.0.0.1/ and that the web server can bind to port 80.
cargo buildThis produces the blockchain server binary at:
target/debug/server
pip install -r requirements.txtStart a local Redis server using your platform's usual command, for example:
redis-servercargo buildpython webserver.pyThe server listens on 0.0.0.0:80 and serves:
/- a short help message/<name>- the StoryCoin UI for a participant name/websocket/<name>- the WebSocket endpoint used by the UI
Example:
http://localhost/alice
From the browser UI you can:
- view the current story,
- propose a new word,
- mine votes for a word in the browser,
- see the list of connected participants, and
- manually advance the story to the most-voted next word.
If you want to run the mesh-network wrapper instead of just the web server:
python network.pyNotes:
network.pystartstarget/debug/server, so the Rust binary must already exist.- The script currently creates
UDPLink('en0', 2010), so you may need to adjust the interface name for your machine.
Run the existing Rust tests with:
cargo testAt the time this README was updated, the existing test suite passed locally.
serde,serde_derive,serde_json- Used to serialize and deserialize blocks, vote chains, and messages exchanged with the Python layer.
rust-crypto- Provides the SHA-512 implementation used by
hash_utils.rsand vote/block hashing.
- Provides the SHA-512 implementation used by
redis- Used by
src/io_queue.rsso the Rust node can read commands and publish responses through Redis lists.
- Used by
rand- Included as a Rust dependency, though the current checked-in code does not appear to use it directly.
nix- Included for Unix-oriented functionality; imported in
src/server.rsbut not actively used in the current code.
- Included for Unix-oriented functionality; imported in
time- Included for time-based behavior; there are commented-out timing hooks in
src/server.rs.
- Included for time-based behavior; there are commented-out timing hooks in
redis- Python Redis client used by
webserver.pyto pass WebSocket messages to the Rust node.
- Python Redis client used by
geventandgevent-websocket- Provide the WSGI server and WebSocket support used by the Bottle app.
bottle- Serves the HTML UI and static assets.
mesh-networking- Supplies
Node,UDPLink, andRedisProgramfor peer-to-peer networking innetwork.py.
- Supplies
The browser UI loads a few third-party libraries directly from CDNs in static/index.html:
- jQuery slim
- Tether
- Bootstrap JavaScript
It also serves local static assets such as bootstrap.min.css, mining.js, and the animated background scripts from /static/.
- The Rust node and Python web server communicate through Redis list keys named
node-recvandnode-send. - The browser mines vote nonces client-side, so multiple open browsers can contribute proof-of-work votes.
- The project is an experiment and still contains a few hard-coded assumptions, including Redis on localhost, port
80, and theen0network interface innetwork.py.