Bitcoin full node and query server

Configuration

Configuring bs, the libbitcoin server: command line options, the running console and the configuration file.

1. Quick start#

The executable is bs (bs.exe on Windows), and the examples run the same on Linux, macOS and Windows. bs runs with built-in mainnet defaults. No configuration file is read unless --config is given.

Run with defaults. The store is created in a bitcoin directory under the current directory if it does not exist.

$ bs

With a configuration file:

$ bs --config bs.cfg

2. Command line#

All options, grouped by purpose:

Group Option Purpose
Configuration -c, --config <path> Read settings from a configuration file
Prompts -a, --accept Accept startup prompts without interaction
Information -h, --help Display command line options
-s, --settings Display all configuration settings (with any --config applied)
-v, --version Display version information
-w, --hardware Display hardware compatibility (CPU features, GPU)
Store -n, --newstore Create a new store in the configured directory
-b, --backup Snapshot the store (also available live from the console)
-r, --restore Restore from the most recent snapshot
Service -d, --daemon <value> Install (true) or uninstall (false) as a daemon/service
-u, --user <credential> Daemon logon credential (defaults to the system account)
Store scans -i, --information Display store information
-f, --flags Display all fork flag transitions
-k, --buckets Display hashmap bucket fill
-l, --collisions Display hashmap collision statistics (time consuming)

Display command line help:

$ bs -h

Usage: bs [-abfhiklnrsvw] [--config value] [--daemon value] [--user
value]

Info: Runs a full node bitcoin server.

Options (named):

-a [--accept]        Accept startup prompts without interaction.
-b [--backup]        Backup to a snapshot (can also do live).
-c [--config]        Specify path to a configuration settings file.
-d [--daemon]        Install ('true') or uninstall ('false') as a daemon.
-f [--flags]         Scan and display all flag transitions.
-h [--help]          Display command line options.
-i [--information]   Scan and display store information.
-k [--buckets]       Scan and display hashmap bucket fill.
-l [--collisions]    Scan and show hashmap collision stats (may SIGKILL).
-n [--newstore]      Create new store in configured directory.
-r [--restore]       Restore from most recent snapshot.
-s [--settings]      Display all configuration settings.
-u [--user]          Daemon logon credential, defaults to system account.
-v [--version]       Display version information.
-w [--hardware]      Display hardware compatibility.

Display version information:

$ bs --version
Version Information...
boost................ 1.91.0
secp256k1............ internal
openssl (tls)........ internal tls 1.3
libbitcoin-system.... 4.0.10255 63f7b348
libbitcoin-database.. 4.0.4703 10e63cfe
libbitcoin-network... 4.0.7306 1feceb44
libbitcoin-node...... 4.0.4262 74e460da
libbitcoin-server.... 4.0.3334 996bec9f
compiled schema...... 4.0.16

Display hardware compatibility:

$ bs --hardware
Hardware configuration (x64)...
aesni....... platform:1 compiled:1.
vaes........ platform:1 compiled:1.
shani....... platform:1 compiled:1.
sha512...... platform:0 compiled:0.
sse41....... platform:1 compiled:1.
avx2........ platform:1 compiled:1.
avx512...... platform:1 compiled:1.
avxifma..... platform:0 compiled:0.
avx512ifma.. platform:1 compiled:1.
cuda........ platform:1 compiled:1.
cuda ecc.... platform:1 enabled:0.

platform shows whether the machine supports a feature and compiled whether this build uses it. A build does not have to be compiled for the hardware it runs on, though in many cases doing so significantly improves performance. Do not compile options that the hardware does not support, as the build will not run. The largest gains in initial block download come from shani (or crypto on Arm), and otherwise from avx.

CUDA (GPU) support is compiled by default, except on macOS. cuda ecc reports whether the GPU's error correcting code (ECC) memory is enabled, which is set in your own environment. ECC is recommended but not required when using the GPU. When enabled it provides the same memory reliability as the main processor.


3. The running console#

Commands typed into a running bs console (press <enter> after the character):

