The verifier is a Docker container. It runs on any always-on machine with Docker. The desktop app is not involved. Being in the majority is not required to be paid.
What you need
| A machine that stays on | Linux, macOS, or Windows with Docker and Docker Compose 2.24 or newer. Outbound internet only. No port forwarding |
| A new wallet | Used only for this. Step 2 creates it |
| 50 TTT | The stake. For your first 50 TTT, ask @xphorm:matrix.org, Torrentech’s admin, in #torrentech:matrix.org |
| A little ETH on Arbitrum One | Gas for the join, and for every commit, reveal, and settlement |
| An Arbitrum One RPC (optional) | The default is the public https://arb1.arbitrum.io/rpc. Your own RPC is more reliable |
The deposit can be taken
The stake is lost for any of these:
- Two different commits on one check. This happens when two copies of the verifier run with the same key. Run one copy per key.
- A reveal that does not match the commit.
- A commit that is never revealed. The reveal needs a salt the verifier keeps in its data volume. Losing that volume between commit and reveal, or stopping the verifier for longer than the reveal window, leaves the commit unrevealed. Anyone can then claim the fault.
An honest answer that loses the vote is not punished. After a slash you can stake again.
1. Get the compose file
mkdir torrentech-verifier && cd torrentech-verifier
curl -fsSLO https://www.torrentech.org/verifier/docker-compose.yml
It runs the public image registry.gitlab.com/torrentech/torrentech-verifier:latest with the Arbitrum One contract addresses already set. No login is needed to pull it.
2. Create the wallet
This writes a new key straight into verifier.env and never prints it:
(umask 077; docker run --rm registry.gitlab.com/torrentech/torrentech-verifier:latest \
node -e "console.log('VERIFIER_CYCLE_PRIVATE_KEY=' + require('ethers').Wallet.createRandom().privateKey)" \
> verifier.env)
verifier.env is the only place the key lives. It is readable by you alone (-rw-------). Back it up somewhere safe; without it the stake cannot be withdrawn. Do not paste it into chat, and do not share docker compose config output, which prints it.
To use an existing wallet instead, write one line into verifier.env yourself: VERIFIER_CYCLE_PRIVATE_KEY=0x<64 hex>, then chmod 600 verifier.env.
3. Turn on checking
Create .env next to the compose file:
printf 'VERIFIER_DIAL=1\nVERIFIER_INTERVAL_SECONDS=300\n' > .env
| Setting | Why |
|---|---|
VERIFIER_DIAL=1 | Dials the pinner. Without it every answer would be “could not reach” |
VERIFIER_INTERVAL_SECONDS=300 | One pass every 5 minutes. The commit window is 15 minutes, so keep this well under 900 |
VERIFIER_RPC_URL=… (optional) | Your own Arbitrum One RPC |
These go in .env, not in verifier.env. Compose reads .env to fill in the settings; verifier.env holds only the key.
4. Fund and join
See the wallet address and balances:
docker compose run --rm verifier node scripts/verifier-stake.js status
Wallet: 0x…
Stake: none
Enrolled: no
TTT balance: 0.0 (stake is 50.0)
ETH for gas: 0.0
Send the address to @xphorm:matrix.org in #torrentech:matrix.org for the 50 TTT, and put a little ETH on Arbitrum One on it. When status shows both, join:
docker compose run --rm verifier node scripts/verifier-stake.js join
join approves 50 TTT to VerifierRegistry, stakes, and enrolls on VerifierAssigner. It skips a step that is already done and prints each transaction hash. It stops with a plain message when the wallet is short of TTT or has no ETH for gas. Run status again: Stake: active, Enrolled: yes.
You enter draws from the first round (30 minutes) that starts after you enroll.
5. Run it
docker compose up -d
docker compose logs -f
The container restarts after a crash and keeps its data in the torrentech-verifier_verifier-data volume. Each pass looks at the recent checks, including the many you are not on, and prints a line for each one it acted on or skipped:
| Line | Meaning |
|---|---|
commit sent 0x… | You are on a check and committed your answer |
reveal sent 0x… | The answer is revealed. Pay follows once the check has a majority |
settle-verifier sent … | Your verifier settled 1 TTT for a committee member, you or another |
settle-pin sent … | Your verifier settled a pinner’s 5 TTT for a passed check |
settle-moderation sent … | Your verifier settled a moderator’s review credit |
slash sent … | Another member committed and never revealed; your verifier reported it |
skip not-committee … | A check you are not on. Normal |
shadow … | Your verifier’s own reading of a recent check, compared with the committee’s answer. Information only |
skip reward-budget … | Today’s verifier pool is spent. It refills at 00:00 UTC |
skip no-dial … | VERIFIER_DIAL=1 is missing from .env |
6. Pay
| Rule | Live behavior |
|---|---|
| Per check | 1 TTT to each member who revealed and was not slashed, once the three have a majority answer |
| Draws | Up to 24 checks every 30 minutes, three verifiers each, picked at random from the active pool. A verifier is never put on its own pins |
| Daily pool | 5,000 TTT for all verifiers together. One wallet can receive at most 5,000 TTT a day across all pay |
| Payout | The verifier sends the settlement itself. There is no claim button |
Updating
docker compose pull
docker compose up -d
The data volume carries pending reveals across the restart. Keep the downtime short: a commit must still be revealed inside its window.
Leaving
- Check that nothing is waiting to be revealed. The last
commit sentindocker compose logsshould have itsreveal sentafter it. If not, wait up to 30 minutes. - Start unbonding. You leave the pool at once:
docker compose run --rm verifier node scripts/verifier-stake.js leave - Stop the verifier with
docker compose down. Leave out-v; the volume is harmless to keep. - One day later, take the stake back.
withdrawsays when it opens if you are early:docker compose run --rm verifier node scripts/verifier-stake.js withdraw
To come back later, run join again.
Troubleshooting
This wallet holds 0.0 TTT. The stake is 50.0 TTT.Ask @xphorm:matrix.org in #torrentech:matrix.org, then runjoinagain.This wallet has no ETH on Arbitrum One for gas.Send a little ETH on Arbitrum One (not Ethereum mainnet) to the wallet address.The RPC is chain …VERIFIER_RPC_URLpoints at another network. Use an Arbitrum One RPC.VERIFIER_CYCLE_PRIVATE_KEY is missing or not a private key.verifier.envis missing, empty, or not next todocker-compose.yml.- Running, and never on a check.
statusmust sayStake: activeandEnrolled: yes. With few pinners there are few checks; a quiet day is normal. Stake: slashed. The stake was taken for one of the faults above. Find out why before joining again, usually a second copy running with the same key.
Help: #torrentech:matrix.org.