# Run a Pruned Bitcoin Node

This guide is written for a Unix based system. It's reasonable to expect some modifications will be required for other operating systems.

When started, the pruned Bitcoin node will take roughly \~24 hours to reach chain tip.

{% hint style="warning" %}
While bitcoin is syncing, it's recommended to keep a stacks-blockchain node at chain tip, or [use a stacks chainstate archive](https://docs.hiro.so/stacks/archive/guides/stacks-blockchain).
{% endhint %}

Requirements:

* Bitcoin Core >= v25.0
  * <https://github.com/bitcoin/bitcoin>
  * <https://bitcoincore.org/en/download/>
* Host with a minimum of:
  * 2 vCPU (a single dedicated cpu for the bitcoind process)
  * 4GB Memory (during sync, more available memory will improve sync time)
  * 50GB free disk space (actual usage is closer to 20GB)
* User account: `bitcoin:bitcoin`
* Chainstate directory located at: `/bitcoin/mainnet`
  * `bitcoin` user must have read/write access.
* Config directory located at: `/etc/bitcoin`
  * `bitcoin` user must have at least read access

Caveats

[BIP-0159](https://github.com/bitcoin/bips/blob/master/bip-0159.mediawiki)

In short, this BIP specifies that pruned nodes will advertise the service bit `NODE_NETWORK_LIMITED`, which restricts syncing blocks older than 288 blocks (\~2 days).

What this means is that in practice, a stacks-blockchain node:

* Cannot sync from genesis using a pruned node.
* Must not be offline or otherwise down for longer than \~2 days (or 288 Bitcoin blocks).

{% stepper %}
{% step %}

#### Add bitcoin user and set file ownership

```shell
$ sudo mkdir -p /bitcoin/mainnet
$ sudo mkdir /etc/bitcoin
$ sudo useradd bitcoin -d /bitcoin
$ sudo chown -R bitcoin:bitcoin /bitcoin /etc/bitcoin/
```

{% endstep %}

{% step %}

#### Bitcoin Config

Below is a sample config used to sync a pruned bitcoin node - feel free to adjust as needed.

{% hint style="info" %}
If using the [systemd unit below](#systemd-unit-file), save this file as `/etc/bitcoin/bitcoin.conf`
{% endhint %}

Notes:

* `btuser:btcpass` is hardcoded as an rpcauth user/password ([generated using this script](https://github.com/bitcoin/bitcoin/tree/master/share/rpcauth)).
* Only localhost access is allowed (`127.0.0.1`) on the standard mainnet ports.
* Pruning is set to be small, storing only the last 1GB of blocks (for p2p traffic, this is more than enough).
* `dbcache` is set to the maximum of 16GB.
* Wallet (and wallet rpc calls) are disabled.

```
## [rpc]

# Accept command line and JSON-RPC commands.
server=1

# Allow JSON-RPC connections from specified source.
rpcallowip=127.0.0.1/0

# Bind to given address to listen for JSON-RPC connections.
rpcbind=127.0.0.1:8332

# Username and HMAC-SHA-256 hashed password for JSON-RPC connections.

#   Use the script at https://github.com/bitcoin/bitcoin/tree/master/share/rpcauth to generate

#   Note: may be specified multiple times for different users.
rpcauth=btcuser:18857b4df4b1f0f5e6b1d7884617ab39$de6e02e1da8ee138ee702e13e0637e24679d844756216b066c3aeac4bcac5e10 # btuser:btcpass

# Optional: rpcwhitelist can restrict listed RPC calls to specific rpcauth users.

#   Uncomment the below the restrict the `limited` user to a small subset of `get` commands

# rpcauth=limited:350c91a60895b567c4662c27e63e9a41$25188b0f51f2f974dcdc75c1e0d41174e8f7ae19fb96927abf68ac5bc1e8897b # limited:limited

# rpcwhitelist=limited:getblockchaininfo,getblock,getblockcount,getblockhash,getblockheader,getnetworkinfo

# rpcwhitelistdefault=0

## [core]

# Specify data directory
datadir=/bitcoin/mainnet

# Do not keep transactions in the mempool longer than <n> hours (default: 336)
mempoolexpiry=24

# Bind to given address and always listen on it (default: 0.0.0.0)
bind=127.0.0.1:8333

# Maximum database cache size <n> MiB (4 to 16384, default: 450). In addition, unused mempool memory is shared for this cache
dbcache=16384

# Maintain a full transaction index, used by the getrawtransaction rpc call (**Running a pruned node requires that this option is disabled**)
txindex=0

# Reduce storage requirements by enabling pruning (deleting) of old

# blocks. This allows the pruneblockchain RPC to be called to

# delete specific blocks and enables automatic pruning of old

# blocks if a target size in MiB is provided. This mode is

# incompatible with -txindex. Warning: Reverting this setting

# requires re-downloading the entire blockchain. (default: 0 =

# disable pruning blocks, 1 = allow manual pruning via RPC, >=550 =

# automatically prune block files to stay under the specified

# target size in MiB)
prune=1024 # 1GB of chainstate is enough for p2p block data (if using the RPC,this can be adjusted higher to store more blocks)

## [wallet]

# Do not load the wallet and disable wallet RPC calls
disablewallet=1
```

{% endstep %}

{% step %}

#### Systemd unit file

ref: <https://github.com/bitcoin/bitcoin/blob/master/contrib/init/bitcoind.service>

```
[Unit]
Description=Bitcoin daemon
Documentation=https://github.com/bitcoin/bitcoin/blob/master/doc/init.md

# https://www.freedesktop.org/wiki/Software/systemd/NetworkTarget/
After=network-online.target
Wants=network-online.target

[Service]
ExecStart=/usr/bin/bitcoind -pid=/run/bitcoind/bitcoind.pid \
                            -conf=/etc/bitcoin/bitcoin.conf \
                            -startupnotify='systemd-notify --ready' \
                            -shutdownnotify='systemd-notify --stopping'

# Make sure the config directory is readable by the service user
PermissionsStartOnly=true
ExecStartPre=/bin/chgrp bitcoin /etc/bitcoin

# Process management
####################

Type=notify
NotifyAccess=all
PIDFile=/run/bitcoind/bitcoind.pid

Restart=on-failure
TimeoutStartSec=infinity
TimeoutStopSec=600

# Directory creation and permissions
####################################

# Run as bitcoin:bitcoin
User=bitcoin
Group=bitcoin

# /run/bitcoind
RuntimeDirectory=bitcoind
RuntimeDirectoryMode=0710

# /etc/bitcoin
ConfigurationDirectory=bitcoin
ConfigurationDirectoryMode=0710

# /var/lib/bitcoind
StateDirectory=bitcoind
StateDirectoryMode=0710

# Hardening measures
####################

# Provide a private /tmp and /var/tmp.
PrivateTmp=true

# Mount /usr, /boot/ and /etc read-only for the process.
ProtectSystem=full

# Deny access to /home, /root and /run/user
ProtectHome=true

# Disallow the process and all of its children to gain

# new privileges through execve().
NoNewPrivileges=true

# Use a new /dev namespace only populated with API pseudo devices

# such as /dev/null, /dev/zero and /dev/random.
PrivateDevices=true

# Deny the creation of writable and executable memory mappings.
MemoryDenyWriteExecute=true

# Restrict ABIs to help ensure MemoryDenyWriteExecute is enforced
SystemCallArchitectures=native

[Install]
WantedBy=multi-user.target
```

{% endstep %}

{% step %}

#### Enable and start the Bitcoin service

```shell
$ sudo systemctl daemon-reload
$ sudo systemctl enable bitcoin.service
$ sudo systemctl start bitcoin.service
```

{% endstep %}

{% step %}

#### Track sync progress

{% hint style="info" %}
Once started, you may track the sync progress:

```
$ sudo tail -f /bitcoin/mainnet/debug.log
2024-12-05T19:35:31Z UpdateTip: new best=00000000000000000058990a84cc8f8eab25dbbd572f123f9190cea7256d7349 height=509258 version=0x20000000 log2_work=88.128280 tx=299522737 date='2018-02-15T03:42:14Z' progress=0.295203 cache=43.5MiB(172740txo)
...
$ bitcoin-cli \
    -rpcconnect=127.0.0.1 \
    -rpcport=8332 \
    -rpcuser=btcuser \
    -rpcpassword=btcpass \
    getblockcount
509016
```

{% endhint %}
{% endstep %}
{% endstepper %}


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://docs.stacks.co/operate/run-a-node/run-a-pruned-bitcoin-node.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