Key Action
m Menu of options and toggles
c Close the node (graceful shutdown, same as <ctrl> c)
b Backup the store (live snapshot)
h Hold network communication
g Go network communication
i Info about the store
e Errors in the store
w Work distribution
z Clear a disk-full condition (not required, automatically clears with sufficient space)

Log on/off typed into a running bs console (press <enter> after the character):

Key Digit Level
a .0 Application
n .1 News: startup, progress and notable events
s .2 Sessions: connect and accept
p .3 Protocols
x .4 Proxies: sockets and channels
r .5 Remote peer behavior
f .6 Own node fault
q .7 Quitting: connections and other components stopping
o .8 Objects: lifetime tracking (debug builds only)
v .9 Verbose detail

Each log entry shows its level as a digit after the timestamp, for example .6 on a fault.


4. The configuration file#

Paths take the platform's form, for example /data/bitcoin or D:\bitcoin. A relative path is relative to the working directory, not to the configuration file.

Integer values may use commas as thousands separators, for example node.maximum_height = 900,000.

Section map:

Area Sections
Logging [log]
Store [database], [table.*]
Chain [bitcoin], [forks], [wallet]
Node [node]
P2P network [network], [peer], [outbound], [inbound], [manual]
Client-server [admin], [native], [bitcoind], [bitcoind_zmq], [btcd], [electrum], [sparrow], [esplora]

Simple example config file:

[database]
path = bitcoin

[log]
path = log

The same settings can be written without section headers, by prefixing each name with its section:

database.path = bitcoin
log.path = log

5. Common setups#

5.1 Sync to a height and stop#

[node]
maximum_height = 900,000

bs will not download a block above that height.

5.2 Milestone sync#

A milestone is a block you have previously validated and therefore know to be valid, which implies that all preceding blocks are valid. A milestone sync verifies the identity of the milestone block and all of its ancestors, and validates the blocks above it. The default milestone is block 950,000. The milestone and pruning are fixed when the store is created (§10).

[bitcoin]
milestone = 000000000000000000010b93c9ea1c29fea277383f0f7d1f26de8b5802e885ff:950000

Pruning reduces download and store size under a milestone sync. With node.limited_blocks, blocks under the milestone are downloaded and stored without their input scripts and witnesses, and the node serves only blocks above the milestone to peers.

[node]
limited_blocks = true

5.3 Full validation#

To validate every block, set the milestone to the genesis block when creating the store (§10):

[bitcoin]
milestone = 000000000019d6689c085ae165831e934ff763ae46a2a6c172b3f1b60a8ce26f:0

5.4 Checkpoints#

Checkpoints are consensus checks, and removing them is a hard fork. However, to do so set a checkpoint to the genesis block:

[bitcoin]
checkpoint = 000000000019d6689c085ae165831e934ff763ae46a2a6c172b3f1b60a8ce26f:0

5.5 Admin site#

bs serves its own administrative site, which also utilizes its native REST interface. Here both are limited to the local machine:

[admin]
bind = 127.0.0.1:8080
bind = [::1]:8080
connections = 10

[native]
bind = 127.0.0.1:8180
bind = [::1]:8180
connections = 10

To view the admin site open http://localhost:8080 in a browser. Its pages are admin REST queries rendered as HTML, the default for a browser request. The same paths return data when JSON is requested, with format=json or an Accept: application/json header.

To serve a custom admin site from a directory instead of the embedded site, set admin.path. A request for / returns admin.default (index.html).

The admin interface is libbitcoin's own, and provides:

5.6 Block explorer#

The native REST interface serves the block explorer. Here it is limited to the local machine:

[native]
bind = 127.0.0.1:8180
bind = [::1]:8180
connections = 10

To view the block explorer open http://localhost:8180 in a browser.

The explorer is the native REST interface rendered as HTML, the default for a browser request. The same paths return each result in any of four formats, chosen with format= or the Accept header:

Format Media type Result
html text/html The explorer page
json application/json JSON
text text/plain Hex encoded bytes
data application/octet-stream Raw bytes

For example, the genesis block header as JSON:

