Bitcoin Core - tulliolo/mobybolt GitHub Wiki

Bitcoin Core logo

We install Bitcoin Core, the reference client implementation of the Bitcoin network. If you prefer to use Bitcoin Knots, please refer to this guide.

❗ You can't install Bitcoin and Knots and Bitcoin Core together.

❗ To follow this section, log in to your node as admin user via Secure Shell (SSH) and access the project's home:

$ cd apps/mobybolt

Table of contents

This may take some time

Bitcoin Core will download the full Bitcoin blockchain, and validate all transactions since 2009. We're talking more than 800000 blocks with a size of over 465 GB, so this is not an easy task.

Prepare

Create the directories:

$ mkdir -p bitcoin-core/patches

Prepare the environment

Edit the .env file and append the following content to the end:

$ nano .env
# bitcoin
BITCOIN_VERSION=28.0
BITCOIN_ADDRESS=172.16.21.4
BITCOIN_GID=1100
BITCOIN_UID=1100

💡 In this file:

  1. we define the BITCOIN_VERSION (check the latest available version here);
  2. we define a static address for the container;
  3. we define the uid (user id) and gid (group id) of the bitcoin user.

Prepare the Dockerfile

Create the Dockerfile and populate it with the following content:

$ nano bitcoin-core/Dockerfile
# base image
FROM debian:stable-slim AS base

