DanSandClaude Opus 5.5 69bb035e7e wallet/main: break the replay -> witness-rebuild -> kill loop on large wallets
A v1.3.0 node with a ~13.6k-note wallet (-dbcache=4084) looked hung for hours:
every start replayed ~62k blocks from a chainstate 26 days stale, then ran a
47-60 min all-core witness rebuild holding LOCK2(cs_main, cs_wallet) (RPC answered
HTTP 500 "Work queue depth exceeded", peers timed out), the GUI killed it before
anything was flushed, and the next start did it all again. Even after escaping,
each new block cost ~30s under LOCK2, so the node fell behind a 36s chain.

D1  BuildWitnessCache: the post-rebuild latch computed witnesses.front().root()
    (~2.4ms) for every pending note on every block, only to feed a log line that
    is printed for bulk rebuilds alone. The anchor check now runs on the Phase-2
    workers and only for a bulk rebuild; the per-block path just sets the latch.
    Phase 2 also runs in parallel whenever the job is big (notes x commitments
    >= 2000), not only for a bulk range, so busy blocks no longer extend every
    note serially. If the OS refuses a worker thread, the remaining shards run
    inline instead of unwinding past joinable threads (std::terminate).

D2  FlushStateToDisk: the coins cache was only flushed on shutdown, gettxoutsetinfo
    or after 24h; on this chain it stays a few MiB, so the size triggers never
    fire and a node that never reached 24h uptime or a clean stop kept its
    chainstate (and block index) weeks behind. Flush at least hourly and every
    DATABASE_FLUSH_BLOCKS (5000) connected blocks -- the latter also inside one
    long ActivateBestChain -- and right after the startup ActivateBestChain when
    it moved the tip.

D3  UpdatedNoteData: a replayed or rescanned tx arrives with FindMySaplingNotes
    data (no nullifier). Witnesses and witnessHeight were carried over but the
    nullifier was dropped, so VerifyAndSetInitialWitness cleared and reseeded the
    witnesses on the next block -- the replay above rewrote 3,750 txs and forced
    the full rebuild. Carry the nullifier with the witnesses, unless the tx was
    re-mined in a different block (its notes moved; reseed as before). When the
    merged data is identical, don't rewrite the tx; just clear the in-memory
    witnessRootValidated so the next block re-checks the kept roots once (a
    rescan still finds and reseeds a witness that went bad, without rebuilding
    the healthy ones). The carry loop no longer deep-copies every note.

    SetBestChain: with hourly coin flushes the wallet locator must not run ahead
    of the async notifier, or a crash permanently skips the blocks it had not yet
    delivered. Stamp the block the wallet's state reflects (pindexWalletTip,
    seeded in init before ThreadNotifyWallets starts -- at the startup rescan's
    checkpoint if that rescan was interrupted -- and advanced contiguously by
    ChainTip), like zcashd's ChainTipAdded. ThreadNotifyWallets no longer hands
    the wallet an empty block after a fatal block-read failure.

Tests: new gtest test_wallet_notedata.cpp (5 tests); 23/23 gtests pass, and the
two core D3 tests fail with D3 reverted. Regtest A/B against master with a
1,008-note wallet: notify-thread CPU per block 1,780ms -> 3ms; worst LOCK2 RPC
stall 1.6-2.9s -> 10-15ms on ordinary blocks and 4.6-7.1s -> ~1.6s on a block
carrying a 40-output self-send; a z_importkey rescan went from 35 reseeds plus a
bulk rebuild (10.6s) to 0 reseeds, same balance; after kill -9 at 150 blocks a
build with a 100-block flush threshold restarted at 100, master at 0. Two
adversarial review rounds; every confirmed finding is addressed here.

Not covered: the hourly SetBestChain/flush paths were reviewed, not exercised
(GetTimeMicros ignores mocktime); no run yet against a copy of a real large wallet.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-30 19:05:45 -05:00
2021-01-26 08:56:08 -05:00
2024-02-27 23:59:59 +01:00
2024-03-15 15:14:26 -04:00
2024-03-31 23:54:32 +02:00
2019-08-07 04:56:24 -07:00
2019-08-07 04:56:24 -07:00
2026-01-01 15:24:57 -05:00
2017-10-22 04:08:53 +02:00

DragonX

DragonX

A fully-private, RandomX CPU-mineable cryptocurrency.

Introduction Build Run Mine
What is DragonX? Build from source Run a node CPU mining
Key facts Install a release Fastest sync Wallets

What is DragonX?

DragonX implements extreme privacy via blockchain technology. It is private from genesis: every ordinary transaction is shielded (z2z), so your transaction metadata stays private. DragonX is based on Bitcoin code with Zcash's zero-knowledge Sapling cryptography, and its defining feature is RandomX Proof-of-Work — it is mined with a CPU, not ASICs or GPUs.

DragonX has its own genesis block. Its lineage is Bitcoin → Zcash → Komodo → Hush → DragonX; it is a fork of the Hush full node, with the Proof-of-Work changed from Equihash to RandomX and privacy enforced from the very first block.

This software is the DragonX full node and command-line client. It downloads and stores the entire history of DragonX transactions; depending on your computer and network connection this can take a while, so most users start from the bootstrap snapshot.