http://localhost:8180/v1/block/height/0/header?format=json

returns:

{
    "hash": "000000000019d6689c085ae165831e934ff763ae46a2a6c172b3f1b60a8ce26f",
    "version": 1,
    "previous": "0000000000000000000000000000000000000000000000000000000000000000",
    "merkle_root": "4a5e1e4baab89f3a32518a88c31bc87f618f76673e2cc77ab2127b7afdeda33b",
    "timestamp": 1231006505,
    "bits": 486604799,
    "nonce": 2083236893
}

The full native REST map, under http://localhost:8180. In block paths, {block} is hash/{block hash} or height/{height}. The method name is the one used in credential method lists (§7.3).

Path Method Result
/v1/configuration configuration Server configuration
/v1/top top Top confirmed height
/v1/top/subscribe top_subscribe Top height notifications (websocket)
/v1/block/{block} block Block
/v1/block/{block}/header block_header Block header
/v1/block/{block}/header/context block_header_context Header validation context
/v1/block/{block}/details block_details Block details
/v1/block/{block}/txs block_txs All transactions of the block
/v1/block/{block}/tx/{position} block_tx Transaction at a position in the block
/v1/block/{block}/filter/{type} block_filter Client filter
/v1/block/{block}/filter/{type}/hash block_filter_hash Client filter hash
/v1/block/{block}/filter/{type}/header block_filter_header Client filter header
/v1/block/subscribe block_subscribe Block notifications (websocket)
/v1/tx/{tx hash} tx Transaction
/v1/tx/{tx hash}/header tx_header Header of the confirming block
/v1/tx/{tx hash}/details tx_details Transaction details
/v1/tx/subscribe tx_subscribe Transaction notifications (websocket)
/v1/input/{tx hash} inputs All inputs of the transaction
/v1/input/{tx hash}/{index} input Input
/v1/input/{tx hash}/{index}/script input_script Input script
/v1/input/{tx hash}/{index}/witness input_witness Input witness
/v1/output/{tx hash} outputs All outputs of the transaction
/v1/output/{tx hash}/{index} output Output
/v1/output/{tx hash}/{index}/script output_script Output script
/v1/output/{tx hash}/{index}/spender output_spender Confirmed spender of the output
/v1/output/{tx hash}/{index}/spenders output_spenders All spenders of the output
/v1/output/{tx hash}/{index}/subscribe output_subscribe Spend notifications (websocket)
/v1/address/{script hash} address All history of an output script
/v1/address/{script hash}/confirmed address_confirmed Confirmed history
/v1/address/{script hash}/unconfirmed address_unconfirmed Unconfirmed history
/v1/address/{script hash}/balance address_balance Confirmed balance
/v1/address/{script hash}/subscribe address_subscribe History notifications (websocket)

Query options, besides format:

Option Applies to Purpose
witness=false block, transaction and input paths Omit witness data
turbo=false address paths Run the query on one thread instead of all (see database.turbo)
stop=true subscribe paths End the subscription

To serve a custom block explorer from a directory instead of the embedded site, set native.path. A request for / returns native.default (index.html).

The native interface is libbitcoin's own, and provides:

5.7 Electrum server#

Electrum on its assigned ports (§6), clear and secure (§7.2):

[electrum]
bind = 0.0.0.0:8580
safe = 0.0.0.0:8543
connections = 100
cert_path = server.pem
key_path = server.key

Beyond the standard Electrum transports (TCP and TLS), bs provides:

5.8 Bitcoind RPC#

The RPC interface listens on its default port, 8280, here limited to the local machine.

[bitcoind]
bind = 127.0.0.1:8280
bind = [::1]:8280
connections = 10
credential = user:password

A credential may end with a list of the methods it permits (§7.3), here three RPC methods and the matching REST block request:

[bitcoind]
credential = reader:password:getblockcount,getblockhash,getblock,block

Beyond the standard bitcoind interfaces (JSON-RPC over HTTP, and REST), bs provides:

5.9 BTCD RPC#

