This document covers the deployment of a secure Covenant Signer setup, following the proposed Architecture.
The architecture contains the following components that need to be deployed:
- Covenant Signer: A publicly reachable server which receives unbonding transactions and returns the same transactions signed by the covenant emulator's key
- bitcoind Offline Wallet: A server containing a single wallet that hosts a single Covenant emulator BTC key; the server is used for signing unbonding transactions forwarded by the Covenant Signer
- bitcoind Full Node: A Bitcoin full node used to verify whether the to-be-unbonded staking transaction has already been submitted to Bitcoin and has the required amount of BTC confirmations
For a production system, we strongly recommend that the bitcoind Offline Wallet and Full Node are distinct bitcoind instances operating on different hosts. For a PoC/testnet setup, one bitcoind instance can serve as both the entities, or both bitcoind instances can run on the same host.
The installation, configuration, and boot steps for the bitcoind Offline Wallet and Full Node are almost identical. We combine them here for brevity. In the next section, we will provide more details on how to perform certain operations on the bitcoind Offline Wallet.
Offline Wallet:
- An instance with at least 4G RAM and 2 vCPUs is expected
- At least 10G of persistent storage should be available for the BTC Wallet
Full Node:
- An instance with at least 4G RAM and 2 vCPUs is expected
- Depending on the BTC network, enough storage to host the complete Bitcoin ledger should be attached (800G for the Mainnet, 100G for the Testnet3, 50G for the Signet)
Notes on storage
- The underlying storage for the offline wallet should be encrypted.
- Both the bitcoind Offline Wallet and Full Node servers should be frequently
backed up on a filesystem level to ensure continuous operation in case of
failure / data corruption.
- We suggest a rolling backup method comprising hourly, daily and weekly backups.
- The bitcoind Offline Wallet is only reachable from the Covenant Signer at the designated BTC RPC port
- The bitcoind Offline Wallet accepts only TLS traffic
- The bitcoind Offline Wallet lives on a private network and doesn't have internet access
Same with the bitcoind Offline Wallet, but the Node should have internet access to sync the BTC ledger.
Download and install the bitcoin binaries according to your operating system
from the official
Bitcoind Core registry.
All programs in this guide are compatible with version 26.0
.
bitcoind is configured through a main configuration file named bitcoin.conf
.
Depending on the operating system, the configuration file should be placed under the corresponding path:
- MacOS:
/Users/<username>/Library/Application Support/Bitcoin
- Linux:
/home/<username>/.bitcoin
- Windows:
C:\Users\<username>\AppData\Roaming\Bitcoin
Both servers can utilize the following base parameter skeleton (adapted for the BTC signet network):
# Accept command line and JSON-RPC commands
server=1
# Enable transaction indexing
txindex=1
# RPC server settings
rpcuser=<rpc-username>
rpcpassword=<rpc-password>
# Optional: In case of non-mainnet BTC node,
# the following two lines specify the network that your
# node will operate; for this example, utilizing signet
signet=1
[signet]
# Port your bitcoin node will listen for incoming requests;
# below port is the canonical port for signet,
# for mainnet, typically 8332 is used
rpcport=38332
# Address your bitcoin node will listen for incoming requests
rpcbind=0.0.0.0
# Optional: Needed for remote node connectivity
rpcallowip=0.0.0.0/0
It's very important to ensure that the Offline Wallet server does not connect with other nodes. To achieve this, append the following to the end of the Offline Wallet server's configuration:
# IMPORTANT: Offline Wallet server shouldn't connect to any external node
connect=0
Notes:
- In case both your bitcoind Offline Wallet and Full Node servers run on the same node (not recommended, please check the infrastructure guidelines), you'll need to use different, non-default directories for each server.
- Instead of hardcoding the RPC server password (
rpcpassword
) in the config, it is recommended to generate its salted hash and use therpcauth
field instead. To generate the salted hash, you can use this platform as reference - however, the salting operation should be executed locally. The resulting config value will look like this:rpcauth=<rpc-password-salted-hash>
- In case you will be connecting to BTC Mainnet network, ensure to remove the
following config skeleton lines:
signet=1 [signet]
In case you're using the default bitcoind home directory, you can boot your bitcoind server by simply running:
bitcoind
In case you're using a non-default home directory:
bitcoind -datadir=/path/to/bitcoin/home
For Linux systems, you can persist each bitcoind server startup process through the following process.
-
Create a systemd service definition
# Create the service file sudo tee /etc/systemd/system/bitcoind.service >/dev/null <<EOF [Unit] Description=bitcoin signet node After=network.target [Service] User=<user> Type=simple ExecStart=/path/to/bitcoind \ -datadir=/path/to/bitcoin/home Restart=on-failure LimitNOFILE=65535 [Install] WantedBy=multi-user.target EOF
-
Start the service
sudo systemctl daemon-reload sudo systemctl enable bitcoind sudo systemctl start bitcoind
The bitcoind server availability can be polled through Prometheus Blackbox Exporter.
Bitcoin-specific Prometheus metrics can also be exposed by utilizing any open-source Prometheus bitcoind exporter (example).
The following operations should be performed by the bitcoind offline wallet so that it can be used by the covenant signer.
The bitcoind Offline Wallet server will host a descriptor BTC wallet. This wallet will contain a single address, whose private key will be used as the Covenant BTC key to sing PSBTs.
Throughout this whole process, the bitcoind Offline Wallet should not have internet access.
-
Create the wallet
bitcoin-cli -named createwallet \ wallet_name=<wallet_name> \ passphrase="<passphrase>" \ load_on_startup=true \
Flags explanation:
wallet_name
: The name of the walletpassphrase
: The passphrase that will be used to encrypt the wallet (IMPORTANT, MUST BE SAFELY STORED)load_on_startup=true
: Ensures that the wallet is automatically loaded in case of server restart
-
Create a new address
# Save the output of this command bitcoin-cli getnewaddress
-
Obtain 33-byte BTC public key derived from the above address
bitcoin-cli getaddressinfo <btc_address> | jq -r .pubkey
Notes:
- In case you used a non-default bitcoin home directory, also include the
-datadir=/path/to/bitcoin/home
flag in all the abovebitcoin-cli
commands. - The BTC public key of the covenant should be included in the global parameters of the network you operate in order for your covenant emulator to be included in the committee.
The Covenant Signer expects that the bitcoind Offline Wallet is unlocked when trying to contact it. To this end, you'll need to manually unlock the wallet before proceeding with the Covenant Signer setup.
To unlock the wallet, execute the following command:
bitcoin-cli walletpassphrase "<passphrase>" <unlock_time>
where:
passphrase
: The wallet passphrase specified during the wallet creation stepunlock_time
: How long (in seconds) the wallet will remain unlocked for
Notes:
- You can either unlock the wallet for a long period of time, or set up an automation to unlock it periodically for shorter time periods. In the latter case, the automation will require secure access to the wallet passphrase.
- In case of server restart, the wallet will need to be unlocked again.
For the bitcoind wallet, bitcoin-level backups can also be obtained through the following process.
# Backup the wallet
bitcoin-cli -rpcwallet=<wallet-name> backupwallet /path/to/backup/wallet.dat
# Restore the wallet
bitcoin-cli restorewallet <wallet-name> /path/to/backup/wallet.dat
Note: We recommend creating multiple backups of the wallet and storing them in separate places.
- An instance with at least 4G RAM and 2 vCPUs is expected
- The component can be horizontally scaled with traffic being load-balanced behind a reverse proxy
- The Covenant Signer is publicly reachable on the configured server port
- The port accepts only TLS traffic (can be achieved by exposing the Covenant Signer through a reverse proxy)
- Ideally, the Covenant Signer is also protected against DDoS attacks
- Ideally, request size is also limited at reverse proxy level
This project requires Go version 1.21 or later.
Install Go by following the instructions on the official Go installation guide.
To get started, clone the repository to your local machine from GitHub; please use the version according to the phase-1 system guidelines -- you can find all versions in the official releases page.
git clone https://github.com/babylonlabs-io/covenant-signer.git
cd covenant-signer
git checkout <release-tag>
At the top-level directory of the project
make install
The above command will build and install the covenant-signer
binary to
$GOPATH/bin
, which is the daemon program for the Covenant Signer server.
If your shell cannot find the installed binaries, make sure $GOPATH/bin
is in
the $PATH
of your shell. The following updates to $PATH
can be performed to
this direction:
export PATH=$HOME/go/bin:$PATH
echo 'export PATH=$HOME/go/bin:$PATH' >> ~/.profile
The default configuration file (config.toml
) should be dumped using the
following command:
covenant-signer dump-cfg
Depending on the operating system, the configuration file will be placed under the corresponding path:
- MacOS:
/Users/<username>/Library/Application Support/Signer
- Linux:
/home/<username>/.signer
- Windows:
C:\Users\<username>\AppData\Local\Signer
Some important configuration file parameters are listed below:
#### Parameters related to the bitcoind full node
[btc-config]
# Btc node host
host = <bitcoind_full_node_endpoint>
# Btc node user
user = <bitcoind_full_node_username>
# Btc node password
pass = <bitcoind_full_node_password>
# Btc network (testnet3|mainnet|regtest|signet)
network = <btc_network>
#### Parameters related to the bitcoind wallet
[btc-signer-config]
# Btc node host
host = <bitcoind_wallet_endpoint>
# Btc node user
user = <bitcoind_wallet_username>
# Btc node password
pass = <bitcoind_wallet_password>
# Btc network (testnet3|mainnet|regtest|signet)
network = <btc_network>
#### Parameters related to the Covenant Signer server
[server-config]
# The address to listen on
host = "127.0.0.1"
# The port to listen on
port = 9791
# Max content length in bytes
max-content-length = 8192
#### Parameters related to the Prometheus metrics server
[metrics]
# The prometheus server host
host = "127.0.0.1"
# The prometheus server port
port = 2112
The Covenant Signer also consumes an additional configuration file containing
global parameters (global-params.json
), i.e. parameters which are shared
between several services of the Babylon BTC Staking system. The file resides
under the same directory as config.toml
.
The global parameters can be obtained from the parameters registry found here. The parameters will be fully specified once all covenant committee participants share their keys.
To start the Covenant Signer, execute the following:
covenant-signer start --config /path/to/signer/home/config.toml \
--params /path/to/signer/home/global-params.toml
Post-boot, the following log is emitted:
{"level":"info","time":"2024-05-07T17:16:18Z","message":"Starting server on 0.0.0.0:9791"}
A successful signing request emits the following log pair:
{"level":"debug","path":"/v1/sign-unbonding-tx","traceId":"5b1872eb-6ec6-4d05-bbc9-f88728e3fb72","time":"2024-05-07T19:01:40Z","message":"request received"}
{"level":"info","path":"/v1/sign-unbonding-tx","traceId":"5b1872eb-6ec6-4d05-bbc9-f88728e3fb72","tracingInfo":{"SpanDetails":null},"requestDuration":42,"time":"2024-05-07T19:01:40Z","message":"Request completed"}
The service exposes Prometheus metrics through a Prometheus server. By default,
the server is reachable under 127.0.0.1:2112
.
The following metrics are exposed:
signer_received_signing_requests
: The total number of signing requests received by the serversigner_succeeded_signing_requests
: The total number times the signer successfully responded with a signaturesigner_failed_signing_requests
: The total number of times signer responded with an internal error
These metrics can be scraped by a Prometheus instance.
A simple Prometheus alerting rule to check for failed signing request follows below:
signer_failed_signing_requests - signer_failed_signing_requests offset 60m > 0
Healthchecks should be configured on the /v1/sign-unbonding-tx
server HTTP
endpoint. By default, the server is reachable under 127.0.0.1:9791
.
One approach to perform HTTP/S healthchecks and expose results in the form of Prometheus metrics is the Prometheus Blackbox Exporter.
These metrics can then be scraped by a Prometheus instance.