DragonX is experimental software. Use at your own risk, just like Bitcoin.

Key facts

Ticker DRAGONX
Proof-of-Work RandomX (CPU-mineable)
Privacy fully private from genesis (ac_private=1, Sapling active at height 1)
Block time 36 seconds
Block reward 3 DRAGONX, halving every 3,500,000 blocks
Max block size 4 MB
RPC port 21769
P2P port 18030
Data directory ~/.hush/DRAGONX (Linux)
Config file DRAGONX.conf
Binaries dragonxd, dragonx-cli, dragonx-tx

Fastest way to sync (bootstrap)

The quickest way to get a fully-synced node is the signed bootstrap snapshot, which installs a pre-built blockchain so you skip re-validating the whole chain from genesis:

# Stop dragonxd first if it is running, then:
./util/bootstrap-dragonx.sh

The script preserves your wallet.dat and DRAGONX.conf, verifies the download's checksums and (once a release key is published) its cryptographic signature, then starts you near the chain tip. If you prefer to sync from the network instead, a larger -dbcache (e.g. -dbcache=2048) noticeably speeds up the initial block download.

Build from source

Building uses 3 build processes by default; you need ~2GB of RAM for each.

Debian or Ubuntu

sudo apt-get install build-essential pkg-config libc6-dev m4 g++-multilib \
      autoconf libtool ncurses-dev unzip git zlib1g-dev wget \
      bsdmainutils automake curl unzip nano libsodium-dev cmake
git clone https://git.dragonx.is/DragonX/dragonx
cd dragonx
./build.sh -j3

Arch

sudo pacman -S gcc libsodium lib32-zlib unzip wget git python rust curl autoconf cmake
git clone https://git.dragonx.is/DragonX/dragonx
cd dragonx
./build.sh -j3

Fedora

sudo dnf install make automake gcc gcc-c++ kernel-devel cmake libtool ncurses-devel patch -y
git clone https://git.dragonx.is/DragonX/dragonx
cd dragonx
./build.sh -j3

macOS

Install Xcode Command Line Tools and Homebrew, then:

xcode-select --install
brew install gcc autoconf automake pkgconf libtool cmake curl

# Install Rust (needed for librustzcash on macOS Sequoia+)
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh
source "$HOME/.cargo/env"

git clone https://git.dragonx.is/DragonX/dragonx
cd dragonx
# Make sure libtool gnubin and cargo are on PATH
export PATH="$HOME/.cargo/bin:/usr/local/opt/libtool/libexec/gnubin:$PATH"
./build.sh -j3

For a release build:

export PATH="$HOME/.cargo/bin:/usr/local/opt/libtool/libexec/gnubin:$PATH"
./build.sh --mac-release -j$(sysctl -n hw.ncpu)

Windows (cross-compiled on Linux)

sudo apt-get install \
      build-essential pkg-config libc6-dev m4 g++-multilib libdb++-dev \
      autoconf libtool ncurses-dev unzip git zip \
      zlib1g-dev wget bsdmainutils automake mingw-w64 cmake libsodium-dev
git clone https://git.dragonx.is/DragonX/dragonx
cd dragonx
./util/build-win.sh -j$(nproc)

ARM (Raspberry Pi)

Any ARMv7 machine cannot build this repo because the underlying zk-SNARK library does not support that instruction set. You need an ARMv8-based board (Raspberry Pi 4 or newer). Either install an aarch64 release package (see below) or cross-compile from amd64.

Installing DragonX binaries

  1. Download a release with a .deb extension.
  2. Install it, substituting the version you downloaded: sudo dpkg -i dragonx-VERSION-amd64.deb (or -aarch64.deb on ARM).
  3. Run with: dragonxd.

Running a node

Start the daemon:

./src/dragonxd

It stores data in ~/.hush/DRAGONX and reads ~/.hush/DRAGONX/DRAGONX.conf. Query it with ./src/dragonx-cli, for example:

./src/dragonx-cli getinfo

To run DragonX as a background service, see doc/dragonxd-systemd.md.

CPU mining (RandomX)

DragonX is CPU-mineable via RandomX (the same algorithm family as Monero); ASICs and GPUs do not apply. To mine with your node, enable generation and choose how many threads to use:

# mine with 4 CPU threads
./src/dragonxd -gen=1 -genproclimit=4

or add to DRAGONX.conf:

gen=1
genproclimit=4

Mining rewards arrive as transparent coinbase, which is directly spendable; you can optionally move it into the shielded pool with z_shieldcoinbase (see doc/shield-coinbase.md). For more on the algorithm and its tuning options, see doc/randomx.md.

Wallets

The DragonX full node includes a built-in wallet, managed via dragonx-cli (see doc/wallet-backup.md and doc/seed-phrase.md).

Graphical and mobile wallets:

DragonX light and mobile wallets use BIP39 seed phrases that are compatible with the full node — see doc/seed-phrase.md.

Support and links

License

For license information see the file COPYING.

S
Description
No description provided
Readme
190 MiB
2026-09-02 03:01:24 -05:00
Languages
C++ 67.8%
C 19.3%
Python 6.8%
M4 1.4%
Shell 1.3%
Other 3.2%