The btcd RPC interface listens on its default port, 8480, here limited to the local machine:

[btcd]
bind = 127.0.0.1:8480
bind = [::1]:8480
connections = 10
credential = user:password

The BTCD interface is the Bitcoind RPC interface (§5.8) with btcd's methods added. Unlike btcd's own implementation, the methods it inherits behave exactly as they do in [bitcoind].

A websocket or raw TCP client may authenticate after connecting, with btcd's authenticate method. A failed authenticate closes the connection. A request for a method the credential does not permit returns an invalid parameters error.

Beyond the standard btcd transports (HTTP and websocket, with TLS), bs provides:

5.10 ZMQ notifications#

ZMQ publishes on its default port, 8380, here limited to the local machine.

[bitcoind_zmq]
bind = 127.0.0.1:8380
bind = [::1]:8380
connections = 10

Beyond the standard bitcoind notifications, bs provides CurveZMQ on its safe addresses (§7.2): encrypted notifications, optionally only to the client keys listed in bitcoind_zmq.cert.

5.11 Esplora REST#

The Esplora REST interface, on its assigned port:

[esplora]
bind = 0.0.0.0:8780
connections = 100

To serve existing Esplora clients, bind it to the port they expect instead (§6). esplora.maximum_history limits the entries returned for one address.

Beyond the standard Esplora REST interface, bs provides:

5.12 Client filters (BIP157/158)#

[node]
provide_filters = true

[table.filter_bk]
buckets = 950001

[table.filter_tx]
buckets = 950001

Client filters are enabled when the store is created (§10). Any count above 0 on both tables enables the client filters index. The value given initializes the index to entries for that many blocks, but the index grows as required.

5.13 Disable the address index#

The address index is disabled when the store is created (§10):

[table.outs]
buckets = 0

5.14 Silent payments#

Silent payments are indexed from node.silent_start_height, and never below taproot activation, so 0 indexes from there. The start height is fixed when the store is created (§10). The index is served to Sparrow by the [sparrow] service, the Electrum protocol with silent payment extensions:

[node]
silent_start_height = 0

[sparrow]
bind = 0.0.0.0:8680
safe = 0.0.0.0:8643
connections = 100
cert_path = server.pem
key_path = server.key

The Sparrow interface is the Electrum interface with silent payment and block statistics methods added, and provides the same transports and security as [electrum] (§5.7).

5.15 Tor#

Outbound through Tor's SOCKS5 proxy, inbound through a Tor hidden service (HiddenServiceDir and HiddenServicePort in torrc) pointing at the node's listening port, and onion address gossip:

[outbound]
socks = 127.0.0.1:9050
seed = <first seed onion address>.onion:8333
seed = <second seed onion address>.onion:8333

[inbound]
self = <hidden service onion address>.onion:8333

[peer]
gossip_tor = true

inbound.self advertises the hidden service address to peers, so they can connect to the node over Tor. Seeds are connected through the proxy, so the default seeds work where Tor can reach them. An onion-only node lists onion seeds.

outbound.socks proxies the outbound session and its seeds. Manual peers (5.17) use their own manual.socks. Each takes an optional username and password.

5.16 I2P#

Outbound through the SOCKS5 proxy pointed at an I2P router's SOCKS port, inbound through the router's SAM bridge, and I2P address gossip. The destination key file is created if it does not exist, and the I2P address derived from it is advertised to peers, so inbound.self is not needed:

[outbound]
socks = 127.0.0.1:4447
seed = <first seed destination>.b32.i2p
seed = <second seed destination>.b32.i2p

[inbound]
sam = 127.0.0.1:7656
key_path = i2p.key

[peer]
gossip_i2p = true

Seeds are connected through the proxy, which reaches only I2P destinations, so an I2P node lists I2P seeds. I2P has no ports, so none is given.

outbound.socks proxies the outbound session and its seeds. Manual peers (5.17) use their own manual.socks. Each takes an optional username and password.

5.17 Fixed peers#

[manual]
peer = 192.168.0.10:8333
peer = 192.168.0.11:8333

[outbound]
connections = 0

[inbound]
connections = 0

Manual peers are automatically reconnected after a delay (network.retry_timeout_seconds) when they drop. outbound.connections = 0 disables the outbound session, which otherwise connects to peers from the address pool, and inbound.connections = 0 disables the inbound session, which otherwise accepts peers that connect to the node. The node then exchanges only with the peers listed.

5.18 Peer services and policy#

What the node provides to and requires of its peers, and its transaction policy:

[node]
limited_blocks  = true      # pruned blocks
provide_blocks  = true      # provides blocks
require_blocks  = true      # requires blocks
provide_witness = true      # provides witnesses (bip144)
require_witness = true      # requires witnesses (bip144)
provide_filters = false     # serves client filters (bip157)
provide_privacy = true      # opportunistic encryption (bip324)
delay_inbound = true
fee_estimate_horizon = 0
minimum_fee_rate = 0.000001

Which peer messages the node sends and accepts:

[peer]
enable_relay = true         # in/out transaction announcements
enable_alert = false        # send/log alert messages (no send option)
enable_reject = false       # send/log reject messages
enable_compact = true       # in/out compact block announcements
enable_address = true       # in/out address messages (false disables address v1 and v2)
enable_address_v2 = true    # in/out address v2 messages (drops down to v1 if gossip is IP only)
enable_witness_tx = true    # in/out wtxid for tx announcements
enable_memory_pool = true   # respond to mempool message with full pool
enable_not_found = true     # send not_found messages (vs. dropping peer for requesting what we don't have)

5.19 Outbound bindings#

By default the operating system chooses the network adapter of each outbound connection from its routing table, and with several adapters it normally uses only one. Binding outbound connections to adapter addresses restricts them to those adapters, and spreads them across the adapters to combine their bandwidth:

[outbound]
bind = 192.168.0.20
bind = 192.168.0.21
connections = 100

Outbound bindings do not affect inbound connections, which are accepted on the inbound.bind addresses. Inbound defaults to 0.0.0.0:8333, and accepts connections on every IPv4 adapter. To accept peers only on the same adapters, bind inbound to the same addresses:

[inbound]
bind = 192.168.0.20:8333
bind = 192.168.0.21:8333

Whether a bound connection actually leaves through its adapter depends on the operating system:

For two Linux adapters on one subnet, eth0 at 192.168.0.20 and eth1 at 192.168.0.21, with gateway 192.168.0.1:

$ sudo ip route add default via 192.168.0.1 dev eth0 table 100
$ sudo ip route add default via 192.168.0.1 dev eth1 table 200
$ sudo ip rule add from 192.168.0.20 lookup 100
$ sudo ip rule add from 192.168.0.21 lookup 200
$ sudo sysctl -w net.ipv4.conf.all.arp_filter=1 net.ipv4.conf.all.arp_ignore=1 net.ipv4.conf.all.arp_announce=2

All five lines are required. The tables and rules send each connection out through its bound adapter. The last line makes each adapter answer only for its own address, so that replies also arrive on that adapter. Adapters on separate networks need only the tables and rules, each with its own gateway. Confirm the route of a bound address with:

$ ip route get 1.1.1.1 from 192.168.0.21

These commands do not persist across a reboot. Add the same tables and rules to the distribution's network configuration (netplan, systemd-networkd or NetworkManager).

Adapters on one subnet share its gateway, so their combined bandwidth is also limited by the gateway's uplink.


6. Ports#

Every service has an assigned port on each chain, clear and secure. A service listens only on the addresses given by its bind and safe settings (§7.1), so the examples on this page give them explicitly.

The P2P network uses its convention on each chain, so peers find the node without configuration. Each libbitcoin service uses its own block, 8N80 for clear connections and 8N43 for secure (TLS), so that bs can run beside bitcoind, Electrum servers and Esplora on one machine without conflict.

Service Section Clear Secure
P2P network [inbound] 8333 8333
Admin web [admin] 8080 8043
Native web and REST [native] 8180 8143
Bitcoind RPC and REST [bitcoind] 8280 8243
Bitcoind ZMQ [bitcoind_zmq] 8380 8343
BTCD RPC [btcd] 8480 8443
Electrum [electrum] 8580 8543
Sparrow [sparrow] 8680 8643
Esplora REST [esplora] 8780 8743

P2P has no separate secure port. BIP324 encryption is negotiated on the same port, and offered when node.provide_privacy is set. ZMQ's secure port uses CurveZMQ.

On the test chains the service ports move by a fixed offset, and the P2P port follows its network's convention:

Chain Service offset Services P2P
mainnet 0 8043–8780 8333
testnet3 +10000 18043–18780 18333
regtest +20000 28043–28780 18444
signet +30000 38043–38780 38333
testnet4 +40000 48043–48780 48333

To use a service as a drop-in replacement, bind it to the port its clients expect instead:

[bitcoind]
bind = 127.0.0.1:8332
bind = [::1]:8332

[btcd]
safe = 127.0.0.1:8334
safe = [::1]:8334

[electrum]
bind = 0.0.0.0:50001
safe = 0.0.0.0:50002

[esplora]
bind = 127.0.0.1:3000
bind = [::1]:3000

A section may list several bind and safe lines, and listens on all of them. This Electrum server accepts clients on its default ports and on the conventional ones, over IPv4 and IPv6:

[electrum]
bind = 0.0.0.0:8580
bind = [::]:8580
bind = 0.0.0.0:50001
bind = [::]:50001
safe = 0.0.0.0:8543
safe = [::]:8543
safe = 0.0.0.0:50002
safe = [::]:50002
connections = 100
cert_path = server.pem
key_path = server.key

And this RPC interface listens on the local machine and on one private network address only:

[bitcoind]
bind = 127.0.0.1:8280
bind = [::1]:8280
bind = 192.168.0.10:8280
connections = 10
credential = user:password

7. Settings shared by every service#

The client services ([admin], [native], [bitcoind], [electrum], [btcd], [sparrow] and [esplora]) share these settings. [bitcoind_zmq] shares the listening settings, and secures its connections using CurveZMQ rather than TLS (§7.2).

7.1 Listening#

A service runs only when it has somewhere to listen and is allowed connections:

Setting Purpose
bind Address and port for clear connections. Multiple allowed.
safe Address and port for secure connections. Multiple allowed.
connections Maximum concurrent connections. 0 disables the service.

An address of 0.0.0.0 (or [::] for IPv6) listens on all interfaces, and 127.0.0.1 (or [::1] for IPv6) on the local machine only. Client services other than [admin] and [native] wait until the chain is current before accepting connections (node.delay_inbound).

7.2 Secure connections#

A safe address serves TLS, and requires a server certificate and its private key. Without both, the service does not listen on its safe addresses.

Setting Purpose
cert_path Server certificate file (PEM).
key_path Server private key file (PEM).
key_pass Password of an encrypted private key, if any.
cert_auth Directory of certificate authority files (PEM). When set, clients must present a certificate issued by one of them.

The same certificate and key may be used by every service. For example, [admin] over TLS only:

[admin]
safe = 127.0.0.1:8043
safe = [::1]:8043
connections = 10
cert_path = server.pem
key_path = server.key

ZMQ uses CurveZMQ instead of TLS. Its safe addresses require the server's secret key (bitcoind_zmq.key, Z85 encoded), and each bitcoind_zmq.cert line authorizes one client public key. With no cert lines, any client may connect.

7.3 Authentication#

Every client service except [bitcoind_zmq] has:

Setting Purpose
credential A user:password for HTTP Basic authentication (RFC 7617, RFC 9110 §11). Multiple allowed. When any is set, every request must present one of them. Basic authentication is not encrypted, so it is exposed unless the connection is secure.

[bitcoind], [btcd], [electrum] and [sparrow] accept raw TCP, HTTP and websocket clients on the same port. Raw TCP carries no HTTP headers, so when a credential is set, a raw TCP connection is closed at its first request, except by [btcd], whose clients authenticate in-band (§5.9). To restrict raw TCP clients, require client certificates (cert_auth) instead.

