Skip to content

Instantly share code, notes, and snippets.

@wileyj
Last active February 23, 2022 19:34
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save wileyj/26cc0a3daf55c9b70d30301e9e4200f2 to your computer and use it in GitHub Desktop.
Save wileyj/26cc0a3daf55c9b70d30301e9e4200f2 to your computer and use it in GitHub Desktop.
stacks-mining

Stacks Blockchain Miner

https://docs.stacks.co/start-mining/mainnet

Prerequisites

VM setup

The VM will not need a lot of resources to run a miner - the most resources will be consumed during blockchain sync.
A single CPU system with at least 4GB of memory should be more than sufficient - as well as roughly 1TB of total disk space

Note: btcuser and btcpass are used for bitcoin RPC auth in this doc. Change as appropriate

  1. Separate disks for chainstates and OS
    • mount a dedicated disk for bitcoin at /bitcoin of 1TB
    • mount a dedicated disk for stacks-blockchain at /stacks-blockchain of at least 100GB
    • root volume / of at least 25GB
  2. Combined Disk for all data
    • root volume / of at least 1TB
$ sudo mkdir -p /bitcoin
$ sudo mkdir -p /stacks-blockchain
$ sudo mkdir -p /etc/bitcoin
$ sudo mkdir -p /etc/stacks-blockchain

Install required packages

$ curl -sL https://deb.nodesource.com/setup_16.x | sudo -E bash -
$ sudo apt-get update -y && sudo apt-get install -y build-essential jq netcat nodejs git autoconf libboost-system-dev libboost-filesystem-dev libboost-thread-dev libboost-chrono-dev libevent-dev libzmq5 libtool m4 automake pkg-config libtool libboost-system-dev libboost-filesystem-dev libboost-chrono-dev libboost-program-options-dev libboost-test-dev libboost-thread-dev libboost-iostreams-dev
$ curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh && source $HOME/.cargo/env

If using mounted disks

mount the disks to each filesystem created above - edit /etc/fstab to automount these disks at boot.

/dev/xvdb1 /bitcoin xfs rw,relatime,attr2,inode64,noquota
/dev/xvdc1 /stacks-blockchain xfs rw,relatime,attr2,inode64,noquota

Install Bitcoin

Choose either method, but bitcoin is required here. Building from source ensures you know what code you are running, but will a while to compile.

Binary Install