# install dependencies
RUN set -eux && \
    apt update && \
    apt install -y \
        # build requirements
        automake \
        autotools-dev \
        bsdmainutils \
        build-essential \
        ccache \
        curl \
        git \
        libtool \
        pkg-config \
        python3 \
        # dependencies
        libboost-dev \
        libevent-dev \
        libsqlite3-dev \
        libzmq3-dev && \    
    rm -rf /var/lib/apt/lists/*


# builder image
FROM base AS builder

ARG BITCOIN_VERSION

ENV BITCOIN_URL="https://github.com/bitcoin/bitcoin.git" \
    BITCOIN_KEYS_URL="https://api.github.com/repositories/355107265/contents/builder-keys"

RUN set -eux && \
    # clone repository
    git clone --branch "v$BITCOIN_VERSION" $BITCOIN_URL  && \
    # imports automatically all signatures from the Bitcoin Core release attestations (Guix) repository
    curl -s \
        $BITCOIN_KEYS_URL |\
        grep download_url |\
        grep -oE "https://[a-zA-Z0-9./-]+" |\
        while read url; do \
            curl -s "$url" |\
            gpg --import; \
        done

# copy patches
COPY patches/ /patches/

WORKDIR bitcoin

RUN set -xe && \
    # verify signature
    git verify-tag "v$BITCOIN_VERSION" && \
    # build bdb 4.8
    make -C depends NO_BOOST=1 NO_LIBEVENT=1 NO_QT=1 NO_SQLITE=1 NO_NATPMP=1 NO_UPNP=1 NO_ZMQ=1 NO_USDT=1 && \
    # apply patches
    for patch in $( find /patches -type f ); do \
        git apply $patch; \
    done && \
    # configure
    ./autogen.sh && \
    export BDB_PREFIX="$PWD/depends/$( ls depends | grep linux-gnu )" && \
    ./configure \
        BDB_LIBS="-L${BDB_PREFIX}/lib -ldb_cxx-4.8" BDB_CFLAGS="-I${BDB_PREFIX}/include" \
        --disable-bench \
        --disable-gui-tests \
        --disable-maintainer-mode \
        --disable-man \
        --disable-tests \
        --with-daemon=yes \
        --with-gui=no \
        --with-qrencode=no \
        --with-utils=yes && \
    # build
    make -j$(nproc) && \
    # install
    make install


# base image
FROM debian:stable-slim

# copy bitcoin binaries and libraries
COPY --from=builder /usr/local/bin/ /usr/local/bin/
COPY --from=builder /usr/local/lib/ /usr/local/lib/

# install dependencies
RUN set -eux && \
    apt update && \
    apt install -y \
        libevent-dev \
        libsqlite3-dev \
        libzmq3-dev && \
    rm -rf /var/lib/apt/lists/*

# default uid for bitcoin user
ARG BITCOIN_GID=1100
ARG BITCOIN_UID=1100

# default gid for tor group
ARG TOR_GID=102

# setup bitcoin user
RUN set -eux && \
    addgroup --gid $BITCOIN_GID bitcoin && \
    adduser --disabled-password --comment "" --gid $BITCOIN_GID --uid $BITCOIN_UID bitcoin && \
    addgroup --gid $TOR_GID tor && \
    adduser bitcoin tor

# setup dirs and permissions
RUN set -eux && \
    mkdir -m 0750 /home/bitcoin/.bitcoin && \
    mkdir -m 0700 /run/bitcoind && \
    chown bitcoin /run/bitcoind && \
    chown bitcoin:bitcoin /home/bitcoin/.bitcoin /run/bitcoind

# setup entrypoint
COPY --chmod=0755 ./docker-entrypoint.sh /usr/local/bin/
ENTRYPOINT ["docker-entrypoint.sh"]

# switch user
USER bitcoin

💡 In this file:

  1. we define a builder image (builder) to buid bitcoin from github sources, verifying version tag signatures;
  2. we define a result image:
    1. installing the needed dependencies;
    2. copying libraries and binaries from the builder image;
    3. configuring the bitcoin user and the directories to which he will have access;
    4. setting the entrypoint (the script to run when the container starts).

Create the entrypoint

Create the entrypoint file and populate it with the following content:

$ nano bitcoin-core/docker-entrypoint.sh
#!/bin/bash
set -eo pipefail

function die_func() {
  echo "INFO: got SIGTERM... exiting"
  exit 1
}
trap die_func TERM

function wait_for_config () {
  echo "WARNING: missing configuration file"
  while ! [[ -f $CONF_FILE ]]; do
    echo "--> waiting for $CONF_FILE"
    sleep 30
  done
  echo "INFO: found configuration file!"
}

CMD=$@

DATA_DIR=/home/bitcoin/.bitcoin
CONF_FILE="$DATA_DIR/bitcoin.conf"
PID_FILE=/run/bitcoind/bitcoind.pid

if [[ $# -eq 0 ]]; then
  # missing parameters, run bitcoind
  CMD="bitcoind -conf=$CONF_FILE -datadir=$DATA_DIR -pid=$PID_FILE"
  if ! [[ -f $CONF_FILE ]]; then
    wait_for_config
  fi
fi

exec $CMD

💡 In this file:

  1. we define the default files and directories;
  2. we wait for a configuration file;
  3. we run bitcoin.

Prepare the spam filter (optional)

Ordinals is a project created to number sats. It also has a feature called inscriptions, which is the problematic part and what is mainly being touched on in this guide. An inscription is basically data stored onchain associated with a sat.

Ordisrespector is a spam patch filter that works by detecting the pattern of Ordinals transactions that are entering the mempool of the node and rejecting them. The original patch was created by Luke Dashjr, you can see it here.

In order to apply the spam filter, simply download the Ordisrespector patch and put it in the pathes dir. The next Bitcoin Core build will apply it:

$ wget -P bitcoin-core/patches/ https://raw.githubusercontent.com/minibolt-guide/minibolt/main/resources/ordisrespector.patch

Carefully check the downloaded patch:

$ cat bitcoin-core/patches/ordisrespector.patch
diff --git a/src/script/interpreter.cpp b/src/script/interpreter.cpp
index 03b157a84..e7d9e96d0 100644
--- a/src/script/interpreter.cpp
+++ b/src/script/interpreter.cpp
@@ -479,6 +479,14 @@ bool EvalScript(std::vector<std::vector<unsigned char> >& stack, const CScript&
                     return set_error(serror, SCRIPT_ERR_MINIMALDATA);
                 }
                 stack.push_back(vchPushValue);
+                if ((flags & SCRIPT_VERIFY_DISCOURAGE_UPGRADABLE_NOPS) && opcode == OP_FALSE) {
+                    auto pc_tmp = pc;
+                    opcodetype next_opcode;
+                    valtype dummy_data;
+                    if (script.GetOp(pc_tmp, next_opcode, dummy_data) && next_opcode == OP_IF) {
+                        return set_error(serror, SCRIPT_ERR_DISCOURAGE_UPGRADABLE_NOPS);
+                    }
+                }
             } else if (fExec || (OP_IF <= opcode && opcode <= OP_ENDIF))
             switch (opcode)
             {

Configure

Create the bitcoin configuration file and populate it with the following content:

$ nano bitcoin-core/bitcoin.conf
# MobyBolt: bitcoind configuration
# /home/bitcoin/.bitcoin/bitcoin.conf

## Bitcoin daemon
server=1
txindex=1

# Additional logs
debug=tor
debug=i2p

# Assign read permission to the Bitcoin group users
startupnotify=chmod g+r /home/bitcoin/.bitcoin/.cookie

# Disable debug.log
nodebuglogfile=1

# Avoid assuming that a block and its ancestors are valid,
# and potentially skipping their script verification.
# We will set it to 0, to verify all.
assumevalid=0

# Enable all compact filters
blockfilterindex=1
# Support filtering of blocks and transactions with bloom filters
peerbloomfilters=1
# Serve compact block filters to peers per BIP 157
peerblockfilters=1
# Maintain coinstats index used by the gettxoutsetinfo RPC
coinstatsindex=1

# Network
bind=172.16.21.4:8333
bind=172.16.21.4:8334=onion
listen=1

# Connect to clearnet using Tor SOCKS5 proxy
proxy=172.16.21.2:9050
onion=172.16.21.2:9050

# Tor control <ip:port> to use if onion listening enabled.
torcontrol=172.16.21.2:9051

# I2P SAM proxy to reach I2P peers and accept I2P connections
i2psam=172.16.21.3:7656

# RPC
rpcbind=0.0.0.0
rpcallowip=172.16.21.0/24

# ZMQ
zmqpubhashblock=tcp://0.0.0.0:8433

# Initial block download optimizations (set dbcache size in megabytes 
# (4 to 16384, default: 300) according to the available RAM of your device,
# recommended: dbcache=1/2 x RAM available e.g: 4GB RAM -> dbcache=2048)
# Remember to comment after IBD!
dbcache=4096
blocksonly=1

âš ī¸ dbcache=... need to be adjusted to your hardware capacity

Reject non-private networks (optional)

Add these lines to the end of the file, remember to add seed nodes. You can add more seed nodes to this list: seed nodes. Save and exit.

# Reject non-private networks
onlynet=onion
onlynet=i2p
dns=0
dnsseed=0

##Tor seed nodes
seednode=2bqghnldu6mcug4pikzprwhtjjnsyederctvci6klcwzepnjd46ikjyd.onion:8333
seednode=4lr3w2iyyl5u5l6tosizclykf5v3smqroqdn2i4h3kq6pfbbjb2xytad.onion:8333
seednode=5g72ppm3krkorsfopcm2bi7wlv4ohhs4u4mlseymasn7g7zhdcyjpfid.onion:8333
seednode=5sbmcl4m5api5tqafi4gcckrn3y52sz5mskxf3t6iw4bp7erwiptrgqd.onion:8333
seednode=776aegl7tfhg6oiqqy76jnwrwbvcytsx2qegcgh2mjqujll4376ohlid.onion:8333
seednode=77mdte42srl42shdh2mhtjr7nf7dmedqrw6bkcdekhdvmnld6ojyyiad.onion:8333
seednode=azbpsh4arqlm6442wfimy7qr65bmha2zhgjg7wbaji6vvaug53hur2qd.onion:8333
seednode=b64xcbleqmwgq2u46bh4hegnlrzzvxntyzbmucn3zt7cssm7y4ubv3id.onion:8333
seednode=bsqbtcparrfihlwolt4xgjbf4cgqckvrvsfyvy6vhiqrnh4w6ghixoid.onion:8333
seednode=bsqbtctulf2g4jtjsdfgl2ed7qs6zz5wqx27qnyiik7laockryvszqqd.onion:8333

##I2P seed nodes
seednode=255fhcp6ajvftnyo7bwz3an3t4a4brhopm3bamyh2iu5r3gnr2rq.b32.i2p:0
seednode=27yrtht5b5bzom2w5ajb27najuqvuydtzb7bavlak25wkufec5mq.b32.i2p:0
seednode=3gocb7wc4zvbmmebktet7gujccuux4ifk3kqilnxnj5wpdpqx2hq.b32.i2p:0
seednode=4fcc23wt3hyjk3csfzcdyjz5pcwg5dzhdqgma6bch2qyiakcbboa.b32.i2p:0
seednode=4osyqeknhx5qf3a73jeimexwclmt42cju6xdp7icja4ixxguu2hq.b32.i2p:0
seednode=4umsi4nlmgyp4rckosg4vegd2ysljvid47zu7pqsollkaszcbpqq.b32.i2p:0
seednode=6j2ezegd3e2e2x3o3pox335f5vxfthrrigkdrbgfbdjchm5h4awa.b32.i2p:0
seednode=6n36ljyr55szci5ygidmxqer64qr24f4qmnymnbvgehz7qinxnla.b32.i2p:0
seednode=72yjs6mvlby3ky6mgpvvlemmwq5pfcznrzd34jkhclgrishqdxva.b32.i2p:0
seednode=a5qsnv3maw77mlmmzlcglu6twje6ttctd3fhpbfwcbpmewx6fczq.b32.i2p:0
seednode=aovep2pco7v2k4rheofrgytbgk23eg22dczpsjqgqtxcqqvmxk6a.b32.i2p:0
seednode=bitcoi656nll5hu6u7ddzrmzysdtwtnzcnrjd4rfdqbeey7dmn5a.b32.i2p:0
seednode=brifkruhlkgrj65hffybrjrjqcgdgqs2r7siizb5b2232nruik3a.b32.i2p:0
seednode=c4gfnttsuwqomiygupdqqqyy5y5emnk5c73hrfvatri67prd7vyq.b32.i2p:0
seednode=day3hgxyrtwjslt54sikevbhxxs4qzo7d6vi72ipmscqtq3qmijq.b32.i2p:0
seednode=du5kydummi23bjfp6bd7owsvrijgt7zhvxmz5h5f5spcioeoetwq.b32.i2p:0
seednode=e55k6wu46rzp4pg5pk5npgbr3zz45bc3ihtzu2xcye5vwnzdy7pq.b32.i2p:0
seednode=eciohu5nq7vsvwjjc52epskuk75d24iccgzmhbzrwonw6lx4gdva.b32.i2p:0

Prepare the Docker Compose file

Create the Docker Compose file and populate it with the following content:

$ nano bitcoin-core/docker-compose.yml
services:
  bitcoin:
    build:
      context: .
      args:
        BITCOIN_VERSION: ${BITCOIN_VERSION}
        BITCOIN_GID: ${BITCOIN_GID}
        BITCOIN_UID: ${BITCOIN_UID}
        TOR_GID: ${TOR_GID}
    container_name: ${COMPOSE_PROJECT_NAME}_bitcoin
    expose:
      - "8332"
      - "8334"
    healthcheck:
      test: ["CMD-SHELL", "bitcoin-cli getconnectioncount | sed 's/^[1-9][0-9]*$/OK/' | grep OK || exit 1"]
      interval: 1m
      timeout: 10s
      retries: 3
      start_period: 5m
    image: ${COMPOSE_PROJECT_NAME}/bitcoin:${BITCOIN_VERSION}
    networks:
      default:
        ipv4_address: ${BITCOIN_ADDRESS}
    restart: unless-stopped
    stop_grace_period: 5m
    volumes:
      - bitcoin-data:/home/bitcoin/.bitcoin/
      - ./bitcoin.conf:/home/bitcoin/.bitcoin/bitcoin.conf:ro
      - tor-data:/var/lib/tor/:ro

volumes:
  bitcoin-data:

💡 In this file:

  1. we build the Dockerfile and create an image named mobybolt/bitcoin:<version>;
  2. we define a healthcheck that will check every minute that the bitcoin client is connected to at least one peer;
  3. we define the restart policy of the container in case of failures;
  4. we provide the container with the BITCOIN_ADDRESS static address;
  5. we provide the container with the previously defined configuration (bind mount) and with a volume named mobybolt_bitcoin-data to store persistent data.

Link the Docker Compose File

Edit the main Docker Compose file and link the bitcoin docker compose file in the include section:

$ nano docker-compose.yml

The file should look like this:

include:
  - ...
  - bitcoin-core/docker-compose.yml

âš ī¸ Be very careful to respect the indentation. Yaml is very sensitive to this! âš ī¸

Test the Docker Compose File

Run the following command and check the output:

$ docker compose config --quiet && printf "OK\n" || printf "ERROR\n"
> OK

💡 If the output is not OK, check the error reported... Maybe some wrong indentation in the yaml files?

Build

Let's build the bitcoin image by typing:

$ docker compose build bitcoin

âš ī¸ This may take a long time.

Check for a new image called mobybolt/bitcoin:<version>:

$ docker images | grep bitcoin
> mobybolt/bitcoin                    28.0   30adc7959c8e   About a minute ago   795MB

Run

Run the following command and check the output:

$ docker compose up -d bitcoin
> [+] Running 2/2
> ✔ Volume "mobybolt_bitcoin-data"  Created
> ✔ Container mobybolt_bitcoin      Started

Check the container logs:

$ docker logs mobybolt_bitcoin
> 2024-05-25T11:55:44Z Bitcoin Core version v27.1 (release build)
> ...
> 2024-05-25T11:55:44Z Default data directory /home/bitcoin/.bitcoin
> 2024-05-25T11:55:44Z Using data directory /home/bitcoin/.bitcoin
> 2024-05-25T11:55:44Z Config file: /home/bitcoin/.bitcoin/bitcoin.conf
> ...
> 2024-05-25T11:55:44Z [tor] Successfully connected!
> 2024-05-25T11:55:44Z [tor] Connected to Tor version 0.4.8.11
> 2024-05-25T11:55:44Z [tor] Supported authentication method: COOKIE
> 2024-05-25T11:55:44Z [tor] Supported authentication method: SAFECOOKIE
> 2024-05-25T11:55:44Z [tor] Using SAFECOOKIE authentication, reading cookie authentication from /var/lib/tor/control_auth_cookie
> ...
> 2024-05-25T11:55:44Z [tor] Authentication successful

Check the container status:

$ docker ps | grep bitcoin
> 5bd04a4dbc34   mobybolt/bitcoin:28.0        "docker-entrypoint.sh"   About a minute ago   Up About a minute (health: starting)   8332/tcp, 8334/tcp                                                                                 mobybolt_bitcoin

âš ī¸ The output of the previous command must be (healthy), or (health: starting). Any other status is incorrect.

💡 If the container is in (health: starting) state, wait a few minutes and repeat the above command until the state changes to (healthy). If this does not happen, the run has failed.

â„šī¸ If not already present, docker will also create the mobybolt_tor-data volume. You can check for it with the command:

$ docker volume ls | grep bitcoin
> local     mobybolt_bitcoin-data

Check bitcoin syncronization status

Run the following command:

$ docker exec mobybolt_bitcoin bitcoin-cli -getinfo
> Chain: main
> Blocks: 844910
> Headers: 844910
> Verification progress: 100.0000%
> ...

Bitcoin Core will be fully syncronized when the verification progress reaches 100% (or 99.xxx%).

Check bitcoin networking status

Run the following command:

$ docker exec mobybolt_bitcoin bitcoin-cli -netinfo
> ...
>         onion     i2p   total   block
> in          0       2       2
> out         2       8      10       2
> total       2      10      12
> 
> Local addresses
> abcdef.onion     port   8333    score      4
> abcdef.b32.i2p   port      0    score      4

You should see some out connections and your onion/i2p local addresses.

Bitcoin Core is syncing

This can take between one day and a week, depending mostly on your PC and network performance. It's best to wait until the synchronization is complete before going ahead.

Explore bitcoin-cli

If everything is running smoothly, this is the perfect time to familiarize yourself with Bitcoin, the technical aspects of Bitcoin Core, and play around with bitcoin-cli until the blockchain is up-to-date.

Activate mempool & reduce dbcache after a full sync

Once Bitcoin Core is fully synched, we can reduce the size of the database cache. A bigger cache speeds up the initial block download, now we want to reduce memory consumption to allow the Lightning client and Electrum server to run in parallel. We also now want to enable the node to listen to and relay transactions.

Edit the bitcoin configuration file and comment (prepending a #) the following lines:

$ nano bitcoin-core/bitcoin.conf
#dbcache=2048
#blocksonly=1
#assumevalid=0

Restart Bitcoin Core:

$ docker compose restart bitcoin
> [+] Restarting 1/1
>  ✔ Container mobybolt_bitcoin  Started

Upgrade

Check the Bitcoin Core release page for a new version and change the BITCOIN_VERSION value in the .env file. Then, redo the steps described in:

  1. Build
  2. Run

If everything is ok, you can clear the old image and build cache, like in the following example:

$ docker image ls | grep bitcoin
> mobybolt/bitcoin                    28.0   30adc7959c8e   46 minutes ago   795MB
> mobybolt/bitcoin                    27.1   56f39c90e8ac   4 weeks ago      795MB
$ docker image rm mobybolt/bitcoin:27.1
> Untagged: mobybolt/bitcoin:27.1
> Deleted: sha256:56f39c90e8accbfae77a3c8ed9e6e5794d67c62d1944c2c0ce4c7bc3dd233f07
$ docker buildx prune
> WARNING! This will remove all dangling build cache. Are you sure you want to continue? [y/N] y
> ID                                              RECLAIMABLE     SIZE            LAST ACCESSED
> nd48am5z5nzmiiule5r8b1t8q*                      true            0B              About an hour ago
> ...
> Total:  5.711GB

Uninstall

Follow the next steps to uninstall bitcoin:

  1. Remove the container:

    $ docker compose down bitcoin
    > [+] Running 2/1
    > ✔ Container mobybolt_bitcoin  Removed
    > ...
    
  2. Remove the image:

    $ docker image rm $(docker images | grep bitcoin | awk '{print $3}')
    > Untagged: mobybolt/bitcoin:28.0
    > Deleted: sha256:13afebf08e29c6b9a526a6e54ab1f93e745b25080add4e37af8f08bdf6cfbcc6
    
  3. Clean the build cache:

    $ docker buildx prune
    > WARNING! This will remove all dangling build cache. Are you sure you want to continue? [y/N] y
    > ID                                              RECLAIMABLE     SIZE            LAST ACCESSED
    > 7r8ccrpq0g0e03deu2dh53ob6*                      true            9.69MB          19 minutes ago
    > ndrhcdo756vejnx17qm775t08*                      true            1.212kB         24 minutes ago
    > ...
    
  4. Remove the volume (optional):
    âš ī¸ you will lose all the synchronized blocks data âš ī¸

    $ docker volume rm mobybolt_bitcoin-data
    > mobybolt_bitcoin-data
    
  5. Remove files and directories (optional):

    $ rm -rf bitcoin-core
    
âš ī¸ **GitHub.com Fallback** âš ī¸