Doichain / Doichain/doichain-install

Mining stack audit: image bootstrap bugs, data-loss datadir mismatch, and AuxPoW headers-presync blocking fresh sync

Closed
#3 4 comments 0 reactions 0 assignees View on GitHub
Dominant language
Shell
Stars
0
Forks
0
Avg merge
1h 10m
Merged PRs (30d)
3

Description

## Context

Found while bringing up the 31.1 mining stack (bitcoind + doichaind + p2pool) on `doichain-core`. Every finding below was **reproduced and confirmed live**, not theorised.

---

## 1. `doichain/core` image — data loss + startup crash

### 1a. `xxd` missing → entrypoint crashes when `RPC_PASSWORD` is unset

`scripts/entrypoint.sh:29` generates the RPC password with `xxd -l 30 -p /dev/urandom`, but `xxd` is **not installed** in the image (`openssl` is):

```
scripts/entrypoint.sh: line 29: xxd: command not found
```

With `set -euo pipefail` this aborts the container. Currently masked in `docker-compose-mining.yml` only because it sets `RPC_PASSWORD=password`.

**Fix:** `RPC_PASSWORD=$(openssl rand -hex 30)`

### 1b. Datadir mismatch → chain data is NOT persisted to the volume :warning:

```
entrypoint writes conf to : /home/doichain/data/doichain/doichain.conf
doichain-start.sh runs : doichaind # no -datadir !
→ doichaind uses $HOME/.doichain = /home/doichain/.doichain
```

Verified: `/home/doichain/.doichain` is a **real directory inside the image**, not a symlink to the mounted volume.

Consequences:
- the generated conf (`rpcuser`, `rpcpassword`, `txindex=1`, `rpcallowip`, `blocknotify`, `walletnotify`) is **never read**
- the blockchain is written **inside the container**, not into `doichain-volume:/home/doichain/data`
- → **every `docker compose up --force-recreate` destroys the chain and triggers a full IBD**

**Fix:** `doichain-start.sh` → `exec doichaind -datadir=/home/doichain/data ...` (or symlink `~/.doichain` → the volume).

### 1c. PID 1 is bash, not doichaind

`scripts/start.sh`:

```bash
scripts/doichain-start.sh &
exec /bin/bash
```

doichaind runs as a background child while PID 1 is bash. A doichaind crash therefore leaves the container "up" (no restart triggered), and `docker stop` signals bash instead of doichaind → unclean shutdown, risking chainstate corruption.

**Fix:** run `exec doichaind ...` as PID 1.

---

## 2. `doichain/bitcoind` image — dead bootstrap URL

`scripts/entrypoint.sh` bootstraps the pruned chain from `https://prunednode.today/latest.zip` — **that domain is dead**. Without a workaround the node falls back to a full IBD from genesis. (`xxd`, `unzip`, `curl` *are* present in this image; only the URL is broken.)

**Fix:** point at the doi.works nightly snapshot `https://www.doi.works/pruned/bitcoin-pruned.tgz` — verified live: `HTTP 200`, 11.0 GB, refreshed nightly (`Last-Modified` ~02:15 UTC) by the existing cron `archive-pruned-bitcoin.sh`.

Currently worked around by the `bitcoin-init` service in `docker-compose-mining.yml`.

---

## 3. `docker-compose-mining.yml`

