lightwalletd used github.com/btcsuite/btcd/rpcclient for exactly one
method, RawRequest, and that package has two defects that together
produce the failure seen on the primary node:
1. It has no timeout and no way to set one. The http.Client is built
in an unexported newHTTPClient() and ConnConfig exposes no Timeout
field, so a call can hang forever. Calls were observed running past
five minutes against a healthy node that answered the same query
from dragonx-cli in 2ms.
2. In HTTP POST mode it runs ONE sendPostHandler goroutine which calls
handleSendPostMessage synchronously, so the whole process has at
most one RPC in flight. One stuck call therefore blocks the block
ingestor, the mempool monitor and every user-facing gRPC handler at
once.
These compound: a timeout alone would not have been enough, because
bounding the caller's wait still leaves the shared goroutine stuck
inside http.Client.Do with everything queued behind it. Only a timeout
on the HTTP client aborts the in-flight request, and only dropping the
shared goroutine lets independent callers proceed.
Patching the vendored copy is not an option here: go.mod declares
go 1.12, so automatic vendor mode (go >= 1.14) is off and the committed
vendor/ tree is silently ignored in favour of the module cache. It is
also stale -- vendor/modules.txt disagrees with go.mod on btcd,
protobuf, logrus, sqlite3 and six other modules, so -mod=vendor cannot
build at all, and `go mod vendor` would discard any patch.
Replace it with package zrpc: a ~150-line JSON-RPC client that is safe
for concurrent use and takes a timeout. The request envelope, ID
sequence, basic auth and error semantics are deliberately identical.
RPCError.Error() still renders as "<code>: <message>" because callers
recover the numeric code from the string -- common.GetSaplingInfo
checks for -8 via strings.SplitN(err.Error(), ":", 2) -- and the
non-JSON body path still reports `status code: %d, response: %q`.
Default timeout 120s, tunable with -rpc-timeout (0 disables). The bound
is set by the slowest legitimate call: coinsupply measured 48s against
a cold UTXO set, 3s once cached, so a tighter timeout would turn a
slow-but-working call into a hard failure.
Also drops rpcclient's Close=true, which opened a fresh TCP connection
per request and left hundreds of sockets in TIME_WAIT on a busy node;
idle connections are now reused and capped.
Verified against a live dragonxd: getblockchaininfo returns chain=main;
a bad height yields exactly "-8: Block height out of range" and parses
back to -8; a 1ns timeout aborts in 54us instead of hanging; and the
built daemon serves GetLightdInfo at the current height with no errors.
The pre-existing parser TestCompactBlocks failure is unrelated and
reproduces on the base commit.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01FU87LdsJZiZkfq1eXubpeo
Overview
DragonX Lightwalletd is a fork of Hush lightwalletd which is itself a fork of lightwalletd originally from Zcash (ZEC).
It is a backend service that provides a bandwidth-efficient interface to the DragonX blockchain for light wallet clients.
Features
- Support for DragonX (standalone chain with
dragonxd) - Support for transparent addresses
- Several RPC calls for light clients
- Lots of perf improvements
- In-memory cache for Compact Blocks (replaces SQLite)
- Tx lookups delegated to dragonxd
- No separate ingestor needed
Running your own DragonX lightwalletd
0. First, install Go
You will need Go >= 1.13 which you can download from the official download page or install via your OS package manager.
This installation document shows how to do it on various OS's.
If you're using Ubuntu or Debian, try:
$ sudo apt install golang
1. Run a DragonX node.
Install the DragonX daemon (dragonxd) and CLI (dragonx-cli).
Next, ensure your DRAGONX.conf file (at ~/.hush/DRAGONX/DRAGONX.conf) has something like the following:
rpcuser=user-CHANGETHIS
rpcpassword=pass-CHANGETHIS
rpcport=21769
server=1
txindex=1
rpcworkqueue=256
rpcallowip=127.0.0.1
rpcbind=127.0.0.1
Then start dragonxd. You might need to run with -reindex the first time if you are enabling the txindex option for the first time. The reindex might take a while.
2. Compile lightwalletd
Run the build script.
make build
3. Get a TLS certificate and run the Lightwalletd frontend
First, get a TLS certificate:
On Ubuntu Linux, I SUGGEST YOU DO NOT USE SNAPD and just sudo apt install certbot and then start on Step 7 of these instructions by the EFF
Next you decide how you want to setup lightwalletd - with (Option A) or without NGINX (Option B).
Option A: "Let's Encrypt" certificate using NGINX as a reverse proxy
If you running a public-facing server, the easiest way to obtain a certificate is to use a NGINX reverse proxy and get a Let's Encrypt certificate.
Create a new section for the NGINX reverse proxy:
server {
listen 443 ssl http2;
listen [::]:443 ssl http2;
server_name your_host.net;
ssl_certificate /etc/letsencrypt/live/your_host.net/fullchain.pem; # managed by Certbot
ssl_certificate_key /etc/letsencrypt/live/your_host.net/privkey.pem; # managed by Certbot
include /etc/letsencrypt/options-ssl-nginx.conf; # managed by Certbot
ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem; # managed by Certbot
location / {
# Replace localhost:9069 with the address and port of your gRPC server if using a custom port
grpc_pass grpc://your_host.net:9069;
}
}
Then run the lightwalletd frontend with the following (Note: we use the "-no-tls" option as we are using NGINX as a reverse proxy and letting it handle the TLS authentication for us instead):
./lightwalletd -bind-addr your_host.net:9069 -conf-file ~/.hush/DRAGONX/DRAGONX.conf -no-tls
Option B: "Let's Encrypt" certificate just using lightwalletd without NGINX
The other option is to configure lightwalletd to handle its own TLS authentication. Once you have a certificate that you want to use (from a certificate authority), pass the certificate to the frontend as follows:
./lightwalletd -bind-addr 127.0.0.1:9069 -conf-file ~/.hush/DRAGONX/DRAGONX.conf -tls-cert /etc/letsencrypt/live/YOURWEBSITE/fullchain.pem -tls-key /etc/letsencrypt/live/YOURWEBSITE/privkey.pem
4. Point a light wallet client to this server
You should start seeing the frontend ingest and cache the DragonX blocks after ~15 seconds.
Lightwalletd Command-line Options
These are the current different command line options for lightwalletd:
| CLI option | Default | What it does |
|---|---|---|
| -bind-addr | 127.0.0.1:9069 | address and port to listen on |
| -tls-cert | blank | the path to a TLS certificate |
| -tls-key | blank | the path to a TLS key file |
| -no-tls | false | Disable TLS, serve un-encrypted traffic |
| -log-file | blank | log file to write to |
| -log-level | logrus.InfoLevel | log level 1 thru 7 (something from logrus) |
| -conf-file | blank | conf file to pull RPC creds from |
| -cache-size | 40000 | number of blocks to hold in the cache |
Support
For support or other questions, join us on Telegram or join Telegram Support.
License
GPLv3 or later
Copyright
2016-2022 The Hush Developers 2024-2026 The DragonX Developers