Initial commit: snapshot of spesmilo/electrumx 2.0.0

Unmodified source tree of upstream commit 280cb339aa158e099eb936033eecd15719770651
("Merge pull request #389 from SomberNight/202607_release_2_0",
https://github.com/spesmilo/electrumx, release 2.0.0, 3 July 2026).

All Palladium-specific changes are in the commits that follow.
This commit is contained in:
davide committed 2026-10-22 15:03:56 +02:00
commit 384d907c65
271 files changed
+27905

No files matched your search

+22
View File
@@ -0,0 +1,22 @@
Thanks to Thomas Voegtlin for creating the Electrum software and
infrastructure and for maintaining it so diligently. Electrum is
probably the best desktop Bitcoin wallet solution for most users. My
faith in it is such that I use Electrum software to store most of my
Bitcoins.
Whilst the vast majority of the code here is my own original work and
includes some new ideas, it is very clear that the general structure
and concept are those of Electrum. Some parts of the code and ideas
of Electrum, some of which it itself took from other projects such as
Abe and pywallet, remain. Thanks to the authors of all the software
this is derived from.
I'd like to thank bauerj, hsmiths and JWU42 of #electrum for their
help and support in testing the versions of ElectrumX prior to 1.0.
Thanks to Daniel Bernstein for daemontools and other software, and to
Matthew Dillon for DragonFlyBSD. They are both deeply inspirational
people.
And of course, thanks to Satoshi for the wonderful creation that is
Bitcoin.
+461
View File
@@ -0,0 +1,461 @@
.. _HOWTO:
=====
HOWTO
=====
Prerequisites
=============
**ElectrumX** should run on any flavour of unix. I have run it
successfully on MacOS and DragonFlyBSD. It won't run out-of-the-box
on Windows, but the changes required to make it do so should be
small - pull requests are welcome.
================ ========================
Package Notes
================ ========================
Python3 ElectrumX uses asyncio. Python version >= 3.10 is
**required**.
`aiohttp`_ Python library for asynchronous HTTP. Version >=
2.0 required.
DB Engine A database engine package is required; two are
supported (see `Database Engine`_ below).
================ ========================
Some coins need an additional package, typically for their block hash
functions. For example, `dash_hash`_ is required for DASH. Scrypt coins
require a Python interpreter compiled and/or linked with OpenSSL 1.1.0
or higher.
You **must** be running a non-pruning bitcoin daemon with::
txindex=1
set in its configuration file. If you have an existing installation
of bitcoind and have not previously set this you will need to reindex
the blockchain with::
bitcoind -reindex
which can take some time.
While not a requirement for running ElectrumX, it is intended to be
run with supervisor software such as Daniel Bernstein's
`daemontools`_, Gerrit Pape's `runit`_ package or :command:`systemd`.
These make administration of secure unix servers very easy, and I
strongly recommend you install one of these and familiarise yourself
with them. The instructions below and sample run scripts assume
``daemontools``; adapting to ``runit`` should be trivial for someone
used to either.
When building the database from the genesis block, ElectrumX has to
flush large quantities of data to disk and its DB. You will have a
better experience if the database directory is on an SSD than on an
HDD. Currently to around height 611,600 of the Bitcoin blockchain the
final size of the leveldb database, and other ElectrumX file metadata
comes to just over 46.9GB (43.7 GiB). LevelDB needs a bit more for
brief periods, and the block chain is only getting longer, so I would
recommend having at least 70-80GB of free space before starting.
Database Engine
===============
You can choose from LevelDB and RocksDB to store transaction
information on disk. On an SSD, RocksDB performs better than LevelDB.
We tried to support LMDB, but its history write performance
was much worse.
You will need to install one of:
+ `plyvel <https://plyvel.readthedocs.io/en/latest/installation.html>`_ for LevelDB.
``apt install libleveldb-dev build-essential``
``pip3 install plyvel`` , or use the ``[leveldb]`` extra install option to ElectrumX.
+ `rocksdb-ng <https://pypi.org/project/rocksdb-ng>`_ for RocksDB
(Should work with RocksDB versions 8-10)
``apt install librocksdb-dev build-essential pkg-config``
``pip3 install rocksdb-ng`` , or use the ``[rocksdb]`` extra install option to ElectrumX.
+ `python-rocksdb <https://pypi.python.org/pypi/python-rocksdb>`_ for an unmaintained version
that doesn't work with recent releases of RocksDB (only <7.0)
Running
=======
Install the prerequisites above.
Check out the code from Github::
git clone https://github.com/spesmilo/electrumx.git
cd electrumx
You can install with::
pip3 install .
There are many extra Python dependencies available to fit the needs of your
system or coins. For example, to install the RocksDB dependencies and a faster
JSON (de)serialization library::
pip3 install ".[rocksdb,orjson]"
see pyproject.toml's ``project.optional-dependencies`` for a complete list.
You can also run the code from the source tree or a copy of it.
You should create a standard user account to run the server under;
your own is probably adequate unless paranoid. The paranoid might
also want to create another user account for the daemontools logging
process. The sample scripts and these instructions assume it is all
under one account which I have called ``electrumx``.
Next create a directory where the database will be stored and make it
writeable by the ``electrumx`` account. I recommend this directory
live on an SSD::
mkdir /path/to/db_directory
chown electrumx /path/to/db_directory
Process limits
--------------
The ElectrumX process needs a large open file limit. On Linux systems,
the default (:command:`ulimit -n`) (soft) open file limit is usually 1,024.
ElectrumX tries to raise this automatically during startup to the hard limit,
which is usually 100,000+. If that fails (which would get logged),
you might have to manually increase the limit.
During sync it should not need more than about 1,024 open files. When
serving it will use approximately 256 for LevelDB plus the number of
incoming connections. It is not unusual to have 1,000 to 2,000
connections being served, so I suggest you set your open files limit
to at least 2,500.
Note that setting the limit in your shell does *NOT* affect ElectrumX
unless you are invoking ElectrumX directly from your shell. If you
are using :command:`systemd`, you need to set it in the
:file:`.service` file (see `contrib/systemd/electrumx.service`_).
Using daemontools
-----------------
Next create a daemontools service directory; this only holds symlinks
(see daemontools documentation). The :command:`svscan` program will
ensure the servers in the directory are running by launching a
:command:`supervise` supervisor for the server and another for its
logging process. You can run :command:`svscan` under the *electrumx*
account if that is the only one involved (server and logger) otherwise
it will need to run as root so that the user can be switched to
electrumx.
Assuming this directory is called :file:`service`, you would do one
of::
mkdir /service # If running svscan as root
mkdir ~/service # As electrumx if running svscan as that a/c
Next create a directory to hold the scripts that the
:command:`supervise` process spawned by :command:`svscan` will run -
this directory must be readable by the :command:`svscan` process.
Suppose this directory is called :file:`scripts`, you might do::
mkdir -p ~/scripts/electrumx
Then copy the all sample scripts from the ElectrumX source tree there::
cp -R /path/to/repo/electrumx/contrib/daemontools ~/scripts/electrumx
This copies 3 things: the top level server run script, a :file:`log/`
directory with the logger :command:`run` script, an :file:`env/`
directory.
You need to configure the :ref:`environment variables <environment>`
under :file:`env/` to your setup. ElectrumX server currently takes no
command line arguments; all of its configuration is taken from its
environment which is set up according to :file:`env/` directory (see
:manpage:`envdir` man page). Finally you need to change the
:command:`log/run` script to use the directory where you want the logs
to be written by multilog. The directory need not exist as
:command:`multilog` will create it, but its parent directory must
exist.
Now start the :command:`svscan` process. This will not do much as the
service directory is still empty::
svscan ~/service & disown
svscan is now waiting for services to be added to the directory::
cd ~/service
ln -s ~/scripts/electrumx electrumx
Creating the symlink will kick off the server process almost immediately.
You can see its logs with::
tail -F /path/to/log/dir/current | tai64nlocal
Using systemd
-------------
This repository contains a sample systemd unit file that you can use
to setup ElectrumX with systemd. Simply copy it to
:file:`/etc/systemd/system`::
cp contrib/systemd/electrumx.service /etc/systemd/system/
The sample unit file assumes that the repository is located at
:file:`/home/electrumx/electrumx`. If that differs on your system, you
need to change the unit file accordingly.
You need to set a few :ref:`environment variables <environment>` in
:file:`/etc/electrumx.conf`.
Now you can start ElectrumX using :command:`systemctl`::
systemctl start electrumx
You can use :command:`journalctl` to check the log output::
journalctl -u electrumx -f
Once configured you may want to start ElectrumX at boot::
systemctl enable electrumx
.. Warning:: systemd is aggressive in forcibly shutting down
processes. Depending on your hardware, ElectrumX can need several
minutes to flush cached data to disk during initial sync. You
should set TimeoutStopSec to *at least* 10 mins in your
:file:`.service` file.
Installing on Raspberry Pi 3
----------------------------
To install on the Raspberry Pi 3 you will need to update to the
``stretch`` distribution. See the full procedure in
`contrib/raspberrypi3/install_electrumx.sh`_.
See also `contrib/raspberrypi3/run_electrumx.sh`_ for an easy way to
configure and launch electrumx.
Sync Progress
=============
Time taken to index the blockchain depends on your hardware of course.
As Python is single-threaded most of the time only 1 core is kept
busy. ElectrumX uses Python's :mod:`asyncio` to prefill a cache of
future blocks asynchronously to keep the CPU busy processing the chain
without pausing.
Consequently there will probably be only a minor boost in performance
if the daemon is on the same host. It may even be beneficial to have
the daemon on a *separate* machine so the machine doing the indexing
has its caches and disk I/O tuned to that task only.
The :envvar:`CACHE_MB` environment variable controls the total cache
size ElectrumX uses; see :ref:`here <CACHE>` for caveats.
Here is my experience with the codebase of early 2017 (the current
codebase is faster), to given heights and rough wall-time. The period
from heights 363,000 to 378,000 is the most sluggish::
Machine A Machine B
181,000 25m 00s 5m 30s
283,500 1h 00m
321,800 1h 40m
357,000 12h 32m 2h 41m
386,000 21h 56m 4h 25m
414,200 1d 12h 29m 6h 30m
447,168 2d 13h 20m 9h 47m
*Machine A*: a low-spec 2011 1.6GHz AMD E-350 dual-core fanless CPU,
8GB RAM and a DragonFlyBSD UFS filesystem on an SSD. It requests
blocks over the LAN from a bitcoind on machine B. :envvar:`DB_CACHE`
the default of 1,200. LevelDB.
*Machine B*: a late 2012 iMac running Sierra 10.12.2, 2.9GHz quad-core
Intel i5 CPU with an HDD and 24GB RAM. Running bitcoind on the same
machine. :envvar:`DB_CACHE` set to 1,800. LevelDB.
For chains other than bitcoin-mainnet synchronization should be much
faster.
.. note:: ElectrumX will not serve normal client connections until it
has fully synchronized and caught up with your daemon.
However LocalRPC connections are served at all times.
Terminating ElectrumX
=====================
The preferred way to terminate the server process is to send it the
``stop`` RPC command::
electrumx_rpc stop
or alternatively on Unix the ``INT`` or ``TERM`` signals. For a
daemontools supervised process this can be done by bringing it down
like so::
svc -d ~/service/electrumx
ElectrumX will note receipt of the signals in the logs, and ensure the
block chain index is flushed to disk before terminating. You should
be patient as flushing data to disk can take many minutes.
ElectrumX uses the transaction functionality, with fsync enabled, of
the databases. I have written it with the intent that, to the extent
the atomicity guarantees are upheld by the DB software, the operating
system, and the hardware, the database should not get corrupted even
if the ElectrumX process if forcibly killed or there is loss of power.
The worst case should be having to restart indexing from the most
recent UTXO flush.
Once the process has terminated, you can start it up again with::
svc -u ~/service/electrumx
You can see the status of a running service with::
svstat ~/service/electrumx
:command:`svscan` can of course handle multiple services
simultaneously from the same service directory, such as a testnet or
altcoin server. See the man pages of these various commands for more
information.
Understanding the Logs
======================
You can see the logs usefully like so::
tail -F /path/to/log/dir/current | tai64nlocal
Here is typical log output on startup::
INFO:BlockProcessor:switching current directory to /crucial/server-good
INFO:BlockProcessor:using leveldb for DB backend
INFO:BlockProcessor:created new database
INFO:BlockProcessor:creating metadata diretcory
INFO:BlockProcessor:software version: ElectrumX 0.10.2
INFO:BlockProcessor:DB version: 5
INFO:BlockProcessor:coin: Bitcoin
INFO:BlockProcessor:network: mainnet
INFO:BlockProcessor:height: -1
INFO:BlockProcessor:tip: 0000000000000000000000000000000000000000000000000000000000000000
INFO:BlockProcessor:tx count: 0
INFO:BlockProcessor:sync time so far: 0d 00h 00m 00s
INFO:BlockProcessor:reorg limit is 200 blocks
INFO:Daemon:daemon at 192.168.0.2:8332/
INFO:BlockProcessor:flushing DB cache at 1,200 MB
INFO:Controller:RPC server listening on localhost:8000
INFO:Prefetcher:catching up to daemon height 447,187...
INFO:Prefetcher:verified genesis block with hash 000000000019d6689c085ae165831e934ff763ae46a2a6c172b3f1b60a8ce26f
INFO:BlockProcessor:our height: 9 daemon: 447,187 UTXOs 0MB hist 0MB
INFO:BlockProcessor:our height: 52,509 daemon: 447,187 UTXOs 9MB hist 14MB
INFO:BlockProcessor:our height: 85,009 daemon: 447,187 UTXOs 12MB hist 31MB
INFO:BlockProcessor:our height: 102,384 daemon: 447,187 UTXOs 15MB hist 47MB
[...]
INFO:BlockProcessor:our height: 133,375 daemon: 447,187 UTXOs 80MB hist 222MB
INFO:BlockProcessor:our height: 134,692 daemon: 447,187 UTXOs 96MB hist 250MB
INFO:BlockProcessor:flushed to FS in 0.7s
INFO:BlockProcessor:flushed history in 16.3s for 1,124,512 addrs
INFO:BlockProcessor:flush #1 took 18.7s. Height 134,692 txs: 941,963
INFO:BlockProcessor:tx/sec since genesis: 2,399, since last flush: 2,400
INFO:BlockProcessor:sync time: 0d 00h 06m 32s ETA: 1d 13h 03m 42s
Under normal operation these cache stats repeat once or twice a
minute. UTXO flushes can take several minutes and look like this::
INFO:BlockProcessor:our height: 378,745 daemon: 447,332 UTXOs 1,013MB hist 184MB
INFO:BlockProcessor:our height: 378,787 daemon: 447,332 UTXOs 1,014MB hist 194MB
INFO:BlockProcessor:flushed to FS in 0.3s
INFO:BlockProcessor:flushed history in 13.4s for 934,933 addrs
INFO:BlockProcessor:flushed 6,403 blocks with 5,879,440 txs, 2,920,524 UTXO adds, 3,646,572 spends in 93.1s, committing...
INFO:BlockProcessor:flush #120 took 226.4s. Height 378,787 txs: 87,695,588
INFO:BlockProcessor:tx/sec since genesis: 1,280, since last flush: 359
INFO:BlockProcessor:sync t ime: 0d 19h 01m 06s ETA: 3d 21h 17m 52s
INFO:BlockProcessor:our height: 378,812 daemon: 447,334 UTXOs 10MB hist 10MB
The ETA shown is just a rough guide and in the short term can be quite
volatile. It tends to be a little optimistic at first; once you get
to height 280,000 is should be fairly accurate.
.. _SSL certificates:
Creating a self-signed SSL certificate
======================================
These instructions are based on those of the ``electrum-server``
documentation.
To run an SSL server you need to generate a self-signed certificate
using openssl. Alternatively you could not set :envvar:`SSL_PORT` in
the environment and not serve over SSL, but this is not recommended.
Use the sample code below to create a self-signed cert with a
recommended validity of 5 years. You may supply any information for
your sign request to identify your server. They are not currently
checked by the client except for the validity date. When asked for a
challenge password just leave it empty and press enter::
$ openssl genrsa -out server.key 2048
$ openssl req -new -key server.key -out server.csr
...
Country Name (2 letter code) [AU]:US
State or Province Name (full name) [Some-State]:California
Common Name (eg, YOUR name) []: electrum-server.tld
...
A challenge password []:
...
$ openssl x509 -req -days 1825 -in server.csr -signkey server.key -out server.crt
The :file:`server.crt` file goes in :envvar:`SSL_CERTFILE` and
:file:`server.key` in :envvar:`SSL_KEYFILE` in the server process's
environment.
Starting with Electrum 1.9, the client will learn and locally cache
the SSL certificate for your server upon the first request to prevent
man-in-the middle attacks for all further connections.
If your certificate is lost or expires on the server side, you will
need to run your server with a different server name and a new
certificate. Therefore it's a good idea to make an offline backup
copy of your certificate and key in case you need to restore them.
Running on a privileged port
============================
You may choose to run electrumx on a different port than 50001
/ 50002. If you choose a privileged port ( < 1024 ) it makes sense to
make use of a iptables NAT rule.
An example, which will forward Port 110 to the internal port 50002 follows::
iptables -t nat -A PREROUTING -p tcp --dport 110 -j DNAT --to-destination 127.0.0.1:50002
You can then set the port as follows and advertise the service externally on the privileged port::
REPORT_SSL_PORT=110
.. _`contrib/systemd/electrumx.service`: https://github.com/spesmilo/electrumx/blob/master/contrib/systemd/electrumx.service
.. _`daemontools`: http://cr.yp.to/daemontools.html
.. _`runit`: http://smarden.org/runit/index.html
.. _`aiohttp`: https://pypi.python.org/pypi/aiohttp
.. _`dash_hash`: https://pypi.python.org/pypi/dash_hash
.. _`contrib/raspberrypi3/install_electrumx.sh`: https://github.com/spesmilo/electrumx/blob/master/contrib/raspberrypi3/install_electrumx.sh
.. _`contrib/raspberrypi3/run_electrumx.sh`: https://github.com/spesmilo/electrumx/blob/master/contrib/raspberrypi3/run_electrumx.sh
+20
View File
@@ -0,0 +1,20 @@
# Minimal makefile for Sphinx documentation
#
# You can set these variables from the command line.
SPHINXOPTS = -W
SPHINXBUILD = sphinx-build
SPHINXPROJ = ElectrumX
SOURCEDIR = .
BUILDDIR = _build
# Put it first so that "make" without argument is like "make help".
help:
@$(SPHINXBUILD) -M help "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O)
.PHONY: help Makefile
# Catch-all target: route all unknown targets to Sphinx using the new
# "make mode" option. $(O) is meant as a shortcut for $(SPHINXOPTS).
%: Makefile
@$(SPHINXBUILD) -M $@ "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O)
+45
View File
@@ -0,0 +1,45 @@
Just some notes on performance with Python 3.5. We are taking these into
account in the code.
- 60% faster to create lists with [] list comprehensions than tuples
or lists with tuple(), list(). Of those list is 10% faster than
tuple.
- however when not initializing from a generator, a fixed-length tuple
is at least 80% faster than a list.
- an implicit default argument is ~5% faster than passing the default
explicitly
- using a local variable x rather than self.x in loops and list
comprehensions is over 50% faster
- struct.pack, struct.unpack are over 60% faster than int.to_bytes and
int.from_bytes. They are faster little endian (presumably because
it matches the host) than big endian regardless of length. Furthermore,
using stored packing and unpacking methods from Struct classes is faster
than using the flexible-format struct.[un]pack equivalents.
After storing the Struct('<Q').unpack_from function as unpack_uint64_from,
later calls to unpack_uint64_from(b, 0) are about 30% faster than calls to
unpack_from('<Q', b, 0).
- single-item list and tuple unpacking. Suppose b = (1, )
a, = b is a about 0.4% faster than (a,) = b
and about 45% faster than a = b[0]
- multiple assignment is faster using tuples only for 3 or more items
- retrieving a previously stored length of a bytes object can be over 200%
faster than a new call to len(b)
- The cpython and pypy stdlibs use a Python-based JSON serializer/deserializer,
which is stable and easy to use and install, but somewhat slower than
system-compiled variants. ElectrumX now looks for known popular
C/Rust-based JSON libraries for Python. If it finds one,
it's used instead of the stdlib module for improved performance.
To install a known-compatible system-compiled JSON lib, install ElectrumX
with the "orjson" extras parameter.
+83
View File
@@ -0,0 +1,83 @@
Architecture
============
.. image:: https://docs.google.com/drawings/d/1Su_DR2c8__-4phm12hAzV65fL2tNm_1IhKr4XivkW6Q/pub?w=720&h=540
:target: https://docs.google.com/drawings/d/1Su_DR2c8__-4phm12hAzV65fL2tNm_1IhKr4XivkW6Q/pub?w=960&h=720
Env
---
Holds configuration taken from the environment, with appropriate
defaulting appropriately. Generally passed to the constructor of
other components which take their settings from it.
Controller
----------
The central part of the server process initialising and coordinating
all the others. Manages resource usage.
LocalRPC
--------
Handles local JSON RPC connections querying ElectrumX server state.
Started when the ElectrumX process starts.
ElectrumX
---------
Handles JSON Electrum client connections over TCP or SSL. One
instance per client session. Should be the only component concerned
with the details of the Electrum wire protocol.
Not started until the Block Processor has caught up with bitcoind.
Daemon
------
Encapsulates the RPC wire protocol with bitcoind for the whole server.
Transparently handles temporary bitcoind connection errors, and fails
over if necessary.
Notifies the Mempool when the list of mempool transaction hashes is
updated.
Block Processor
---------------
Responsible for managing block chain state (UTXO set, history,
transaction and undo information) and for handling block chain
reorganisations.
When caught up, processes new blocks as they are found, and flushes
the updates to the Database immediately.
When syncing uses caches for in-memory state updates since the prior
flush. Occasionally flushes state to the storage layer when caches
get large.
Prefetcher
----------
Cooperates with the Block Processor to asynchronously prefetch blocks
from bitcoind. Once it has caught up it additionally asks the Daemon
to refresh its view of bitcoind's mempool transaction hashes. Serves
blocks to the Block Processor via a queue.
Mempool
-------
Handles all the details of maintaining a representation of bitcoind's
mempool state. Obtains the list of current mempool transaction hashes
from the Daemon when notified by the Prefetcher.
Notifies the Controller that addresses have been touched when the
mempool refreshes (or implicitly when a new block is found).
Database
--------
The underlying data store, made up of the DB backend (such as
`leveldb`) and the host filesystem.
+20
View File
@@ -0,0 +1,20 @@
.. _Authors:
Authors
=======
* Neil Booth
Original creator, past maintainer.
* Electrum developers
Current maintainers.
* Johann Bauer
Backend DB abstraction.
* John Jegutanis
Alt-chain integrations.
+431
View File
@@ -0,0 +1,431 @@
===========
ChangeLog
===========
Version 2.0.0 (03 July 2026)
==============================
TL;DR:
- new DB schema, so you need to rebuild from scratch. No more "DB::flush_count overflow".
- Bitcoin Core >=31 is now required, with `txospenderindex=1`
- added support for Electrum Protocol 1.7
- running with free-threaded CPython is now (experimentally) supported, and is much faster
-----
* Breaking changes to on-disk database. Server operators need to manually delete old DB,
no migration path. New DB will be rebuilt while rescanning again from genesis.
- in return, no more manual "history compaction" and unexpected downtimes every year:
no more "DB::flush_count overflow" (`spesmilo/electrumx#88`_)
- the size of the new DB is comparable to the old one, however:
* We now require Bitcoin Core to have :code:`txospenderindex=1` (added in Bitcoin Core 31)
in addition to :code:`txindex=1`. This is needed to serve the :code:`blockchain.outpoint.subscribe` RPC
added in Electrum Protocol 1.7.
For reference, on Bitcoin mainnet around height=950k,
- the ElectrumX db uses around 122 GiB (using LevelDB, roughly same for both of e-x 1.x and 2.0),
- note: using RocksDB 9, it is a bit smaller, around 106 GiB
- :code:`.bitcoin/blocks/` uses 788 GiB,
- :code:`.bitcoin/chainstate/` uses 12 GiB,
- :code:`.bitcoin/indexes/txindex/` uses 66 GiB,
- :code:`.bitcoin/indexes/txospenderindex/` uses 88 GiB (new!)
- This also means that we now require Bitcoin Core 31.0 or newer (for :code:`COIN=Bitcoin`).
* env: the previously optional envvar :code:`DB_ENGINE`, is now mandatory.
- choose either :code:`leveldb` or :code:`rocksdb`
- in ElectrumX 1.x versions, the default was leveldb.
You need to install the appropriate dependencies for your engine, see the :code:`[leveldb]` and
:code:`[rocksdb]` pip extras and the "Database Engine" section of the HOWTO.
Previously RocksDB was difficult to use as the python bindings for it have been unmaintained for years.
By the super-slop-powers of LLMs, we revived the python bindings as :code:`rocksdb-ng` and made it compatible with modern
cpython, cython, and rocksdb. The changes are reviewable and not really slop. (see `spesmilo/electrumx#347`_)
rocksdb-ng (starting with version 2.3) is also compatible with `free-threaded python`_, see "performance" section.
LevelDB was written with HDDs in mind. RocksDB is more modern
and on an SSD takes around ~25% less time than LevelDB to sync from genesis.
Given that this release contains breaking DB changes and a resync is needed anyway, maybe try out RocksDB :)
* performance:
- the BlockProcessor is now massively multi-threaded, both inside a single block and across a span of blocks.
This can mainly only be taken advantage of if the GIL (Global Interpreter Lock) is disabled, that is,
when using a `free-threaded python`_ interpreter: e.g. cpython :code:`3.14t`, compiled with :code:`--disable-gil`.
On a decent modern machine with a multi-core CPU, this has been measured to cut initial sync time
from genesis to a bit less than half. OTOH, much more RAM is required for the parallel processing
(example: approx 2 GB when syncing with GIL, 8 GB when syncing without GIL).
- processing a single block at the tip, when already caught up, is expected to take around half the time,
regardless of the GIL. Still, without the GIL, it is even faster.
- for more details, see `spesmilo/electrumx#369`_
- the (block)Prefetcher and the Mempool code are now partially event-based (but still also polling):
e.g. a mempool update is triggered as soon as processing a new block begins (and part of the work
is done concurrently)
- json (de)serialization can now optionally use the Rust-based
:code:`orjson` library (via the :code:`orjson` pip extra), replacing the
previous :code:`ujson` and :code:`rapidjson` extras.
* Dockerfiles: the existing Dockerfile was updated and cleaned up a bit, and it serves
as a simple minimal example to show how to run ElectrumX. There is now also a second Dockerfile
that sets up a free-threaded python for a beefy server to utilise the above-mentioned performance gains.
See them in :code:`contrib/`. (also see the new runtime logline "Python GIL enabled" to verify effect)
* protocol:
- new: implement electrum protocol version 1.7 (`spesmilo/electrum-protocol#2`_).
The min supported protocol version remains 1.4, the max is now 1.7.
* LocalRPC: new command: "inspect_session" (`spesmilo/electrumx#361`_).
Version 1.20.0 (03 June 2026)
=============================
Small fixes and general maintenance.
After this release, the master branch will move towards a 2.0 release, which will require
a resync from genesis. So for a while, master might be less stable than usual.
* fix: lib/tx.py: vsize calculation was off by 6-8 vbytes (`spesmilo/electrumx#328`_).
Added tests. The discrepancy was externally observable via the `mempool.get_fee_histogram` RPC.
* fix: don't get stuck during shutdown waiting for SessionManager to stop (`spesmilo/electrumx#339`_)
* fix: protocol: name of arg for broadcast_package RPC: tx_package->raw_txs (`c9b72e7e`_)
* changed: peer discovery: allow short chain splits (`spesmilo/electrumx#351`_)
* changed: rm 'attrs' as a direct dependency, use stdlib `dataclasses` instead (`spesmilo/electrumx#345`_)
* new: daemon: check early "txindex" is enabled for bitcoind, error if missing (`spesmilo/electrumx#349`_)
* new: coins: add Bitcoin mutinynet (`spesmilo/electrumx#352`_)
* maintenance: coins: some clean-up (`spesmilo/electrumx#344`_, `spesmilo/electrumx#348`_, ...)
* maintenance: moved CI from Cirrus CI to Github Actions (`spesmilo/electrumx#340`_)
(We also made some changes to make RocksDB practical and nicer to use, but if you currently use LevelDB,
maybe consider waiting for 2.0 before you resync the DB)
Version 1.19.0 (11 Nov 2025)
=============================
* protocol:
- new: implement electrum protocol version 1.6 (`spesmilo/electrumx#317`_, ...)
(`spesmilo/electrum-protocol#6`_).
The min supported protocol version remains 1.4, the max is now 1.6.
* coins:
- changed: for `COIN=Bitcoin`, there is now a min required bitcoind version:
Bitcoin Core 28.0 (or Knots 28) (`spesmilo/electrumx#316`_).
This is due to protocol 1.6 requiring a bitcoind with working `submitpackage` RPC.
* security:
- fix DOS vector: if MAX_SESSIONS was reached, when using python 3.12+, the server
stopped accepting new incoming sessions until full-restart (`spesmilo/electrumx#312`_)
* session:
- changed: add warmup budget to PaddedRSTransport (`spesmilo/electrumx#323`_):
this is a small relaxation of the traffic analysis countermeasures added in 1.18,
where the first 1024 bytes we send are now exempt from buffering (and hence delays)
- fix ReplyAndDisconnect for PaddedRSTransport: flush message buffer (`spesmilo/electrumx#322`_)
* env:
- rm DROP_CLIENT_UNKNOWN opt-in env var: this behaviour is now mandated by protocol 1.6
and we just always enforce it (~small breaking change, affected clients would have
already been considered misbehaving)
* misc:
- new: try to raise `ulimit -n` open file limit automatically at startup
(`spesmilo/electrumx#326`_)
Version 1.18.0 (14 June 2025)
=============================
* protocol:
- add basic countermeasures against traffic analysis by padding the jsonrpc payload
with whitespaces to have ~uniform-size TCP packets, and by artificially delaying
sending messages a bit. (`spesmilo/electrumx#301`_)
* dependencies:
- bump required aiorpcx to >=0.25.0,<0.26
Version 1.17.0 (16 Apr 2025)
============================
Long time no see!
* coins:
- rm support for legacy coin name "BitcoinSegwit" (`ca59151d`_)
(users should just change their config files to :code:`COIN=Bitcoin`)
- add support for Bitcoin Signet (`spesmilo/electrumx#122`_)
- add support for Bitcoin Testnet4 (`spesmilo/electrumx#273`_)
* dependencies:
- bump required python to >=3.10
- bump required aiorpcx to >=0.23.0,<0.25
- rm "pylru" dep, instead bundle stripped-down "cachetools" (`spesmilo/electrumx#248`_)
* session: log IP address of excessive resusage sessions (`spesmilo/electrumx#75`_)
* robustness:
- session: more robust session handling (`25339328`_, `8198ab99`_)
- daemon: catch RPC_PARSE_ERROR from bitcoind and simply retry (`31489365`_)
* env:
- add MAX_RECV environment variable (`a0d3053f`_)
- increase default for MAX_SEND (`2969ab11`_)
* protocol: increase resolution of :code:`mempool.get_fee_histogram` (`265a5a87`_)
* LocalRPC:
- add --timeout arg (`5f4dd2cd`_)
- add commands to help debug memory leaks (`f5582b29`_)
* build/maintenance:
- add scripts for reproducible build (`0ba87447`_)
- migrate from setup.py to pyproject.toml
- refactor file layout flat->src (`spesmilo/electrumx#298`_)
* some internal refactors in preparation for future changes
Version 1.16.0 (10 Dec 2020)
============================
Note: this is the first release since forking from kyuupichan/electrumx.
kyuupichan has the :code:`electrumx` name on PyPI, so we needed a new name there.
We are using the `e-x <https://pypi.org/project/e-x/>`_ name on PyPI, so you can
install this package via e.g. :code:`pip install e-x`.
* security: a vulnerability has been fixed that allowed a remote attacker to
crash electrumx if peer discovery was enabled (`#22`_)
* fixed some peer-discovery-related bugs (e.g. `#35`_)
* ENV: when using Bitcoin, the COIN ENV var can now be set to :code:`Bitcoin`.
For compatibility, using :code:`BitcoinSegwit` will also keep working.
(`#5`_)
* session resource limits: made more useful in general. connection-time-based
grouping has been removed (`#70`_). Disconnects of over-limit sessions happen
sooner (`4b3f6510`_). Subnet sizes for IP-based grouping can now be
configured (`a61136c5`_).
* protocol: :code:`mempool.get_fee_histogram` now returns fee rates with
0.1 sat/byte resolution instead of 1 sat/byte, and the compact histogram
is calculated differently. (`#67`_)
* performance: bitcoind is now queried less frequently as estimatefee,
relayfee, and server.banner requests are now cached (`#24`_)
* performance: json ser/deser is now abstracted away and the :code:`ujson` and
:code:`rapidjson` exras can be used for somewhat faster block processing.
(`#11`_)
* multiple other small performance improvements
Version 1.15.0 (27 May 2020)
============================
* switch to 5-byte txnums to handle larger blockchains. Upgrade DBs during restart.
* accurate clearing of stale caches
* coin additions / updates: NavCoin + Hush + VersusCoin + Zero (cipig), DashRegtest (colmenero),
Quebecoin (morinpa), Primecoin (Sunny King), multiple (Panagiotis David), RVN (standard-error),
Sumcoin
* other: Jeremy Rand, Jin Eguchi, ddude, Jonathan Cross, Carsen Klock, cipig
Version 1.14.0 (19 Jan 2020)
============================
* require Python 3.7
* support for Bitcoin SV Genesis activation
* DB upgrade to allow for larger transactions. Your DB will automatically upgrade when
starting, the upgrade should take approximately 15 mintues.
* fix server shutdown process
* fix cache race condition (issue `#909`_)
* faster initial sync
* coin additions / updates: Emercoin (yakimka), Feathercoin (wellenreiter01),
Peercoin (peerchemist), Namecoin (JeremyRand), Zcoin (a-bezrukov), Simplicity,
Mice (ComputerCraftr), Sibcoin testnet (TriKriSta), Odin (Manbearpixel),
* other: h2o10, osagga, Sombernight, breign, pedr0-fr, wingsuit
Version 1.13.0 (26 Sep 2019)
============================
* daemon: use a single connection for all requests rather than a connection per request.
Distinguish handling of JSON and HTTP errors
* recognise OP_FALSE OP_RETURN scripts as unspendable
* peers - attempt to bind to correct local IP address
* improve name support (domob1812)
* coin additions / updates: BitZeny (y-chan), ZCoin (a-bezrukov), Emercoin (yakimka),
BSV (Roger Taylor), Bellcoin (streetcrypto7), Ritocoin (traysi), BTC (Sombernight),
PIVX (mrcarlanthony), Monacoin (wakiyamap)), NamecoinRegtest (JeremyRand), Axe (ddude1),
Xaya (domob1812), GZRO (MrNaif2018), Ravencoin (standard-error)
* other: gits7r
Version 1.12.0 (13 May 2019)
============================
* require aiorpcX 0.18.1. This introduces websocket support. The environment variables
changed accordingly; see :envvar:`SERVICES` and :envvar:`REPORT_SERVICES`.
* work around bug in recent versions of uvloop
* aiorpcX upgrade fixes from Shane M
* coin additions / updates: BitcoinSV, Bolivarcoin (Jose Luis Estevez), BTC Testnet (ghost43),
Odin (Pixxl)
Version 1.11.0 (18 Apr 2019)
============================
* require aiorpcX 0.15.x
* require aiohttp 3.3 or higher; earlier versions had a problematic bug
* add :envvar:`REQUEST_TIMEOUT` and :envvar:`LOG_LEVEL` environment variables
* mark 4 old environment variables obsolete. ElectrumX won't start until they are removed
* getinfo local RPC cleaned up and shows more stats
* miscellaneous fixes and improvements
* more efficient handling of some RPC methods, particularly
:func:`blockchain.transaction.get_merkle`
* coin additions / updates: BitcoinSV scaling testnet (Roger Taylor), Dash (zebra lucky),
* issues resolved: `#566`_, `#731`_, `#795`_
Version 1.10.1 (13 Apr 2019)
============================
* introduce per-request costing. See environment variables documentation for new
variables :envvar:`COST_SOFT_LIMIT`, :envvar:`COST_HARD_LIMIT`, :envvar:`REQUEST_SLEEP`,
:envvar:`INITIAL_CONCURRENT`, :envvar:`BANDWIDTH_UNIT_COST`. Sessions are placed in groups
with which they share some of their costs. Prior cost is remembered across reconnects.
* require aiorpcX 0.13.5 for better concurrency handling
* require clients use protocol 1.4 or higher
* handle transaction.get_merkle requests more efficiently (ghost43)
* Windows support (sancoder)
* peers improvements (ghost43)
* report mempool and block sizes in logs
* electrumx_rpc: timeout raised to 30s, fix session request counts
* other tweaks and improvements by Bjorge Dijkstra, ghost43, peleion,
* coin additions / updates: ECA (Jenova7), ECCoin (smogm), GXX (DEVCØN), BZX (2INFINITY),
DeepOnion (Liam Alford), CivX / EXOS (turcol)
Version 1.10.0 (15 Mar 2019)
============================
* extra countermeasures to limit BTC phishing effectiveness (ghost43)
* peers: mark blacklisted peers bad; force retry blacklisted peers (ghost43)
* coin additions / updates: Monacoin (wakiyamap), Sparks (Mircea Rila), ColossusXT,
Polis, MNPCoin, Zcoin, GINCoin (cronos), Grosetlcoin (gruve-p), Dash (konez2k),
Bitsend (David), Ravencoin (standard-error), Onixcoin (Jose Estevez), SnowGem
* coin removals: Gobyte, Moneci (cronos)
* minor tweaks by d42
* issues fixed `#660`_ - unclean shutdowns during initial sync
Version 1.9.5 (08 Feb 2019)
===========================
* server blacklist logic (ecdsa)
* require aiorpcX 0.10.4
* remove dead wallet code
* fix `#727`_ - not listing same peer twice
Version 1.9.4 (07 Feb 2019)
===========================
* require aiorpcX 0.10.3
* fix `#713`_
Version 1.9.3 (05 Feb 2019)
===========================
* ignore potential sybil peers
* coin additions / updates: BitcoinCashABC (cculianu), Monacoin (wakiyamap)
Version 1.9.2 (03 Feb 2019)
===========================
* restore protocol version 1.2 and send a warning for old BTC Electrum clients that they
need to upgrade. This is an attempt to protect users of old versions of Electrum from
the ongoing phishing attacks
* increase default MAX_SEND for AuxPow Chains. Truncate AuxPow for block heights covered
by a checkpoint. (jeremyrand)
* coin additions / updates: NMC (jeremyrand), Dash (zebra-lucky), PeerCoin (peerchemist),
BCH testnet (Mark Lundeberg), Unitus (ChekaZ)
* tighter RPC param checking (ghost43)
Version 1.9.1 (11 Jan 2019)
===========================
* fix `#684`_
Version 1.9.0 (10 Jan 2019)
===========================
* minimum protocol version is now 1.4
* coin additions / updates: BitcoinSV, SmartCash (rc125), NIX (phamels), Minexcoin (joesixpack),
BitcoinABC (mblunderburg), Dash (zebra-lucky), BitcoinABCRegtest (ezegom), AXE (slowdive),
NOR (flo071), BitcoinPlus (bushsolo), Myriadcoin (cryptapus), Trezarcoin (ChekaZ),
Bitcoin Diamond (John Shine),
* close `#554`_, `#653`_, `#655`_
* other minor tweaks (Michael Schmoock, Michael Taborsky)
Original author of ElectrumX:
**Neil Booth** kyuupichan@gmail.com https://github.com/kyuupichan
This fork maintained by:
**Electrum developers** electrumdev@gmail.com https://github.com/spesmilo
.. _#554: https://github.com/kyuupichan/electrumx/issues/554
.. _#566: https://github.com/kyuupichan/electrumx/issues/566
.. _#653: https://github.com/kyuupichan/electrumx/issues/653
.. _#655: https://github.com/kyuupichan/electrumx/issues/655
.. _#660: https://github.com/kyuupichan/electrumx/issues/660
.. _#684: https://github.com/kyuupichan/electrumx/issues/684
.. _#713: https://github.com/kyuupichan/electrumx/issues/713
.. _#727: https://github.com/kyuupichan/electrumx/issues/727
.. _#731: https://github.com/kyuupichan/electrumx/issues/731
.. _#795: https://github.com/kyuupichan/electrumx/issues/795
.. _#909: https://github.com/kyuupichan/electrumx/issues/909
.. _#5: https://github.com/spesmilo/electrumx/pull/5
.. _#11: https://github.com/spesmilo/electrumx/pull/11
.. _#22: https://github.com/spesmilo/electrumx/issues/22
.. _#24: https://github.com/spesmilo/electrumx/pull/24
.. _#35: https://github.com/spesmilo/electrumx/pull/35
.. _#67: https://github.com/spesmilo/electrumx/pull/67
.. _#70: https://github.com/spesmilo/electrumx/pull/70
.. _spesmilo/electrumx#75: https://github.com/spesmilo/electrumx/pull/75
.. _spesmilo/electrumx#88: https://github.com/spesmilo/electrumx/issues/88
.. _spesmilo/electrumx#122: https://github.com/spesmilo/electrumx/pull/122
.. _spesmilo/electrumx#248: https://github.com/spesmilo/electrumx/pull/248
.. _spesmilo/electrumx#273: https://github.com/spesmilo/electrumx/pull/273
.. _spesmilo/electrumx#298: https://github.com/spesmilo/electrumx/pull/298
.. _spesmilo/electrumx#301: https://github.com/spesmilo/electrumx/pull/301
.. _spesmilo/electrumx#312: https://github.com/spesmilo/electrumx/pull/312
.. _spesmilo/electrumx#316: https://github.com/spesmilo/electrumx/pull/316
.. _spesmilo/electrumx#317: https://github.com/spesmilo/electrumx/pull/317
.. _spesmilo/electrumx#322: https://github.com/spesmilo/electrumx/pull/322
.. _spesmilo/electrumx#323: https://github.com/spesmilo/electrumx/pull/323
.. _spesmilo/electrumx#326: https://github.com/spesmilo/electrumx/pull/326
.. _spesmilo/electrumx#328: https://github.com/spesmilo/electrumx/pull/328
.. _spesmilo/electrumx#339: https://github.com/spesmilo/electrumx/pull/339
.. _spesmilo/electrumx#340: https://github.com/spesmilo/electrumx/pull/340
.. _spesmilo/electrumx#344: https://github.com/spesmilo/electrumx/pull/344
.. _spesmilo/electrumx#345: https://github.com/spesmilo/electrumx/pull/345
.. _spesmilo/electrumx#347: https://github.com/spesmilo/electrumx/pull/347
.. _spesmilo/electrumx#348: https://github.com/spesmilo/electrumx/pull/348
.. _spesmilo/electrumx#349: https://github.com/spesmilo/electrumx/pull/349
.. _spesmilo/electrumx#351: https://github.com/spesmilo/electrumx/pull/351
.. _spesmilo/electrumx#352: https://github.com/spesmilo/electrumx/pull/352
.. _spesmilo/electrumx#361: https://github.com/spesmilo/electrumx/pull/361
.. _spesmilo/electrumx#369: https://github.com/spesmilo/electrumx/pull/369
.. _4b3f6510: https://github.com/spesmilo/electrumx/commit/4b3f6510e94670a013c1abe6247cdd2b0e7e6f8c
.. _a61136c5: https://github.com/spesmilo/electrumx/commit/a61136c596d6a0290a6be9d21fb7c095c3cea21e
.. _ca59151d: https://github.com/spesmilo/electrumx/commit/ca59151d7365aabd2394fb39aac1faa25949b49d
.. _25339328: https://github.com/spesmilo/electrumx/commit/25339328a7468235071d152f728b214df10d4c56
.. _8198ab99: https://github.com/spesmilo/electrumx/commit/8198ab99603a7e74083b3569c15dad13850c721e
.. _31489365: https://github.com/spesmilo/electrumx/commit/314893655a7cc0bfcc216b07900fa77b5f66e148
.. _a0d3053f: https://github.com/spesmilo/electrumx/commit/a0d3053f60074264b54b3ef7583f2600f4b73ead
.. _2969ab11: https://github.com/spesmilo/electrumx/commit/2969ab110412bebddc3f3e815467fb59538b613d
.. _265a5a87: https://github.com/spesmilo/electrumx/commit/265a5a87b8ad01f739049c0b1e80923aab318f58
.. _5f4dd2cd: https://github.com/spesmilo/electrumx/commit/5f4dd2cdb414464484407affbbaae6b7407696cb
.. _f5582b29: https://github.com/spesmilo/electrumx/commit/f5582b29792625e8cca7cf137a6718c2520bb9cb
.. _0ba87447: https://github.com/spesmilo/electrumx/commit/0ba87447cb293cfc4a8a26c1c27842b95666875a
.. _c9b72e7e: https://github.com/spesmilo/electrumx/commit/c9b72e7ea76bfb706b2df3e90c739116bf49678d
.. _spesmilo/electrum-protocol#2: https://github.com/spesmilo/electrum-protocol/pull/2
.. _spesmilo/electrum-protocol#6: https://github.com/spesmilo/electrum-protocol/pull/6
.. _free-threaded python: https://docs.python.org/3/howto/free-threading-python.html
+165
View File
@@ -0,0 +1,165 @@
# -*- coding: utf-8 -*-
#
# Configuration file for the Sphinx documentation builder.
#
# This file does only contain a selection of the most common options. For a
# full list see the documentation:
# http://www.sphinx-doc.org/en/stable/config
# -- Path setup --------------------------------------------------------------
# If extensions (or modules to document with autodoc) are in another directory,
# add these directories to sys.path here. If the directory is relative to the
# documentation root, use os.path.abspath to make it absolute, like shown here.
import os
import sys
sys.path.insert(0, os.path.abspath('..'))
VERSION="ElectrumX 2.0.0"
# -- Project information -----------------------------------------------------
project = 'ElectrumX'
copyright = '2016-2026, various'
author = 'Electrum developers'
# The full version including branding
release = VERSION
# The short X.Y version
version = VERSION.split()[-1]
# -- General configuration ---------------------------------------------------
# If your documentation needs a minimal Sphinx version, state it here.
#
# needs_sphinx = '1.0'
# Add any Sphinx extension module names here, as strings. They can be
# extensions coming with Sphinx (named 'sphinx.ext.*') or your custom
# ones.
extensions = [
]
# Add any paths that contain templates here, relative to this directory.
templates_path = ['_templates']
# The suffix(es) of source filenames.
# You can specify multiple suffix as a list of string:
#
# source_suffix = ['.rst', '.md']
source_suffix = '.rst'
# The master toctree document.
master_doc = 'index'
# The language for content autogenerated by Sphinx. Refer to documentation
# for a list of supported languages.
#
# This is also used if you do content translation via gettext catalogs.
# Usually you set "language" from the command line for these cases.
language = 'en'
# List of patterns, relative to source directory, that match files and
# directories to ignore when looking for source files.
# This pattern also affects html_static_path and html_extra_path .
exclude_patterns = ['_build', 'Thumbs.db', '.DS_Store']
# The name of the Pygments (syntax highlighting) style to use.
pygments_style = 'sphinx'
# -- Options for HTML output -------------------------------------------------
# The theme to use for HTML and HTML Help pages. See the documentation for
# a list of builtin themes.
#
html_theme = 'alabaster'
# Theme options are theme-specific and customize the look and feel of a theme
# further. For a list of options available for each theme, see the
# documentation.
#
html_theme_options = {
'description': 'Lightweight Electrum Server in Python',
'github_user': 'spesmilo',
'github_repo': 'electrumx',
'github_button': True,
'github_type': 'star',
'github_banner': True,
}
# Add any paths that contain custom static files (such as style sheets) here,
# relative to this directory. They are copied after the builtin static files,
# so a file named "default.css" will overwrite the builtin "default.css".
# html_static_path = ['_static']
# Custom sidebar templates, must be a dictionary that maps document names
# to template names.
#
# The default sidebars (for documents that don't match any pattern) are
# defined by theme itself. Builtin themes are using these templates by
# default: ``['localtoc.html', 'relations.html', 'sourcelink.html',
# 'searchbox.html']``.
html_sidebars = {
'**': [
'about.html', 'navigation.html', 'searchbox.html',
]
}
# -- Options for HTMLHelp output ---------------------------------------------
# Output file base name for HTML help builder.
htmlhelp_basename = 'ElectrumXdoc'
# -- Options for LaTeX output ------------------------------------------------
latex_elements = {
# The paper size ('letterpaper' or 'a4paper').
#
# 'papersize': 'letterpaper',
# The font size ('10pt', '11pt' or '12pt').
#
# 'pointsize': '10pt',
# Additional stuff for the LaTeX preamble.
#
# 'preamble': '',
# Latex figure (float) alignment
#
# 'figure_align': 'htbp',
}
# Grouping the document tree into LaTeX files. List of tuples
# (source start file, target name, title,
# author, documentclass [howto, manual, or own class]).
latex_documents = [
(master_doc, 'ElectrumX.tex', 'ElectrumX Documentation',
'Neil Booth', 'manual'),
]
# -- Options for manual page output ------------------------------------------
# One entry per manual page. List of tuples
# (source start file, name, description, authors, manual section).
man_pages = [
(master_doc, 'electrumx', 'ElectrumX Documentation',
[author], 1)
]
# -- Options for Texinfo output ----------------------------------------------
# Grouping the document tree into Texinfo files. List of tuples
# (source start file, target name, title, author,
# dir menu entry, description, category)
texinfo_documents = [
(master_doc, 'ElectrumX', 'ElectrumX Documentation',
author, 'ElectrumX', 'One line description of project.',
'Miscellaneous'),
]
+510
View File
@@ -0,0 +1,510 @@
.. _environment:
=====================
Environment Variables
=====================
ElectrumX takes no command line arguments, instead its behaviour is controlled by
environment variables. Only a few are required to be given, the rest will have sensible
defaults if not specified. Many of the defaults around resource usage are conservative; I
encourage you to review them.
.. note:: set :envvar:`SERVICES` appropriately to be able to connect to your server. For
clients across the internet to know what services you offer you must advertize your
services with :envvar:`REPORT_SERVICES`.
Required
========
These environment variables are always required:
.. envvar:: DB_DIRECTORY
The path to the database directory. Relative paths should be
relative to the parent process working directory. This is the
directory of the `run` script if you use it.
.. envvar:: DB_ENGINE
Database engine for the UTXO and history database.
Choose one of ``leveldb`` or ``rocksdb``.
You will need to install the appropriate python package for your engine.
In ElectrumX 1.x versions, the default was leveldb.
Warning: It is not possible to switch back and forth,
the on-disk DB formats are not compatible with each other: you have to resync from genesis.
LevelDB was written with HDDs in mind. RocksDB is more modern
and on an SSD takes around ~25% less time than LevelDB to sync from genesis.
.. envvar:: DAEMON_URL
A comma-separated list of daemon URLs. If more than one is provided
ElectrumX will initially connect to the first, and failover to
subsequent ones round-robin style if one stops working.
The generic form of a daemon URL is::
http://username:password@hostname:port/
The leading ``http://`` is optional, as is the trailing slash. The
``:port`` part is also optional and will default to the standard RPC
port for :envvar:`COIN` and :envvar:`NET` if omitted.
.. note:: With the above set your server will run and index the chain. To enable incoming
connections you must set :envvar:`SERVICES`, and for others to be aware of your server
set :envvar:`REPORT_SERVICES`.
For the ``run`` script
======================
The following are required if you use the ``run`` script:
.. envvar:: ELECTRUMX
The path to the electrumx_server script. Relative paths should
be relative to the directory of the ``run`` script.
.. envvar:: USERNAME
The username the server will run as.
Services
========
These two environment variables are comma-separated lists of individual *services*.
A **service** has the general form::
protocol://host:port
*protocol* is case-insensitive. The recognised protocols are::
tcp Plaintext TCP sockets
ssl SSL-encrypted TCP sockets
ws Plaintext websockets
wss SSL-encrypted websockets
rpc Plaintext RPC
In a services list, a protocol can be specified multiple times, with different hosts or
ports. This might be useful for multi-homed hosts, or if you offer both Tor and clearnet
services.
*host* can be a hostname, an IPv4 address, or an IPv6 address enclosed in square brackets.
*port* is an integer from :const:`1` to :const:`65535` inclusive.
Where documented, one or more of *protocol*, *host* and *port* can be omitted, in which
case a default value will be assumed.
Here are some examples of valid services::
tcp://host.domain.tld:50001 # Hostname, lowercase protocol, port
SSL://23.45.67.78:50002 # An IPv4 address, upper-case protocol, port
rpC://localhost # Host as a string, mixed-case protocol, default port
ws://[1234:5678:abcd::5601]:8000 # Host as an IPv6 address
wss://h3ubaasdlkheryasd.onion:50001 # Host as a Tor ".onion" address
rpc://:8000 # Default host, port given
host.domain.tld:5151 # Default protocol, hostname, port
rpc:// # RPC protocol, default host and port
.. note:: ElectrumX will not serve any incoming connections until it has fully caught up
with your bitcoin daemon. The only exception is local **RPC** connections,
which are served at any time after the server has initialized.
.. envvar:: SERVICES
A comma-separated list of services ElectrumX will accept incoming connections for.
This environment variable determines what interfaces and ports the server listens on, so
must be set correctly for any connection to the server to succeed. If unset or empty,
ElectrumX will not listen for any incoming connections.
*protocol* can be any recognised protocol.
*host* defaults to all of the machine's interfaces, except if the protocol is **rpc**,
when it defaults to :const:`localhost`.
*port* can only be defaulted for **rpc** where the default is :const:`8000`.
On most Unix systems ports below 1024 require elevated privileges so choosing a higher
port is advisable. On Debian for example, this can be achieved by installing
libcap2-bin package::
sudo apt-get update && sudo apt-get -y install libcap2-bin
sudo setcap cap_net_bind_service=+ep /path/to/electrumx_server
If any listed service has protocol **ssl** or **wss** then :envvar:`SSL_CERTFILE` and
:envvar:`SSL_KEYFILE` must be defined.
Tor **onion** addresses are invalid in :envvar:`SERVICES`.
Here is an example value of the :envvar:`SERVICES` environment variable::
tcp://:50001,ssl://:50002,wss://:50004,rpc://
This serves **tcp**, **ssl**, **wss** on all interfaces on ports 50001, 50002 and 50004
respectively. **rpc** is served on its default host :const:`localhost` and default port
:const:`8000`.
.. envvar:: REPORT_SERVICES
A comma-separated list of services ElectrumX will advertize and other servers in the
server network (if peer discovery is enabled), and any successful connection.
This environment variable must be set correctly, taking account of your network,
firewall and router setup, for clients and other servers to see how to connect to your
server. If not set or empty, no services are advertized.
The **rpc** protocol, special IP addresses (including private ones if peer discovery is
enabled), and :const:`localhost` are invalid in :envvar:`REPORT_SERVICES`.
Here is an example value of the :envvar:`REPORT_SERVICES` environment variable::
tcp://example.com:50001,ssl://example.com:50002,wss://example.com:50004
This advertizes **tcp**, **ssl**, **wss** services at :const:`example.com` on ports
50001, 50002 and 50004 respectively.
.. note:: Certificate Authority-signed certificates don't work over Tor, so you should
only have Tor services` in :envvar:`REPORT_SERVICES` if yours is self-signed.
.. envvar:: SSL_CERTFILE
The filesystem path to your SSL certificate file.
:ref:`SSL certificates`
.. envvar:: SSL_KEYFILE
The filesystem path to your SSL key file.
:ref:`SSL certificates`
Miscellaneous
=============
These environment variables are optional:
.. envvar:: COIN
Must be a :attr:`NAME` from one of the :class:`Coin` classes in
`lib/coins.py`_. Defaults to ``Bitcoin``.
.. envvar:: NET
Must be a :attr:`NET` from one of the :class:`Coin` classes in
`lib/coins.py`_. Defaults to ``mainnet``.
.. envvar:: LOG_FORMAT
The Python logging `format string
<https://docs.python.org/3/library/logging.html#logrecord-attributes>`_
to use. Defaults to ``%(levelname)s:%(name)s:%(message)s``.
.. envvar:: LOG_LEVEL
The default Python logging level, a case-insensitive string. Useful values
are 'debug', 'info', 'warning' and 'error'.
.. envvar:: ALLOW_ROOT
Set this environment variable to anything non-empty to allow running
ElectrumX as root.
.. envvar:: DONATION_ADDRESS
The server donation address reported to Electrum clients. Defaults
to empty, which Electrum interprets as meaning there is none.
.. envvar:: BANNER_FILE
The path to a banner file to serve to clients in Electrum's
"Console" tab. Relative file paths must be relative to
:envvar:`DB_DIRECTORY`. The banner file is re-read for each new
client.
You can place several meta-variables in your banner file, which will be
replaced before serving to a client.
+ ``$SERVER_VERSION`` is replaced with the ElectrumX version you are
running, such as ``1.0.10``.
+ ``$SERVER_SUBVERSION`` is replaced with the ElectrumX user agent
string. For example, ``ElectrumX 1.0.10``.
+ ``$DAEMON_VERSION`` is replaced with the daemon's version as a
dot-separated string. For example ``0.12.1``.
+ ``$DAEMON_SUBVERSION`` is replaced with the daemon's user agent
string. For example, ``/BitcoinUnlimited:0.12.1(EB16; AD4)/``.
+ ``$DONATION_ADDRESS`` is replaced with the address from the
:envvar:`DONATION_ADDRESS` environment variable.
See `here <https://github.com/shsmith/electrumx-banner-updater>`_
for a script that updates a banner file periodically with useful
statistics about fees, last block time and height, etc.
.. envvar:: TOR_BANNER_FILE
As for :envvar:`BANNER_FILE` (which is also the default) but shown
to incoming connections believed to be to your Tor hidden service.
.. envvar:: ANON_LOGS
Set to anything non-empty to replace IP addresses in logs with
redacted text like ``xx.xx.xx.xx:xxx``. By default IP addresses
will be written to logs.
.. envvar:: LOG_SESSIONS
The number of seconds between printing session statistics to the
log. The output is identical to the :ref:`sessions` RPC command
except that :envvar:`ANON_LOGS` is honoured. Defaults to 3600. Set
to zero to suppress this logging.
.. envvar:: REORG_LIMIT
The maximum number of blocks to be able to handle in a chain
reorganisation. ElectrumX retains some fairly compact undo
information for this many blocks in levelDB. The default is a
function of :envvar:`COIN` and :envvar:`NET`; for Bitcoin mainnet it
is 200.
.. envvar:: EVENT_LOOP_POLICY
The name of an event loop policy to replace the default asyncio
policy, if any. At present only ``uvloop`` is accepted, in which
case you must have installed the `uvloop`_ Python package.
If you are not sure what this means leave it unset.
.. envvar:: DROP_CLIENT
Set a regular expression to disconnect any client based on their
version string. For example to drop versions from 1.0 to 1.2 use
the regex ``1\.[0-2]\.\d+``.
Resource Usage Limits
=====================
The following environment variables are all optional and help to limit
server resource consumption and prevent simple DoS.
Address subscriptions in ElectrumX are very cheap - they consume about
160 bytes of memory each and are processed efficiently. I feel the
two subscription-related defaults below are low and encourage you to
raise them.
.. envvar:: MAX_SESSIONS
The maximum number of incoming connections. Once reached, TCP and
SSL listening sockets are closed until the session count drops
naturally to 95% of the limit. Defaults to 1,000.
.. envvar:: MAX_RECV
The maximum size of an incoming message in bytes, the default is 1,000,000 bytes.
Note that the smallest sane/safe value for Bitcoin is ~800,100 bytes,
as the largest standard tx can have a weight of 400K but the protocol hex-encodes that,
plus there is a few bytes of protocol overhead. Setting this to lower than that
would preclude clients from broadcasting txs that could propagate over the network.
.. envvar:: MAX_SEND
The maximum size of a response message to send over the wire, in
bytes. Defaults to 8,100,000 (except for AuxPoW coins, which default
to 10,000,000). Values smaller than 350,000 are taken as 350,000
because standard Electrum protocol header "chunk" requests are almost
that large.
The Electrum protocol has a flaw in that address histories must be
served all at once or not at all, an obvious avenue for abuse.
:envvar:`MAX_SEND` is a stop-gap until the protocol is improved to
admit incremental history requests. Each history entry is
approximately 100 bytes, so the default is equivalent to a history
limit of around 80,000 entries, which should be ample for most
legitimate users. If you use a higher default, bear in mind one
client can request history for multiple addresses.
Also note that the largest raw transaction you will be able to serve to a client is
just under half of :envvar:`MAX_SEND`, as each raw byte becomes 2 hexadecimal
ASCII characters on the wire. For Bitcoin, the consensus limit for tx size is
4 M weight units, while the standardness (policy) limit is 400 K weight units.
When serialized as bytes, 4 M weight units is 4 MB, and when encoded as hex that is 8 MB.
The default was chosen so that such a tx could still be served.
(Note: in multi-party protocol, such as Lightning, a counterparty might collude with a miner
to get a tx mined. Being able to obtain such a raw tx might be part of the security
requirements of a protocol.)
.. envvar:: COST_SOFT_LIMIT
.. envvar:: COST_HARD_LIMIT
.. envvar:: REQUEST_SLEEP
.. envvar:: INITIAL_CONCURRENT
.. envvar:: SESSION_GROUP_BY_SUBNET_IPV4
.. envvar:: SESSION_GROUP_BY_SUBNET_IPV6
All values are integers. :envvar:`COST_SOFT_LIMIT` defaults to :const:`1,000`,
:envvar:`COST_HARD_LIMIT` to :const:`10,000`, :envvar:`REQUEST_SLEEP` to :const:`2,500`
milliseconds, and :envvar:`INITIAL_CONCURRENT` to :const:`10` concurrent requests.
The server prices each request made to it based upon an estimate of the resources needed
to process it. Factors include whether the request uses bitcoind, how much bandwidth
it uses, and how hard it hits the databases.
To set a base for the units, a :func:`blockchain.scripthash.subscribe` subscription to
an address with a history of 2 or fewer transactions is costed at :const:`1.0` before
considering the bandwidth consumed. :func:`server.ping` is costed at :const:`0.1`.
As the total cost of a session goes over the soft limit, its requests start to be
throttled in two ways. First, the number of requests for that session that the server
will process concurrently is reduced. Second, each request starts to sleep a little
before being handled.
Before throttling starts, the server will process up to :envvar:`INITIAL_CONCURRENT`
requests concurrently without sleeping. As the session cost ranges from
:envvar:`COST_SOFT_LIMIT` to :envvar:`COST_HARD_LIMIT`, concurrency drops linearly to
zero and each request's sleep time increases linearly up to :envvar:`REQUEST_SLEEP`
milliseconds. Once the hard limit is reached, the session is disconnected.
In order that non-abusive sessions can continue to be served, a session's cost gradually
decays over time. Subscriptions have an ongoing servicing cost, so the decay is slower
as the number of subscriptions increases.
If a session disconnects, ElectrumX continues to associate its cost with its IP address,
so if it immediately reconnects it will re-acquire its previous cost allocation.
Moreover, sessions are also grouped together based on their IP address subnets, and cost
is accrued for the whole group. What subnet sizes to use can be configured via
:envvar:`SESSION_GROUP_BY_SUBNET_IPV4` (by default /24) and
:envvar:`SESSION_GROUP_BY_SUBNET_IPV6` (by default /48).
A server operator should experiment with different values according to server loads. It
is not necessarily true that e.g. having a low soft limit, decreasing concurrency and
increasing sleep will help handling heavy loads, as it will also increase the backlog of
requests the server has to manage in memory. It will also give a much worse experience
for genuine connections.
.. envvar:: BANDWIDTH_UNIT_COST
The number of bytes, sent and received, by a session that is deemed to cost :const:`1.0`.
The default value :const:`5,000` bytes, meaning the bandwidth cost assigned to a response
of 100KB is 20. If your bandwidth is cheap you should probably raise this.
.. envvar:: REQUEST_TIMEOUT
An integer number of seconds defaulting to :const:`30`. If a request takes longer than
this to respond to, either because of request limiting or because the request is
expensive, the server rejects it and returns a timeout error to the client indicating
that the server is busy.
This can help prevent large backlogs of unprocessed requests building up under heavy load.
.. envvar:: SESSION_TIMEOUT
An integer number of seconds defaulting to :const:`600`. Sessions that have not sent a
request for longer than this are disconnected. Properly functioning clients should send
a :func:`server.ping` request once roughly 450 seconds have passed since the previous
request, in order to avoid disconnection.
Peer Discovery
==============
In response to the :func:`server.peers.subscribe` RPC call, ElectrumX
will only return peer servers that it has recently connected to and
verified basic functionality.
If you are not running a Tor proxy ElectrumX will be unable to connect
to onion server peers, in which case rather than returning no onion
peers it will fall back to a hard-coded list.
To give incoming clients a full range of onion servers, you will need
to be running a Tor proxy for ElectrumX to use.
ElectrumX will perform peer-discovery by default and announce itself
to other peers. If your server is private you may wish to disable
some of this.
.. envvar:: PEER_DISCOVERY
This environment variable is case-insensitive and defaults to
``on``.
If ``on``, ElectrumX will occasionally connect to and verify its
network of peer servers.
If ``off``, peer discovery is disabled and a hard-coded default list
of servers will be read in and served. If set to ``self`` then peer
discovery is disabled and the server will only return itself in the
peers list.
.. envvar:: PEER_ANNOUNCE
Set this environment variable to empty to disable announcing itself.
If not defined, or non-empty, ElectrumX will announce itself to
peers.
If peer discovery is disabled this environment variable has no
effect, because ElectrumX only announces itself to peers when doing
peer discovery if it notices it is not present in the peer's
returned list.
.. envvar:: FORCE_PROXY
By default peer discovery happens over the clear internet. Set this
to non-empty to force peer discovery to be done via the proxy. This
might be useful if you are running a Tor service exclusively and
wish to keep your IP address private.
.. envvar:: TOR_PROXY_HOST
The host where your Tor proxy is running. Defaults to
``localhost``.
If you are not running a Tor proxy just leave this environment
variable undefined.
.. envvar:: TOR_PROXY_PORT
The port on which the Tor proxy is running. If not set, ElectrumX
will autodetect any proxy running on the usual ports 9050 (Tor),
9150 (Tor browser bundle) and 1080 (socks).
.. envvar:: BLACKLIST_URL
URL to retrieve a list of blacklisted peers. If not set, a coin-
specific default is used.
Cache
=====
If synchronizing from the Genesis block your performance might change
by tweaking the cache size. Cache size is only checked roughly every
minute, so the cache can grow beyond the specified size. Moreover,
the Python process is often quite a bit fatter than the cache size,
because of Python overhead and also because leveldb consumes a lot of
memory when flushing. So I recommend you do not set this over 60% of
your available physical RAM:
.. _CACHE:
.. envvar:: CACHE_MB
The amount of cache, in MB, to use. The default is 1,200.
A portion of the cache is reserved for unflushed history, which is
written out frequently. The bulk is used to cache UTXOs.
Larger caches probably increase performance a little as there is
significant searching of the UTXO cache during indexing. However, I
don't see much benefit in my tests pushing this too high, and in
fact performance begins to fall, probably because LevelDB already
caches, and also because of Python GC.
I do not recommend raising this above 2000.
.. _lib/coins.py: https://github.com/spesmilo/electrumx/blob/master/src/electrumx/lib/coins.py
.. _uvloop: https://pypi.python.org/pypi/uvloop
+59
View File
@@ -0,0 +1,59 @@
Features
========
- Efficient, lightweight reimplementation of electrum-server
- Fast synchronization of bitcoin mainnet from Genesis. Recent
hardware should synchronize in well under 24 hours. The fastest
time to height 448k (mid January 2017) reported is under 4h 30m. On
the same hardware JElectrum would take around 4 days and
electrum-server probably around 1 month.
- Various configurable means of controlling resource consumption and
handling bad clients and denial of service attacks. These include
maximum connection counts, subscription limits per-connection and
across all connections, maximum response size, per-session bandwidth
limits, and session timeouts.
- Minimal resource usage once caught up and serving clients; tracking the
transaction mempool appears to be the most expensive part.
- Mostly asynchronous processing of new blocks, mempool updates, and
client requests. Busy clients should not noticeably impede other
clients' requests and notifications, nor the processing of incoming
blocks and mempool updates.
- Daemon failover. More than one daemon can be specified, and
ElectrumX will failover round-robin style if the current one fails
for any reason.
- Peer discovery protocol removes need for IRC
- Coin abstraction makes compatible altcoin and testnet support easy.
Implementation
==============
ElectrumX does not do any pruning or throwing away of history. I want
to retain this property for as long as it is feasible, and it appears
efficiently achievable for the foreseeable future with plain Python.
The following all play a part in making it efficient as a Python
blockchain indexer:
- aggressive caching and batching of DB writes
- more compact and efficient representation of UTXOs, address index,
and history. Electrum Server stores full transaction hash and
height for each UTXO, and does the same in its pruned history. In
contrast ElectrumX just stores the transaction number in the linear
history of transactions. ElectrumX can determine block
height from a simple binary search of tx counts stored on disk.
ElectrumX stores historical transaction hashes in a linear array on
disk.
- placing static append-only metadata indexable by position on disk
rather than in levelDB. It would be nice to do this for histories
but I cannot think of a way.
- avoiding unnecessary or redundant computations, such as converting
address hashes to human-readable ASCII strings with expensive bignum
arithmetic, and then back again.
- better choice of Python data structures giving lower memory usage as
well as faster traversal
- leveraging asyncio for asynchronous prefetch of blocks to mostly
eliminate CPU idling. As a Python program ElectrumX is unavoidably
single-threaded in its essence; we must keep that CPU core busy.
Python's :mod:`asyncio` means ElectrumX has no (direct) use for threads
and associated complications.
+71
View File
@@ -0,0 +1,71 @@
=========
ElectrumX
=========
.. image:: https://github.com/spesmilo/electrumx/actions/workflows/ci.yml/badge.svg?branch=master
:target: https://github.com/spesmilo/electrumx/actions/workflows/ci.yml
This project is a fork of `kyuupichan/electrumx <https://github.com/kyuupichan/electrumx>`_.
The original author dropped support for Bitcoin, which we intend to keep.
ElectrumX allows users to run their own Electrum server. It connects to your
full node and indexes the blockchain, allowing efficient querying of history of
arbitrary addresses. The server can be exposed publicly, and joined to the public network
of servers via peer discovery. As of May 2020, a significant chunk of the public
Electrum server network runs ElectrumX.
The current version is |release|.
Source Code
===========
The project is hosted on `GitHub
<https://github.com/spesmilo/electrumx/>`_. and uses `GitHub Actions
<https://github.com/spesmilo/electrumx/actions>`_ for Continuous
Integration.
Please submit an issue on the `bug tracker
<https://github.com/spesmilo/electrumx/issues>`_ if you have found a
bug or have a suggestion to improve the server.
Authors and License
===================
Neil Booth wrote the vast majority of the code; see :ref:`Authors`.
Python version at least 3.10 is required.
The code is released under the `MIT Licence
<https://github.com/spesmilo/electrumx/LICENCE>`_.
Getting Started
===============
See :ref:`HOWTO`.
There is also an `installer`_ available that simplifies the
installation on various Linux-based distributions, and a `Dockerfile`_
available.
.. _installer: https://github.com/bauerj/electrumx-installer
.. _Dockerfile: https://github.com/lukechilds/docker-electrumx
Documentation
=============
.. toctree::
features
changelog
HOWTO
environment
protocol
peer_discovery
rpc-interface
architecture
authors
Indices and tables
==================
* :ref:`genindex`
* :ref:`search`
+36
View File
@@ -0,0 +1,36 @@
@ECHO OFF
pushd %~dp0
REM Command file for Sphinx documentation
if "%SPHINXBUILD%" == "" (
set SPHINXBUILD=sphinx-build
)
set SOURCEDIR=.
set BUILDDIR=_build
set SPHINXPROJ=ElectrumX
if "%1" == "" goto help
%SPHINXBUILD% >NUL 2>NUL
if errorlevel 9009 (
echo.
echo.The 'sphinx-build' command was not found. Make sure you have Sphinx
echo.installed, then set the SPHINXBUILD environment variable to point
echo.to the full path of the 'sphinx-build' executable. Alternatively you
echo.may add the Sphinx directory to PATH.
echo.
echo.If you don't have Sphinx installed, grab it from
echo.http://sphinx-doc.org/
exit /b 1
)
%SPHINXBUILD% -M %1 %SOURCEDIR% %BUILDDIR% %SPHINXOPTS%
goto end
:help
%SPHINXBUILD% -M help %SOURCEDIR% %BUILDDIR% %SPHINXOPTS%
:end
popd
+154
View File
@@ -0,0 +1,154 @@
.. _Peer Discovery:
Peer Discovery
==============
This was implemented in ElectrumX as of version 0.11.0. Support for
IRC peer discovery was removed in ElectrumX version 1.2.1.
The :dfn:`peer database` is an in-memory store of peers with at least
the following information about a peer, required for a response to the
:func:`server.peers.subscribe` RPC call:
* host name
* ip address
* TCP and SSL port numbers
* protocol version
* pruning limit, if any
Hard-coded Peers
----------------
A list of hard-coded, well-known peers seeds the peer discovery
process. Ideally it should have at least 4 servers that have shown
commitment to reliable service.
In ElectrumX this is a per-coin property in `lib/coins.py
<https://github.com/spesmilo/electrumx/blob/master/electrumx/lib/coins.py>`_.
server.peers.subscribe
----------------------
:func:`server.peers.subscribe` is used by Electrum clients to get a
list of peer servers, in preference to a hard-coded list of peer
servers in the client, which it will fall back to if necessary.
The server should craft its response in a way that reduces the
effectiveness of server sybil attacks and peer spamming.
The response should only include peers it has successfully connected
to recently. Only reporting recent good peers ensures that those that
have gone offline will be forgotten quickly and not be passed around
for long.
In ElectrumX, "recently" is taken to be the last 24 hours. Only one
peer from each IPv4/16 netmask is returned, and the number of onion
peers is limited.
Maintaining the Peer Database
-----------------------------
In order to keep its peer database up-to-date and fresh, after some
time has passed since the last successful connection to a peer, an
Electrum server should make another attempt to connect, choosing
either the TCP or SSL port.
On connecting it should issue :func:`server.peers.subscribe`,
:func:`blockchain.headers.subscribe`, and :func:`server.features` RPC
calls to collect information about the server and its peers. If the
peer seems to not know of you, you can issue a :func:`server.add_peer`
call to advertise yourself. Once this is done and replies received,
terminate the connection.
The peer database should view information obtained from an outgoing
connection as authoritative, and prefer it to information obtained
from any other source.
On connecting, a server should confirm the peer is serving the same
network, ideally via the genesis block hash of the
:func:`server.features` RPC call below. Also the height reported by
the peer should be within a small number of the expected value. If a
peer is on the wrong network it should never be advertised to clients
or other peers. Such invalid peers should perhaps be remembered for a
short time to prevent redundant revalidation if other peers persist in
advertising them, and later forgotten.
If a connection attempt fails, subsequent reconnection attempts should
follow some kind of exponential backoff.
If a long period of time has elapsed since the last successful
connection attempt, the peer entry should be removed from the
database. This ensures that all peers that have gone offline will
eventually be forgotten by the network entirely.
ElectrumX will connect to the SSL port if both ports are available.
If that fails it will fall back to the TCP port. It tries to
reconnect to a good peer at least once every 24 hours, and a failing
after 5 minutes but with exponential backoff. It forgets a peer
entirely if a few days have passed since a successful connection.
ElectrumX attempts to connect to onion peers through a Tor proxy that
can be configured or that it will try to autodetect.
server.features
---------------
:func:`server.features` is a fairly new RPC call that a server can use
to advertise what services and features it offers. It is intended for
use by Electrum clients as well as other peers. Peers will use it to
gather peer information from the peer itself.
The call takes no arguments and returns a dictionary keyed by feature
name whose value gives details about the feature where appropriate.
If a key is missing the feature is presumed not to be offered.
server.add_peer
---------------
:func:`server.add_peer` is intended for a new server to get itself in
the connected set.
A server receiving a :func:`server.add_peer` call should not replace
existing information about the host(s) given, but instead schedule a
separate connection to verify the information for itself.
To prevent abuse a server may do nothing with second and subsequent
calls to this method from a single connection.
The result should be True if accepted and False otherwise.
Notes for Implementors
----------------------
* it is very important to only accept peers that appear to be on the
same network. At a minimum the genesis hash should be compared (if
the peer supports :func:`server.features`), and also that the peer's
reported height is within a few blocks of your own server's height.
* care should be taken with the :func:`server.add_peer` call.
Consider only accepting it once per connection. Clearnet peer
requests should check the peer resolves to the requesting IP
address, to prevent attackers from being able to trigger arbitrary
outgoing connections from your server. This doesn't work for onion
peers so they should be rate-limited.
* it should be possible for a peer to change their port assignments -
presumably connecting to the old ports to perform checks will not
work.
* peer host names should be checked for validity before accepting
them; and `localhost` should probably be rejected. If it is an IP
address it should be a normal public one (not private, multicast or
unspecified).
* you should limit the number of new peers accepted from any single
source to at most a handful, to limit the effectiveness of malicious
peers wanting to trigger arbitrary outgoing connections or fill your
peer tables with junk data.
* in the response to :func:`server.peers.subscribe` calls, consider
limiting the number of peers on similar IP subnets to protect
against sybil attacks, and in the case of onion servers the total
returned.
* you should not advertise a peer's IP address if it also advertises a
hostname (avoiding duplicates).
+7
View File
@@ -0,0 +1,7 @@
Electrum Protocol
=================
See rendered `protocol docs here <https://electrum-protocol.readthedocs.io/>`_,
and `git repository here <https://github.com/spesmilo/electrum-protocol>`_.
+33
View File
@@ -0,0 +1,33 @@
# Release process
### 1. Add changelog
### 2. Update version number
- `docs/conf.py`
- `electrumx/__init__.py`
### 3. Tag
```
$ git tag -s "$VERSION" -m "$VERSION"
$ git push "$REMOTE_ORIGIN" tag "$VERSION"
```
### 4. Build sdist
see [`contrib/sdist/`](contrib/sdist)
```
$ ELECBUILD_COMMIT=HEAD ELECBUILD_NOCACHE=1 ./contrib/sdist/build.sh
```
### 5. Upload to PyPI
```
// $ python3 -m twine upload --repository testpypi dist/$DISTNAME
$ python3 -m twine upload dist/$DISTNAME
```
This will prompt for a username and password. For the username, use `__token__`.
For the password, use API token from https://pypi.org/manage/account/ , including the pypi- prefix.
+1
View File
@@ -0,0 +1 @@
Sphinx
+280
View File
@@ -0,0 +1,280 @@
RPC Interface
=============
You can query the status of a running server, and affect its behaviour
by sending **JSON RPC** commands to the LocalRPC port it is listening
on. This is best done using the :file:`electrumx_rpc` script
provided.
The general form of invocation is::
electrumx_rpc [-p PORT] <command> [arg1 [arg2...]]
The port to send the commands to can be specified on the command line,
otherwise the environment variable :envvar:`RPC_PORT` is used, and if
that is not set then **8000** is assumed.
The following commands are available:
add_peer
--------
Add a peer to the peers list. ElectrumX will schedule an immediate
connection attempt. This command takes a single argument: the peer's
"real name" as it used to advertise itself on IRC::
$ electrumx_rpc add_peer "ecdsa.net v1.0 s110 t"
"peer 'ecdsa.net v1.0 s110 t' added"
daemon_url
----------
This command takes an optional argument that is interpreted
identically to the :envvar:`DAEMON_URL` environment variable. If
omitted, the default argument value is the process's existing
:envvar:`DAEMON_URL` environment variable.
This command replaces the daemon's URL at run-time, and also
forcefully rotates to the first URL in the list.
For example, in case ElectrumX has previously failed over to a
secondary daemon and you want to revert to the primary having resolved
the connectivity issue, invoking this command without an argument will
have that effect.
disconnect
----------
Disconnect the given session IDs or group names.
Session IDs can be obtained in the logs or with the `sessions`_ RPC command. Group
names can be obtained with the `groups`_ RPC command.
The special string :const:`all` disconnects all sessions.
Example::
$ electrumx_rpc disconnect 209.59.102 34 2
[
"disconnecting session 34",
"disconnecting group 209.59.102"
"unknown: 2",
]
getinfo
-------
Return a summary of server state. This command takes no arguments.
A typical result is as follows (with annotated comments)::
$ electrumx_rpc getinfo
{
"coin": "Bitcoin",
"daemon": "127.0.0.1:9334/",
"daemon height": 572154, # The daemon's height when last queried
"db height": 572154, # The height to which the DB is flushed
"groups": 586, # The number of session groups
"history cache": "185,014 lookups 9,756 hits 1,000 entries",
"merkle cache": "280 lookups 54 hits 213 entries",
"peers": { # Peer information
"bad": 1,
"good": 51,
"never": 2,
"stale": 0,
"total": 54
},
"pid": 11804, # Process ID
"request counts": { # Count of RPC requests by method name
"blockchain.block.header": 245,
"blockchain.block.headers": 70,
"blockchain.estimatefee": 12776,
"blockchain.headers.subscribe": 2825,
"blockchain.relayfee": 740,
"blockchain.scripthash.get_history": 196,
"blockchain.scripthash.subscribe": 184626,
"blockchain.transaction.broadcast": 19,
"blockchain.transaction.get": 213,
"blockchain.transaction.get_merkle": 289,
"getinfo": 3,
"groups": 1,
"mempool.get_fee_histogram": 3194,
"mempool.get_info": 121,
"server.add_peer": 9,
"server.banner": 740,
"server.donation_address": 754,
"server.features": 50,
"server.peers.subscribe": 792,
"server.ping": 6412,
"server.version": 2866
},
"request total": 216820, # Total requests served
"sessions": { # Live session stats
"count": 670,
"count with subs": 45,
"errors": 0,
"logged": 0,
"paused": 0,
"pending requests": 79, # Number of requests currently being processed
"subs": 36292 # Total subscriptions
},
"tx hashes cache": "289 lookups 38 hits 213 entries",
"txs sent": 19, # Transactions broadcast
"uptime": "01h 39m 04s",
"version": "ElectrumX 1.10.1"
}
Each ill-formed request, or one that does not follow the Electrum
protocol, increments the error count of the session that sent it.
:ref:`logging <session logging>` of sessions can be enabled by RPC.
For more information on peers see :ref:`here <peers>`.
Clients that are slow to consume data sent to them are :dfn:`paused` until their socket
buffer drains sufficiently, at which point processing of requests resumes.
Apart from very short intervals, typically after a new block or when a client has just
connected, the number of unprocessed requests should be low, say 250 or fewer. If it is
over 1,000 the server is overloaded.
Sessions are put into groups, primarily as an anti-DoS measure. Each session goes into
a group based on its IP subnet (e.g. /24 for IPv4). Each member of a group incurs a fraction
of the costs of the other group members. This appears in the `sessions_` list under the
column XCost.
groups
------
Return a list of all current session groups. Takes no arguments.
The output is quite similar to the `sessions`_ command.
log
---
Toggle logging of the given session IDs or group names. All incoming requests for a
logged session are written to the server log. The arguments are case-insensitive.
When a group is specified, logging is toggled for its current members only; there is no
effect on future group members.
Session IDs can be obtained in the logs or with the `sessions`_ RPC command. Group
names can be obtained with the `groups`_ RPC command.
The special string :const:`all` turns on logging of all current and future sessions,
:const:`none` turns off logging of all current and future sessions, and :const:`new`
toggles logging of future sessions.
Example::
$ electrumx_rpc log new 6 t0 z
[
"logging new sessions",
"logging session 6",
"logging session 3",
"logging session 57",
"logging session 12"
"unknown: z",
]
In the above command sessions 3, 12 and 57 were in group `t0` (in fact, session 6 was
too).
.. _peers:
peers
-----
Return a list of peer Electrum servers serving the same coin network.
This command takes no arguments.
Peer data is obtained via a peer discovery protocol documented
:ref:`here <Peer Discovery>`::
$ electrumx_rpc peers
Host Status TCP SSL Server Min Max Pruning Last Good Last Try Tries Source IP Address
bch.tedy.pw good 50001 50002 ElectrumX 1.2.1 0.9 1.2 07h 29m 23s 07h 30m 40s 0 peer 185.215.224.26
shsmithgoggryfbx.onion good 60001 60002 ElectrumX 1.2.1 0.9 1.2 07h 30m 34s 07h 30m 38s 0 peer
bccarihace4jdcnt.onion good 52001 52002 ElectrumX 1.2.1 0.9 1.2 07h 30m 34s 07h 30m 39s 0 peer
[...]
electroncash.checksum0.com good 50001 50002 ElectrumX 1.2.1 0.9 1.1 07h 30m 40s 07h 30m 41s 0 peer 149.56.198.233
.. _query:
query
-----
Run a query of the UTXO and history databases against one or more
addresses, hex scripts or ASCII names (for coins that have an index
on names like Namecoin). `--limit <N>` or `-l <N>` limits the output
for each kind to that many entries. History is printed in blockchain
order; UTXOs in an arbitrary order.
For example::
$ electrumx_rpc query --limit 5 76a91462e907b15cbf27d5425399ebf6f0fb50ebb88f1888ac
Script: 76a91462e907b15cbf27d5425399ebf6f0fb50ebb88f1888ac
History #1: height 123,723 tx_hash 3387418aaddb4927209c5032f515aa442a6587d6e54677f08a03b8fa7789e688
History #2: height 127,280 tx_hash 4574958d135e66a53abf9c61950aba340e9e140be50efeea9456aa9f92bf40b5
History #3: height 127,909 tx_hash 8b960c87f9f1a6e6910e214fcf5f9c69b60319ba58a39c61f299548412f5a1c6
History #4: height 127,943 tx_hash 8f6b63012753005236b1b76e4884e4dee7415e05ab96604d353001662cde6b53
History #5: height 127,943 tx_hash 60ff2dfdf67917040139903a0141f7525a7d152365b371b35fd1cf83f1d7f704
UTXO #1: tx_hash 9aa497bf000b20f5ec5dc512bb6c1b60b68fc584d38b292b434e839ea8807bf0 tx_pos 0 height 254,148 value 5,500
UTXO #2: tx_hash 1c998142a5a5aae6f8c1eab245351413fe8d4032a3f14345f9943a0d0bc90ec0 tx_pos 0 height 254,161 value 5,500
UTXO #3: tx_hash 53345491b4829140be53f30079c6e4556a18545343b122900ebbfa158f9ca97a tx_pos 0 height 254,163 value 5,500
UTXO #4: tx_hash c71ad947ac46af217da3cd5521113cbd03e36ddada2b4452afe6c15f944d2529 tx_pos 0 height 372,916 value 1,000
UTXO #5: tx_hash c944a6acac054275a5e294e746d9ce79f6dcae91f3b4f5a84561aee6404a55b3 tx_pos 0 height 254,148 value 5,500
Balance: 17.8983303 BCH
reorg
-----
Force a block chain reorganisation, primarily for debugging purposes.
This command takes an optional argument - the number of blocks to
reorg - which defaults to 3.
That number of blocks will be backed up - using undo information
stored in ElectrumX's database - and then ElectrumX will move forwards
on the daemon's main chain to its current height.
.. _sessions:
sessions
--------
Return a list of all current sessions. Takes no arguments::
ID Flags Client Proto Cost XCost Reqs Txs Subs Recv Recv KB Sent Sent KB Time Peer
1 S6 1.1.1 1.4 0 16 0 0 0 3 0 3 0 05m42s 165.255.191.213:22349
2 S6 all_seeing_eye 1.4 0 16 0 0 0 2 0 2 0 05m40s 67.170.52.226:24995
4 S6 3.3.2 1.4 0 16 0 0 34 45 5 45 3 05m40s 185.220.100.252:40463
3 S6 1.1.2 1.4 0 16 0 0 0 3 0 3 0 05m40s 89.17.142.28:59241
The columns show information by session: the session ID, flags (see below), how the client
identifies itself - typically the Electrum client version, the protocol version
negotiated, the session cost, the additional session cost accrued from its groups, the
number of unprocessed requests, the number of transactions sent, the number of address
subscriptions, the number of requests received and their total size, the number of
messages sent and their size, how long the client has been connected, and the client's IP
address (if anonymous logging is disabled).
The flags are:
* ``S`` an SSL connection
* ``T`` a TCP connection
* ``R`` a local RPC connection
* ``L`` a logged session
* ``C`` a connection that is being closed
* the non-negative number is the connection "cost", with lower
numbers having higher priority. RPC connections have cost ``0``,
normal connections have cost at least ``1``.
stop
----
Flush all cached data to disk and shut down the server cleanly, as if
sending the `KILL` signal. Be patient - during initial sync flushing
all cached data to disk can take several minutes. This command takes
no arguments.
.. _session logging: