An open API service indexing awesome lists of open source software.

https://github.com/ben-arnao/messagechain

A blockchain for sending messages. Quantum-resistant, proof-of-stake, built to last centuries.
https://github.com/ben-arnao/messagechain

blockchain censorship-resistant cryptocurrency decentralized messaging proof-of-stake python quantum-resistant

Last synced: 20 days ago
JSON representation

A blockchain for sending messages. Quantum-resistant, proof-of-stake, built to last centuries.

Awesome Lists containing this project

README

          

# MessageChain

[![release](https://img.shields.io/github/v/release/ben-arnao/MessageChain)](https://github.com/ben-arnao/MessageChain/releases)
[![license](https://img.shields.io/github/license/ben-arnao/MessageChain)](./LICENSE)

An uncensorable public square. Posts, replies, communities, votes —
on-chain forever. **Your message can never be deleted.** A
well-formed message that pays the fee floor is guaranteed inclusion;
suppression is slashable — validators that drop or refuse to attest
to such a message lose stake on chain.

**Status:** mainnet live. Chain ID `messagechain-v1`, genesis block 0
`4eeb9edaadb42f1a460e95919bc667a3173c4a84aa9b5488da040ac7a1c054f6`.

**Live feed:** [messagechain.org](https://messagechain.org)

## Why

- **Your message can never be deleted.** Once a message is on-chain,
no platform, government, ISP, or validator can hide, filter, or
remove it. The ledger is the source of truth and there is no
takedown path.
- **Suppression is slashable.** A well-formed message that pays the
per-byte floor and fits the block budget cannot be quietly dropped.
Refusing to include or attest to such a message produces evidence
that any node can submit, and the offending validators lose stake.
- **Permanence is funded forever.** Storage is paid for by perpetual
validator rewards, not a one-shot endowment. The security budget
never runs out, so the promise of permanence does not have an
expiry date.
- **Costly to spam.** Every message costs real tokens, with the fee
scaling linearly in stored bytes. Bots can participate, but they
pay the same price as everyone else — AI-generated noise has a
floor.
- **Simple and durable.** Designed to run for centuries with minimal
moving parts. Slow blocks and expensive fees are features, not bugs.
Zero runtime dependencies outside the Python stdlib.
- **Democratic by default.** On-chain governance, distributed
validation, no privileged operators, no permissioned validator set.
L2s can layer reputation, identity, and moderation on top.
- **Cheap to validate.** Runs on commodity hardware — no GPUs, no
specialized rigs. Quantum-resistant signatures throughout.

## Install

Python 3.10+, no third-party deps.

```bash
git clone https://github.com/ben-arnao/MessageChain.git
cd MessageChain
pip install .
```

This puts a `messagechain` command on your PATH. You can run it the
same way via `python -m messagechain ` if you prefer.

## Getting started — your first message

### 1. Generate a private key (offline)

```bash
messagechain generate-key # write the 24-word recovery phrase on paper, 2–3 copies
messagechain verify-key # re-type to confirm the backup
```

`generate-key` prints a **24-word BIP-39 recovery phrase** as the
primary backup. The phrase has a built-in checksum that catches
single-word transcription errors when you type it back on
recovery — the hex form (also printed, labeled "alternative") has
no such protection, so a single typo silently produces a
different key and loses access.

Paper beats files — files get swept by cloud sync, backups, and
malware. Don't copy-paste (clipboard managers log history). Close
the terminal when done.

Your entity_id and `mc1…` address are derived deterministically from
the key.

### 2. Get tokens

MessageChain uses a **receive-to-exist** model: you do not need to
register anything on-chain to receive tokens. Your account appears in
chain state the moment someone sends you a transfer.

### 3. Post

**Fees.** Every CLI submission auto-prices by default. The picker
samples fee-per-byte across the last 50 blocks and bids the
percentile that matches your urgency rung — `high` (~1 block, 90th
pct), `normal` (~3 blocks, 75th pct, default), `low` (~10 blocks,
25th pct) — then multiplies by the tx's stored byte count, never
dropping below the protocol floor. Override with `--fee N` for a
specific bid. `messagechain estimate-fee --tx-type ...`
previews the cost of any tx without submitting.

**Post a message.**

```bash
messagechain send "hello world"
messagechain send "hello world" --fee 500 # manual fee
messagechain send "hi" --urgency high # ~1-block target
```

**Tag a community.** `--community-id NAME` groups the message under
a Reddit-style topic. The on-chain id is `sha256(name)[:16]`; any
human-readable name maps deterministically. No registry, no claim —
first-poster semantics; moderation is an app/indexer concern.

```bash
messagechain send "build report" --community-id mc-dev
```

**Reply to a message.** `--prev ` attaches a 32-byte
pointer to a prior on-chain message — apps render this as a reply,
chained long-form, citation, etc. The referenced tx must already
be in a strictly earlier block.

```bash
messagechain send "good point" --prev
```

**Long-form posts (>1024 chars).** A single message is capped at
1024 chars. For longer content, send a sequence and chain each
piece with `--prev` pointing at the previous tx_hash. The chain
requires each `--prev` target to be in a strictly earlier block,
so you'll wait one block (~10 min) between pieces.

**Run a poll.** `--poll-option TEXT` (repeat 1–4 times) turns a
message into a structured on-chain poll. The message body is the
question; the option list is the answer set. Options are immutable
once on chain.

```bash
messagechain send "favourite colour?" \
--poll-option red --poll-option green --poll-option blue
```

**Vote on a poll.** `--vote-target POLL_TXID:INDEX` references the
poll's tx_hash and the 0-based option you're picking. One vote per
(entity, poll) is enforced at consensus — the first vote is binding
forever, and the poll's author cannot vote on their own poll. The
running tally is computable from chain alone; the receipt page
(`/r/`) shows it live.

```bash
messagechain send --vote-target :2
```

**Up/down-vote a message.** `react --choice up|down|clear`
votes on a message. Re-voting supersedes; `--choice clear` retracts.
Each (voter, target) pair has a single latest choice in consensus
state.

```bash
messagechain react --choice up
messagechain react --choice clear
```

**Trust/flag a user.** Same `react` command with
`--target-type user`, passing the target's entity_id (raw hex).
`--choice up` = trust, `--choice down` = flag, `--choice clear` =
retract. Self-trust is rejected by the protocol.

```bash
messagechain react --target-type user --choice up # vouch
messagechain react --target-type user --choice down # flag
```

**First send.** Your first outgoing transaction reveals your
public key on-chain (the "first-spend pubkey install" path).
Subsequent transactions verify against the installed key — the CLI
handles this automatically.

**Defending against single-node suppression.** The default `send`
posts through one RPC endpoint. If you have reason to believe a
single validator might suppress your tx — say, posting under a
nation-state takedown threat — `send-multi` fans the signed tx out
to N≥3 validator HTTPS submission endpoints in parallel, persists
the signed receipts each accepting validator returns, and lets you
file a `CensorshipEvidenceTx` later if any receipted tx fails to
land. Fee / nonce / leaf-watermark auto-resolve via `--server`
(same as `send`); only `--keyfile` and `--endpoint` (×3+) are required.

```bash
messagechain --keyfile ~/.messagechain/keyfile send-multi "message body" \
--endpoint val-a.example:8443 \
--endpoint val-b.example:8443 \
--endpoint val-c.example:8443
```

`--keyfile` accepts the same formats `generate-key` produces — 24-word
mnemonic, 72-char checksummed hex, or raw hex. Omit it to be prompted
interactively for your recovery phrase.

The protocol's structural defense against validator collusion is
the slashable-suppression rule. `send-multi` is the user-side tool
for invoking it: one honest validator in the fan-out set is enough
to land the message, and any colluder that took the tx and dropped
it produces evidence the chain will slash on.

### 4. Read messages back

Wait one block (~10 minutes) for your message to be included, then:

```bash
messagechain read --last 20
```

### 5. Back up your wallet

**Your 24-word recovery phrase is your backup.** Write it down on
paper (or stamp it into metal) and store it offline. Anyone with
those words controls the account; lose them and the funds are gone
with no recovery. Don't put it in cloud sync, don't email it to
yourself, don't photograph it.

That's it. Restoring on a new machine just means feeding the phrase
back to any signing command (`--keyfile ` to a file containing
the phrase, or paste it at the prompt) — the wallet re-derives the
keypair and queries the network for your highest-used leaf so it can
resume signing safely.

#### Offline-signing power users only

If you sign on an air-gapped machine and broadcast later, the
network can't see leaves you've used until you broadcast them. In
that workflow the local leaf cursor at
`~/.messagechain/leaves/.idx` IS security-critical
between signings: re-signing at a leaf you've already burned offline
discloses that leaf's WOTS+ private key and produces equivocation
evidence on chain (100% slash on detection). Bundle the cursor with
your keyfile when moving the offline signer to new hardware:

```bash
messagechain backup-wallet --keyfile /path/to/keyfile
# writes -wallet-backup-.tar.gz in CWD
```

For online wallets — the default path — ignore this section. The
cursor is rebuilt from chain state on restore.

## CLI reference

### Personal wallet

```bash
messagechain generate-key # new private key (offline)
messagechain verify-key # confirm backup
messagechain account # print your address + entity_id
messagechain balance # liquid + staked tokens
messagechain send "hello" # post a message
messagechain send "hi" --community-id mc-dev # tag with a community
messagechain send "reply" --prev # reply/chain to a prior message
messagechain --keyfile send-multi "msg" \
--endpoint host:port --endpoint host:port \
--endpoint host:port # multi-validator HTTPS fan-out
# (defends against single-node
# suppression; auto fee/nonce)
messagechain react --choice up # up/down/clear-vote a message
messagechain react --target-type user --choice up # trust/flag a user
messagechain transfer --to mc1… --amount 100 # send tokens
messagechain read --last 50 # recent messages
messagechain estimate-fee --tx-type message --message "hi" # fee preview
messagechain receipt # cross-check inclusion +
# auto-prints next-step
# escalation command on
# NOT_FOUND / PENDING
messagechain submit-evidence censorship \
--receipt ~/.messagechain/receipts/.json
# file slashable evidence
# if validators are dropping
# your tx (receipt bundle is
# what `send` writes on submit)
messagechain backup-wallet --keyfile # offline-signers only:
# bundle keyfile + leaf cursor
```

### Chain & validator info

```bash
messagechain info # chain height, supply, sync
messagechain validators # validator set, stakes, shares
messagechain peers # P2P peers of the target node
messagechain status --server HOST:9334 # one-call health check
messagechain status --server HOST:9334 --entity YOUR_ID
# validator-specific leaf usage
messagechain ping # first-run sanity check
```

### Governance

```bash
messagechain propose --title "…" --description "…"
messagechain vote --proposal --yes
messagechain proposals # open proposals + tallies
```

### Validator operations

```bash
messagechain stake --amount 200 # lock as validator stake
messagechain unstake --amount 200 # ~15-day unbonding
messagechain start --mine # run a validator
messagechain key-status # WOTS+ leaf usage
messagechain rotate-key # fresh keypair, old key retired
messagechain upgrade # install the latest mainnet tag
```

## Run a validator

You need 300 tokens (one faucet drip — 200 stays staked, 100 covers
the stake-tx fee) and an always-on Linux host (Python 3.10+, ~2 GB
RAM) with inbound TCP **9333 + 9334** open in your cloud firewall.

```bash
# 1. on the host (as root) — installs MessageChain, generates the validator's
# keyfile, and prints its mc1... address. Save that address.
#
# Pull the script down and read it before running. The installer pins
# the install to the latest signed `vX.Y.Z-mainnet` tag and refuses to
# proceed if the tag isn't signed by a release signer baked into the
# script — but the script itself is the trust root, so eyeball it.
curl -fsSL -o install-validator.sh \
https://raw.githubusercontent.com/ben-arnao/MessageChain/main/scripts/install-validator.sh
less install-validator.sh # review before running as root
sudo bash install-validator.sh

# 2. fund the address printed above with one faucet drip from
# messagechain.org, or transfer 300 tokens from any wallet:
messagechain transfer --to mc1... --amount 300

# 3. back on the host, lock 200 of those tokens as stake (the
# remaining 100 covers the stake-tx fee):
sudo -u messagechain messagechain stake --amount 200

# 4. start
systemctl enable --now messagechain-validator messagechain-upgrade.timer messagechain-rotate-key.timer

# 5. verify
messagechain status
```

The installer's keyfile **is** the validator's identity — the same
key signs blocks and owns the stake. Back it up:
`sudo cat /etc/messagechain/keyfile` and store the hex offline.
**Important:** the keyfile alone is not a complete backup. See
*Operating a live validator → Back up the keyfile* below for the
WOTS+ leaf-state files that must be preserved alongside it; restoring
a keyfile without the matching leaf state will cause one-time WOTS+
leaves to be re-used and the chain will slash 100% of your stake on
detection.

Rewards = block reward + tx fees + attester pool share, pro-rata by
stake. The 200-token floor is a true minimum — there is no capital
wall on validator entry, and rewards scale linearly with stake at
this end of the curve. `messagechain validators` shows the live set
and per-validator share. Unbonding takes ~15 days (2176 blocks) —
slashing windows extend past departure, so don't shut a validator
down inside the unbonding window.

Operating a live validator (backups, migration, retirement, monitoring)

**Back up the keyfile AND the leaf-index files.** Three files together
make up a complete validator backup:

1. `/etc/messagechain/keyfile` — the hex secret. `sudo cat` it and
store offline (paper, hardware token, encrypted USB). Lose this
and the staked funds are gone with no recovery.
2. `/var/lib/messagechain/leaf_index.json` — the WOTS+ next-leaf
counter for block signing.
3. `/var/lib/messagechain/receipt_leaf_index.json` — the WOTS+
next-leaf counter for the submission-receipt key (only present on
validators that issue receipts).

The leaf-index files record which one-time WOTS+ leaves the keyfile
has already burned. **Restoring the keyfile without the matching
leaf-index files re-signs already-used leaves**, which mathematically
discloses the WOTS+ private key for those leaves and produces
equivocation evidence on chain. Pre-Tier 20 the protocol slashed
100% of stake on detection (`SLASH_PENALTY_PCT = 100`) with no
recovery path. At/after `SOFT_SLASH_HEIGHT = 15000` the per-offense
penalty drops to `SOFT_SLASH_PCT = 5` and the validator stays in
the set with reduced stake — but a leaf-index restore burns leaves
in BULK, producing many distinct equivocation events that compound
geometrically `(1 - 0.05)^N` toward total stake loss. Treat the
leaf-index files as security-critical state, not as a regenerable
cache. Snapshot them whenever you snapshot the keyfile, and never
restore one without the other.

**Migrate to a new host.** Stop the validator on the old host
(`systemctl stop messagechain-validator`), then copy **both** the
keyfile and the leaf-index files to the new host:

```bash
# on the OLD host — capture keyfile + leaf state atomically
# (after systemctl stop, so leaf_index.json is no longer being written).
sudo tar czf /tmp/mc-validator-backup.tgz \
-C / etc/messagechain/keyfile \
var/lib/messagechain/leaf_index.json \
var/lib/messagechain/receipt_leaf_index.json
# transfer /tmp/mc-validator-backup.tgz to the new host (scp, etc.)

# on the NEW host — extract, fix ownership, then run the installer
sudo tar xzf /tmp/mc-validator-backup.tgz -C /
sudo chown messagechain:messagechain /etc/messagechain/keyfile \
/var/lib/messagechain/leaf_index.json \
/var/lib/messagechain/receipt_leaf_index.json
sudo chmod 0600 /etc/messagechain/keyfile
```

Then run the installer on the new host. Init reuses the existing
keyfile rather than regenerating — no multi-hour keygen, and no
double-sign risk because only one host runs at a time. Skipping the
leaf-index files (e.g. copying just the keyfile, or restoring from a
keyfile-only paper backup after a disk-loss event) **will cause leaf
reuse and a 100% slash** the first time the new validator signs.
If you ever find yourself with a keyfile but no leaf-index, do NOT
start the validator — instead, reach out to a peer for a chain-state
inspection of your entity's existing on-chain signatures so you can
recover the high-water-mark leaf index before signing again.

**Drain & retire.** `messagechain unstake --amount 200` (or whatever
your current stake is — `messagechain status --entity YOUR_ID`
prints it), wait the full ~15-day unbonding window so the slashing
window closes, *then* shut the host down. Bringing a validator down
with stake still bonded risks downtime slashing.

**What gets you slashed.** Double-signing or equivocating — signing
two competing blocks at the same height — or WOTS+ leaf reuse, which
is detected as equivocation under the same rule. Leaf reuse is most
commonly caused by restoring a keyfile from backup without the
matching `leaf_index.json` (see *Back up the keyfile AND the
leaf-index files* above). The unbonding window exists so peers can
prove misbehavior committed before you left.

**Health monitoring.** `messagechain validators` (your stake share +
whether you're in the active set). `messagechain key-status` (WOTS+
leaf consumption — auto-rotation handles this at ≥95% but check by
hand if curious). `journalctl -u messagechain-validator -f` to follow
the log live.

**Manual upgrade.** `messagechain upgrade` installs the latest mainnet
tag. The weekly timer does this automatically; run it by hand if you
disabled the timer.

**Toggle automation.** `messagechain config set auto_upgrade false` /
`auto_rotate false` disables the timers.

**Cold authority.** `messagechain set-authority-key --authority-pubkey
` requires a cold-signed key for future rotations.
`messagechain emergency-revoke --entity-id ` is the cold-signed
kill switch.

**Manual run (no installer).** `messagechain generate-key`, store the
hex on paper, then `messagechain start --mine --rpc-bind 0.0.0.0
--data-dir /var/lib/messagechain --keyfile /etc/messagechain/keyfile`.
A systemd unit example ships at
[`examples/messagechain-validator.service.example`](./examples/messagechain-validator.service.example).
`messagechain doctor` runs preflight checks. `messagechain init` is
what the installer wraps — run it directly if you don't want the
curl-pipe.

## Learn more

Deeper dives on specific features and the design thinking behind
them — written for users, not implementers. Full index in
[guides/](./guides/README.md).

- [Identity, keys, and rotation](./guides/identity.md) — one live
key per entity, rotation preserves identity, plus cold authority
key and emergency revoke.
- [Quantum resistance and WOTS+](./guides/quantum-resistance.md)
— why MessageChain signs with hash-based signatures from day
one, and how versioned schemes handle future migrations.
- [Stable money over centuries](./guides/stable-money.md) —
dormancy-filtered active supply and why "X tokens" should mean
the same thing in 2126 as it does today.
- [Fees: how pricing actually works](./guides/fees.md) — flat
floor, per-byte component, EIP-1559-style burn, auto-fee picker.
- [Keeping rewards fair](./guides/fair-rewards.md) — the
diminishing-returns curve, founder divestment, and the lottery
that redistributes seed stake to the broader validator set.
- [Validator economics](./guides/validator-economics.md) — what
running a validator costs, what you earn, what's at risk, and
rough break-even math.
- [Governance: expensive proposals, permanent record](./guides/governance.md)
— how proposals work, who gets paid for voting, why most
results are advisory but recorded forever.
- [Anti-bloat: keeping the chain small enough to run forever](./guides/anti-bloat.md)
— slow blocks, the 1024-byte message cap, and worst-case storage
projections out to 50+ years.
- [Permanence guarantees](./guides/permanence.md) — the
protocol-level mechanics behind "your message can never be
deleted": archive duty, forced inclusion, slashable censorship
evidence.
- [Forum primitives](./guides/forum-primitives.md) — replies,
up/down votes, communities, long-form threading — the on-chain
building blocks any front-end can reassemble.
- [Reputation primitive](./guides/reputation.md) — trust and flag
votes between users, what the protocol stores, and where richer
reputation systems can be built on top.
- [Combating AI spam](./guides/ai-spam.md) — the thesis: real fee
floor + permanent reputation graph = bulk-AI-spam economics
that don't pencil out. No detection, no blocklists, no
proof-of-human.

## How MessageChain compares

How MessageChain stacks up against Nostr, Arweave, and DeSo: see
[COMPARISON.md](./COMPARISON.md).

## Security & changelog

- Vulnerabilities: see [SECURITY.md](./SECURITY.md) — private email
disclosure, 72h ack, 7d triage. Do not open a public issue.
- Release notes: see [CHANGELOG.md](./CHANGELOG.md).