You need Divi 3.0.0 installed as in start your first regtest node. The script below makes its own data folder and its own ports, so it can run next to the node in ~/divi-regtest without touching it. Blocks are made by the C++ node with setgenerate; IronDivi cannot make regtest blocks, but it can follow a chain built this way, as shown in two regtest nodes.
1Two kinds of "the same"
A regtest chain can be "the same" in two different ways, and it pays to know which one your test needs.
| Same shape | Same bytes | |
|---|---|---|
| How you get it | Run the same script on an empty folder | Copy a stopped node's folder and start the copy |
| Heights, balances, amounts, confirmations | Identical | Identical |
| Genesis block | Identical | Identical |
| Addresses, transaction ids, block hashes | New every run | Identical |
| Good for | Tests that check amounts and states | Tests that compare hashes, fixtures shared between machines, bug reports |
Why do hashes change? Every fresh wallet makes new random keys, so every reward goes to a different address, and every block records the time it was made. The node has no switch to fix either one: its generateblock command can add chosen transactions to a block but cannot set the block's time. So a script gives you the same shape, and a snapshot gives you the same bytes.
2The script
Download make-chain.sh and make it executable. It takes three arguments: a data folder and two ports. It writes a regtest divi.conf with a fresh random RPC password, starts the node, makes 101 blocks, sends 500 DIVI to an address called Alice and 250 to one called Bob, and confirms both.
curl -O https://services.divi.domains/tutorials/reproducible-chain/make-chain.sh chmod +x make-chain.sh ./make-chain.sh ~/regtest-fixture 51496 51497
The parts worth reading before you run it:
- It deletes the folder you give it. That is what makes every run start from nothing. To keep you from losing something by a typo, it refuses unless the folder is empty, does not exist, or holds a
divi.confwithregtest=1. - It stops if the node does not start. If either port is taken,
dividexits, and the script says so and points at the log instead of waiting forever. - The password never appears on a command line. It is written straight into
divi.conf, which only you can read, anddivi-clireads it from there. - Binaries come from
~/divi-3.0.0/binunless you setDIVIDandCLIto other paths.
Change the middle of the script to build the chain your test needs: more addresses, a vault (see vaults on regtest), payments at exact heights (see give yourself coins on regtest). Keep the shape of it: make blocks, act, make blocks.
3Run it twice and compare
Two runs, two folders, two sets of ports, one after the other:
./make-chain.sh ~/regtest-fixture 51496 51497 height 107 balance 99999.99995480 alice 500.00000000 in 915b92eeba6a21f9e616d8f84b52fd15f6878bf01f09f58f56ca0bdc3ece9841 ("confirmations":6) bob 250.00000000 in cd4ddcce07ac1bcd356aff93589838c90ec806c95762bd17ca4ad7aaa6c25fa4 ("confirmations":5) tip hash 9d105aa50f23c71bc4061b3743783dec650c1ae442d25d56a6890dccc90308c3 genesis 0000000b3f9980dcf71f5f52d69e30d3b02f807e0a77b91b6091701e4ae51a6f ./make-chain.sh ~/regtest-fixture-2 51506 51507 height 107 balance 99999.99995480 alice 500.00000000 in ac6fbccd2b41d5f8fe40ef4114528e1487d1fc0ed182c48840978615f0b6b5a9 ("confirmations":6) bob 250.00000000 in 5474c91ccdb2a99aeae79ceef1f5d9bd026c56aaac541ca0333f73ceb7551fd5 ("confirmations":5) tip hash 140a5ec76990699fb2163ac1a6dda2584b4938e5c1806bccb00d305101220e78 genesis 0000000b3f9980dcf71f5f52d69e30d3b02f807e0a77b91b6091701e4ae51a6f
Every number matches; every hash after the genesis block differs. Each run took four to five seconds.
Two details explain the numbers. The balance is 99,999.9999548, not 99,250, because Alice and Bob are addresses in the node's own wallet, so the only money that left the wallet is the two fees. And Bob has 5 confirmations to Alice's 6 because his payment went into block 103 and hers into block 102.
4Freeze a chain with a snapshot
To get the same bytes, build the chain once, stop the node, and pack its regtest folder. Stop first: copying the files of a running node can catch the database half-written.
divi-cli -datadir=~/regtest-fixture stop
tar -C ~/regtest-fixture -czf ~/regtest-fixture.tgz regtest
ls -l ~/regtest-fixture.tgz
… 496457 … regtest-fixture.tgz
The 107-block chain packs to under half a megabyte (19 MB unpacked, mostly preallocated block files).
regtest, not divi.conf
The snapshot holds the chain and the wallet, which is what you want. Leave divi.conf out: it holds the RPC password, and a snapshot often ends up in a git repository or a shared folder. Each machine that uses the snapshot writes its own divi.conf with its own password and ports, as the script does. The wallet inside is a regtest wallet, worth nothing anywhere else, so sharing it is fine.
5Play, then reset
Unpack the snapshot into any folder that has a regtest divi.conf and start a node on it. It comes back at the same height with the same tip hash, and the same transaction is still there with the same confirmations:
divid -datadir=~/regtest-play -daemon divi-cli -datadir=~/regtest-play getbestblockhash 9d105aa50f23c71bc4061b3743783dec650c1ae442d25d56a6890dccc90308c3 divi-cli -datadir=~/regtest-play getbalance 99999.99995480 divi-cli -datadir=~/regtest-play gettransaction 915b92eeba6a21f9e616d8f84b52fd15f6878bf01f09f58f56ca0bdc3ece9841 … "confirmations" : 6, …
Now do whatever your test does. Here, a payment and three blocks:
divi-cli -datadir=~/regtest-play sendtoaddress $(divi-cli -datadir=~/regtest-play getnewaddress) 42
divi-cli -datadir=~/regtest-play setgenerate 3
divi-cli -datadir=~/regtest-play getblockcount
110
To go back, stop the node, replace the regtest folder with the snapshot, and start again. The three blocks and the payment are gone:
divi-cli -datadir=~/regtest-play stop rm -rf ~/regtest-play/regtest tar -C ~/regtest-play -xzf ~/regtest-fixture.tgz regtest divid -datadir=~/regtest-play -daemon divi-cli -datadir=~/regtest-play getblockcount 107 divi-cli -datadir=~/regtest-play getbestblockhash 9d105aa50f23c71bc4061b3743783dec650c1ae442d25d56a6890dccc90308c3
The rm -rf line deletes the chain in that folder. Check the path before you press Enter, and never point it at a folder you have not restored from a snapshot.
7Use it in a test run
Which to use depends on the test:
- The script when your test checks amounts, balances and states, and you want the fixture to follow the node version you test against. Five seconds per run is cheap.
- The snapshot when your test compares hashes, or several machines must see one chain, or you want to attach the exact chain to a bug report.
Either way, each test run follows the same four steps: build or restore, start and wait until getblockcount answers, run the tests, stop the node. The waiting loop in the script is the one to copy: it gives up if divid exits rather than spinning forever. How to talk to the node from Python or JavaScript is in test your app on regtest.
If something goes wrong
| Symptom | Cause | Fix |
|---|---|---|
divid exited: see …/debug.log (port … already in use?) | Another node or program holds one of the two ports | Pick two other ports. On Linux, ss -ltn lists the ports in use. |
refusing to delete …: it is not empty and has no regtest divi.conf | The folder you named holds something else | Name a new or empty folder. The guard is doing its job. |
| Restored node starts at height 0 | The snapshot was unpacked one level too deep, so there is no regtest folder directly inside the data folder | List the data folder: it should contain divi.conf and regtest. |
| Restored node's tip hash differs from the snapshot's | The snapshot was taken while the node was running, or the node made blocks after the restore | Stop the node before packing; restore again. |
| Your test asserts a transaction id and fails on every new run | Ids change between script runs | Assert amounts and confirmations, or switch to a snapshot. |
Still stuck? Ask the Divi chatbot, or see all tutorials.