| # | Issue | Fix |
|---|---|---|
| 3a | `DOICHAIN_VER: feat/digishield-daa` | pin to release tag `v31.1.1` |
| 3b | builds from the **private** `doichain-core` repo → `docker compose build` fails on a clean node | publish `doichain/core:v31.1.1` to Docker Hub |
| 3c | `doichain` service relies on the broken default entrypoint (see 1b/1c) | override with `entrypoint: doichaind` + explicit `-datadir=/home/doichain/data` |
| 3d | existing volume data is `root:root 0600` while the image runs as uid 1000 (`doichain`) | `user: root`, or chown the volume |
| 3e | p2pool env names don't match the image | image `start.sh` reads `MERGED_MINGIN_URL`, `P2POOL_BITCOIN_DEFAULT_ADDR`, `P2POOL_DOICHAIN_DEFAULT_ADDR`; compose sets `DOICHAIN_RPC_*` → the merge-mining URL never reaches p2pool |
| 3f | p2pool receives no bitcoin RPC credentials | p2pool has **no** `--bitcoind-rpc-username/password` flags; it reads them from `bitcoin.conf` via `--bitcoind-config-path`. A `bitcoin.conf` must exist in the bitcoin datadir |

---

## 4. `doichain-core`: headers-presync is not AuxPoW-aware — blocks ALL fresh P2P sync :warning::warning:

*(This one belongs to `doichain-core`, but it blocks this stack end-to-end, so recording it here.)*

A fresh doichaind connects to peers (all advertising `blocks=431016`) and then **never syncs**:

- pulls exactly one ~4.2 MB header batch (~2000 headers) from the sync peer, then goes silent — with `net` logging on, **not a single further `getheaders`**
- `headers=0`, only genesis in `getchaintips`
- peers rotated out with `Outbound peer has old chain, best known block = ` — and notably **no ban / no "Misbehaving"**

Both an old `/Satoshi:0.20.99/` peer and a new `/Satoshi:31.1.0/` peer stall at the identical ~4.2 MB → **not** a 0.20-vs-31 serialization issue.

**The chainparams are correct** — verified against the real chain after a successful sync:

```
height = 431016
bestblockhash = 4f5e8c0e4efb3504f8923ea175e4e5e688963819dcfbe33cc7f5a28c33616823 == defaultAssumeValid OK
actual chainwork = 0x2bef1dd2f4acd13484a70 == nMinimumChainWork OK (ratio 1.000)
```

**Root cause:** Bitcoin Core 24+ `HeadersSyncState` (headers presync) validates PoW against the **bare block-header hash**. For AuxPoW blocks the PoW lives on the *parent* chain, so the check fails at Doichain's first AuxPoW block (~height 2000 — exactly where presync stalls) and presync aborts. The normal, non-presync header path *is* AuxPoW-aware and works fine.

**Workaround (verified):** `-minimumchainwork=0` bypasses presync entirely → full sync `0 → 431016` in **~5 minutes**:

```
14:22:47 blocks=0 headers=0
14:23:48 blocks=10056 headers=431016
14:27:53 blocks=431016 headers=431016
```

**Fix options:**
- **(a)** make the PoW check in `HeadersSyncState` AuxPoW-aware — the correct fix, belongs in the release
- **(b)** set `nMinimumChainWork = 0` in chainparams — pragmatic, but gives up the presync anti-DoS floor
- **(c)** pass `-minimumchainwork=0` from compose as a stopgap

This likely also explains why the two `/Satoshi:31.1.0/` nodes currently on the network (`2.28.75.43`, `136.243.155.62`, both Hetzner) appear to have been bootstrapped by datadir copy rather than P2P sync.

---

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Contributor guide

No contributing guide indexed for this repository

Research direction

Start with scripts/entrypoint.sh, scripts/doichain-start.sh, scripts/start.sh, and docker-compose-mining.yml, then inspect the image and volume behavior described in the report. Verify password generation, datadir persistence, PID 1 shutdown, snapshot bootstrap, compose variables, credentials, and permissions. For the sync blocker, trace HeadersSyncState and confirm fresh P2P sync reaches the reported height without the workaround; the compose stack should start cleanly and retain chain data.

Written by the indexing model from the issue text.

Assessment

Tech stack
docker, docker-compose, shell
Domain
devops, distributed-systems, infrastructure
Issue type
Bug
Difficulty
5/5
Estimated time
Over a week
Activity status
Active
Clarity
Mostly clear
Newbie friendliness
28/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.