A credential may end with a list of the methods it permits, user:password:method,.... A request for any other method is refused, with HTTP 403 or by closing a websocket. JSON-RPC interfaces use their RPC method names, such as getblock or blockchain.headers.subscribe. REST interfaces use these names, one for each kind of request path:

Section REST method names
[bitcoind] chain_information, block, block_txs, block_hash, block_headers, block_filter, block_filter_headers, block_part, block_spent_tx_outputs, deployment_info, get_utxos, mempool, mempool_information, tx
[native] configuration, top, top_subscribe, block, block_header, block_header_context, block_details, block_tx, block_txs, block_filter, block_filter_hash, block_filter_header, block_subscribe, tx, tx_header, tx_details, tx_subscribe, inputs, input, input_script, input_witness, outputs, output, output_script, output_spender, output_spenders, output_subscribe, address, address_confirmed, address_unconfirmed, address_balance, address_subscribe
[esplora] blocks, block, block_header, block_height, block_status, block_txid, block_txids, block_txs, tip_hash, tip_height, tx, tx_status, tx_merkle_proof, tx_merkleblock_proof, tx_outspend, tx_outspends, address, address_txs, address_txs_chain, address_txs_mempool, address_utxo, mempool, mempool_txids, mempool_recent, fee_estimates, broadcast, broadcast_package
[admin] log_subscribe, event_subscribe

7.4 HTTP services#

[admin], [native], [bitcoind], [btcd] and [esplora] are HTTP services, and also have:

Setting Purpose
host Allowed Host header values (RFC 9110 §7.2). Multiple allowed.
origin Allowed Origin header values for cross-origin requests (RFC 6454). Multiple allowed.
allow_opaque_origin Allow requests with an opaque origin (RFC 6454 §7.3), such as from a page opened as a local file.

7.5 Limits#

Each service has the limits that apply to its protocol. They apply to each connection separately.

Time#

Setting Purpose
inactivity_minutes A connection that has received nothing for this long is closed. This is also the HTTP keep-alive period. Sending does not count as activity. 0 disables it.
expiration_minutes A connection is closed this long after it opened, whether or not it is active. 0 disables it.
connect_timeout_seconds Time allowed for a new connection to complete its transport layer handshake (TLS, or ZMTP for ZMQ) before it is dropped. Application layer handshakes, such as Electrum version negotiation, are not covered. Each connection's limit is chosen at random between half and all of this value, so that many clients do not time out together. 0 uses network.connect_timeout_seconds, which defaults to 5 seconds.

Throughput#

Setting Purpose
rate_limit Maximum send rate of a connection, in bytes per second. The limit is continuous, not a cliff: each send is paced by its size, so a connection is slowed to the rate rather than cut off at a quota. Sends are delayed, not dropped, and throttling never disconnects a client. A client that requests faster than its responses drain is bounded by maximum_backlog. This protects against denial of service by bounding the rate at which one client can draw data from the server. network.rate_limit applies the same limit to every connection. When both are set the lower applies, and 0 leaves the other in effect (both 0 is unlimited).
maximum_backlog Maximum bytes of responses waiting to be sent to a connection, such as to a client that reads slower than it asks. A connection that exceeds it is closed. ZMQ instead drops the notifications that do not fit. This protects against denial of service by bounding the memory a client that does not read can hold on the server.

Memory#

Setting Purpose
maximum_request Largest request accepted, in bytes, by every service: an HTTP body, a websocket message, an Electrum JSON-RPC message, a ZMQ frame, or a P2P message ([inbound], [outbound] and [manual]). A larger request closes the connection. This protects against denial of service by bounding the memory a client can make the server allocate.
minimum_buffer Buffer memory a connection keeps for reading requests, and for writing JSON responses. A buffer expanded beyond this by a large request or response is trimmed back to this size once it is idle.
maximum_buffer Size of the buffer a JSON response is written through. A larger response is sent in pieces of this size, so it limits the memory per connection, not the response size.

8. Performance settings#

