Repository navigation
Upgrade to ElectrumX 2.0.0 and port the Doichain coin classes (green CI, replaces #11) - #12
Merged
Merged
Conversation
docs: fix lib/coins.py link in environment.rst
to help distinguish logs from kyuupichan/electrumx ref spesmilo/electrumx#306
This prevents the DoS attack vector caused by hitting the max number of sessions. Prior to this change if the max number of sessions was reached, the server would stop listening for new connections until ALL existing connections were closed. Now, the listening port is closed, the existing connections remain live and when the lower threshold is reached, the listening socket is reopened.
…implementation fix: prevent incorrect session limit DoS attack vector
Adds the `mempool.get_info` rpc to fetch mempoolminfee, minrelaytxfee and incrementalrelayfee from the daemons getmempoolinfo rpc for protocol version 1.6. Updates the relayfee comments as the fee returned by `blockchain.relayfee` doesn't guarantee to get into the mempool as previously stated in the docstrings.
The parsing of the version number returned from 'getnetworkinfo' was not adapted to the changed bitcoin core version number scheme since core went from beta to stable. The banner incorrectly showed 0.29.0 instead of 29.0.0.
Checks the daemon version on startup against a minimum allowed daemon version hardcoded in the corresponding `Coin`. This allows ensure that the connected daemon is running a version that supports all the rpc calls electrumx requires.
Guards the new `blockchain.transaction.broadcast_package` and `mempool.get_info` methods of protocol 1.6 behind this versions ptuple in `set_request_handlers` so they are only exposed in protocol versions >= 1.6. Also stops exposing the `blockchain.relayfee` endpoint for version >= 1.6 as it got removed in 1.6.
implements mempool.get_info and clarifies comments of relayfee
check daemon version on startup, fix version in banner
Removes the incorrect and unnecessary txid calculation in `ElectrumX.package_broadcast()`, the daemon will complain anyways if the transactions are invalid.
Make mode uppercase if passed as neither the protocol nor core do specify any requirement here.
session: estimatefee: normalize mode arg
session: broadcast_package: followup #288
session.py: sanitize inputs for tx broadcast RPCs
was just sending back a response with value 1, instead of a jsonrpc error ref spesmilo/electrumx@860ff53
session: fix ReplyAndDisconnect. was broken for PaddedRSTransport
Adds a 1024 (unpadded) byte sending budget to the PaddedRSTransport below which messages are instantly flushed down the socket before the transport will beginn waiting for the buffer to reach MIN_PACKET_SIZE (1024). This allows to get the first couple of messages sent quickly when a wallet connects to improve its ux.
add warmup budget to PaddedRSTransport
We already enforce that server.version must be the first received message in a session, but we also need to ensure that the server finishes processing that message and sets up the correct protocol version before starting to process further messages.
to leave room for future extensions
protocol 1.6: "server.version" must be first msg, must tolerate unknown args
Note that this is a soft fork: the server can apply it even for past
protocol versions.
Previously, with the order being undefined, if an address had multiple
mempool transactions touching it, switching between different servers
could result in a change in address status simply as a result of these
servers ordering mempool txs differently. This would result in the client
re-requesting the whole history of the address.
-----
D/i | interface.[electrum.blockstream.info:60002] | <-- ('blockchain.scripthash.subscribe', ['660b44502503064f9d5feee48726287c0973e25bc531b4b8a072f57f143d5cd0']) {} (id: 12)
D/i | interface.[electrum.blockstream.info:60002] | --> 9da27f9df91e3f860212f65b736fa20a539ba6e3d509f6370367ee7f10a4d5b0 (id: 12)
D/i | interface.[electrum.blockstream.info:60002] | <-- ('blockchain.scripthash.get_history', ['660b44502503064f9d5feee48726287c0973e25bc531b4b8a072f57f143d5cd0']) {} (id: 13)
D/i | interface.[electrum.blockstream.info:60002] | --> [
{'fee': 200, 'height': 0, 'tx_hash': '3ee6d6e26291ce360127fe039b816470fce6eeea19b5c9d10829a1e4efc2d0c7'},
{'fee': 239, 'height': 0, 'tx_hash': '9e050f09b676b9b0ee26aa02ccee623fae585a85d6a5e24ecedd6f8d6d2d3b1d'},
{'fee': 178, 'height': 0, 'tx_hash': 'fb80adbf8274190418cb3fb0385d82fe9d47a844d9913684fa5fb3d48094b35a'},
{'fee': 200, 'height': 0, 'tx_hash': '713933c50b7c43f606dad5749ea46e3bc6622657e9b13ace9d639697da266e8b'}
] (id: 13)
D/i | interface.[testnet.hsmiths.com:53012] | <-- ('blockchain.scripthash.subscribe', ['660b44502503064f9d5feee48726287c0973e25bc531b4b8a072f57f143d5cd0']) {} (id: 12)
D/i | interface.[testnet.hsmiths.com:53012] | --> f7ef7237d2d62a3280acae05616200b96ad9dd85fd0473c29152a4a41e05686c (id: 12)
D/i | interface.[testnet.hsmiths.com:53012] | <-- ('blockchain.scripthash.get_history', ['660b44502503064f9d5feee48726287c0973e25bc531b4b8a072f57f143d5cd0']) {} (id: 13)
D/i | interface.[testnet.hsmiths.com:53012] | --> [
{'tx_hash': '9e050f09b676b9b0ee26aa02ccee623fae585a85d6a5e24ecedd6f8d6d2d3b1d', 'height': 0, 'fee': 239},
{'tx_hash': 'fb80adbf8274190418cb3fb0385d82fe9d47a844d9913684fa5fb3d48094b35a', 'height': 0, 'fee': 178},
{'tx_hash': '3ee6d6e26291ce360127fe039b816470fce6eeea19b5c9d10829a1e4efc2d0c7', 'height': 0, 'fee': 200},
{'tx_hash': '713933c50b7c43f606dad5749ea46e3bc6622657e9b13ace9d639697da266e8b', 'height': 0, 'fee': 200}
] (id: 13)
…ed hex string Array headers: fix type error Array headers: move variable initialization
storage: add some type hints
dedupe min python version
utxo db: incrementally clear excess undo infos as we go
mempool: refresh_hashes: log time taken
mempool: partially revert threading _process_mempool
protocol 1.7: revert adding chaintip to responses
session: bump PROTOCOL_MAX to 1.7
also, - don't pin python patch version - use default env var values - "docker stop" seems cleaner, more intuitive, than kill
dockerfile: switch to rocksdb, and show how to build free-threaded python
prepare release 2.0.0
Our fleet runs ElectrumX 1.15.0 (2020). Upstream 2.0.0 moved the tree to
src/, merged the name and AuxPoW mixins into NameIndexAuxPoWMixin (which
carries SESSIONCLS), turned P2SH_VERBYTES and NAME_OPERATIONS into tuples,
added NAME_EXPIRATION, and dropped XPUB/XPRV/WIF entirely -- they have no
remaining use anywhere in the tree.
Values come from the chain and the consensus rules rather than being carried
over unchanged:
RPC_PORT 8339 / 18339 8338 is the P2P port since Core 31, so the old
value pointed ElectrumX at the wrong socket
TX_COUNT 2,742,220 getchaintxstats at height 431,763
NAME_EXPIRATION 36,000 / 30 Consensus::MainNetConsensus::NameExpirationDepth
(36,000 above height 48,000; regtest 30)
Testnet and regtest inherit from Doichain now instead of repeating every
declaration, matching how upstream keeps the Namecoin classes.
Verified with the package installed: ElectrumX resolves all three classes,
with SESSIONCLS NameIndexAuxPoWElectrumX, DESERIALIZER DeserializerAuxPowSegWit,
BLOCK_PROCESSOR NameIndexBlockProcessor, four name operations including
name_doi, and REQUIRED_DAEMON_INDEXES empty -- so no extra daemon index is
required. tests/lib/test_coins.py: 16 passed.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Resolves the conflicts the upgrade branch had against master, which still carries ElectrumX 1.15.0 plus our seven commits. - .travis.yml: upstream deleted it in 2.0 (CI moved to GitHub Actions); master's last edit to it is dropped with the file. - .gitignore: upstream's version, which already covers the src/ layout and both egg-info names, plus our /certs entry. - contrib/systemd/electrumx.service: merged cleanly, Restart=always and RuntimeMaxSec=604800 are kept. - electrumX.egg-info/: a build artefact committed by accident in 2021; removed, and .gitignore now covers it. The one that needed care: git detected electrumx/lib/coins.py -> src/electrumx/ lib/coins.py as a rename and merged master's 121 lines of Doichain classes into the file that already carries the ported ones -- **without a conflict marker**. That left every class defined twice, and in Python the second definition wins, so the server would silently have run the old classes again: no SESSIONCLS, hence no name RPC, RPC port 8338, no NAME_EXPIRATION. The 1.15-era block is removed. Verified after the resolution: exactly three Doichain classes; ElectrumX resolves all three with SESSIONCLS NameIndexAuxPoWElectrumX, RPC ports 8339/18339/18332, NAME_EXPIRATION 36,000 (regtest 30) and four name operations including name_doi; tests/lib/test_coins.py 16 passed. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
CI failed on tests/test_blocks.py::test_all_coins_are_covered: upstream requires every mainnet coin class to come with at least one block fixture, and Doichain had none. 1.15.0 had no such test, so the gap only appears with 2.0. Two blocks, taken from a synced node: - **431,320** -- two transactions, the second a `name_doi`. This is the block the name index was verified against, so the fixture now covers the operation that distinguishes Doichain from Namecoin, through DeserializerAuxPowSegWit. - **100,000** -- an ordinary single-coinbase block, for the plain path. test_block checks the header hash, the previous hash and every txid against the deserialised block; both pass. The remaining failures in that file are `ModuleNotFoundError: No module named 'blake256'` on unrelated coins, which occur with or without these files. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
NiKrause
added a commit
to Doichain/doichain-install
that referenced
this pull request
Sep 16, 2026
The build context pointed at 9afddfec, a commit that only ever lived on the upgrade branch. Doichain/electrumx#12 was squash-merged, so that commit is not an ancestor of master and survives only as long as nobody deletes the branch -- the pin held by habit rather than by guarantee. It now points at 11877d7b, the commit carrying the signed tag v2.0.0-doi1. The commit is pinned rather than the tag name, because a tag can be moved and a commit cannot; the tag is named in the comment next to it. The image doichain/electrumx:v2.0.0-doi1 was rebuilt from that commit, so the source tag and the image tag now describe the same state; the image records the commit in /electrumx-source-commit. Also corrects the ElectrumX timing in the compose comment to the value measured with the 2.0 image (~22 min). Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Same upgrade as #11, with the failing unit test fixed. Merging this one is enough — it contains everything from #10 and #11.
What was red
tests/test_blocks.py::test_all_coins_are_covered. Upstream requires every mainnet coin class to ship at least one block fixture, andDoichainhad none. 1.15.0 carried no such test, so the gap only surfaces with 2.0.pycodestyleandbuild_docswere green throughout.The fix
Two fixtures taken from a synced node:
name_doiDeserializerAuxPowSegWittest_blockdeserialises each with the coin class and checks the header hash, the previous hash and every txid. Both pass.The four remaining failures in that file are
ModuleNotFoundError: No module named 'blake256'on unrelated coins (Decred and friends); they occur identically without these files — verified by removing them and re-running: 5 failures without, 4 with, the difference being exactly the coverage test.Everything else is unchanged from #11
Upgrade from ElectrumX 1.15.0 to upstream 2.0.0 with the Doichain coin classes ported onto it,
mastermerged in and the conflicts resolved — including the one that produced no conflict marker: git treatedelectrumx/lib/coins.py→src/electrumx/lib/coins.pyas a rename and merged the 1.15-era classes into the already-ported file, leaving every class defined twice. Details in #11.Please close #10 and #11 in favour of this one.
🤖 Generated with Claude Code