Clementine provides a single binary, that can act as 3 different actors services:
- Verifier (We sometimes call this as signer)
- Operator
- Aggregator
These services communicate via gRPC and use a Postgresql database. They can be configured to share the same database.
An entity can choose to run these services on a single host to be a part of the peg-in and peg-out process. All the services that are run by a single entity should ideally share the same database. Typical entities are:
- Operator entity
- Runs both an operator and a verifier service
- Verifier entity
- Runs a verifier service
- Aggregator entity
- Runs both an aggregator and a verifier service
Before compiling Clementine:
-
Install Rust: rustup.rs
-
Install RiscZero (2.1.0): dev.risczero.com/api/zkvm/install
curl -L https://risczero.com/install | bash rzup install cargo-risczero 2.1.0 # Or v2.1.0 rzup install r0vm 2.1.0 rzup install rust 1.85.0
-
If on Mac, install XCode and its app from AppStore (if
xcrun metalgives an error):xcode-select --install
-
If on Ubuntu, install these packages:
sudo apt install build-essential libssl-dev pkg-config
Before running Clementine:
-
Install and configure a Bitcoin node (at least v29.0)
-
Install and configure PostgreSQL. Using docker:
docker run --name clementine-test-db \ -e POSTGRES_USER=clementine \ -e POSTGRES_PASSWORD=clementine \ -e POSTGRES_DB=clementine \ -p 5432:5432 \ --restart always \ -d postgres:15 \ bash -c "exec docker-entrypoint.sh postgres -c 'max_connections=1000'" -
Install RISC Zero toolchain:
cargo install cargo-risczero
-
[Optional] TLS certificates required to start and connect to a Clementine server. For tests, these are automatically generated, if not present. Please check RPC Authentication and Security Considerations sections when generating certificates for a deployment.
./scripts/generate_certs.sh
-
Set
RISC0_DEV_MODEenvironment variable if tests are going to be run or deployment that requires it:export RISC0_DEV_MODE=1 -
[Optional] Download pre-generated BitVM cache. If not downloaded, it will be generated automatically.
wget https://static.testnet.citrea.xyz/common/bitvm_cache_v3.bin -O bitvm_cache.bin wget https://static.testnet.citrea.xyz/common/bitvm_cache_dev.bin -O bitvm_cache_dev.bin export BITVM_CACHE_PATH=/path/to/bitvm_cache.bin # If RISC0_DEV_MODE is not set export BITVM_CACHE_PATH=/path/to/bitvm_cache_dev.bin # If RISC0_DEV_MODE is set
-
Set
RUST_MIN_STACKenvironment variable to at least33554432# On Unix-like systems: export RUST_MIN_STACK=33554432
Clementine can be configured to enable automation at build-time via the
automation feature. The automation feature enables the State Manager and
Transaction Sender which automatically fulfills the duties of
verifier/operator/aggregator entities. It also enables automatic sending and
management of transactions to the Bitcoin network via Transaction Sender.
cargo build --release --features automationClementine supports two runtime primary configuration methods:
- Configuration Files: Specify main configuration and protocol parameters via TOML files
- Environment Variables: Configure the application entirely through environment variables
Running the binary as a verifier, aggregator, or operator requires a
configuration file. An example configuration file is located at
core/src/test/data/bridge_config.toml and can
be taken as reference. Please copy that configuration file to another location
and modify fields to your local configuration.
Additionally, Clementine requires protocol parameters, that are either specified
by a file or from the environment. You can specify a separate protocol
parameters file using the --protocol-params option. This file contains
protocol-specific settings that affect transactions in the contract.
It is also possible to use environment variables instead of configuration files.
The .env.example file can be taken as a reference for this matter.
Clementine uses the following logic to determine the configuration source:
-
Main Configuration:
- If
READ_CONFIG_FROM_ENV=1orREAD_CONFIG_FROM_ENV=on, configuration is read from environment variables - If
READ_CONFIG_FROM_ENV=0orREAD_CONFIG_FROM_ENV=offor not set, configuration is read from the specified config file
- If
-
Protocol Parameters:
- If
READ_PARAMSET_FROM_ENV=1orREAD_PARAMSET_FROM_ENV=on, protocol parameters are read from environment variables - If
READ_PARAMSET_FROM_ENV=0orREAD_PARAMSET_FROM_ENV=offor not set, protocol parameters are read from the specified protocol parameters file
- If
You can mix these approaches - for example, reading main configuration from a file but protocol parameters from environment variables.
Clementine uses mutual TLS (mTLS) to secure gRPC communications between entities and to authenticate clients. Client certificates are verified and filtered by the verifier/operator to ensure that:
- Verifier/Operator methods can only be called by the aggregator (using
aggregator's client certificate
aggregator_cert_path) - Internal methods can only be called by the entity's own client certificate
(using the entity's client certificate
client_cert_path)
The aggregator does not enforce client certificates but does use TLS for encryption.
Before running the servers, you need to generate certificates. A script is provided for this purpose:
# Run from the project root
./scripts/generate_certs.shThis will create certificates in the following structure:
certs/
├── ca/
│ ├── ca.key # CA private key
│ └── ca.pem # CA certificate
├── server/
│ ├── ca.pem # Copy of CA certificate (for convenience)
│ ├── server.key # Server private key
│ └── server.pem # Server certificate
├── client/
│ ├── ca.pem # Copy of CA certificate (for convenience)
│ ├── client.key # Client private key
│ └── client.pem # Client certificate
└── aggregator/
├── ca.pem # Copy of CA certificate (for convenience)
├── aggregator.key # Aggregator private key
└── aggregator.pem # Aggregator certificate
Note
For production use, you should use certificates signed by a trusted CA rather than self-signed ones.
Clementine is designed to be run multiple times for every actor that an entity requires. An actor's server can be started using its corresponding argument. Please follow instruction steps before trying to start a server.
# Build the binary (with optional automation)
cargo build --release [--features automation]
# Run binary with configuration file
./target/release/clementine-core verifier --config /path/to/config.toml
./target/release/clementine-core operator --config /path/to/config.toml
./target/release/clementine-core aggregator --config /path/to/config.toml
# Run with both configuration and protocol parameter files
./target/release/clementine-core verifier --config /path/to/config.toml --protocol-params /path/to/params.toml
# Run with environment variables
READ_CONFIG_FROM_ENV=1 READ_PARAMSET_FROM_ENV=1 ./target/release/clementine-core verifier
# Mixing configuration sources
READ_CONFIG_FROM_ENV=0 READ_PARAMSET_FROM_ENV=1 ./target/release/clementine-core verifier --config /path/to/config.tomlA server's log level can be specified with --verbose flag:
./target/release/clementine-core operator --config /path/to/config.toml --verbose 5 # Logs everythingSetting RUST_LIB_BACKTRACE to full will enable full backtraces for errors
RUST_LIB_BACKTRACE=full ./target/release/clementine-core operator --config /path/to/config.tomlFor more information, use --help flag:
./target/release/clementine-core --helpA docker image is provided in Docker Hub. It can also be locally built with:
docker build -f scripts/docker/Dockerfile -t clementine:latest .Also, there are multiple Docker compose files located at scripts/docker/ which can be used to start Bitcoin, PostgreSQL, Citrea and Clementine. Config files for these compose files can be found at scripts/docker/configs/. They are configured for a typical deployment and needs modification before deployment. Please note that, apart from regtest, new wallet that is created won't have any funds and users are responsible for configuring their own address.
docker compose -f scripts/docker/docker-compose.verifier.testnet4.yml up
docker compose -f scripts/docker/docker-compose.full.regtest.yml upTo run all tests:
cargo test --all-featuresAlso, due to the test directory hierarchy, unit and integration tests can be run separately:
cargo test_unit
cargo test_integrationThere are handful amount of scripts in scripts/ directory. Most of them are for testing but still can be used for setting up the environment. They can change quite frequently. So, please check for useful ones.
Each script should have a name and comment inside that explain its purpose.
To debug tokio tasks, you can uncomment the console-subscriber dependency in Cargo.toml and the console_subscriber::init(); line in src/utils.rs. Then, rebuild the project with cargo build_console which is an alias defined with the necessary flags.
cargo build_consoleAfter running Clementine, you can access the console by running the following command:
tokio-console- Keep private keys (*.key) secure and don't commit them to version control
- In production, use properly signed certificates from a trusted CA
- Rotate certificates regularly
- Consider using distinct client certificates for different clients/services