The defaults suit most machines. These are the settings that most affect sync and query speed.

8.1 Processor#

Setting Default Purpose
network.threads 0 Threads that run the network: peer and client connections. 0 uses one per hardware thread, at most 32.
node.threads 0 Threads that validate blocks. 0 uses one per hardware thread, which is two per core on a processor with hyperthreading (SMT).
node.thread_priority true Run validation threads at high priority, ahead of other programs. false leaves them at normal priority.
node.memory_priority true Keep the process at normal memory priority. false lowers it, so the operating system reclaims its memory first.
database.turbo true Allow a single client query to use all processors, so large queries return sooner.

8.2 Signature verification and silent payment indexing#

When a sufficient GPU is available, signatures are verified, and silent payment transactions indexed, in batches on the GPU, which is much faster than on a CPU. Run bs -w to see whether a GPU is available, and which processor features apply.

Setting Default Purpose
node.use_gpu true Use the GPU when one is available, for signature verification, silent payment indexing and silent payment scans.
node.batch_verify 1,000,000 Signatures verified in each GPU batch. 0 disables GPU verification.
node.batch_silent 1,000,000 Silent payment transactions indexed in each GPU batch. 0 disables GPU indexing.
database.gpu_scan_minimum 65,536 Smallest silent payment scan, in transactions, sent to the GPU. Smaller scans run on the CPU, where they return sooner.

8.3 Network#

Setting Default Purpose
node.maximum_concurrency 50,000 Blocks downloaded concurrently. Blocks arrive out of order, and this window lets download run ahead of validation. 0 is unlimited.
outbound.connections 100 Outgoing peer connections while syncing. More peers may be required to saturate a high bandwidth network connection.
outbound.current_connections 10 Outgoing peer connections once the chain is current, when fewer are needed. 0 keeps outbound.connections.

9. Store table sizing ([table.*])#

The [table.*] settings are advanced and generally do not need to be changed. Each table has some of buckets, expected, size and rate, and the defaults are sized for mainnet at 950,000 blocks.

The common changes are:

bs -k and bs -l report bucket fill and collisions on an existing store.

9.1 Bucket autotuning#

The hashmap tables (header, tx, ins, outs, pool and wtxid) derive their bucket count from their expected entry count and the installed memory, unless buckets is configured. The ratio of entries to buckets is the load factor. More buckets shorten searches but enlarge the table heads, which must generally be held in memory during initial sync.

Installed memory Load factor Address index (outs)
8 GB or less 7.5 50
32 GB or more 2.5 5

Between 8 and 32 GB the load factor falls in proportion to the memory. So a store created on a smaller machine uses less memory for its heads, and one created on a larger machine searches faster. A configured buckets value replaces the derived count, and 0 disables an optional table.


10. Settings fixed at store creation#

Some settings are captured in the store when it is created, in its envelope, and govern that store from then on. The general rules are that hashmap bucket counts cannot be changed (would require table rewrites), optional indexation cannot be altered (would result in hidden gaps), and consensus rules cannot be modified (would result in an inconsistent chain).

Each time bs opens an existing store (or restores one), it compares the captured values with the configuration. Where a setting differs, the store's value is used for that run, and the configured value is ignored. The configuration file is not changed. Each overridden setting is logged by name:

Database envelope [milestone] overrides configuration.

The captured settings are:

Section Settings
[bitcoin] the chain parameters, soft fork activations and the milestone
[forks] all
[database] interval_depth
[table.*] buckets of header, tx, ins, outs, duplicate, pool and wtxid, and whether client filters are enabled
[node] limited_blocks and silent_start_height

A different top checkpoint is logged but not replaced, and client filters cannot be added to a store created without them. To change any of these settings, create a new store. The setups that depend on them, from milestone sync and pruning to disabling the address index, take effect only on a new store.


11. Settings Reference#

Every setting, by section, with its description and default, is on the Settings Reference page.

Settings for the test chains are on their own pages: Testnet3, Testnet4 and Regtest.

Copyright © 2011-2026 libbitcoin developers