Run a local network
This guide creates a private usernet node, two wallets and a miner on one machine. It does not use mainnet.
Build the three binaries first: build the binaries.
Why usernet
| Network | Flag | P2P port | API port | Use for |
|---|---|---|---|---|
| Mainnet | none | 3414 | 3413 | Real value. See connecting to mainnet |
| Floonet | --floonet | 13414 | 13413 | A test network with no public seed running |
| Usernet | --usernet | 23414 | 23413 | A private chain on your own machine |
Use usernet. It needs no seed peers and runs as a private chain on your machine. The CLI reference has the full per-network offsets.
Floonet's DNS seed does not resolve and no public node is running, so a floonet node finds no peers at height 0 unless you configure peers manually.
Neither test network produces blocks on its own. That is what the miner is for.
Lay it out first
Where files sit matters more than usual, because both binaries resolve their config from the current
working directory before falling back to ~/.epic/<network>. The directory you launch from is
therefore the instance selector, and that is what lets one wallet binary drive several wallets.
A layout that works:
epic-local/
.epic/user/ node data, the three binaries,
epic-server.toml and epic-miner.toml
wallet_alice/ epic-wallet.toml and wallet_data/, no binary
wallet_bob/ same
The node and miner share a directory safely, because their config filenames differ. Keep one wallet per
directory, and run the shared epic-wallet binary from inside whichever wallet you mean to act as.
1. Configure and start the node
Generate a config from inside the chain directory, so the paths land there:
epic --usernet server config
Then make four changes. only_randomx changes consensus, so the comment in the block is part of the
instruction:
[server]
# Consensus-changing. If you set this on a chain that already has blocks, delete
# chain_data first: blocks mined under the old policy will not validate under this one.
only_randomx = true
[server.p2p_config]
peer_min_preferred_outbound_count = 0
[server.stratum_mining_config]
enable_stratum_server = true
[logging]
log_to_file = true
Each one is required.
only_randomx = true forces a 100% RandomX policy. Epic normally assigns each height one of several
algorithms, and a single CPU miner can only answer the RandomX ones. On a real network other miners
cover the rest; on your own chain nobody does, so without this the miner idles on most heights. See
the block policy.
peer_min_preferred_outbound_count = 0 is not written into the generated file, so add the line
yourself. A node below that threshold reports itself as syncing forever, and a syncing node refuses to
hand out mining work. Usernet has no peers by design, so it can never reach the default of 4.
enable_stratum_server = true switches on the mining port. It is off by default on every network,
usernet included.
log_to_file = true because you will want the log when something does not mine.
Leave burn_reward = false and wallet_listener_url alone for now. A generated usernet config already
points at port 23415, which will be Alice.
epic --usernet server run
No peers available, can not sync in the log is the state you want, not an error. It means the node
stopped waiting for peers, which is what allows it to serve mining work.
2. Create the two wallets
Each in its own directory, using -w so the wallet is created there rather than in ~/.epic/user:
- Linux and macOS
- Windows
cd wallet_alice && epic-wallet --usernet init -w
cd ../wallet_bob && epic-wallet --usernet init -w
Set-Location wallet_alice; epic-wallet --usernet init -w
Set-Location ..\wallet_bob; epic-wallet --usernet init -w
-w takes no value. It is declared on init only, so later commands use --current_dir <path>
instead, or you run them from inside the wallet directory.
Record both recovery phrases. They are worthless here, but the habit is not.
Two wallets on one machine collide on two ports, so edit Bob's:
api_listen_port = 23425 # Foreign API. Alice keeps 23415
owner_api_listen_port = 3421 # Owner API, see below
[tor]
use_tor_listener = false
The Foreign port is derived from the network, so usernet already moved it away from mainnet's. The Owner
port does not shift per network. It is 3420 everywhere, so a second wallet on the
same machine always collides there whatever chain it runs. Set use_tor_listener = false in both wallets,
per turn off the Tor listener. Both wallets also need an
[epicbox] section before the epicbox transport will work on this chain, which
run a local epicbox relay sets up.
~/.epic need the node's API secretLeft in the default location, node and wallet share ~/.epic/<network>/ and resolve the node API secret
to the same .api_secret file, so this is invisible. Because -w put each wallet elsewhere, each
generated its own secret, which the node will reject with a 401. See
the credential the wallet presents to the node.
Two ways out. Either copy the node's .api_secret into each wallet directory, which leaves every
default working, since the wallet only creates that file when it is missing. Or, for a throwaway chain,
comment out api_secret_path in epic-server.toml and node_api_secret_path in both wallet configs.
Both keys are optional, so an absent key means no secret, and no credential path is exercised.
3. Mine coins into Alice
The Stratum server asks a wallet listener to build each coinbase, so Alice must be listening before blocks are worth anything.
# in wallet_alice
epic-wallet --usernet listen -n
Then start the miner from the chain directory, with epic-miner.toml alongside it:
[mining]
algorithm = "RandomX"
stratum_server_addr = "127.0.0.1:23416"
miner_plugin_config = []
[mining.randomx_config]
threads = 3
jit = true
miner_plugin_config is required even for RandomX, and it must sit inside [mining] above every
sub-table, or TOML attaches it to the wrong table and the miner exits with
missing field 'miner_plugin_config'.
epic-miner
Success looks like this:
INFO Mining: RandomX at 475 hps (hashes per second)
INFO Block Found!!
INFO Share Accepted!!
Watch Alice's balance climb. Each block pays 14.5792 EPIC at era 1, being the 16 EPIC base reward less the 8.88% foundation levy:
epic-wallet --usernet info
Coinbase maturity on usernet is 3 blocks
(USER_TESTING_COINBASE_MATURITY),
against mainnet's 1,440. See emission timing. The
wallet's own confirmation floor is separate, so pass --min_conf 3 on send and info here; see
read what the wallet knows.
4. Decouple mining from the wallets
Once Alice has coins, stop the miner and set:
[server.stratum_mining_config]
burn_reward = true
Restart the node and the miner. Rewards are now discarded. With burn_reward = false and no listener up,
the node cannot build a coinbase and stops producing blocks entirely, which couples block production
to a wallet being up. Alice keeps what she already mined.
You can now stop Alice's listener. Blocks keep coming, so transactions keep confirming.
5. Confirm the rig
epic --usernet client status # height climbing
epic-wallet --usernet info # from each wallet directory
Alice should show a spendable balance and Bob zero. That is the starting state for your first transfer.
If something goes wrong
| Symptom | Cause |
|---|---|
Miner logs Node is syncing - Please wait | peer_min_preferred_outbound_count is still 4 |
Miner logs 0 hps and algo from job progpow | only_randomx is not set |
Node log fills with Share ... submitted too late | The same idle miner, still submitting against the previous height's job |
| Node stops producing blocks | burn_reward = false with no wallet listener up, so no coinbase can be built |
Node loops on CoinbaseSumMismatch at height 1440 and its API goes unreachable | The first foundation levy boundary, one day of blocks in. Observed with burn_reward = true. Set enable_stratum_server = false to get the API back and read the chain, and treat 1440 as the ceiling for a burned-reward chain |
| Wallet gets 401 from the node | Wallet and node disagree about the API secret, see step 2 |
Balance shows but Currently Spendable is zero | Coinbase maturity, or the --min_conf default of 10 |
Blocks rejected with InvalidSortAlgo, or Block rejected with Expected RandomX got Cuckoo15 | run_test_miner is enabled somewhere. It produces Cuckoo proofs only, which the RandomX policy rejects |
| A wallet command acts on the wrong wallet | Run it from that wallet's directory, or pass --current_dir <path> |
Reset
Delete chain_data for a fresh chain. The wallet databases will then disagree with it, so delete each
wallet_data and re-init, or accept wrong balances. Deleting the whole tree and rebuilding from this
page takes a couple of minutes.