$ sudo curl -L https://bitcoin.org/bin/bitcoin-core-22.0/bitcoin-22.0-x86_64-linux-gnu.tar.gz -o /tmp/bitcoin-22.0.tar.gz
$ sudo tar -xzvf /tmp/bitcoin-22.0.tar.gz -C /tmp
$ sudo cp /tmp/bitcoin-22.0/bin/* /usr/local/bin/

Source Install

$ git clone --depth 1 --branch v22.0 https://github.com/bitcoin/bitcoin /tmp/bitcoin && cd /tmp/bitcoin
$ sh contrib/install_db4.sh .
$ ./autogen.sh
$ export BDB_PREFIX="/tmp/bitcoin/db4" && ./configure BDB_LIBS="-L${BDB_PREFIX}/lib -ldb_cxx-4.8" BDB_CFLAGS="-I${BDB_PREFIX}/include" \
  --disable-gui-tests \
  --enable-static \
  --without-miniupnpc \
  --with-pic \
  --enable-cxx \
  --with-boost-libdir=/usr/lib/x86_64-linux-gnu
$ make -j2
$ sudo make install

Bitcoin Config

$ sudo bash -c 'cat <<EOF> /etc/bitcoin/bitcoin.conf
server=1
#disablewallet=1
datadir=/bitcoin
rpcuser=btcuser
rpcpassword=btcpass
rpcallowip=0.0.0.0/0
bind=0.0.0.0:8333
rpcbind=0.0.0.0:8332
dbcache=512
banscore=1
rpcthreads=256
rpcworkqueue=256
rpctimeout=100
txindex=1
EOF'

Add bitcoin user and configure dirs

$ sudo useradd bitcoin
$ sudo chown -R bitcoin:bitcoin /bitcoin/

Install bitcoin.service unit

$ sudo bash -c 'cat <<EOF> /etc/systemd/system/bitcoin.service
[Unit]
Description=Bitcoin daemon
After=network.target

[Service]
ExecStart=/usr/local/bin/bitcoind -daemon \
                            -pid=/run/bitcoind/bitcoind.pid \
                            -conf=/etc/bitcoin/bitcoin.conf

# Process management
####################
Type=forking
PIDFile=/run/bitcoind/bitcoind.pid
Restart=on-failure
TimeoutStopSec=600
# Directory creation and permissions
####################################
# Run as bitcoin:bitcoin
User=bitcoin
Group=bitcoin
RuntimeDirectory=bitcoind
RuntimeDirectoryMode=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

[Install]
WantedBy=multi-user.target

EOF'

Enable service and start bitcoin

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

now we wait a few days until bitcoin syncs to chain tip

$ sudo tail -f /bitcoin/debug.log
$ bitcoin-cli \
  -rpcconnect=localhost \
  -rpcport=8332 \
  -rpcuser=btcuser \
  -rpcpassword=btcpass \
getblockchaininfo | jq .blocks

Generate keychain

save this output in a safe place!

$ cd $HOME && npm install @stacks/cli shx rimraf
$ npx @stacks/cli make_keychain 2>/dev/null | jq
{
  "mnemonic": "frown lens very suit ocean trigger animal flip retire dose various mobile record emerge torch client sorry shy party session until planet member exclude",
  "keyInfo": {
    "privateKey": "ooxeemeitar4ahw0ca8anu4thae7aephahshae1pahtae5oocahthahho4ahn7eici",
    "address": "STTXOG3AIHOHNAEH5AU6IEX9OOTOH8SEIWEI5IJ9",
    "btcAddress": "Ook6goo1Jee5ZuPualeiqu9RiN8wooshoo",
    "wif": "rohCie2ein2chaed9kaiyoo6zo1aeQu1yae4phooShov2oosh4ox",
    "index": 0
  }
}

Create bitcoin wallet and import it into this instance

We'll be using the wallet values from the previous npx command, "btcAddress" and "wif"

$ bitcoin-cli \
  -rpcconnect=localhost \
  -rpcport=8332 \
  -rpcuser=btcuser \
  -rpcpassword=btcpass \
createwallet "miner"
$ sudo systemctl restart bitcoin
$ bitcoin-cli \
  -rpcconnect=localhost \
  -rpcport=8332 \
  -rpcuser=btcuser \
  -rpcpassword=btcpass \
importmulti '[{ "scriptPubKey": { "address": "<npx btcAddress>" }, "timestamp":"now", "keys": [ "<npx wif>" ]}]' '{"rescan": true}'
$ bitcoin-cli \
  -rpcconnect=localhost \
  -rpcport=8332 \
  -rpcuser=btcuser \
  -rpcpassword=btcpass \
getaddressinfo <npx btcAddress>

Once imported, the wallet will need to be funded with some bitcoin.

stacks-blockchain

Build and install stacks-blockchain from source (via script)

$ cd $HOME && cat <<EOF> $HOME/build-stacks.sh
#!/bin/sh
CURDIR=\$(pwd)
DEST=/usr/local/bin/stacks-node
GIT_DIR=\$HOME/stacks-blockchain
if [ ! -d \${GIT_DIR} ]; then
  git clone https://github.com/blockstack/stacks-blockchain.git \${GIT_DIR}
else
  git -C \${GIT_DIR} pull -r
fi
cd \${GIT_DIR}/testnet/stacks-node
cargo build --features monitoring_prom,slog_json --release --bin stacks-node
if [ "\$?" -eq "0" ]; then
  if [ -f \${DEST} ]; then
    sudo rm -f \${DEST}
  fi
  echo "Copying stacks-node to $DEST using sudo"
  sudo cp -a \${GIT_DIR}/target/release/stacks-node \${DEST}
fi
cd \${CURDIR}
EOF
$ sh $HOME/build-stacks.sh

Build and install stacks-blockchain from source

$ git clone https://github.com/blockstack/stacks-blockchain.git $HOME/stacks-blockchain
$ cd $HOME/stacks-blockchain/testnet/stacks-node
$ cargo build --features monitoring_prom,slog_json --release --bin stacks-node
$ sudo cp -a $HOME/stacks-blockchain/target/release/stacks-node /usr/local/bin/stacks-node
$ sudo bash -c 'cat <<EOF> /etc/stacks-blockchain/follower.toml
[node]
working_dir = "/stacks-blockchain"
rpc_bind = "0.0.0.0:20443"
p2p_bind = "0.0.0.0:20444"
bootstrap_node = "02da7a464ac770ae8337a343670778b93410f2f3fef6bea98dd1c3e9224459d36b@seed-0.mainnet.stacks.co:20444,02afeae522aab5f8c99a00ddf75fbcb4a641e052dd48836408d9cf437344b63516@seed-1.mainnet.stacks.co:20444,03652212ea76be0ed4cd83a25c06e57819993029a7b9999f7d63c36340b34a4e62@seed-2.mainnet.stacks.co:20444"

[burnchain]
chain = "bitcoin"
mode = "mainnet"
peer_host = "127.0.0.1"
username = "btcuser"
password = "btcpass"
rpc_port = 8332
peer_port = 8333
EOF'

replace seed and local_peer_seed with the privateKey value from the previous npx command

$ sudo bash -c 'cat <<EOF> /etc/stacks-blockchain/miner.toml
[node]
working_dir = "/stacks-blockchain"
rpc_bind = "0.0.0.0:20443"
p2p_bind = "0.0.0.0:20444"
bootstrap_node = "02da7a464ac770ae8337a343670778b93410f2f3fef6bea98dd1c3e9224459d36b@seed-0.mainnet.stacks.co:20444,02afeae522aab5f8c99a00ddf75fbcb4a641e052dd48836408d9cf437344b63516@seed-1.mainnet.stacks.co:20444,03652212ea76be0ed4cd83a25c06e57819993029a7b9999f7d63c36340b34a4e62@seed-2.mainnet.stacks.co:20444"
seed = "<npx privateKey>"
local_peer_seed = "<npx privateKey>"
miner = true
mine_microblocks = true
wait_time_for_microblocks = 10000

[burnchain]
chain = "bitcoin"
mode = "mainnet"
peer_host = "127.0.0.1"
username = "btcuser"
password = "btcpass"
rpc_port = 8332
peer_port = 8333
satoshis_per_byte = 100
#burn_fee_cap = 20000
burn_fee_cap = 450000

[miner]
first_attempt_time_ms = 5000
subsequent_attempt_time_ms = 180000
microblock_attempt_time_ms = 30000

[fee_estimation]
cost_estimator = "naive_pessimistic"
fee_estimator = "scalar_fee_rate"
cost_metric = "proportion_dot_product"
log_error = true
enabled = true
EOF'

Add stacks user and configure dirs

$ sudo useradd stacks
$ sudo chown -R stacks:stacks /stacks-blockchain/

Install stacks.service unit

$ sudo bash -c 'cat <<EOF> /etc/systemd/system/stacks.service
[Unit]
Description=Stacks Blockchain
Requires=bitcoin.service
After=bitcoin.service
ConditionFileIsExecutable=/usr/local/bin/stacks-node
ConditionPathExists=/stacks-blockchain/

[Service]
ExecStart=/bin/sh -c "/usr/local/bin/stacks-node start --config=/etc/stacks-blockchain/follower.toml >> /stacks-blockchain/follower.log 2>&1"
ExecStartPost=/bin/sh -c "umask 022; sleep 2 && pgrep -f \"/usr/local/bin/stacks-node start --config=/etc/stacks-blockchain/follower.toml\" > /run/stacks-blockchain/stacks.pid"
ExecStopPost=/bin/sh -c "if [ -f \"/run/stacks-blockchain/stacks.pid\" ]; then rm -f /run/stacks-blockchain/stacks.pid; fi"

# Process management
####################
Type=simple
PIDFile=/run/stacks-blockchain/stacks.pid
Restart=on-failure
TimeoutStopSec=600
KillSignal=SIGTERM

# Directory creation and permissions
####################################
# Run as bitcoin:bitcoin
User=stacks
Group=stacks
RuntimeDirectory=stacks-blockchain
RuntimeDirectoryMode=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

[Install]
WantedBy=multi-user.target
EOF'

Enable service and start stacks

$ sudo systemctl daemon-reload
$ sudo systemctl enable stacks.service
$ sudo systemctl start stacks.service
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment