# CLAUDE.md This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository. ## Project `plm-electrumx`: a fork of ElectrumX 2.0.0 with its own versioning (package name `plm-electrumx`, version in `src/electrumx/__init__.py` and `docs/conf.py`, import name `electrumx`), an Electrum-protocol server (asyncio) that indexes a coin daemon into a local DB (LevelDB or RocksDB), supporting **Palladium (PLM) only**. All other coins and their code were removed (see the "Fork notes" in `README.md` for the upstream base commit and how to merge upstream). Keep changes to core files small so upstream merges stay easy. MIT license: keep `LICENCE`. ## Commands ```bash pip install -e ".[leveldb,rocksdb]" # at least one DB engine extra is required pip install pytest pytest-asyncio pytest-cov pycodestyle pytest # all tests (what CI runs, with --cov=electrumx) pytest tests/lib/test_palladium.py # single file pytest tests/server/test_mempool.py::test_name # single test pycodestyle --max-line-length=140 src # the only lint, enforced in CI cd docs && make html # docs (Sphinx) DB_ENGINE=rocksdb DB_DIRECTORY=... DAEMON_URL=http://user:pass@host:port/ electrumx_server electrumx_rpc getinfo # needs rpc:// in SERVICES (the Docker image does not enable it) contrib/docker-smoke-test.sh # after `docker build -t plm-electrumx .`: checks the SSL handling of the entrypoint ``` Docker: needs `.env` (copy `.env.example`; `PLM_RPC_USER`/`PLM_RPC_PASSWORD` are required, the rest has defaults) and the data directory created as your user first: `mkdir -p ~/.plm-electrumx/db ~/.plm-electrumx/ssl`. Then `docker compose up -d --build` (root `Dockerfile`, `docker-compose.yml`, `.env` from `.env.example`) runs the server on the external `palladium` network of the Palladium node container, daemon at `palladiumd:2332`. `docker-entrypoint.sh` sets up SSL: it uses `SSL_CERTFILE`/`SSL_KEYFILE` if given, else the self-signed certificate in `ssl/` of the data directory (`~/.plm-electrumx`, bind-mounted), generating it only if missing (never overwrite it: clients pin it), and sets `SERVICES`. Do not run Python with `src/electrumx/lib/` as the current directory: `lib/enum.py` shadows the standard `enum` module and breaks the interpreter. Configuration is entirely via environment variables, parsed in `src/electrumx/server/env.py` (documented in `docs/environment.rst`). `DB_ENGINE` is mandatory in 2.0 (`leveldb` or `rocksdb`). Python >=3.10; free-threaded 3.14t is experimental. ## Architecture Pipeline (see `docs/architecture.rst`): `Env` → `Controller` (`server/controller.py`) wires together `Daemon` (RPC client to the coin node, `server/daemon.py`), `BlockProcessor` (`block_processor.py`, indexes blocks/handles reorgs, writes via `db.py`/`history.py`/`storage.py`), `MemPool` (`mempool.py`), `SessionManager`/`ElectrumX` sessions (`session.py`, the only place that knows the Electrum wire protocol and its versions), and `PeerManager` (`peers.py`). `Notifications` in `controller.py` merges block and mempool "touched" hashXs/outpoints so clients are not notified twice. Coin abstraction: `lib/coins.py` defines `Coin` and the `Palladium`, `PalladiumTestnet`, `PalladiumRegtest` subclasses. A coin class selects behavior through class attributes: `DESERIALIZER` (block/tx format, in `lib/tx.py`, only the segwit one remains), `DAEMON`, `BLOCK_PROCESSOR`, `SESSIONCLS`, address verbytes, `GENESIS_HASH`, `REORG_LIMIT`, `RPC_PORT`, `PEERS`, header handling, etc. Coins are discovered by walking `Coin` subclasses (`lookup_coin_class` matches `NAME` + `NET`; `COIN` defaults to `Palladium`). Concrete classes must define `TX_COUNT`, `TX_COUNT_HEIGHT`, `TX_PER_BLOCK` (used only for sync ETAs) or lookup raises. Daemon: Palladium Core is based on Bitcoin Core 0.19: no `getindexinfo`, `txospenderindex` or `submitpackage`. So `MIN_REQUIRED_DAEMON_VERSION`/`REQUIRED_DAEMON_INDEXES` (see `Coin`) are unset, and `blockchain.outpoint.subscribe` / `blockchain.transaction.broadcast_package` return a daemon error to clients. The daemon needs `txindex=1`. DB schema changed in 2.0 with no migration; changing on-disk format requires a full resync. ## Tests `tests/lib` (Palladium params, addresses, hashes, scripts), `tests/server` (env, daemon, mempool, storage, API), plus fixture-driven `tests/test_blocks.py` / `test_transactions.py` using JSON files named `__.json` in `tests/blocks` and `tests/transactions` (real mainnet data from a synced node; tx vout values in satoshis). `test_storage.py` needs both DB engines installed. Bech32 addresses are not supported by `Coin.address_to_hashX` (base58 only). Fixtures were taken from a synced node (`getblock 0|1`, `getrawtransaction true `, run via `docker compose exec palladiumd palladium-cli ...` in the node's project); vout values converted to satoshis. Ports, SSL, RPC credentials and donation address are documented in `DEPLOY.md`. ## Repository and workflow - Default branch `main`, remotes `origin` (palladium-coin/plm-electrumx) and `upstream` (spesmilo/electrumx). With two remotes `gh` needs `--repo palladium-coin/plm-electrumx` (or `gh repo set-default`). - History is a snapshot of upstream commit `280cb33` plus Palladium commits: no common history, `git merge upstream` does not work. Update with `git diff 280cb33 upstream/master | git apply --3way` (see the "Fork notes" in `README.md`). - Do not create, move or delete git tags. - Do not `git add -A`: generated files (`.coverage`, `.env`) get swept in. Add files by name. `.coverage` and `.env` are in `.gitignore`. - CI (`.github/workflows/ci.yml`, on `main`): `unittests`, `pycodestyle`, `build_docs`, `docker` (builds the image, runs the smoke test). It runs on Ubuntu 24.04; `test_storage.py` fails with RocksDB 9.10 (Debian trixie) in teardown. - In repo documentation never cite paths or links of the palladiumcore repository; describe the concept (the Palladium node, the `palladium` Docker network).