From 7518a78015c7e0dd3419aa49467676df57e12f08 Mon Sep 17 00:00:00 2001 From: Sam Ricotta Date: Fri, 15 Nov 2024 12:10:55 +0200 Subject: [PATCH 01/53] Update README.md From c7c64a5832fed6f41b6d03ddea54d7d673bb46b3 Mon Sep 17 00:00:00 2001 From: Sam Ricotta Date: Fri, 15 Nov 2024 12:42:33 +0200 Subject: [PATCH 02/53] Update README.md --- README.md | 698 +++++++++++++++++++++++++++++++++++++++++++++++------- 1 file changed, 614 insertions(+), 84 deletions(-) diff --git a/README.md b/README.md index 4d10096..1ed54e5 100644 --- a/README.md +++ b/README.md @@ -1,119 +1,649 @@ -# Finality Provider +# Finality Provider Phase 2 Migration Guide -A toolset crafted for the creation and -management of Finality Providers. +This guide covers the Phase 2 launch of the Babylon network, +a critical transition that introduces active participation +in finality voting, rewards distribution, and the Proof of +Stake (PoS) system. This migration represents a shift from +the limited role of finality providers in Phase 1 to a fully +active role in network security and governance in Phase 2. +This guide provides a step-by-step process for operators to +onboard, whether setting up anew or using a pre-existing setup, +with a focus on Phase 2-specific requirements. -## 1. Overview +The following explains the migration from Phase 1 to 2. -Finality providers are responsible for voting -at a finality round on top of [CometBFT](https://github.com/cometbft/cometbft). -Similar to any native PoS validator, -a finality provider can receive voting power delegations from BTC stakers, and -can earn commission from the staking rewards denominated in Babylon tokens. -The core logic of a finality provider instance can be found in -[Finality Provider Core](./docs/fp-core.md). +## Phase 1 (Previous phase) -The finality provider toolset does not have -any special hardware requirements -and can operate on standard mid-sized machines -running a UNIX-flavored operating system. -It consists of the following programs: +- Only involves Bitcoin holders submitting staking transactions +- No active Proof of Stake (PoS) chain operation +- Finality providers only need EOTS keys registered +- No need to run finality service -- *Babylon full node*: An instance of a Babylon node connecting to - the Babylon network. Running one is not a strict requirement, - but it is recommended for security compared to trusting a third-party RPC node. -- *Extractable One-Time Signature (EOTS) manager*: - A daemon responsible for securely maintaining the finality provider’s - private key and producing extractable one time signatures from it. -- *Finality Provider*: A daemon managing the finality provider. - It connects to the EOTS manager to generate EOTS public randomness and - finality votes for Babylon blocks, which it submits to Babylon through - the node connection. +## Phase 2 (New phase) -The following graphic demonstrates the interconnections between the above programs: +- Active participation in finality voting +- Running the complete finality provider toolset: + - Babylon full node + - EOTS manager daemon + - Finality provider daemon +- Earning commissions from delegations +- Proof of Stake (PoS) and network security +- Rewards distribution +- Participating in governance -![Finality Provider Interconnections](./docs/finality-toolset.png) +There are 2 different types of paths for Finality providers -## 2. Installation +1. **New Setup** + - For operators starting fresh + - Need to generate both EOTS and FP keys + - Complete full configuration process -### Prerequisites +If you are a new operator, start with the +[Install Finality Provider Binary](#install-finality-provider-binary) section. -This project requires Go version 1.23 or later. + 2. **Has existing EOTS Key** + - Already have EOTS key from Phase 1 + - Reference existing EOTS key in setup -Install Go by following the instructions on -the [official Go installation guide](https://golang.org/doc/install). +If you have an existing EOTS key from Phase 1 please skip to +[Loading Existing Keys](#loading-existing-keys-only-for-phase-1-finality-providers) +steps -### Downloading the code +For an introduction on the finality providers see (here) + -To get started, clone the repository to your local machine from Github: +## Install Finality Provider Binary + +Download [Golang 1.21](https://go.dev/dl)  -```bash -git clone https://github.com/babylonlabs-io/finality-provider.git +Download and install Golang 1.21. Verify the installation with the following command: + +```shell +go version +``` + +### Step 1: Clone the Finality Provider Repository + +Subsequently Clone the finality provider +[repository](https://github.com/babylonlabs-io/finality-provider) and navigate to the +`bbn-testnet-5` tag. + +```shell +git clone https://github.com/babylonchain/finality-provider.git +cd finality-provider +git checkout +``` + +### Step 2: Build and Install Finality Provider Binaries + +Run: +```shell +make install +``` + +This command will: +- Build and compile all Go packages +- Install binaries to `$GOPATH/bin`: + - `eotsd`: EOTS manager daemon + - `fpd`: Finality provider daemon + - `fpcli`: Finality provider CLI tool +- Make commands globally accessible from your terminal + +### Step 3: Verify Installation + +Run `eotsd` to check the available actions: + +```shell +eotsd +``` + +Sample output: + +```shell +NAME: + eotsd - Extractable One Time Signature Daemon (eotsd). + +USAGE: + eotsd [global options] command [command options] [arguments...] + +COMMANDS: + start Start the Extractable One Time Signature Daemon. + init Initialize the eotsd home directory. + sign-schnorr Signs a Schnorr signature over arbitrary data with +... +``` + +If your shell cannot find the installed binaries, make sure `$GOPATH/bin` is in +the `$PATH` of your shell. Usually these commands will do the job + +```shell +export PATH=$HOME/go/bin:$PATHecho 'export PATH=$HOME/go/bin:$PATH' >> +~/.profile +``` + +## Install Babylon Binary + +Clone the Babylon [repository](https://github.com/babylonlabs-io/babylon) and +checkout the `bbn-testnet-5` tag: + +```shell +git clone git@github.com:babylonlabs-io/babylon.git +cd babylon +git checkout ``` -You can choose a specific version from -the [official releases page](https://github.com/babylonlabs-io/finality-provider/releases) +### Step 1: Build and Install the Babylon Binary -```bash -cd finality-provider # cd into the project directory -git checkout +Run: +```shell +make install ``` -### Building and installing the binary +This command will: +- Build and compile all Go packages +- Install binary to `$GOPATH/bin`: + - `babylond`: Babylon network daemon +- Make command globally accessible from your terminal + +### Step 2: Verify Installation -At the top-level directory of the project +Run `babylond` to see the available commands: -```bash -make install +```shell +babylond ``` -The above command will build and install the following binaries to -`$GOPATH/bin`: +Sample output: -- `eotsd`: The daemon program for the EOTS manager. -- `fpd`: The daemon program for the finality-provider with overall commands. +```shell +Available Commands: + add-genesis-account Add a genesis account to genesis.json + collect-gentxs Collect genesis txs and output a genesis.json file + comet CometBFT subcommands + config Utilities for managing application configuration ... +``` -If your shell cannot find the installed binaries, make sure `$GOPATH/bin` is in -the `$PATH` of your shell. Usually these commands will do the job +If your shell cannot find the installed binaries, make sure `$GOPATH/bin`  +is in the `$PATH` of your shell. The following command should help this issue. -```bash +```shell export PATH=$HOME/go/bin:$PATH echo 'export PATH=$HOME/go/bin:$PATH' >> ~/.profile ``` -## 3. Setting up a finality provider +## Connecting to a Babylon Node -### 3.1. Setting up a Babylon Full Node +To operate as a finality provider, the Finality Provider program must be connected +to a Babylon node. It is highly recommended for each finality provider to set up +their own node to ensure network reliability and direct access to network updates. -Before setting up the finality provider toolset, -an operator must ensure a working connection with a Babylon full node. -It is highly recommended that operators run their own node to avoid -trusting third parties. Instructions on how to set up a full Babylon node -can be found in -[the Babylon documentation](https://docs.babylonchain.io/docs/user-guides/btc-staking-testnet/setup-node). +For detailed instructions on setting up a Babylon node, please refer to the +[Setting up a Node](https://github.com/babylonlabs-io/networks/syncing-a-node) +section of the Babylon Networks repository. -### 3.2. Setting up the EOTS Manager +## Setting up the EOTS Manager -After a node and a keyring have been set up, -the operator can set up and run the +>Note: If you have already set up an EOTS Manager, you can skip this section. +The following steps are only for users who have not yet set up an EOTS Manager. +Phase 1 users who already have an EOTS Manager set up can skip to the +[Loading Existing Keys](#loading-existing-keys-only-for-phase-1-finality-providers) +section at the end of this guide for specific instructions +on re-using their Phase 1 EOTS keys. + +After a node and a keyring have been set up, the operator can set up and run the Extractable One Time Signature (EOTS) manager daemon. -A complete overview of the EOTS manager, its operation, and -its configuration options can be found in the -[EOTS Manager page](docs/eots.md) - -### 3.3. Setting up a Finality Provider - -The last step is to set up and run -the finality daemon. -A complete overview of the finality daemon, its operation, and -its configuration options can be found in the -[Finality page](docs/finality-provider.md). - -## 4. Delegations & Rewards - -A finality provider receives BTC delegations through delegators -interacting with Babylon and choosing it as the recipient of their delegations. -To perform a self-delegation, -the operator can either visit the staking web app we provide, -or run the Babylon [BTC Staker program](https://github.com/babylonlabs-io/btc-staker) once. -The BTC staker connects to a Bitcoin wallet and Babylon to perform delegations. + +The EOTS daemon is responsible for managing EOTS keys, producing EOTS +randomness, and using them to produce EOTS signatures. To read more on the EOTS +Manager see [here](#) + +### Step 1: Initialize the EOTS Manager + +Use the `eotsd init` command to initialize a home directory for the EOTS Manager. +You can set or change your home directory using the `--home` tag. For example, use +`--home ./eotsKey` to specify a custom directory. + +```shell +eotsd init --home +``` + +### Step 2: Create an EOTS Key + +Once the EOTS Manager is initialized, you need to create an EOTS key: + +``` shell +eotsd keys add --key-name --home +``` + +You will be prompted to enter and confirm a passphrase. +Ensure this is completed before starting the daemon. + +Sample output: + +```json +{ + "name": "eots", + "pub_key_hex": + "e1e72d270b90b24f395e76b417218430a75683bd07cf98b91cf9219d1c777c19", + "mnemonic": "parade hybrid century project toss gun undo ocean exercise + figure decorate basket peace raw spot gap dose daring patch ski purchase + prefer can pair" +} +``` + +## Loading Existing Keys (Only for Phase 1 Finality Providers) + +Note: This section is only for users who participated in Phase 1 and already +have an EOTS key. If you are a new user, you can skip this section. + +If you participated in Phase 1, follow these steps to load your existing EOTS +key and configure it for Phase 2. + +### Step 1: Verify Your EOTS Key Backup +Before proceeding, ensure you have a backup of your Phase 1 EOTS key. +You will need this backup file to import the key into the Phase 2 environment. + +### Step 2: Import Your EOTS Key into the Keyring +To load your existing EOTS key, use the following command to import it into the +keyring: + +```shell +eotsd keys import +``` + +- ``: The name you want to assign to this key in Phase 2. +- ``: The path to your EOTS key backup file from Phase 1. + +## Starting the EOTS Daemon + +You will need to navigate to the You can start the EOTS daemon using the following command: + +```shell +eotsd start --home +``` + +This command starts the EOTS RPC server at the address specified in eotsd.conf +under the RpcListener field (default: 127.0.0.1:12582). You can override this value +by specifying a custom address with the --rpc-listener flag. + +```shell +2024-10-30T12:42:29.393259Z info Metrics server is starting +{"addr": "127.0.0.1:2113"} +2024-10-30T12:42:29.393278Z info RPC server listening {"address": "127.0.0.1:12582"} +2024-10-30T12:42:29.393363Z info EOTS Manager Daemon is fully active! +EOTS Manager Daemon is fully active! +``` + +>**Note**: It is recommended to run the `eotsd` daemon on a separate machine or +network segment to enhance security. This helps isolate the key management +functionality and reduces the potential attack surface. You can edit +the`EOTSManagerAddress` in the configuration file of the finality provider to +reference the address of the machine where `eotsd` is running. + +## Setting up the Finality Provider + +The Finality Provider Daemon (FPD) is responsible for monitoring new Babylon blocks, +committing public randomness for the blocks it intends to provide finality signatures for, +and submitting finality signatures. For more information on Finality Providers, please see +[here](#). + +### Step 1: Initialize the Finality Provider Daemon + +Use the fpd init command to initialize a home directory for the Finality Provider. +You can set or change the home directory using the `--home` tag. For example, use +`--home ./fpKeys` to specify a custom directory. + +```shell +fpd init --home +``` + +>Note: Running this command may return the message +`service injective.evm.v1beta1.Msg does not have cosmos.msg.v1.service proto annotation`, +which is expected and can be ignored. + +### Step 2: Add a Key for the Finality Provider on the Babylon Chain + +The Finality Provider Daemon uses a keyring to store keys locally, enabling it to sign +transactions on the Babylon chain. + +Add a key for your finality provider: + +```shell +Copy code +fpd keys add --keyname --keyring-backend test --home +--keyring-backend +``` + +Options: +- `test`: Stores keys unencrypted on disk. This is suitable for testing but not recommended +for production. +- `file`: Stores encrypted keys on disk, offering more security than the test option. +- `os`: Uses the operating system's native keyring for the highest level of security, +relying on OS-managed encryption and access controls. + +The command will create a new key pair and store it in your keyring. Sample output: + +```shell +- address: bbn19gulf0a4yz87twpjl8cxnerc2wr2xqm9fsygn9 + name: finality-provider + pubkey: '{"@type":"/cosmos.crypto.secp256k1.PubKey", + "key":"AhZAL00gKplLQKpLMiXPBqaKCoiessoewOaEATKd4Rcy"}' + type: local +``` + +>Note: Verify the chain-id by checking the Babylon RPC node status at +[https://rpc.testnet5.babylonlabs.io/status](https://rpc.testnet5.babylonlabs.io/status). + +### Step 3: Configure fpd.config + +After initializing the Finality Provider Daemon, it will generate an fpd.config file. +Open config.toml to set the necessary parameters as shown below: + +```shell +[Application Options] +EOTSManagerAddress = 127.0.0.1:12582 +RpcListener = 127.0.0.1:12581 + +[babylon] +Key = # the key you used above +ChainID = bbn-test-5 +RPCAddr = http://127.0.0.1:26657 +GRPCAddr = https://127.0.0.1:9090 +KeyDirectory = ./fpKey +``` + +The Key field stores the name of the key used for signing transactions on the +Babylon chain and should match the key name specified during key creation. +KeyDirectory points to the location where the keyring is stored. + +The Finality Provider Daemon is responsible for monitoring for new Babylon +blocks, committing public randomness for the blocks it intends to provide +finality signatures for, and submitting finality signatures. To read more on +Finality Providers please see [here](#) + + +The `fpd init` command initializes a home directory for the EOTS manager. You +can wish to set/change your home directory with the `--home` tag. For the home +`` we have used `./fpKey` + +``` shell +fpd init --home +``` + +Note: will return +`service injective.evm.v1beta1.Msg does not have cosmos.msg.v1.service proto annotation` +which is expected and can be ignored. + +### Step 4: Add key for the finality provider on the Babylon chain + +The keyring is maintained by the finality provider daemon, this is local storage +of the keys that the daemon uses. The account associated with this key exists on +the babylon chain. + +Use the following command to add a key for your finality provider: + +```shell +fpd keys add --keyname --keyring-backend test --home +``` + +We use `--keyring-backend test`, which specifies which backend to use for the +keyring, `test` stores keys unencrypted on disk. For production environments, +use `file` or `os` backend. + + + There are three options for the keyring backend: + + `test`: Stores keys unencrypted on disk. It’s meant for testing purposes and + should never be used in production. `file`: Stores encrypted keys on disk, + which is a more secure option than test but less secure than using the OS + keyring. `os`: Uses the operating system's native keyring, providing the + highest level of security by relying on OS-managed encryption and access + controls. + +This command will create a new key pair and store it in your keyring. The output +should look similar to the below. + +``` shell +- address: bbn19gulf0a4yz87twpjl8cxnerc2wr2xqm9fsygn9 + name: finality-provider pubkey: + '{"@type":"/cosmos.crypto.secp256k1.PubKey", + "key":"AhZAL00gKplLQKpLMiXPBqaKCoiessoewOaEATKd4Rcy"}' + type: local +``` + +>Note: Please verify the `chain-id` from the Babylon RPC +node [https://rpc.testnet5.babylonlabs.io/status] +(https://rpc.testnet5.babylonlabs.io/status) + + >The configuration below requires to point to the path where this keyring is + stored `KeyDirectory`. This `Key` field stores the key name used for + interacting with the babylon chain and will be specified along with + the `KeyringBackend`field in the next step. So we can ignore the setting of the + two fields in this step. + +Once the node is initialized with the above command. It should generate a +`fpd.config` Edit the `config.toml` to set the necessary parameters with the +below + +```shell +[Application Options] EOTSManagerAddress = 127.0.0.1:12582 RpcListener += 127.0.0.1:12581 + +[babylon] Key = // the key you used above +ChainID = bbn-test-5 RPCAddr = http://127.0.0.1:26657 GRPCAddr = +https://127.0.0.1:9090 KeyDirectory = ./fpKey +``` + +### Step 3: Verify the Key Import +After importing, verify that your EOTS key was successfully loaded: + +```shell +eotsd keys list +``` + +You should see your EOTS key listed with the correct details, confirming that +it has been imported correctly. + +>Note: Make sure you're using the same key name and EOTS public key that were +registered in Phase 1. + + +## Starting the Finality provider Daemon + +The finality provider daemon (FPD) needs to be running before proceeding with +registration or voting participation. + +Start the daemon with: + +``` shell +fpd start --home ./fp +``` + +The command flags: +- `start`: Initiates the FPD daemon +- `--home`: Specifies the directory for daemon data and configuration + +The daemon will start the RPC server for CLI communication then begin listening +for incoming requests and finally initialize finality provider services + +You should see logs indicating successful startup: + +``` +[INFO] Starting finality provider daemon... +[INFO] RPC server listening on... +``` + +>Note: Keep this terminal window open as the daemon needs to run continuously. + +The above will start the Finality provider RPC server at the address specified +in `fpd.conf` under the `RpcListener` field, which has a default value +of `127.0.0.1:12581`. You can change this value in the configuration file or +override this value and specify a custom address using +the `--rpc-listener` flag. + +To start the daemon with a specific finality provider instance, use +the `--btc-pk` flag followed by the hex string of the BTC public key of the +finality provider (`btc_pk_hex`) in the next step + +All the available CLI options can be viewed using the `--help` flag. These +options can also be set in the configuration file. + +## Create Finality Provider + +The `create-finality-provider` command initializes a new finality provider +instance locally. This command: + +- Generates a BTC public key that uniquely identifies your finality provider +- Creates a Babylon account to receive staking rewards + +``` shell +fpd create-finality-provider \ --daemon-address 127.0.0.1:12581 \ --chain-id +bbn-test-5 \ --commission 0.05 \ --key-name finality-provider \ --moniker +"MyFinalityProvider" \ --website "https://myfinalityprovider.com" \ +--security-contact "security@myfinalityprovider.com" \ --details "finality +provider for the Babylon network" \ --home ./fp \ --passphrase "passphrase" +``` + +Required parameters: - `--chain-id`: The Babylon chain ID (`bbn-test-5`) - +`--commission`: The commission rate (between 0 and 1) that you'll receive from +delegators - `--key-name`: Name of the key in your keyring for signing +transactions - `--moniker`: A human-readable name for your finality provider + +Optional parameters: - `--website`: Your finality provider's website - +`--security-contact`: Contact email for security issues - `--details`: +Additional description of your finality provider - `--daemon-address`: RPC +address of the finality provider daemon (default: 127.0.0.1:12581) + +Upon successful creation, the command will return a JSON response containing +your finality provider's details: + +``` json +{ + "fp_addr": "bbn1ht2nxa6hlyl89m8xpdde9xsj40n0sxd2f9shsq", + "btc_pk_hex": + "cf0f03b9ee2d4a0f27240e2d8b8c8ef609e24358b2eb3cfd89ae4e4f472e1a41", + "description": + { + "moniker": "MyFinalityProvider", + "website": "https://myfinalityprovider.com", + "security_contact": "security@myfinalityprovider.com", + "details": "finality provider for the Babylon network" + }, + "commission": "0.050000000000000000", + "status": "CREATED" +} +``` + +The response includes: +- `fp_addr`: Your Babylon account address for receiving +rewards +- `btc_pk_hex`: Your unique BTC public key identifier (needed for +registration) +- `description`: Your finality provider's metadata +- `commission`: +Your set commission rate +- `status`: Current status of the finality provider + +## Register Finality Provider + +The `register-finality-provider` command registers your finality provider on the +Babylon chain. This command requires: + +1. The BTC public key (obtained from the `create-finality-provider` command) +2. A funded Babylon account (needs BBN tokens for transaction fees) +3. A running FPD daemon + +``` shell +fpd register-finality-provider \ +cf0f03b9ee2d4a0f27240e2d8b8c8ef609e24358b2eb3cfd89ae4e4f472e1a41 \ +--daemon-address 127.0.0.1:12581 \ --passphrase "Zubu99012" \ --home ./fp \ +``` + +> Note: The BTC public key (`cf0f03...1a41`) is obtained from the previous +`create-finality-provider` command. + +If successful, the command will return a transaction hash: + +``` shell +{ "tx_hash": +"C08377CF289DF0DC5FA462E6409ADCB65A3492C22A112C58EA449F4DC544A3B1" } +``` + + You can query this hash to confirm the transaction was successful by navigating + to the babylon chain and making a query, such as below: + +```shell +babylond query tx --chain-id bbn-test-5 +``` + +>Note: This query must be executed using the Babylon daemon (`babylond`), not +the finality provider daemon (`fpd`), as the registration transaction is +recorded on the Babylon blockchain. + +The hash returned should look something similar to below: + +```shell + type: message +- attributes: + - index: true + key: fp value: + '{ + "addr":"bbn1ht2nxa6hlyl89m8xpdde9xsj40n0sxd2f9shsq", + "description": + { + "moniker":"MyFinalityProvider", + "identity":" + ","website":"https://myfinalityprovider.com", + "security_contact":"security@myfinalityprovider.com", + "details":"Reliablefinality provider for the Babylon + network" + }, + "commission":"0.050000000000000000", + "btc_pk":"cf0f03b9ee2d4a0f27240e2d8b8c8ef609e24358b2eb3cfd89ae4e4f472e1a41", + "pop":{"btc_sig_type":"BIP340", + "btc_sig":"YJgc6NU7Z011imqSfPc9w/Namr1hFj48oTlEjGqbAVvHJv+9h3p/1shTohEb1g0fDWij7Ti9yKZzjAgNVepObA=="}, + "slashed_babylon_height":"0", + "slashed_btc_height":"0", + "jailed":false, + "consumer_id":"euphrates-0.5.0" + }' + - index: true + key: msg_index value: "0" + type: babylon.btcstaking.v1.EventNewFinalityProvider +gas_used: "82063" gas_wanted: "94429" height: "66693" info: "" logs: [] raw_log:"" +``` + +When a finality provider is created, it's associated with two key elements: + +**a) BTC Public Key:** - This serves as the unique identifier for the finality +provider. - It's derived from a Bitcoin private key, likely using the secp256k1 +elliptic curve. - This key is used in the Bitcoin-based security model of +Babylon. + +**b) Babylon Account:** - This is an account on the Babylon blockchain. - It's +where staking rewards for the finality provider are sent. - This account is +controlled by the key you use to create and manage the finality provider (the +one you added with fpd keys add). + +This dual association allows the finality provider to interact with both the +Bitcoin network (for security) and the Babylon network (for rewards and +governance). + +## Slashing Conditions + +Slashing occurs when a finality provider **double signs**. This occurs when a +finality provider signs conflicting blocks at the same height. This results in +the extraction of the provider's private key and automatically triggers shutdown +of the finality provider. + +### Withdrawing Rewards + +When withdrawing rewards, you need to use the Babylon chain's CLI since rewards +are managed by the main chain. + +To withdraw your finality provider rewards: + +``` babylond tx incentive finality_provider ... ``` + + From ac92b7197d3c51538fe89386ae22e4fb15c6aa02 Mon Sep 17 00:00:00 2001 From: Sam Ricotta Date: Fri, 15 Nov 2024 14:00:39 +0200 Subject: [PATCH 03/53] Revert "Update README.md" This reverts commit c7c64a5832fed6f41b6d03ddea54d7d673bb46b3. --- README.md | 698 +++++++----------------------------------------------- 1 file changed, 84 insertions(+), 614 deletions(-) diff --git a/README.md b/README.md index 1ed54e5..4d10096 100644 --- a/README.md +++ b/README.md @@ -1,649 +1,119 @@ -# Finality Provider Phase 2 Migration Guide +# Finality Provider -This guide covers the Phase 2 launch of the Babylon network, -a critical transition that introduces active participation -in finality voting, rewards distribution, and the Proof of -Stake (PoS) system. This migration represents a shift from -the limited role of finality providers in Phase 1 to a fully -active role in network security and governance in Phase 2. -This guide provides a step-by-step process for operators to -onboard, whether setting up anew or using a pre-existing setup, -with a focus on Phase 2-specific requirements. +A toolset crafted for the creation and +management of Finality Providers. -The following explains the migration from Phase 1 to 2. +## 1. Overview -## Phase 1 (Previous phase) +Finality providers are responsible for voting +at a finality round on top of [CometBFT](https://github.com/cometbft/cometbft). +Similar to any native PoS validator, +a finality provider can receive voting power delegations from BTC stakers, and +can earn commission from the staking rewards denominated in Babylon tokens. +The core logic of a finality provider instance can be found in +[Finality Provider Core](./docs/fp-core.md). -- Only involves Bitcoin holders submitting staking transactions -- No active Proof of Stake (PoS) chain operation -- Finality providers only need EOTS keys registered -- No need to run finality service +The finality provider toolset does not have +any special hardware requirements +and can operate on standard mid-sized machines +running a UNIX-flavored operating system. +It consists of the following programs: -## Phase 2 (New phase) +- *Babylon full node*: An instance of a Babylon node connecting to + the Babylon network. Running one is not a strict requirement, + but it is recommended for security compared to trusting a third-party RPC node. +- *Extractable One-Time Signature (EOTS) manager*: + A daemon responsible for securely maintaining the finality provider’s + private key and producing extractable one time signatures from it. +- *Finality Provider*: A daemon managing the finality provider. + It connects to the EOTS manager to generate EOTS public randomness and + finality votes for Babylon blocks, which it submits to Babylon through + the node connection. -- Active participation in finality voting -- Running the complete finality provider toolset: - - Babylon full node - - EOTS manager daemon - - Finality provider daemon -- Earning commissions from delegations -- Proof of Stake (PoS) and network security -- Rewards distribution -- Participating in governance +The following graphic demonstrates the interconnections between the above programs: -There are 2 different types of paths for Finality providers +![Finality Provider Interconnections](./docs/finality-toolset.png) -1. **New Setup** - - For operators starting fresh - - Need to generate both EOTS and FP keys - - Complete full configuration process +## 2. Installation -If you are a new operator, start with the -[Install Finality Provider Binary](#install-finality-provider-binary) section. +### Prerequisites - 2. **Has existing EOTS Key** - - Already have EOTS key from Phase 1 - - Reference existing EOTS key in setup +This project requires Go version 1.23 or later. -If you have an existing EOTS key from Phase 1 please skip to -[Loading Existing Keys](#loading-existing-keys-only-for-phase-1-finality-providers) -steps +Install Go by following the instructions on +the [official Go installation guide](https://golang.org/doc/install). -For an introduction on the finality providers see (here) - +### Downloading the code -## Install Finality Provider Binary - -Download [Golang 1.21](https://go.dev/dl)  +To get started, clone the repository to your local machine from Github: -Download and install Golang 1.21. Verify the installation with the following command: - -```shell -go version -``` - -### Step 1: Clone the Finality Provider Repository - -Subsequently Clone the finality provider -[repository](https://github.com/babylonlabs-io/finality-provider) and navigate to the -`bbn-testnet-5` tag. - -```shell -git clone https://github.com/babylonchain/finality-provider.git -cd finality-provider -git checkout -``` - -### Step 2: Build and Install Finality Provider Binaries - -Run: -```shell -make install -``` - -This command will: -- Build and compile all Go packages -- Install binaries to `$GOPATH/bin`: - - `eotsd`: EOTS manager daemon - - `fpd`: Finality provider daemon - - `fpcli`: Finality provider CLI tool -- Make commands globally accessible from your terminal - -### Step 3: Verify Installation - -Run `eotsd` to check the available actions: - -```shell -eotsd -``` - -Sample output: - -```shell -NAME: - eotsd - Extractable One Time Signature Daemon (eotsd). - -USAGE: - eotsd [global options] command [command options] [arguments...] - -COMMANDS: - start Start the Extractable One Time Signature Daemon. - init Initialize the eotsd home directory. - sign-schnorr Signs a Schnorr signature over arbitrary data with -... -``` - -If your shell cannot find the installed binaries, make sure `$GOPATH/bin` is in -the `$PATH` of your shell. Usually these commands will do the job - -```shell -export PATH=$HOME/go/bin:$PATHecho 'export PATH=$HOME/go/bin:$PATH' >> -~/.profile -``` - -## Install Babylon Binary - -Clone the Babylon [repository](https://github.com/babylonlabs-io/babylon) and -checkout the `bbn-testnet-5` tag: - -```shell -git clone git@github.com:babylonlabs-io/babylon.git -cd babylon -git checkout +```bash +git clone https://github.com/babylonlabs-io/finality-provider.git ``` -### Step 1: Build and Install the Babylon Binary +You can choose a specific version from +the [official releases page](https://github.com/babylonlabs-io/finality-provider/releases) -Run: -```shell -make install +```bash +cd finality-provider # cd into the project directory +git checkout ``` -This command will: -- Build and compile all Go packages -- Install binary to `$GOPATH/bin`: - - `babylond`: Babylon network daemon -- Make command globally accessible from your terminal - -### Step 2: Verify Installation +### Building and installing the binary -Run `babylond` to see the available commands: +At the top-level directory of the project -```shell -babylond +```bash +make install ``` -Sample output: +The above command will build and install the following binaries to +`$GOPATH/bin`: -```shell -Available Commands: - add-genesis-account Add a genesis account to genesis.json - collect-gentxs Collect genesis txs and output a genesis.json file - comet CometBFT subcommands - config Utilities for managing application configuration ... -``` +- `eotsd`: The daemon program for the EOTS manager. +- `fpd`: The daemon program for the finality-provider with overall commands. -If your shell cannot find the installed binaries, make sure `$GOPATH/bin`  -is in the `$PATH` of your shell. The following command should help this issue. +If your shell cannot find the installed binaries, make sure `$GOPATH/bin` is in +the `$PATH` of your shell. Usually these commands will do the job -```shell +```bash export PATH=$HOME/go/bin:$PATH echo 'export PATH=$HOME/go/bin:$PATH' >> ~/.profile ``` -## Connecting to a Babylon Node +## 3. Setting up a finality provider -To operate as a finality provider, the Finality Provider program must be connected -to a Babylon node. It is highly recommended for each finality provider to set up -their own node to ensure network reliability and direct access to network updates. +### 3.1. Setting up a Babylon Full Node -For detailed instructions on setting up a Babylon node, please refer to the -[Setting up a Node](https://github.com/babylonlabs-io/networks/syncing-a-node) -section of the Babylon Networks repository. +Before setting up the finality provider toolset, +an operator must ensure a working connection with a Babylon full node. +It is highly recommended that operators run their own node to avoid +trusting third parties. Instructions on how to set up a full Babylon node +can be found in +[the Babylon documentation](https://docs.babylonchain.io/docs/user-guides/btc-staking-testnet/setup-node). -## Setting up the EOTS Manager +### 3.2. Setting up the EOTS Manager ->Note: If you have already set up an EOTS Manager, you can skip this section. -The following steps are only for users who have not yet set up an EOTS Manager. -Phase 1 users who already have an EOTS Manager set up can skip to the -[Loading Existing Keys](#loading-existing-keys-only-for-phase-1-finality-providers) -section at the end of this guide for specific instructions -on re-using their Phase 1 EOTS keys. - -After a node and a keyring have been set up, the operator can set up and run the +After a node and a keyring have been set up, +the operator can set up and run the Extractable One Time Signature (EOTS) manager daemon. - -The EOTS daemon is responsible for managing EOTS keys, producing EOTS -randomness, and using them to produce EOTS signatures. To read more on the EOTS -Manager see [here](#) - -### Step 1: Initialize the EOTS Manager - -Use the `eotsd init` command to initialize a home directory for the EOTS Manager. -You can set or change your home directory using the `--home` tag. For example, use -`--home ./eotsKey` to specify a custom directory. - -```shell -eotsd init --home -``` - -### Step 2: Create an EOTS Key - -Once the EOTS Manager is initialized, you need to create an EOTS key: - -``` shell -eotsd keys add --key-name --home -``` - -You will be prompted to enter and confirm a passphrase. -Ensure this is completed before starting the daemon. - -Sample output: - -```json -{ - "name": "eots", - "pub_key_hex": - "e1e72d270b90b24f395e76b417218430a75683bd07cf98b91cf9219d1c777c19", - "mnemonic": "parade hybrid century project toss gun undo ocean exercise - figure decorate basket peace raw spot gap dose daring patch ski purchase - prefer can pair" -} -``` - -## Loading Existing Keys (Only for Phase 1 Finality Providers) - -Note: This section is only for users who participated in Phase 1 and already -have an EOTS key. If you are a new user, you can skip this section. - -If you participated in Phase 1, follow these steps to load your existing EOTS -key and configure it for Phase 2. - -### Step 1: Verify Your EOTS Key Backup -Before proceeding, ensure you have a backup of your Phase 1 EOTS key. -You will need this backup file to import the key into the Phase 2 environment. - -### Step 2: Import Your EOTS Key into the Keyring -To load your existing EOTS key, use the following command to import it into the -keyring: - -```shell -eotsd keys import -``` - -- ``: The name you want to assign to this key in Phase 2. -- ``: The path to your EOTS key backup file from Phase 1. - -## Starting the EOTS Daemon - -You will need to navigate to the You can start the EOTS daemon using the following command: - -```shell -eotsd start --home -``` - -This command starts the EOTS RPC server at the address specified in eotsd.conf -under the RpcListener field (default: 127.0.0.1:12582). You can override this value -by specifying a custom address with the --rpc-listener flag. - -```shell -2024-10-30T12:42:29.393259Z info Metrics server is starting -{"addr": "127.0.0.1:2113"} -2024-10-30T12:42:29.393278Z info RPC server listening {"address": "127.0.0.1:12582"} -2024-10-30T12:42:29.393363Z info EOTS Manager Daemon is fully active! -EOTS Manager Daemon is fully active! -``` - ->**Note**: It is recommended to run the `eotsd` daemon on a separate machine or -network segment to enhance security. This helps isolate the key management -functionality and reduces the potential attack surface. You can edit -the`EOTSManagerAddress` in the configuration file of the finality provider to -reference the address of the machine where `eotsd` is running. - -## Setting up the Finality Provider - -The Finality Provider Daemon (FPD) is responsible for monitoring new Babylon blocks, -committing public randomness for the blocks it intends to provide finality signatures for, -and submitting finality signatures. For more information on Finality Providers, please see -[here](#). - -### Step 1: Initialize the Finality Provider Daemon - -Use the fpd init command to initialize a home directory for the Finality Provider. -You can set or change the home directory using the `--home` tag. For example, use -`--home ./fpKeys` to specify a custom directory. - -```shell -fpd init --home -``` - ->Note: Running this command may return the message -`service injective.evm.v1beta1.Msg does not have cosmos.msg.v1.service proto annotation`, -which is expected and can be ignored. - -### Step 2: Add a Key for the Finality Provider on the Babylon Chain - -The Finality Provider Daemon uses a keyring to store keys locally, enabling it to sign -transactions on the Babylon chain. - -Add a key for your finality provider: - -```shell -Copy code -fpd keys add --keyname --keyring-backend test --home ---keyring-backend -``` - -Options: -- `test`: Stores keys unencrypted on disk. This is suitable for testing but not recommended -for production. -- `file`: Stores encrypted keys on disk, offering more security than the test option. -- `os`: Uses the operating system's native keyring for the highest level of security, -relying on OS-managed encryption and access controls. - -The command will create a new key pair and store it in your keyring. Sample output: - -```shell -- address: bbn19gulf0a4yz87twpjl8cxnerc2wr2xqm9fsygn9 - name: finality-provider - pubkey: '{"@type":"/cosmos.crypto.secp256k1.PubKey", - "key":"AhZAL00gKplLQKpLMiXPBqaKCoiessoewOaEATKd4Rcy"}' - type: local -``` - ->Note: Verify the chain-id by checking the Babylon RPC node status at -[https://rpc.testnet5.babylonlabs.io/status](https://rpc.testnet5.babylonlabs.io/status). - -### Step 3: Configure fpd.config - -After initializing the Finality Provider Daemon, it will generate an fpd.config file. -Open config.toml to set the necessary parameters as shown below: - -```shell -[Application Options] -EOTSManagerAddress = 127.0.0.1:12582 -RpcListener = 127.0.0.1:12581 - -[babylon] -Key = # the key you used above -ChainID = bbn-test-5 -RPCAddr = http://127.0.0.1:26657 -GRPCAddr = https://127.0.0.1:9090 -KeyDirectory = ./fpKey -``` - -The Key field stores the name of the key used for signing transactions on the -Babylon chain and should match the key name specified during key creation. -KeyDirectory points to the location where the keyring is stored. - -The Finality Provider Daemon is responsible for monitoring for new Babylon -blocks, committing public randomness for the blocks it intends to provide -finality signatures for, and submitting finality signatures. To read more on -Finality Providers please see [here](#) - - -The `fpd init` command initializes a home directory for the EOTS manager. You -can wish to set/change your home directory with the `--home` tag. For the home -`` we have used `./fpKey` - -``` shell -fpd init --home -``` - -Note: will return -`service injective.evm.v1beta1.Msg does not have cosmos.msg.v1.service proto annotation` -which is expected and can be ignored. - -### Step 4: Add key for the finality provider on the Babylon chain - -The keyring is maintained by the finality provider daemon, this is local storage -of the keys that the daemon uses. The account associated with this key exists on -the babylon chain. - -Use the following command to add a key for your finality provider: - -```shell -fpd keys add --keyname --keyring-backend test --home -``` - -We use `--keyring-backend test`, which specifies which backend to use for the -keyring, `test` stores keys unencrypted on disk. For production environments, -use `file` or `os` backend. - - - There are three options for the keyring backend: - - `test`: Stores keys unencrypted on disk. It’s meant for testing purposes and - should never be used in production. `file`: Stores encrypted keys on disk, - which is a more secure option than test but less secure than using the OS - keyring. `os`: Uses the operating system's native keyring, providing the - highest level of security by relying on OS-managed encryption and access - controls. - -This command will create a new key pair and store it in your keyring. The output -should look similar to the below. - -``` shell -- address: bbn19gulf0a4yz87twpjl8cxnerc2wr2xqm9fsygn9 - name: finality-provider pubkey: - '{"@type":"/cosmos.crypto.secp256k1.PubKey", - "key":"AhZAL00gKplLQKpLMiXPBqaKCoiessoewOaEATKd4Rcy"}' - type: local -``` - ->Note: Please verify the `chain-id` from the Babylon RPC -node [https://rpc.testnet5.babylonlabs.io/status] -(https://rpc.testnet5.babylonlabs.io/status) - - >The configuration below requires to point to the path where this keyring is - stored `KeyDirectory`. This `Key` field stores the key name used for - interacting with the babylon chain and will be specified along with - the `KeyringBackend`field in the next step. So we can ignore the setting of the - two fields in this step. - -Once the node is initialized with the above command. It should generate a -`fpd.config` Edit the `config.toml` to set the necessary parameters with the -below - -```shell -[Application Options] EOTSManagerAddress = 127.0.0.1:12582 RpcListener -= 127.0.0.1:12581 - -[babylon] Key = // the key you used above -ChainID = bbn-test-5 RPCAddr = http://127.0.0.1:26657 GRPCAddr = -https://127.0.0.1:9090 KeyDirectory = ./fpKey -``` - -### Step 3: Verify the Key Import -After importing, verify that your EOTS key was successfully loaded: - -```shell -eotsd keys list -``` - -You should see your EOTS key listed with the correct details, confirming that -it has been imported correctly. - ->Note: Make sure you're using the same key name and EOTS public key that were -registered in Phase 1. - - -## Starting the Finality provider Daemon - -The finality provider daemon (FPD) needs to be running before proceeding with -registration or voting participation. - -Start the daemon with: - -``` shell -fpd start --home ./fp -``` - -The command flags: -- `start`: Initiates the FPD daemon -- `--home`: Specifies the directory for daemon data and configuration - -The daemon will start the RPC server for CLI communication then begin listening -for incoming requests and finally initialize finality provider services - -You should see logs indicating successful startup: - -``` -[INFO] Starting finality provider daemon... -[INFO] RPC server listening on... -``` - ->Note: Keep this terminal window open as the daemon needs to run continuously. - -The above will start the Finality provider RPC server at the address specified -in `fpd.conf` under the `RpcListener` field, which has a default value -of `127.0.0.1:12581`. You can change this value in the configuration file or -override this value and specify a custom address using -the `--rpc-listener` flag. - -To start the daemon with a specific finality provider instance, use -the `--btc-pk` flag followed by the hex string of the BTC public key of the -finality provider (`btc_pk_hex`) in the next step - -All the available CLI options can be viewed using the `--help` flag. These -options can also be set in the configuration file. - -## Create Finality Provider - -The `create-finality-provider` command initializes a new finality provider -instance locally. This command: - -- Generates a BTC public key that uniquely identifies your finality provider -- Creates a Babylon account to receive staking rewards - -``` shell -fpd create-finality-provider \ --daemon-address 127.0.0.1:12581 \ --chain-id -bbn-test-5 \ --commission 0.05 \ --key-name finality-provider \ --moniker -"MyFinalityProvider" \ --website "https://myfinalityprovider.com" \ ---security-contact "security@myfinalityprovider.com" \ --details "finality -provider for the Babylon network" \ --home ./fp \ --passphrase "passphrase" -``` - -Required parameters: - `--chain-id`: The Babylon chain ID (`bbn-test-5`) - -`--commission`: The commission rate (between 0 and 1) that you'll receive from -delegators - `--key-name`: Name of the key in your keyring for signing -transactions - `--moniker`: A human-readable name for your finality provider - -Optional parameters: - `--website`: Your finality provider's website - -`--security-contact`: Contact email for security issues - `--details`: -Additional description of your finality provider - `--daemon-address`: RPC -address of the finality provider daemon (default: 127.0.0.1:12581) - -Upon successful creation, the command will return a JSON response containing -your finality provider's details: - -``` json -{ - "fp_addr": "bbn1ht2nxa6hlyl89m8xpdde9xsj40n0sxd2f9shsq", - "btc_pk_hex": - "cf0f03b9ee2d4a0f27240e2d8b8c8ef609e24358b2eb3cfd89ae4e4f472e1a41", - "description": - { - "moniker": "MyFinalityProvider", - "website": "https://myfinalityprovider.com", - "security_contact": "security@myfinalityprovider.com", - "details": "finality provider for the Babylon network" - }, - "commission": "0.050000000000000000", - "status": "CREATED" -} -``` - -The response includes: -- `fp_addr`: Your Babylon account address for receiving -rewards -- `btc_pk_hex`: Your unique BTC public key identifier (needed for -registration) -- `description`: Your finality provider's metadata -- `commission`: -Your set commission rate -- `status`: Current status of the finality provider - -## Register Finality Provider - -The `register-finality-provider` command registers your finality provider on the -Babylon chain. This command requires: - -1. The BTC public key (obtained from the `create-finality-provider` command) -2. A funded Babylon account (needs BBN tokens for transaction fees) -3. A running FPD daemon - -``` shell -fpd register-finality-provider \ -cf0f03b9ee2d4a0f27240e2d8b8c8ef609e24358b2eb3cfd89ae4e4f472e1a41 \ ---daemon-address 127.0.0.1:12581 \ --passphrase "Zubu99012" \ --home ./fp \ -``` - -> Note: The BTC public key (`cf0f03...1a41`) is obtained from the previous -`create-finality-provider` command. - -If successful, the command will return a transaction hash: - -``` shell -{ "tx_hash": -"C08377CF289DF0DC5FA462E6409ADCB65A3492C22A112C58EA449F4DC544A3B1" } -``` - - You can query this hash to confirm the transaction was successful by navigating - to the babylon chain and making a query, such as below: - -```shell -babylond query tx --chain-id bbn-test-5 -``` - ->Note: This query must be executed using the Babylon daemon (`babylond`), not -the finality provider daemon (`fpd`), as the registration transaction is -recorded on the Babylon blockchain. - -The hash returned should look something similar to below: - -```shell - type: message -- attributes: - - index: true - key: fp value: - '{ - "addr":"bbn1ht2nxa6hlyl89m8xpdde9xsj40n0sxd2f9shsq", - "description": - { - "moniker":"MyFinalityProvider", - "identity":" - ","website":"https://myfinalityprovider.com", - "security_contact":"security@myfinalityprovider.com", - "details":"Reliablefinality provider for the Babylon - network" - }, - "commission":"0.050000000000000000", - "btc_pk":"cf0f03b9ee2d4a0f27240e2d8b8c8ef609e24358b2eb3cfd89ae4e4f472e1a41", - "pop":{"btc_sig_type":"BIP340", - "btc_sig":"YJgc6NU7Z011imqSfPc9w/Namr1hFj48oTlEjGqbAVvHJv+9h3p/1shTohEb1g0fDWij7Ti9yKZzjAgNVepObA=="}, - "slashed_babylon_height":"0", - "slashed_btc_height":"0", - "jailed":false, - "consumer_id":"euphrates-0.5.0" - }' - - index: true - key: msg_index value: "0" - type: babylon.btcstaking.v1.EventNewFinalityProvider -gas_used: "82063" gas_wanted: "94429" height: "66693" info: "" logs: [] raw_log:"" -``` - -When a finality provider is created, it's associated with two key elements: - -**a) BTC Public Key:** - This serves as the unique identifier for the finality -provider. - It's derived from a Bitcoin private key, likely using the secp256k1 -elliptic curve. - This key is used in the Bitcoin-based security model of -Babylon. - -**b) Babylon Account:** - This is an account on the Babylon blockchain. - It's -where staking rewards for the finality provider are sent. - This account is -controlled by the key you use to create and manage the finality provider (the -one you added with fpd keys add). - -This dual association allows the finality provider to interact with both the -Bitcoin network (for security) and the Babylon network (for rewards and -governance). - -## Slashing Conditions - -Slashing occurs when a finality provider **double signs**. This occurs when a -finality provider signs conflicting blocks at the same height. This results in -the extraction of the provider's private key and automatically triggers shutdown -of the finality provider. - -### Withdrawing Rewards - -When withdrawing rewards, you need to use the Babylon chain's CLI since rewards -are managed by the main chain. - -To withdraw your finality provider rewards: - -``` babylond tx incentive finality_provider ... ``` - - +A complete overview of the EOTS manager, its operation, and +its configuration options can be found in the +[EOTS Manager page](docs/eots.md) + +### 3.3. Setting up a Finality Provider + +The last step is to set up and run +the finality daemon. +A complete overview of the finality daemon, its operation, and +its configuration options can be found in the +[Finality page](docs/finality-provider.md). + +## 4. Delegations & Rewards + +A finality provider receives BTC delegations through delegators +interacting with Babylon and choosing it as the recipient of their delegations. +To perform a self-delegation, +the operator can either visit the staking web app we provide, +or run the Babylon [BTC Staker program](https://github.com/babylonlabs-io/btc-staker) once. +The BTC staker connects to a Bitcoin wallet and Babylon to perform delegations. From b70a447909ade741071b31fc07b2f2fd08c97b15 Mon Sep 17 00:00:00 2001 From: Sam Ricotta Date: Fri, 15 Nov 2024 14:00:47 +0200 Subject: [PATCH 04/53] Create finality-provider-phase2.md --- docs/finality-provider-phase2.md | 649 +++++++++++++++++++++++++++++++ 1 file changed, 649 insertions(+) create mode 100644 docs/finality-provider-phase2.md diff --git a/docs/finality-provider-phase2.md b/docs/finality-provider-phase2.md new file mode 100644 index 0000000..1ed54e5 --- /dev/null +++ b/docs/finality-provider-phase2.md @@ -0,0 +1,649 @@ +# Finality Provider Phase 2 Migration Guide + +This guide covers the Phase 2 launch of the Babylon network, +a critical transition that introduces active participation +in finality voting, rewards distribution, and the Proof of +Stake (PoS) system. This migration represents a shift from +the limited role of finality providers in Phase 1 to a fully +active role in network security and governance in Phase 2. +This guide provides a step-by-step process for operators to +onboard, whether setting up anew or using a pre-existing setup, +with a focus on Phase 2-specific requirements. + +The following explains the migration from Phase 1 to 2. + +## Phase 1 (Previous phase) + +- Only involves Bitcoin holders submitting staking transactions +- No active Proof of Stake (PoS) chain operation +- Finality providers only need EOTS keys registered +- No need to run finality service + +## Phase 2 (New phase) + +- Active participation in finality voting +- Running the complete finality provider toolset: + - Babylon full node + - EOTS manager daemon + - Finality provider daemon +- Earning commissions from delegations +- Proof of Stake (PoS) and network security +- Rewards distribution +- Participating in governance + +There are 2 different types of paths for Finality providers + +1. **New Setup** + - For operators starting fresh + - Need to generate both EOTS and FP keys + - Complete full configuration process + +If you are a new operator, start with the +[Install Finality Provider Binary](#install-finality-provider-binary) section. + + 2. **Has existing EOTS Key** + - Already have EOTS key from Phase 1 + - Reference existing EOTS key in setup + +If you have an existing EOTS key from Phase 1 please skip to +[Loading Existing Keys](#loading-existing-keys-only-for-phase-1-finality-providers) +steps + +For an introduction on the finality providers see (here) + + +## Install Finality Provider Binary + +Download [Golang 1.21](https://go.dev/dl)  + +Download and install Golang 1.21. Verify the installation with the following command: + +```shell +go version +``` + +### Step 1: Clone the Finality Provider Repository + +Subsequently Clone the finality provider +[repository](https://github.com/babylonlabs-io/finality-provider) and navigate to the +`bbn-testnet-5` tag. + +```shell +git clone https://github.com/babylonchain/finality-provider.git +cd finality-provider +git checkout +``` + +### Step 2: Build and Install Finality Provider Binaries + +Run: +```shell +make install +``` + +This command will: +- Build and compile all Go packages +- Install binaries to `$GOPATH/bin`: + - `eotsd`: EOTS manager daemon + - `fpd`: Finality provider daemon + - `fpcli`: Finality provider CLI tool +- Make commands globally accessible from your terminal + +### Step 3: Verify Installation + +Run `eotsd` to check the available actions: + +```shell +eotsd +``` + +Sample output: + +```shell +NAME: + eotsd - Extractable One Time Signature Daemon (eotsd). + +USAGE: + eotsd [global options] command [command options] [arguments...] + +COMMANDS: + start Start the Extractable One Time Signature Daemon. + init Initialize the eotsd home directory. + sign-schnorr Signs a Schnorr signature over arbitrary data with +... +``` + +If your shell cannot find the installed binaries, make sure `$GOPATH/bin` is in +the `$PATH` of your shell. Usually these commands will do the job + +```shell +export PATH=$HOME/go/bin:$PATHecho 'export PATH=$HOME/go/bin:$PATH' >> +~/.profile +``` + +## Install Babylon Binary + +Clone the Babylon [repository](https://github.com/babylonlabs-io/babylon) and +checkout the `bbn-testnet-5` tag: + +```shell +git clone git@github.com:babylonlabs-io/babylon.git +cd babylon +git checkout +``` + +### Step 1: Build and Install the Babylon Binary + +Run: +```shell +make install +``` + +This command will: +- Build and compile all Go packages +- Install binary to `$GOPATH/bin`: + - `babylond`: Babylon network daemon +- Make command globally accessible from your terminal + +### Step 2: Verify Installation + +Run `babylond` to see the available commands: + +```shell +babylond +``` + +Sample output: + +```shell +Available Commands: + add-genesis-account Add a genesis account to genesis.json + collect-gentxs Collect genesis txs and output a genesis.json file + comet CometBFT subcommands + config Utilities for managing application configuration ... +``` + +If your shell cannot find the installed binaries, make sure `$GOPATH/bin`  +is in the `$PATH` of your shell. The following command should help this issue. + +```shell +export PATH=$HOME/go/bin:$PATH +echo 'export PATH=$HOME/go/bin:$PATH' >> ~/.profile +``` + +## Connecting to a Babylon Node + +To operate as a finality provider, the Finality Provider program must be connected +to a Babylon node. It is highly recommended for each finality provider to set up +their own node to ensure network reliability and direct access to network updates. + +For detailed instructions on setting up a Babylon node, please refer to the +[Setting up a Node](https://github.com/babylonlabs-io/networks/syncing-a-node) +section of the Babylon Networks repository. + +## Setting up the EOTS Manager + +>Note: If you have already set up an EOTS Manager, you can skip this section. +The following steps are only for users who have not yet set up an EOTS Manager. +Phase 1 users who already have an EOTS Manager set up can skip to the +[Loading Existing Keys](#loading-existing-keys-only-for-phase-1-finality-providers) +section at the end of this guide for specific instructions +on re-using their Phase 1 EOTS keys. + +After a node and a keyring have been set up, the operator can set up and run the +Extractable One Time Signature (EOTS) manager daemon. + +The EOTS daemon is responsible for managing EOTS keys, producing EOTS +randomness, and using them to produce EOTS signatures. To read more on the EOTS +Manager see [here](#) + +### Step 1: Initialize the EOTS Manager + +Use the `eotsd init` command to initialize a home directory for the EOTS Manager. +You can set or change your home directory using the `--home` tag. For example, use +`--home ./eotsKey` to specify a custom directory. + +```shell +eotsd init --home +``` + +### Step 2: Create an EOTS Key + +Once the EOTS Manager is initialized, you need to create an EOTS key: + +``` shell +eotsd keys add --key-name --home +``` + +You will be prompted to enter and confirm a passphrase. +Ensure this is completed before starting the daemon. + +Sample output: + +```json +{ + "name": "eots", + "pub_key_hex": + "e1e72d270b90b24f395e76b417218430a75683bd07cf98b91cf9219d1c777c19", + "mnemonic": "parade hybrid century project toss gun undo ocean exercise + figure decorate basket peace raw spot gap dose daring patch ski purchase + prefer can pair" +} +``` + +## Loading Existing Keys (Only for Phase 1 Finality Providers) + +Note: This section is only for users who participated in Phase 1 and already +have an EOTS key. If you are a new user, you can skip this section. + +If you participated in Phase 1, follow these steps to load your existing EOTS +key and configure it for Phase 2. + +### Step 1: Verify Your EOTS Key Backup +Before proceeding, ensure you have a backup of your Phase 1 EOTS key. +You will need this backup file to import the key into the Phase 2 environment. + +### Step 2: Import Your EOTS Key into the Keyring +To load your existing EOTS key, use the following command to import it into the +keyring: + +```shell +eotsd keys import +``` + +- ``: The name you want to assign to this key in Phase 2. +- ``: The path to your EOTS key backup file from Phase 1. + +## Starting the EOTS Daemon + +You will need to navigate to the You can start the EOTS daemon using the following command: + +```shell +eotsd start --home +``` + +This command starts the EOTS RPC server at the address specified in eotsd.conf +under the RpcListener field (default: 127.0.0.1:12582). You can override this value +by specifying a custom address with the --rpc-listener flag. + +```shell +2024-10-30T12:42:29.393259Z info Metrics server is starting +{"addr": "127.0.0.1:2113"} +2024-10-30T12:42:29.393278Z info RPC server listening {"address": "127.0.0.1:12582"} +2024-10-30T12:42:29.393363Z info EOTS Manager Daemon is fully active! +EOTS Manager Daemon is fully active! +``` + +>**Note**: It is recommended to run the `eotsd` daemon on a separate machine or +network segment to enhance security. This helps isolate the key management +functionality and reduces the potential attack surface. You can edit +the`EOTSManagerAddress` in the configuration file of the finality provider to +reference the address of the machine where `eotsd` is running. + +## Setting up the Finality Provider + +The Finality Provider Daemon (FPD) is responsible for monitoring new Babylon blocks, +committing public randomness for the blocks it intends to provide finality signatures for, +and submitting finality signatures. For more information on Finality Providers, please see +[here](#). + +### Step 1: Initialize the Finality Provider Daemon + +Use the fpd init command to initialize a home directory for the Finality Provider. +You can set or change the home directory using the `--home` tag. For example, use +`--home ./fpKeys` to specify a custom directory. + +```shell +fpd init --home +``` + +>Note: Running this command may return the message +`service injective.evm.v1beta1.Msg does not have cosmos.msg.v1.service proto annotation`, +which is expected and can be ignored. + +### Step 2: Add a Key for the Finality Provider on the Babylon Chain + +The Finality Provider Daemon uses a keyring to store keys locally, enabling it to sign +transactions on the Babylon chain. + +Add a key for your finality provider: + +```shell +Copy code +fpd keys add --keyname --keyring-backend test --home +--keyring-backend +``` + +Options: +- `test`: Stores keys unencrypted on disk. This is suitable for testing but not recommended +for production. +- `file`: Stores encrypted keys on disk, offering more security than the test option. +- `os`: Uses the operating system's native keyring for the highest level of security, +relying on OS-managed encryption and access controls. + +The command will create a new key pair and store it in your keyring. Sample output: + +```shell +- address: bbn19gulf0a4yz87twpjl8cxnerc2wr2xqm9fsygn9 + name: finality-provider + pubkey: '{"@type":"/cosmos.crypto.secp256k1.PubKey", + "key":"AhZAL00gKplLQKpLMiXPBqaKCoiessoewOaEATKd4Rcy"}' + type: local +``` + +>Note: Verify the chain-id by checking the Babylon RPC node status at +[https://rpc.testnet5.babylonlabs.io/status](https://rpc.testnet5.babylonlabs.io/status). + +### Step 3: Configure fpd.config + +After initializing the Finality Provider Daemon, it will generate an fpd.config file. +Open config.toml to set the necessary parameters as shown below: + +```shell +[Application Options] +EOTSManagerAddress = 127.0.0.1:12582 +RpcListener = 127.0.0.1:12581 + +[babylon] +Key = # the key you used above +ChainID = bbn-test-5 +RPCAddr = http://127.0.0.1:26657 +GRPCAddr = https://127.0.0.1:9090 +KeyDirectory = ./fpKey +``` + +The Key field stores the name of the key used for signing transactions on the +Babylon chain and should match the key name specified during key creation. +KeyDirectory points to the location where the keyring is stored. + +The Finality Provider Daemon is responsible for monitoring for new Babylon +blocks, committing public randomness for the blocks it intends to provide +finality signatures for, and submitting finality signatures. To read more on +Finality Providers please see [here](#) + + +The `fpd init` command initializes a home directory for the EOTS manager. You +can wish to set/change your home directory with the `--home` tag. For the home +`` we have used `./fpKey` + +``` shell +fpd init --home +``` + +Note: will return +`service injective.evm.v1beta1.Msg does not have cosmos.msg.v1.service proto annotation` +which is expected and can be ignored. + +### Step 4: Add key for the finality provider on the Babylon chain + +The keyring is maintained by the finality provider daemon, this is local storage +of the keys that the daemon uses. The account associated with this key exists on +the babylon chain. + +Use the following command to add a key for your finality provider: + +```shell +fpd keys add --keyname --keyring-backend test --home +``` + +We use `--keyring-backend test`, which specifies which backend to use for the +keyring, `test` stores keys unencrypted on disk. For production environments, +use `file` or `os` backend. + + + There are three options for the keyring backend: + + `test`: Stores keys unencrypted on disk. It’s meant for testing purposes and + should never be used in production. `file`: Stores encrypted keys on disk, + which is a more secure option than test but less secure than using the OS + keyring. `os`: Uses the operating system's native keyring, providing the + highest level of security by relying on OS-managed encryption and access + controls. + +This command will create a new key pair and store it in your keyring. The output +should look similar to the below. + +``` shell +- address: bbn19gulf0a4yz87twpjl8cxnerc2wr2xqm9fsygn9 + name: finality-provider pubkey: + '{"@type":"/cosmos.crypto.secp256k1.PubKey", + "key":"AhZAL00gKplLQKpLMiXPBqaKCoiessoewOaEATKd4Rcy"}' + type: local +``` + +>Note: Please verify the `chain-id` from the Babylon RPC +node [https://rpc.testnet5.babylonlabs.io/status] +(https://rpc.testnet5.babylonlabs.io/status) + + >The configuration below requires to point to the path where this keyring is + stored `KeyDirectory`. This `Key` field stores the key name used for + interacting with the babylon chain and will be specified along with + the `KeyringBackend`field in the next step. So we can ignore the setting of the + two fields in this step. + +Once the node is initialized with the above command. It should generate a +`fpd.config` Edit the `config.toml` to set the necessary parameters with the +below + +```shell +[Application Options] EOTSManagerAddress = 127.0.0.1:12582 RpcListener += 127.0.0.1:12581 + +[babylon] Key = // the key you used above +ChainID = bbn-test-5 RPCAddr = http://127.0.0.1:26657 GRPCAddr = +https://127.0.0.1:9090 KeyDirectory = ./fpKey +``` + +### Step 3: Verify the Key Import +After importing, verify that your EOTS key was successfully loaded: + +```shell +eotsd keys list +``` + +You should see your EOTS key listed with the correct details, confirming that +it has been imported correctly. + +>Note: Make sure you're using the same key name and EOTS public key that were +registered in Phase 1. + + +## Starting the Finality provider Daemon + +The finality provider daemon (FPD) needs to be running before proceeding with +registration or voting participation. + +Start the daemon with: + +``` shell +fpd start --home ./fp +``` + +The command flags: +- `start`: Initiates the FPD daemon +- `--home`: Specifies the directory for daemon data and configuration + +The daemon will start the RPC server for CLI communication then begin listening +for incoming requests and finally initialize finality provider services + +You should see logs indicating successful startup: + +``` +[INFO] Starting finality provider daemon... +[INFO] RPC server listening on... +``` + +>Note: Keep this terminal window open as the daemon needs to run continuously. + +The above will start the Finality provider RPC server at the address specified +in `fpd.conf` under the `RpcListener` field, which has a default value +of `127.0.0.1:12581`. You can change this value in the configuration file or +override this value and specify a custom address using +the `--rpc-listener` flag. + +To start the daemon with a specific finality provider instance, use +the `--btc-pk` flag followed by the hex string of the BTC public key of the +finality provider (`btc_pk_hex`) in the next step + +All the available CLI options can be viewed using the `--help` flag. These +options can also be set in the configuration file. + +## Create Finality Provider + +The `create-finality-provider` command initializes a new finality provider +instance locally. This command: + +- Generates a BTC public key that uniquely identifies your finality provider +- Creates a Babylon account to receive staking rewards + +``` shell +fpd create-finality-provider \ --daemon-address 127.0.0.1:12581 \ --chain-id +bbn-test-5 \ --commission 0.05 \ --key-name finality-provider \ --moniker +"MyFinalityProvider" \ --website "https://myfinalityprovider.com" \ +--security-contact "security@myfinalityprovider.com" \ --details "finality +provider for the Babylon network" \ --home ./fp \ --passphrase "passphrase" +``` + +Required parameters: - `--chain-id`: The Babylon chain ID (`bbn-test-5`) - +`--commission`: The commission rate (between 0 and 1) that you'll receive from +delegators - `--key-name`: Name of the key in your keyring for signing +transactions - `--moniker`: A human-readable name for your finality provider + +Optional parameters: - `--website`: Your finality provider's website - +`--security-contact`: Contact email for security issues - `--details`: +Additional description of your finality provider - `--daemon-address`: RPC +address of the finality provider daemon (default: 127.0.0.1:12581) + +Upon successful creation, the command will return a JSON response containing +your finality provider's details: + +``` json +{ + "fp_addr": "bbn1ht2nxa6hlyl89m8xpdde9xsj40n0sxd2f9shsq", + "btc_pk_hex": + "cf0f03b9ee2d4a0f27240e2d8b8c8ef609e24358b2eb3cfd89ae4e4f472e1a41", + "description": + { + "moniker": "MyFinalityProvider", + "website": "https://myfinalityprovider.com", + "security_contact": "security@myfinalityprovider.com", + "details": "finality provider for the Babylon network" + }, + "commission": "0.050000000000000000", + "status": "CREATED" +} +``` + +The response includes: +- `fp_addr`: Your Babylon account address for receiving +rewards +- `btc_pk_hex`: Your unique BTC public key identifier (needed for +registration) +- `description`: Your finality provider's metadata +- `commission`: +Your set commission rate +- `status`: Current status of the finality provider + +## Register Finality Provider + +The `register-finality-provider` command registers your finality provider on the +Babylon chain. This command requires: + +1. The BTC public key (obtained from the `create-finality-provider` command) +2. A funded Babylon account (needs BBN tokens for transaction fees) +3. A running FPD daemon + +``` shell +fpd register-finality-provider \ +cf0f03b9ee2d4a0f27240e2d8b8c8ef609e24358b2eb3cfd89ae4e4f472e1a41 \ +--daemon-address 127.0.0.1:12581 \ --passphrase "Zubu99012" \ --home ./fp \ +``` + +> Note: The BTC public key (`cf0f03...1a41`) is obtained from the previous +`create-finality-provider` command. + +If successful, the command will return a transaction hash: + +``` shell +{ "tx_hash": +"C08377CF289DF0DC5FA462E6409ADCB65A3492C22A112C58EA449F4DC544A3B1" } +``` + + You can query this hash to confirm the transaction was successful by navigating + to the babylon chain and making a query, such as below: + +```shell +babylond query tx --chain-id bbn-test-5 +``` + +>Note: This query must be executed using the Babylon daemon (`babylond`), not +the finality provider daemon (`fpd`), as the registration transaction is +recorded on the Babylon blockchain. + +The hash returned should look something similar to below: + +```shell + type: message +- attributes: + - index: true + key: fp value: + '{ + "addr":"bbn1ht2nxa6hlyl89m8xpdde9xsj40n0sxd2f9shsq", + "description": + { + "moniker":"MyFinalityProvider", + "identity":" + ","website":"https://myfinalityprovider.com", + "security_contact":"security@myfinalityprovider.com", + "details":"Reliablefinality provider for the Babylon + network" + }, + "commission":"0.050000000000000000", + "btc_pk":"cf0f03b9ee2d4a0f27240e2d8b8c8ef609e24358b2eb3cfd89ae4e4f472e1a41", + "pop":{"btc_sig_type":"BIP340", + "btc_sig":"YJgc6NU7Z011imqSfPc9w/Namr1hFj48oTlEjGqbAVvHJv+9h3p/1shTohEb1g0fDWij7Ti9yKZzjAgNVepObA=="}, + "slashed_babylon_height":"0", + "slashed_btc_height":"0", + "jailed":false, + "consumer_id":"euphrates-0.5.0" + }' + - index: true + key: msg_index value: "0" + type: babylon.btcstaking.v1.EventNewFinalityProvider +gas_used: "82063" gas_wanted: "94429" height: "66693" info: "" logs: [] raw_log:"" +``` + +When a finality provider is created, it's associated with two key elements: + +**a) BTC Public Key:** - This serves as the unique identifier for the finality +provider. - It's derived from a Bitcoin private key, likely using the secp256k1 +elliptic curve. - This key is used in the Bitcoin-based security model of +Babylon. + +**b) Babylon Account:** - This is an account on the Babylon blockchain. - It's +where staking rewards for the finality provider are sent. - This account is +controlled by the key you use to create and manage the finality provider (the +one you added with fpd keys add). + +This dual association allows the finality provider to interact with both the +Bitcoin network (for security) and the Babylon network (for rewards and +governance). + +## Slashing Conditions + +Slashing occurs when a finality provider **double signs**. This occurs when a +finality provider signs conflicting blocks at the same height. This results in +the extraction of the provider's private key and automatically triggers shutdown +of the finality provider. + +### Withdrawing Rewards + +When withdrawing rewards, you need to use the Babylon chain's CLI since rewards +are managed by the main chain. + +To withdraw your finality provider rewards: + +``` babylond tx incentive finality_provider ... ``` + + From ca832e6bb24c33eee7cd82e27a97cf32250ff928 Mon Sep 17 00:00:00 2001 From: Sam Ricotta Date: Fri, 15 Nov 2024 14:04:11 +0200 Subject: [PATCH 05/53] Update README.md --- README.md | 698 +++++++++++++++++++++++++++++++++++++++++++++++------- 1 file changed, 614 insertions(+), 84 deletions(-) diff --git a/README.md b/README.md index 4d10096..eeea8be 100644 --- a/README.md +++ b/README.md @@ -1,119 +1,649 @@ -# Finality Provider +# Finality Provider Phase 2 Migration Guide -A toolset crafted for the creation and -management of Finality Providers. +This guide covers the Phase 2 launch of the Babylon network, +a critical transition that introduces active participation +in finality voting, rewards distribution, and the Proof of +Stake (PoS) system. This migration represents a shift from +the limited role of finality providers in Phase 1 to a fully +active role in network security and governance in Phase 2. +This guide provides a step-by-step process for operators to +onboard, whether setting up anew or using a pre-existing setup, +with a focus on Phase 2-specific requirements. -## 1. Overview +The following explains the migration from Phase 1 to 2. -Finality providers are responsible for voting -at a finality round on top of [CometBFT](https://github.com/cometbft/cometbft). -Similar to any native PoS validator, -a finality provider can receive voting power delegations from BTC stakers, and -can earn commission from the staking rewards denominated in Babylon tokens. -The core logic of a finality provider instance can be found in -[Finality Provider Core](./docs/fp-core.md). +## Phase 1 (Previous phase) -The finality provider toolset does not have -any special hardware requirements -and can operate on standard mid-sized machines -running a UNIX-flavored operating system. -It consists of the following programs: +- Only involves Bitcoin holders submitting staking transactions +- No active Proof of Stake (PoS) chain operation +- Finality providers only need EOTS keys registered +- No need to run finality service -- *Babylon full node*: An instance of a Babylon node connecting to - the Babylon network. Running one is not a strict requirement, - but it is recommended for security compared to trusting a third-party RPC node. -- *Extractable One-Time Signature (EOTS) manager*: - A daemon responsible for securely maintaining the finality provider’s - private key and producing extractable one time signatures from it. -- *Finality Provider*: A daemon managing the finality provider. - It connects to the EOTS manager to generate EOTS public randomness and - finality votes for Babylon blocks, which it submits to Babylon through - the node connection. +## Phase 2 (New phase) -The following graphic demonstrates the interconnections between the above programs: +- Active participation in finality voting +- Running the complete finality provider toolset: + - Babylon full node + - EOTS manager daemon + - Finality provider daemon +- Earning commissions from delegations +- Proof of Stake (PoS) and network security +- Rewards distribution +- Participating in governance -![Finality Provider Interconnections](./docs/finality-toolset.png) +There are 2 different types of paths for Finality providers -## 2. Installation +1. **New Setup** + - For operators starting fresh + - Need to generate both EOTS and FP keys + - Complete full configuration process -### Prerequisites +If you are a new operator, start with the +[Install Finality Provider Binary](#install-finality-provider-binary) section. -This project requires Go version 1.23 or later. + 2. **Has existing EOTS Key** + - Already have EOTS key from Phase 1 + - Reference existing EOTS key in setup -Install Go by following the instructions on -the [official Go installation guide](https://golang.org/doc/install). +If you have an existing EOTS key from Phase 1 please skip to +[Loading Existing Keys](#loading-existing-keys-only-for-phase-1-finality-providers) +steps -### Downloading the code +For an introduction on the finality providers see (here) + -To get started, clone the repository to your local machine from Github: +## Install Finality Provider Binary + +Download [Golang 1.21](https://go.dev/dl)  -```bash -git clone https://github.com/babylonlabs-io/finality-provider.git +Download and install Golang 1.21. Verify the installation with the following command: + +```shell +go version +``` + +### Step 1: Clone the Finality Provider Repository + +Subsequently Clone the finality provider +[repository](https://github.com/babylonlabs-io/finality-provider) and navigate to the +`bbn-testnet-5` tag. + +```shell +git clone https://github.com/babylonchain/finality-provider.git +cd finality-provider +git checkout +``` + +### Step 2: Build and Install Finality Provider Binaries + +Run: +```shell +make install +``` + +This command will: +- Build and compile all Go packages +- Install binaries to `$GOPATH/bin`: + - `eotsd`: EOTS manager daemon + - `fpd`: Finality provider daemon + - `fpcli`: Finality provider CLI tool +- Make commands globally accessible from your terminal + +### Step 3: Verify Installation + +Run `eotsd` to check the available actions: + +```shell +eotsd +``` + +Sample output: + +```shell +NAME: + eotsd - Extractable One Time Signature Daemon (eotsd). + +USAGE: + eotsd [global options] command [command options] [arguments...] + +COMMANDS: + start Start the Extractable One Time Signature Daemon. + init Initialize the eotsd home directory. + sign-schnorr Signs a Schnorr signature over arbitrary data with +... +``` + +If your shell cannot find the installed binaries, make sure `$GOPATH/bin` is in +the `$PATH` of your shell. Usually these commands will do the job + +```shell +export PATH=$HOME/go/bin:$PATHecho 'export PATH=$HOME/go/bin:$PATH' >> +~/.profile +``` + +## Install Babylon Binary + +Clone the Babylon [repository](https://github.com/babylonlabs-io/babylon) and +checkout the `bbn-testnet-5` tag: + +```shell +git clone git@github.com:babylonlabs-io/babylon.git +cd babylon +git checkout ``` -You can choose a specific version from -the [official releases page](https://github.com/babylonlabs-io/finality-provider/releases) +### Step 1: Build and Install the Babylon Binary -```bash -cd finality-provider # cd into the project directory -git checkout +Run: +```shell +make install ``` -### Building and installing the binary +This command will: +- Build and compile all Go packages +- Install binary to `$GOPATH/bin`: + - `babylond`: Babylon network daemon +- Make command globally accessible from your terminal + +### Step 2: Verify Installation -At the top-level directory of the project +Run `babylond` to see the available commands: -```bash -make install +```shell +babylond ``` -The above command will build and install the following binaries to -`$GOPATH/bin`: +Sample output: -- `eotsd`: The daemon program for the EOTS manager. -- `fpd`: The daemon program for the finality-provider with overall commands. +```shell +Available Commands: + add-genesis-account Add a genesis account to genesis.json + collect-gentxs Collect genesis txs and output a genesis.json file + comet CometBFT subcommands + config Utilities for managing application configuration ... +``` -If your shell cannot find the installed binaries, make sure `$GOPATH/bin` is in -the `$PATH` of your shell. Usually these commands will do the job +If your shell cannot find the installed binaries, make sure `$GOPATH/bin`  +is in the `$PATH` of your shell. The following command should help this issue. -```bash +```shell export PATH=$HOME/go/bin:$PATH echo 'export PATH=$HOME/go/bin:$PATH' >> ~/.profile ``` -## 3. Setting up a finality provider +## Connecting to a Babylon Node -### 3.1. Setting up a Babylon Full Node +To operate as a finality provider, the Finality Provider program must be connected +to a Babylon node. It is highly recommended for each finality provider to set up +their own node to ensure network reliability and direct access to network updates. -Before setting up the finality provider toolset, -an operator must ensure a working connection with a Babylon full node. -It is highly recommended that operators run their own node to avoid -trusting third parties. Instructions on how to set up a full Babylon node -can be found in -[the Babylon documentation](https://docs.babylonchain.io/docs/user-guides/btc-staking-testnet/setup-node). +For detailed instructions on setting up a Babylon node, please refer to the +[Setting up a Node](https://github.com/babylonlabs-io/networks/syncing-a-node) +section of the Babylon Networks repository. -### 3.2. Setting up the EOTS Manager +## Setting up the EOTS Manager -After a node and a keyring have been set up, -the operator can set up and run the +>Note: If you have already set up an EOTS Manager, you can skip this section. +The following steps are only for users who have not yet set up an EOTS Manager. +Phase 1 users who already have an EOTS Manager set up can skip to the +[Loading Existing Keys](#loading-existing-keys-only-for-phase-1-finality-providers) +section at the end of this guide for specific instructions +on re-using their Phase 1 EOTS keys. + +After a node and a keyring have been set up, the operator can set up and run the Extractable One Time Signature (EOTS) manager daemon. -A complete overview of the EOTS manager, its operation, and -its configuration options can be found in the -[EOTS Manager page](docs/eots.md) - -### 3.3. Setting up a Finality Provider - -The last step is to set up and run -the finality daemon. -A complete overview of the finality daemon, its operation, and -its configuration options can be found in the -[Finality page](docs/finality-provider.md). - -## 4. Delegations & Rewards - -A finality provider receives BTC delegations through delegators -interacting with Babylon and choosing it as the recipient of their delegations. -To perform a self-delegation, -the operator can either visit the staking web app we provide, -or run the Babylon [BTC Staker program](https://github.com/babylonlabs-io/btc-staker) once. -The BTC staker connects to a Bitcoin wallet and Babylon to perform delegations. + +The EOTS daemon is responsible for managing EOTS keys, producing EOTS +randomness, and using them to produce EOTS signatures. To read more on the EOTS +Manager see [here](#) + +### Step 1: Initialize the EOTS Manager + +Use the `eotsd init` command to initialize a home directory for the EOTS Manager. +You can set or change your home directory using the `--home` tag. For example, use +`--home ./eotsKey` to specify a custom directory. + +```shell +eotsd init --home +``` + +### Step 2: Create an EOTS Key + +Once the EOTS Manager is initialized, you need to create an EOTS key: + +``` shell +eotsd keys add --key-name --home +``` + +You will be prompted to enter and confirm a passphrase. +Ensure this is completed before starting the daemon. + +Sample output: + +```json +{ + "name": "eots", + "pub_key_hex": + "e1e72d270b90b24f395e76b417218430a75683bd07cf98b91cf9219d1c777c19", + "mnemonic": "parade hybrid century project toss gun undo ocean exercise + figure decorate basket peace raw spot gap dose daring patch ski purchase + prefer can pair" +} +``` + +## Loading Existing Keys (Only for Phase 1 Finality Providers) + +Note: This section is only for users who participated in Phase 1 and already +have an EOTS key. If you are a new user, you can skip this section. + +If you participated in Phase 1, follow these steps to load your existing EOTS +key and configure it for Phase 2. + +### Step 1: Verify Your EOTS Key Backup +Before proceeding, ensure you have a backup of your Phase 1 EOTS key. +You will need this backup file to import the key into the Phase 2 environment. + +### Step 2: Import Your EOTS Key into the Keyring +To load your existing EOTS key, use the following command to import it into the +keyring: + +```shell +eotsd keys import +``` + +- ``: The name you want to assign to this key in Phase 2. +- ``: The path to your EOTS key backup file from Phase 1. + +## Starting the EOTS Daemon + +You will need to navigate to the You can start the EOTS daemon using the following command: + +```shell +eotsd start --home +``` + +This command starts the EOTS RPC server at the address specified in eotsd.conf +under the RpcListener field (default: 127.0.0.1:12582). You can override this value +by specifying a custom address with the --rpc-listener flag. + +```shell +2024-10-30T12:42:29.393259Z info Metrics server is starting +{"addr": "127.0.0.1:2113"} +2024-10-30T12:42:29.393278Z info RPC server listening {"address": "127.0.0.1:12582"} +2024-10-30T12:42:29.393363Z info EOTS Manager Daemon is fully active! +EOTS Manager Daemon is fully active! +``` + +>**Note**: It is recommended to run the `eotsd` daemon on a separate machine or +network segment to enhance security. This helps isolate the key management +functionality and reduces the potential attack surface. You can edit +the`EOTSManagerAddress` in the configuration file of the finality provider to +reference the address of the machine where `eotsd` is running. + +## Setting up the Finality Provider + +The Finality Provider Daemon (FPD) is responsible for monitoring new Babylon blocks, +committing public randomness for the blocks it intends to provide finality signatures for, +and submitting finality signatures. For more information on Finality Providers, please see +[here](#). + +### Step 1: Initialize the Finality Provider Daemon + +Use the fpd init command to initialize a home directory for the Finality Provider. +You can set or change the home directory using the `--home` tag. For example, use +`--home ./fpKeys` to specify a custom directory. + +```shell +fpd init --home +``` + +>Note: Running this command may return the message +`service injective.evm.v1beta1.Msg does not have cosmos.msg.v1.service proto annotation`, +which is expected and can be ignored. + +### Step 2: Add a Key for the Finality Provider on the Babylon Chain + +The Finality Provider Daemon uses a keyring to store keys locally, enabling it to sign +transactions on the Babylon chain. + +Add a key for your finality provider: + +```shell +Copy code +fpd keys add --keyname --keyring-backend test --home +--keyring-backend +``` + +Options: +- `test`: Stores keys unencrypted on disk. This is suitable for testing but not recommended +for production. +- `file`: Stores encrypted keys on disk, offering more security than the test option. +- `os`: Uses the operating system's native keyring for the highest level of security, +relying on OS-managed encryption and access controls. + +The command will create a new key pair and store it in your keyring. Sample output: + +```shell +- address: bbn19gulf0a4yz87twpjl8cxnerc2wr2xqm9fsygn9 + name: finality-provider + pubkey: '{"@type":"/cosmos.crypto.secp256k1.PubKey", + "key":"AhZAL00gKplLQKpLMiXPBqaKCoiessoewOaEATKd4Rcy"}' + type: local +``` + +>Note: Verify the chain-id by checking the Babylon RPC node status at +[https://rpc.testnet5.babylonlabs.io/status](https://rpc.testnet5.babylonlabs.io/status). + +### Step 3: Configure fpd.config + +After initializing the Finality Provider Daemon, it will generate an fpd.config file. +Open config.toml to set the necessary parameters as shown below: + +```shell +[Application Options] +EOTSManagerAddress = 127.0.0.1:12582 +RpcListener = 127.0.0.1:12581 + +[babylon] +Key = # the key you used above +ChainID = bbn-test-5 +RPCAddr = http://127.0.0.1:26657 +GRPCAddr = https://127.0.0.1:9090 +KeyDirectory = ./fpKey +``` + +The Key field stores the name of the key used for signing transactions on the +Babylon chain and should match the key name specified during key creation. +KeyDirectory points to the location where the keyring is stored. + +The Finality Provider Daemon is responsible for monitoring for new Babylon +blocks, committing public randomness for the blocks it intends to provide +finality signatures for, and submitting finality signatures. To read more on +Finality Providers please see [here](#) + + +The `fpd init` command initializes a home directory for the EOTS manager. You +can wish to set/change your home directory with the `--home` tag. For the home +`` we have used `./fpKey` + +``` shell +fpd init --home +``` + +Note: will return +`service injective.evm.v1beta1.Msg does not have cosmos.msg.v1.service proto annotation` +which is expected and can be ignored. + +### Step 4: Add key for the finality provider on the Babylon chain + +The keyring is maintained by the finality provider daemon, this is local storage +of the keys that the daemon uses. The account associated with this key exists on +the babylon chain. + +Use the following command to add a key for your finality provider: + +```shell +fpd keys add --keyname --keyring-backend test --home +``` + +We use `--keyring-backend test`, which specifies which backend to use for the +keyring, `test` stores keys unencrypted on disk. For production environments, +use `file` or `os` backend. + + + There are three options for the keyring backend: + + `test`: Stores keys unencrypted on disk. It’s meant for testing purposes and + should never be used in production. `file`: Stores encrypted keys on disk, + which is a more secure option than test but less secure than using the OS + keyring. `os`: Uses the operating system's native keyring, providing the + highest level of security by relying on OS-managed encryption and access + controls. + +This command will create a new key pair and store it in your keyring. The output +should look similar to the below. + +``` shell +- address: bbn19gulf0a4yz87twpjl8cxnerc2wr2xqm9fsygn9 + name: finality-provider pubkey: + '{"@type":"/cosmos.crypto.secp256k1.PubKey", + "key":"AhZAL00gKplLQKpLMiXPBqaKCoiessoewOaEATKd4Rcy"}' + type: local +``` + +>Note: Please verify the `chain-id` from the Babylon RPC +node [https://rpc.testnet5.babylonlabs.io/status] +(https://rpc.testnet5.babylonlabs.io/status) + + >The configuration below requires to point to the path where this keyring is + stored `KeyDirectory`. This `Key` field stores the key name used for + interacting with the babylon chain and will be specified along with + the `KeyringBackend`field in the next step. So we can ignore the setting of the + two fields in this step. + +Once the node is initialized with the above command. It should generate a +`fpd.config` Edit the `config.toml` to set the necessary parameters with the +below + +```shell +[Application Options] EOTSManagerAddress = 127.0.0.1:12582 RpcListener += 127.0.0.1:12581 + +[babylon] Key = // the key you used above +ChainID = bbn-test-5 RPCAddr = http://127.0.0.1:26657 GRPCAddr = +https://127.0.0.1:9090 KeyDirectory = ./fpKey +``` + +### Step 3: Verify the Key Import +After importing, verify that your EOTS key was successfully loaded: + +```shell +eotsd keys list +``` + +You should see your EOTS key listed with the correct details, confirming that +it has been imported correctly. + +>Note: Make sure you're using the same key name and EOTS public key that were +registered in Phase 1. + + +## Starting the Finality provider Daemon + +The finality provider daemon (FPD) needs to be running before proceeding with +registration or voting participation. + +Start the daemon with: + +``` shell +fpd start --home ./fp +``` + +The command flags: +- `start`: Initiates the FPD daemon +- `--home`: Specifies the directory for daemon data and configuration + +The daemon will start the RPC server for CLI communication then begin listening +for incoming requests and finally initialize finality provider services + +You should see logs indicating successful startup: + +``` +[INFO] Starting finality provider daemon... +[INFO] RPC server listening on... +``` + +>Note: Keep this terminal window open as the daemon needs to run continuously. + +The above will start the Finality provider RPC server at the address specified +in `fpd.conf` under the `RpcListener` field, which has a default value +of `127.0.0.1:12581`. You can change this value in the configuration file or +override this value and specify a custom address using +the `--rpc-listener` flag. + +To start the daemon with a specific finality provider instance, use +the `--btc-pk` flag followed by the hex string of the BTC public key of the +finality provider (`btc_pk_hex`) in the next step + +All the available CLI options can be viewed using the `--help` flag. These +options can also be set in the configuration file. + +## Create Finality Provider + +The `create-finality-provider` command initializes a new finality provider +instance locally. This command: + +- Generates a BTC public key that uniquely identifies your finality provider +- Creates a Babylon account to receive staking rewards + +``` shell +fpd create-finality-provider \ --daemon-address 127.0.0.1:12581 \ --chain-id +bbn-test-5 \ --commission 0.05 \ --key-name finality-provider \ --moniker +"MyFinalityProvider" \ --website "https://myfinalityprovider.com" \ +--security-contact "security@myfinalityprovider.com" \ --details "finality +provider for the Babylon network" \ --home ./fp \ --passphrase "passphrase" +``` + +Required parameters: - `--chain-id`: The Babylon chain ID (`bbn-test-5`) - +`--commission`: The commission rate (between 0 and 1) that you'll receive from +delegators - `--key-name`: Name of the key in your keyring for signing +transactions - `--moniker`: A human-readable name for your finality provider + +Optional parameters: - `--website`: Your finality provider's website - +`--security-contact`: Contact email for security issues - `--details`: +Additional description of your finality provider - `--daemon-address`: RPC +address of the finality provider daemon (default: 127.0.0.1:12581) + +Upon successful creation, the command will return a JSON response containing +your finality provider's details: + +``` json +{ + "fp_addr": "bbn1ht2nxa6hlyl89m8xpdde9xsj40n0sxd2f9shsq", + "btc_pk_hex": + "cf0f03b9ee2d4a0f27240e2d8b8c8ef609e24358b2eb3cfd89ae4e4f472e1a41", + "description": + { + "moniker": "MyFinalityProvider", + "website": "https://myfinalityprovider.com", + "security_contact": "security@myfinalityprovider.com", + "details": "finality provider for the Babylon network" + }, + "commission": "0.050000000000000000", + "status": "CREATED" +} +``` + +The response includes: +- `fp_addr`: Your Babylon account address for receiving +rewards +- `btc_pk_hex`: Your unique BTC public key identifier (needed for +registration) +- `description`: Your finality provider's metadata +- `commission`: +Your set commission rate +- `status`: Current status of the finality provider + +## Register Finality Provider + +The `register-finality-provider` command registers your finality provider on the +Babylon chain. This command requires: + +1. The BTC public key (obtained from the `create-finality-provider` command) +2. A funded Babylon account (needs BBN tokens for transaction fees) +3. A running FPD daemon + +``` shell +fpd register-finality-provider \ +cf0f03b9ee2d4a0f27240e2d8b8c8ef609e24358b2eb3cfd89ae4e4f472e1a41 \ +--daemon-address 127.0.0.1:12581 \ --passphrase "Zubu99012" \ --home ./fp \ +``` + +> Note: The BTC public key (`cf0f03...1a41`) is obtained from the previous +`create-finality-provider` command. + +If successful, the command will return a transaction hash: + +``` shell +{ "tx_hash": +"C08377CF289DF0DC5FA462E6409ADCB65A3492C22A112C58EA449F4DC544A3B1" } +``` + + You can query this hash to confirm the transaction was successful by navigating + to the babylon chain and making a query, such as below: + +```shell +babylond query tx --chain-id bbn-test-5 +``` + +>Note: This query must be executed using the Babylon daemon (`babylond`), not +the finality provider daemon (`fpd`), as the registration transaction is +recorded on the Babylon blockchain. + +The hash returned should look something similar to below: + +```shell + type: message +- attributes: + - index: true + key: fp value: + '{ + "addr":"bbn1ht2nxa6hlyl89m8xpdde9xsj40n0sxd2f9shsq", + "description": + { + "moniker":"MyFinalityProvider", + "identity":" + ","website":"https://myfinalityprovider.com", + "security_contact":"security@myfinalityprovider.com", + "details":"Reliablefinality provider for the Babylon + network" + }, + "commission":"0.050000000000000000", + "btc_pk":"cf0f03b9ee2d4a0f27240e2d8b8c8ef609e24358b2eb3cfd89ae4e4f472e1a41", + "pop":{"btc_sig_type":"BIP340", + "btc_sig":"YJgc6NU7Z011imqSfPc9w/Namr1hFj48oTlEjGqbAVvHJv+9h3p/1shTohEb1g0fDWij7Ti9yKZzjAgNVepObA=="}, + "slashed_babylon_height":"0", + "slashed_btc_height":"0", + "jailed":false, + "consumer_id":"euphrates-0.5.0" + }' + - index: true + key: msg_index value: "0" + type: babylon.btcstaking.v1.EventNewFinalityProvider +gas_used: "82063" gas_wanted: "94429" height: "66693" info: "" logs: [] raw_log:"" +``` + +When a finality provider is created, it's associated with two key elements: + +**a) BTC Public Key:** - This serves as the unique identifier for the finality +provider. - It's derived from a Bitcoin private key, likely using the secp256k1 +elliptic curve. - This key is used in the Bitcoin-based security model of +Babylon. + +**b) Babylon Account:** - This is an account on the Babylon blockchain. - It's +where staking rewards for the finality provider are sent. - This account is +controlled by the key you use to create and manage the finality provider (the +one you added with fpd keys add). + +This dual association allows the finality provider to interact with both the +Bitcoin network (for security) and the Babylon network (for rewards and +governance). + +## Slashing Conditions + +Slashing occurs when a finality provider **double signs**. This occurs when a +finality provider signs conflicting blocks at the same height. This results in +the extraction of the provider's private key and automatically triggers shutdown +of the finality provider. + +### Withdrawing Rewards + +When withdrawing rewards, you need to use the Babylon chain's CLI since rewards +are managed by the main chain. + +To withdraw your finality provider rewards: + +``` babylond tx incentive finality_provider ... ``` + + From 92e37d30dc5b7cd3c2d10dbb4b6cc7a121aacfcd Mon Sep 17 00:00:00 2001 From: Sam Ricotta Date: Fri, 15 Nov 2024 14:04:21 +0200 Subject: [PATCH 06/53] Revert "Update README.md" This reverts commit ca832e6bb24c33eee7cd82e27a97cf32250ff928. --- README.md | 698 +++++++----------------------------------------------- 1 file changed, 84 insertions(+), 614 deletions(-) diff --git a/README.md b/README.md index eeea8be..4d10096 100644 --- a/README.md +++ b/README.md @@ -1,649 +1,119 @@ -# Finality Provider Phase 2 Migration Guide +# Finality Provider -This guide covers the Phase 2 launch of the Babylon network, -a critical transition that introduces active participation -in finality voting, rewards distribution, and the Proof of -Stake (PoS) system. This migration represents a shift from -the limited role of finality providers in Phase 1 to a fully -active role in network security and governance in Phase 2. -This guide provides a step-by-step process for operators to -onboard, whether setting up anew or using a pre-existing setup, -with a focus on Phase 2-specific requirements. +A toolset crafted for the creation and +management of Finality Providers. -The following explains the migration from Phase 1 to 2. +## 1. Overview -## Phase 1 (Previous phase) +Finality providers are responsible for voting +at a finality round on top of [CometBFT](https://github.com/cometbft/cometbft). +Similar to any native PoS validator, +a finality provider can receive voting power delegations from BTC stakers, and +can earn commission from the staking rewards denominated in Babylon tokens. +The core logic of a finality provider instance can be found in +[Finality Provider Core](./docs/fp-core.md). -- Only involves Bitcoin holders submitting staking transactions -- No active Proof of Stake (PoS) chain operation -- Finality providers only need EOTS keys registered -- No need to run finality service +The finality provider toolset does not have +any special hardware requirements +and can operate on standard mid-sized machines +running a UNIX-flavored operating system. +It consists of the following programs: -## Phase 2 (New phase) +- *Babylon full node*: An instance of a Babylon node connecting to + the Babylon network. Running one is not a strict requirement, + but it is recommended for security compared to trusting a third-party RPC node. +- *Extractable One-Time Signature (EOTS) manager*: + A daemon responsible for securely maintaining the finality provider’s + private key and producing extractable one time signatures from it. +- *Finality Provider*: A daemon managing the finality provider. + It connects to the EOTS manager to generate EOTS public randomness and + finality votes for Babylon blocks, which it submits to Babylon through + the node connection. -- Active participation in finality voting -- Running the complete finality provider toolset: - - Babylon full node - - EOTS manager daemon - - Finality provider daemon -- Earning commissions from delegations -- Proof of Stake (PoS) and network security -- Rewards distribution -- Participating in governance +The following graphic demonstrates the interconnections between the above programs: -There are 2 different types of paths for Finality providers +![Finality Provider Interconnections](./docs/finality-toolset.png) -1. **New Setup** - - For operators starting fresh - - Need to generate both EOTS and FP keys - - Complete full configuration process +## 2. Installation -If you are a new operator, start with the -[Install Finality Provider Binary](#install-finality-provider-binary) section. +### Prerequisites - 2. **Has existing EOTS Key** - - Already have EOTS key from Phase 1 - - Reference existing EOTS key in setup +This project requires Go version 1.23 or later. -If you have an existing EOTS key from Phase 1 please skip to -[Loading Existing Keys](#loading-existing-keys-only-for-phase-1-finality-providers) -steps +Install Go by following the instructions on +the [official Go installation guide](https://golang.org/doc/install). -For an introduction on the finality providers see (here) - +### Downloading the code -## Install Finality Provider Binary - -Download [Golang 1.21](https://go.dev/dl)  +To get started, clone the repository to your local machine from Github: -Download and install Golang 1.21. Verify the installation with the following command: - -```shell -go version -``` - -### Step 1: Clone the Finality Provider Repository - -Subsequently Clone the finality provider -[repository](https://github.com/babylonlabs-io/finality-provider) and navigate to the -`bbn-testnet-5` tag. - -```shell -git clone https://github.com/babylonchain/finality-provider.git -cd finality-provider -git checkout -``` - -### Step 2: Build and Install Finality Provider Binaries - -Run: -```shell -make install -``` - -This command will: -- Build and compile all Go packages -- Install binaries to `$GOPATH/bin`: - - `eotsd`: EOTS manager daemon - - `fpd`: Finality provider daemon - - `fpcli`: Finality provider CLI tool -- Make commands globally accessible from your terminal - -### Step 3: Verify Installation - -Run `eotsd` to check the available actions: - -```shell -eotsd -``` - -Sample output: - -```shell -NAME: - eotsd - Extractable One Time Signature Daemon (eotsd). - -USAGE: - eotsd [global options] command [command options] [arguments...] - -COMMANDS: - start Start the Extractable One Time Signature Daemon. - init Initialize the eotsd home directory. - sign-schnorr Signs a Schnorr signature over arbitrary data with -... -``` - -If your shell cannot find the installed binaries, make sure `$GOPATH/bin` is in -the `$PATH` of your shell. Usually these commands will do the job - -```shell -export PATH=$HOME/go/bin:$PATHecho 'export PATH=$HOME/go/bin:$PATH' >> -~/.profile -``` - -## Install Babylon Binary - -Clone the Babylon [repository](https://github.com/babylonlabs-io/babylon) and -checkout the `bbn-testnet-5` tag: - -```shell -git clone git@github.com:babylonlabs-io/babylon.git -cd babylon -git checkout +```bash +git clone https://github.com/babylonlabs-io/finality-provider.git ``` -### Step 1: Build and Install the Babylon Binary +You can choose a specific version from +the [official releases page](https://github.com/babylonlabs-io/finality-provider/releases) -Run: -```shell -make install +```bash +cd finality-provider # cd into the project directory +git checkout ``` -This command will: -- Build and compile all Go packages -- Install binary to `$GOPATH/bin`: - - `babylond`: Babylon network daemon -- Make command globally accessible from your terminal - -### Step 2: Verify Installation +### Building and installing the binary -Run `babylond` to see the available commands: +At the top-level directory of the project -```shell -babylond +```bash +make install ``` -Sample output: +The above command will build and install the following binaries to +`$GOPATH/bin`: -```shell -Available Commands: - add-genesis-account Add a genesis account to genesis.json - collect-gentxs Collect genesis txs and output a genesis.json file - comet CometBFT subcommands - config Utilities for managing application configuration ... -``` +- `eotsd`: The daemon program for the EOTS manager. +- `fpd`: The daemon program for the finality-provider with overall commands. -If your shell cannot find the installed binaries, make sure `$GOPATH/bin`  -is in the `$PATH` of your shell. The following command should help this issue. +If your shell cannot find the installed binaries, make sure `$GOPATH/bin` is in +the `$PATH` of your shell. Usually these commands will do the job -```shell +```bash export PATH=$HOME/go/bin:$PATH echo 'export PATH=$HOME/go/bin:$PATH' >> ~/.profile ``` -## Connecting to a Babylon Node +## 3. Setting up a finality provider -To operate as a finality provider, the Finality Provider program must be connected -to a Babylon node. It is highly recommended for each finality provider to set up -their own node to ensure network reliability and direct access to network updates. +### 3.1. Setting up a Babylon Full Node -For detailed instructions on setting up a Babylon node, please refer to the -[Setting up a Node](https://github.com/babylonlabs-io/networks/syncing-a-node) -section of the Babylon Networks repository. +Before setting up the finality provider toolset, +an operator must ensure a working connection with a Babylon full node. +It is highly recommended that operators run their own node to avoid +trusting third parties. Instructions on how to set up a full Babylon node +can be found in +[the Babylon documentation](https://docs.babylonchain.io/docs/user-guides/btc-staking-testnet/setup-node). -## Setting up the EOTS Manager +### 3.2. Setting up the EOTS Manager ->Note: If you have already set up an EOTS Manager, you can skip this section. -The following steps are only for users who have not yet set up an EOTS Manager. -Phase 1 users who already have an EOTS Manager set up can skip to the -[Loading Existing Keys](#loading-existing-keys-only-for-phase-1-finality-providers) -section at the end of this guide for specific instructions -on re-using their Phase 1 EOTS keys. - -After a node and a keyring have been set up, the operator can set up and run the +After a node and a keyring have been set up, +the operator can set up and run the Extractable One Time Signature (EOTS) manager daemon. - -The EOTS daemon is responsible for managing EOTS keys, producing EOTS -randomness, and using them to produce EOTS signatures. To read more on the EOTS -Manager see [here](#) - -### Step 1: Initialize the EOTS Manager - -Use the `eotsd init` command to initialize a home directory for the EOTS Manager. -You can set or change your home directory using the `--home` tag. For example, use -`--home ./eotsKey` to specify a custom directory. - -```shell -eotsd init --home -``` - -### Step 2: Create an EOTS Key - -Once the EOTS Manager is initialized, you need to create an EOTS key: - -``` shell -eotsd keys add --key-name --home -``` - -You will be prompted to enter and confirm a passphrase. -Ensure this is completed before starting the daemon. - -Sample output: - -```json -{ - "name": "eots", - "pub_key_hex": - "e1e72d270b90b24f395e76b417218430a75683bd07cf98b91cf9219d1c777c19", - "mnemonic": "parade hybrid century project toss gun undo ocean exercise - figure decorate basket peace raw spot gap dose daring patch ski purchase - prefer can pair" -} -``` - -## Loading Existing Keys (Only for Phase 1 Finality Providers) - -Note: This section is only for users who participated in Phase 1 and already -have an EOTS key. If you are a new user, you can skip this section. - -If you participated in Phase 1, follow these steps to load your existing EOTS -key and configure it for Phase 2. - -### Step 1: Verify Your EOTS Key Backup -Before proceeding, ensure you have a backup of your Phase 1 EOTS key. -You will need this backup file to import the key into the Phase 2 environment. - -### Step 2: Import Your EOTS Key into the Keyring -To load your existing EOTS key, use the following command to import it into the -keyring: - -```shell -eotsd keys import -``` - -- ``: The name you want to assign to this key in Phase 2. -- ``: The path to your EOTS key backup file from Phase 1. - -## Starting the EOTS Daemon - -You will need to navigate to the You can start the EOTS daemon using the following command: - -```shell -eotsd start --home -``` - -This command starts the EOTS RPC server at the address specified in eotsd.conf -under the RpcListener field (default: 127.0.0.1:12582). You can override this value -by specifying a custom address with the --rpc-listener flag. - -```shell -2024-10-30T12:42:29.393259Z info Metrics server is starting -{"addr": "127.0.0.1:2113"} -2024-10-30T12:42:29.393278Z info RPC server listening {"address": "127.0.0.1:12582"} -2024-10-30T12:42:29.393363Z info EOTS Manager Daemon is fully active! -EOTS Manager Daemon is fully active! -``` - ->**Note**: It is recommended to run the `eotsd` daemon on a separate machine or -network segment to enhance security. This helps isolate the key management -functionality and reduces the potential attack surface. You can edit -the`EOTSManagerAddress` in the configuration file of the finality provider to -reference the address of the machine where `eotsd` is running. - -## Setting up the Finality Provider - -The Finality Provider Daemon (FPD) is responsible for monitoring new Babylon blocks, -committing public randomness for the blocks it intends to provide finality signatures for, -and submitting finality signatures. For more information on Finality Providers, please see -[here](#). - -### Step 1: Initialize the Finality Provider Daemon - -Use the fpd init command to initialize a home directory for the Finality Provider. -You can set or change the home directory using the `--home` tag. For example, use -`--home ./fpKeys` to specify a custom directory. - -```shell -fpd init --home -``` - ->Note: Running this command may return the message -`service injective.evm.v1beta1.Msg does not have cosmos.msg.v1.service proto annotation`, -which is expected and can be ignored. - -### Step 2: Add a Key for the Finality Provider on the Babylon Chain - -The Finality Provider Daemon uses a keyring to store keys locally, enabling it to sign -transactions on the Babylon chain. - -Add a key for your finality provider: - -```shell -Copy code -fpd keys add --keyname --keyring-backend test --home ---keyring-backend -``` - -Options: -- `test`: Stores keys unencrypted on disk. This is suitable for testing but not recommended -for production. -- `file`: Stores encrypted keys on disk, offering more security than the test option. -- `os`: Uses the operating system's native keyring for the highest level of security, -relying on OS-managed encryption and access controls. - -The command will create a new key pair and store it in your keyring. Sample output: - -```shell -- address: bbn19gulf0a4yz87twpjl8cxnerc2wr2xqm9fsygn9 - name: finality-provider - pubkey: '{"@type":"/cosmos.crypto.secp256k1.PubKey", - "key":"AhZAL00gKplLQKpLMiXPBqaKCoiessoewOaEATKd4Rcy"}' - type: local -``` - ->Note: Verify the chain-id by checking the Babylon RPC node status at -[https://rpc.testnet5.babylonlabs.io/status](https://rpc.testnet5.babylonlabs.io/status). - -### Step 3: Configure fpd.config - -After initializing the Finality Provider Daemon, it will generate an fpd.config file. -Open config.toml to set the necessary parameters as shown below: - -```shell -[Application Options] -EOTSManagerAddress = 127.0.0.1:12582 -RpcListener = 127.0.0.1:12581 - -[babylon] -Key = # the key you used above -ChainID = bbn-test-5 -RPCAddr = http://127.0.0.1:26657 -GRPCAddr = https://127.0.0.1:9090 -KeyDirectory = ./fpKey -``` - -The Key field stores the name of the key used for signing transactions on the -Babylon chain and should match the key name specified during key creation. -KeyDirectory points to the location where the keyring is stored. - -The Finality Provider Daemon is responsible for monitoring for new Babylon -blocks, committing public randomness for the blocks it intends to provide -finality signatures for, and submitting finality signatures. To read more on -Finality Providers please see [here](#) - - -The `fpd init` command initializes a home directory for the EOTS manager. You -can wish to set/change your home directory with the `--home` tag. For the home -`` we have used `./fpKey` - -``` shell -fpd init --home -``` - -Note: will return -`service injective.evm.v1beta1.Msg does not have cosmos.msg.v1.service proto annotation` -which is expected and can be ignored. - -### Step 4: Add key for the finality provider on the Babylon chain - -The keyring is maintained by the finality provider daemon, this is local storage -of the keys that the daemon uses. The account associated with this key exists on -the babylon chain. - -Use the following command to add a key for your finality provider: - -```shell -fpd keys add --keyname --keyring-backend test --home -``` - -We use `--keyring-backend test`, which specifies which backend to use for the -keyring, `test` stores keys unencrypted on disk. For production environments, -use `file` or `os` backend. - - - There are three options for the keyring backend: - - `test`: Stores keys unencrypted on disk. It’s meant for testing purposes and - should never be used in production. `file`: Stores encrypted keys on disk, - which is a more secure option than test but less secure than using the OS - keyring. `os`: Uses the operating system's native keyring, providing the - highest level of security by relying on OS-managed encryption and access - controls. - -This command will create a new key pair and store it in your keyring. The output -should look similar to the below. - -``` shell -- address: bbn19gulf0a4yz87twpjl8cxnerc2wr2xqm9fsygn9 - name: finality-provider pubkey: - '{"@type":"/cosmos.crypto.secp256k1.PubKey", - "key":"AhZAL00gKplLQKpLMiXPBqaKCoiessoewOaEATKd4Rcy"}' - type: local -``` - ->Note: Please verify the `chain-id` from the Babylon RPC -node [https://rpc.testnet5.babylonlabs.io/status] -(https://rpc.testnet5.babylonlabs.io/status) - - >The configuration below requires to point to the path where this keyring is - stored `KeyDirectory`. This `Key` field stores the key name used for - interacting with the babylon chain and will be specified along with - the `KeyringBackend`field in the next step. So we can ignore the setting of the - two fields in this step. - -Once the node is initialized with the above command. It should generate a -`fpd.config` Edit the `config.toml` to set the necessary parameters with the -below - -```shell -[Application Options] EOTSManagerAddress = 127.0.0.1:12582 RpcListener -= 127.0.0.1:12581 - -[babylon] Key = // the key you used above -ChainID = bbn-test-5 RPCAddr = http://127.0.0.1:26657 GRPCAddr = -https://127.0.0.1:9090 KeyDirectory = ./fpKey -``` - -### Step 3: Verify the Key Import -After importing, verify that your EOTS key was successfully loaded: - -```shell -eotsd keys list -``` - -You should see your EOTS key listed with the correct details, confirming that -it has been imported correctly. - ->Note: Make sure you're using the same key name and EOTS public key that were -registered in Phase 1. - - -## Starting the Finality provider Daemon - -The finality provider daemon (FPD) needs to be running before proceeding with -registration or voting participation. - -Start the daemon with: - -``` shell -fpd start --home ./fp -``` - -The command flags: -- `start`: Initiates the FPD daemon -- `--home`: Specifies the directory for daemon data and configuration - -The daemon will start the RPC server for CLI communication then begin listening -for incoming requests and finally initialize finality provider services - -You should see logs indicating successful startup: - -``` -[INFO] Starting finality provider daemon... -[INFO] RPC server listening on... -``` - ->Note: Keep this terminal window open as the daemon needs to run continuously. - -The above will start the Finality provider RPC server at the address specified -in `fpd.conf` under the `RpcListener` field, which has a default value -of `127.0.0.1:12581`. You can change this value in the configuration file or -override this value and specify a custom address using -the `--rpc-listener` flag. - -To start the daemon with a specific finality provider instance, use -the `--btc-pk` flag followed by the hex string of the BTC public key of the -finality provider (`btc_pk_hex`) in the next step - -All the available CLI options can be viewed using the `--help` flag. These -options can also be set in the configuration file. - -## Create Finality Provider - -The `create-finality-provider` command initializes a new finality provider -instance locally. This command: - -- Generates a BTC public key that uniquely identifies your finality provider -- Creates a Babylon account to receive staking rewards - -``` shell -fpd create-finality-provider \ --daemon-address 127.0.0.1:12581 \ --chain-id -bbn-test-5 \ --commission 0.05 \ --key-name finality-provider \ --moniker -"MyFinalityProvider" \ --website "https://myfinalityprovider.com" \ ---security-contact "security@myfinalityprovider.com" \ --details "finality -provider for the Babylon network" \ --home ./fp \ --passphrase "passphrase" -``` - -Required parameters: - `--chain-id`: The Babylon chain ID (`bbn-test-5`) - -`--commission`: The commission rate (between 0 and 1) that you'll receive from -delegators - `--key-name`: Name of the key in your keyring for signing -transactions - `--moniker`: A human-readable name for your finality provider - -Optional parameters: - `--website`: Your finality provider's website - -`--security-contact`: Contact email for security issues - `--details`: -Additional description of your finality provider - `--daemon-address`: RPC -address of the finality provider daemon (default: 127.0.0.1:12581) - -Upon successful creation, the command will return a JSON response containing -your finality provider's details: - -``` json -{ - "fp_addr": "bbn1ht2nxa6hlyl89m8xpdde9xsj40n0sxd2f9shsq", - "btc_pk_hex": - "cf0f03b9ee2d4a0f27240e2d8b8c8ef609e24358b2eb3cfd89ae4e4f472e1a41", - "description": - { - "moniker": "MyFinalityProvider", - "website": "https://myfinalityprovider.com", - "security_contact": "security@myfinalityprovider.com", - "details": "finality provider for the Babylon network" - }, - "commission": "0.050000000000000000", - "status": "CREATED" -} -``` - -The response includes: -- `fp_addr`: Your Babylon account address for receiving -rewards -- `btc_pk_hex`: Your unique BTC public key identifier (needed for -registration) -- `description`: Your finality provider's metadata -- `commission`: -Your set commission rate -- `status`: Current status of the finality provider - -## Register Finality Provider - -The `register-finality-provider` command registers your finality provider on the -Babylon chain. This command requires: - -1. The BTC public key (obtained from the `create-finality-provider` command) -2. A funded Babylon account (needs BBN tokens for transaction fees) -3. A running FPD daemon - -``` shell -fpd register-finality-provider \ -cf0f03b9ee2d4a0f27240e2d8b8c8ef609e24358b2eb3cfd89ae4e4f472e1a41 \ ---daemon-address 127.0.0.1:12581 \ --passphrase "Zubu99012" \ --home ./fp \ -``` - -> Note: The BTC public key (`cf0f03...1a41`) is obtained from the previous -`create-finality-provider` command. - -If successful, the command will return a transaction hash: - -``` shell -{ "tx_hash": -"C08377CF289DF0DC5FA462E6409ADCB65A3492C22A112C58EA449F4DC544A3B1" } -``` - - You can query this hash to confirm the transaction was successful by navigating - to the babylon chain and making a query, such as below: - -```shell -babylond query tx --chain-id bbn-test-5 -``` - ->Note: This query must be executed using the Babylon daemon (`babylond`), not -the finality provider daemon (`fpd`), as the registration transaction is -recorded on the Babylon blockchain. - -The hash returned should look something similar to below: - -```shell - type: message -- attributes: - - index: true - key: fp value: - '{ - "addr":"bbn1ht2nxa6hlyl89m8xpdde9xsj40n0sxd2f9shsq", - "description": - { - "moniker":"MyFinalityProvider", - "identity":" - ","website":"https://myfinalityprovider.com", - "security_contact":"security@myfinalityprovider.com", - "details":"Reliablefinality provider for the Babylon - network" - }, - "commission":"0.050000000000000000", - "btc_pk":"cf0f03b9ee2d4a0f27240e2d8b8c8ef609e24358b2eb3cfd89ae4e4f472e1a41", - "pop":{"btc_sig_type":"BIP340", - "btc_sig":"YJgc6NU7Z011imqSfPc9w/Namr1hFj48oTlEjGqbAVvHJv+9h3p/1shTohEb1g0fDWij7Ti9yKZzjAgNVepObA=="}, - "slashed_babylon_height":"0", - "slashed_btc_height":"0", - "jailed":false, - "consumer_id":"euphrates-0.5.0" - }' - - index: true - key: msg_index value: "0" - type: babylon.btcstaking.v1.EventNewFinalityProvider -gas_used: "82063" gas_wanted: "94429" height: "66693" info: "" logs: [] raw_log:"" -``` - -When a finality provider is created, it's associated with two key elements: - -**a) BTC Public Key:** - This serves as the unique identifier for the finality -provider. - It's derived from a Bitcoin private key, likely using the secp256k1 -elliptic curve. - This key is used in the Bitcoin-based security model of -Babylon. - -**b) Babylon Account:** - This is an account on the Babylon blockchain. - It's -where staking rewards for the finality provider are sent. - This account is -controlled by the key you use to create and manage the finality provider (the -one you added with fpd keys add). - -This dual association allows the finality provider to interact with both the -Bitcoin network (for security) and the Babylon network (for rewards and -governance). - -## Slashing Conditions - -Slashing occurs when a finality provider **double signs**. This occurs when a -finality provider signs conflicting blocks at the same height. This results in -the extraction of the provider's private key and automatically triggers shutdown -of the finality provider. - -### Withdrawing Rewards - -When withdrawing rewards, you need to use the Babylon chain's CLI since rewards -are managed by the main chain. - -To withdraw your finality provider rewards: - -``` babylond tx incentive finality_provider ... ``` - - +A complete overview of the EOTS manager, its operation, and +its configuration options can be found in the +[EOTS Manager page](docs/eots.md) + +### 3.3. Setting up a Finality Provider + +The last step is to set up and run +the finality daemon. +A complete overview of the finality daemon, its operation, and +its configuration options can be found in the +[Finality page](docs/finality-provider.md). + +## 4. Delegations & Rewards + +A finality provider receives BTC delegations through delegators +interacting with Babylon and choosing it as the recipient of their delegations. +To perform a self-delegation, +the operator can either visit the staking web app we provide, +or run the Babylon [BTC Staker program](https://github.com/babylonlabs-io/btc-staker) once. +The BTC staker connects to a Bitcoin wallet and Babylon to perform delegations. From cab8454e260f6cbd36b2cd1348ade76d4661cee5 Mon Sep 17 00:00:00 2001 From: Sam Ricotta Date: Fri, 15 Nov 2024 14:06:15 +0200 Subject: [PATCH 07/53] Update README.md --- README.md | 678 +++++++++++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 620 insertions(+), 58 deletions(-) diff --git a/README.md b/README.md index 4d10096..43079c3 100644 --- a/README.md +++ b/README.md @@ -3,7 +3,7 @@ A toolset crafted for the creation and management of Finality Providers. -## 1. Overview +## Overview Finality providers are responsible for voting at a finality round on top of [CometBFT](https://github.com/cometbft/cometbft). @@ -32,88 +32,650 @@ It consists of the following programs: The following graphic demonstrates the interconnections between the above programs: -![Finality Provider Interconnections](./docs/finality-toolset.png) -## 2. Installation +## Finality Provider Phase 2 Migration Guide -### Prerequisites +This guide covers the Phase 2 launch of the Babylon network, +a critical transition that introduces active participation +in finality voting, rewards distribution, and the Proof of +Stake (PoS) system. This migration represents a shift from +the limited role of finality providers in Phase 1 to a fully +active role in network security and governance in Phase 2. +This guide provides a step-by-step process for operators to +onboard, whether setting up anew or using a pre-existing setup, +with a focus on Phase 2-specific requirements. -This project requires Go version 1.23 or later. +The following explains the migration from Phase 1 to 2. -Install Go by following the instructions on -the [official Go installation guide](https://golang.org/doc/install). +### Phase 1 (Previous phase) -### Downloading the code +- Only involves Bitcoin holders submitting staking transactions +- No active Proof of Stake (PoS) chain operation +- Finality providers only need EOTS keys registered +- No need to run finality service -To get started, clone the repository to your local machine from Github: +### Phase 2 (New phase) -```bash -git clone https://github.com/babylonlabs-io/finality-provider.git +- Active participation in finality voting +- Running the complete finality provider toolset: + - Babylon full node + - EOTS manager daemon + - Finality provider daemon +- Earning commissions from delegations +- Proof of Stake (PoS) and network security +- Rewards distribution +- Participating in governance + +There are 2 different types of paths for Finality providers + +1. **New Setup** + - For operators starting fresh + - Need to generate both EOTS and FP keys + - Complete full configuration process + +If you are a new operator, start with the +[Install Finality Provider Binary](#install-finality-provider-binary) section. + + 2. **Has existing EOTS Key** + - Already have EOTS key from Phase 1 + - Reference existing EOTS key in setup + +If you have an existing EOTS key from Phase 1 please skip to +[Loading Existing Keys](#loading-existing-keys-only-for-phase-1-finality-providers) +steps + +## Install Finality Provider Binary + +Download [Golang 1.21](https://go.dev/dl)  + +Download and install Golang 1.21. Verify the installation with the following command: + +```shell +go version +``` + +### Step 1: Clone the Finality Provider Repository + +Subsequently Clone the finality provider +[repository](https://github.com/babylonlabs-io/finality-provider) and navigate to the +`bbn-testnet-5` tag. + +```shell +git clone https://github.com/babylonchain/finality-provider.git +cd finality-provider +git checkout +``` + +### Step 2: Build and Install Finality Provider Binaries + +Run: +```shell +make install ``` -You can choose a specific version from -the [official releases page](https://github.com/babylonlabs-io/finality-provider/releases) +This command will: +- Build and compile all Go packages +- Install binaries to `$GOPATH/bin`: + - `eotsd`: EOTS manager daemon + - `fpd`: Finality provider daemon + - `fpcli`: Finality provider CLI tool +- Make commands globally accessible from your terminal -```bash -cd finality-provider # cd into the project directory -git checkout +### Step 3: Verify Installation + +Run `eotsd` to check the available actions: + +```shell +eotsd ``` -### Building and installing the binary +Sample output: + +```shell +NAME: + eotsd - Extractable One Time Signature Daemon (eotsd). -At the top-level directory of the project +USAGE: + eotsd [global options] command [command options] [arguments...] -```bash -make install +COMMANDS: + start Start the Extractable One Time Signature Daemon. + init Initialize the eotsd home directory. + sign-schnorr Signs a Schnorr signature over arbitrary data with +... ``` -The above command will build and install the following binaries to -`$GOPATH/bin`: +If your shell cannot find the installed binaries, make sure `$GOPATH/bin` is in +the `$PATH` of your shell. Usually these commands will do the job + +```shell +export PATH=$HOME/go/bin:$PATHecho 'export PATH=$HOME/go/bin:$PATH' >> +~/.profile +``` -- `eotsd`: The daemon program for the EOTS manager. -- `fpd`: The daemon program for the finality-provider with overall commands. +## Install Babylon Binary -If your shell cannot find the installed binaries, make sure `$GOPATH/bin` is in -the `$PATH` of your shell. Usually these commands will do the job +Clone the Babylon [repository](https://github.com/babylonlabs-io/babylon) and +checkout the `bbn-testnet-5` tag: -```bash +```shell +git clone git@github.com:babylonlabs-io/babylon.git +cd babylon +git checkout +``` + +### Step 1: Build and Install the Babylon Binary + +Run: +```shell +make install +``` + +This command will: +- Build and compile all Go packages +- Install binary to `$GOPATH/bin`: + - `babylond`: Babylon network daemon +- Make command globally accessible from your terminal + +### Step 2: Verify Installation + +Run `babylond` to see the available commands: + +```shell +babylond +``` + +Sample output: + +```shell +Available Commands: + add-genesis-account Add a genesis account to genesis.json + collect-gentxs Collect genesis txs and output a genesis.json file + comet CometBFT subcommands + config Utilities for managing application configuration ... +``` + +If your shell cannot find the installed binaries, make sure `$GOPATH/bin`  +is in the `$PATH` of your shell. The following command should help this issue. + +```shell export PATH=$HOME/go/bin:$PATH echo 'export PATH=$HOME/go/bin:$PATH' >> ~/.profile ``` -## 3. Setting up a finality provider +## Connecting to a Babylon Node + +To operate as a finality provider, the Finality Provider program must be connected +to a Babylon node. It is highly recommended for each finality provider to set up +their own node to ensure network reliability and direct access to network updates. -### 3.1. Setting up a Babylon Full Node +For detailed instructions on setting up a Babylon node, please refer to the +[Setting up a Node](https://github.com/babylonlabs-io/networks/syncing-a-node) +section of the Babylon Networks repository. -Before setting up the finality provider toolset, -an operator must ensure a working connection with a Babylon full node. -It is highly recommended that operators run their own node to avoid -trusting third parties. Instructions on how to set up a full Babylon node -can be found in -[the Babylon documentation](https://docs.babylonchain.io/docs/user-guides/btc-staking-testnet/setup-node). +## Setting up the EOTS Manager -### 3.2. Setting up the EOTS Manager +>Note: If you have already set up an EOTS Manager, you can skip this section. +The following steps are only for users who have not yet set up an EOTS Manager. +Phase 1 users who already have an EOTS Manager set up can skip to the +[Loading Existing Keys](#loading-existing-keys-only-for-phase-1-finality-providers) +section at the end of this guide for specific instructions +on re-using their Phase 1 EOTS keys. -After a node and a keyring have been set up, -the operator can set up and run the +After a node and a keyring have been set up, the operator can set up and run the Extractable One Time Signature (EOTS) manager daemon. -A complete overview of the EOTS manager, its operation, and -its configuration options can be found in the -[EOTS Manager page](docs/eots.md) - -### 3.3. Setting up a Finality Provider - -The last step is to set up and run -the finality daemon. -A complete overview of the finality daemon, its operation, and -its configuration options can be found in the -[Finality page](docs/finality-provider.md). - -## 4. Delegations & Rewards - -A finality provider receives BTC delegations through delegators -interacting with Babylon and choosing it as the recipient of their delegations. -To perform a self-delegation, -the operator can either visit the staking web app we provide, -or run the Babylon [BTC Staker program](https://github.com/babylonlabs-io/btc-staker) once. -The BTC staker connects to a Bitcoin wallet and Babylon to perform delegations. + +The EOTS daemon is responsible for managing EOTS keys, producing EOTS +randomness, and using them to produce EOTS signatures. To read more on the EOTS +Manager see [here](#) + +### Step 1: Initialize the EOTS Manager + +Use the `eotsd init` command to initialize a home directory for the EOTS Manager. +You can set or change your home directory using the `--home` tag. For example, use +`--home ./eotsKey` to specify a custom directory. + +```shell +eotsd init --home +``` + +### Step 2: Create an EOTS Key + +Once the EOTS Manager is initialized, you need to create an EOTS key: + +``` shell +eotsd keys add --key-name --home +``` + +You will be prompted to enter and confirm a passphrase. +Ensure this is completed before starting the daemon. + +Sample output: + +```json +{ + "name": "eots", + "pub_key_hex": + "e1e72d270b90b24f395e76b417218430a75683bd07cf98b91cf9219d1c777c19", + "mnemonic": "parade hybrid century project toss gun undo ocean exercise + figure decorate basket peace raw spot gap dose daring patch ski purchase + prefer can pair" +} +``` + +## Loading Existing Keys (Only for Phase 1 Finality Providers) + +Note: This section is only for users who participated in Phase 1 and already +have an EOTS key. If you are a new user, you can skip this section. + +If you participated in Phase 1, follow these steps to load your existing EOTS +key and configure it for Phase 2. + +### Step 1: Verify Your EOTS Key Backup +Before proceeding, ensure you have a backup of your Phase 1 EOTS key. +You will need this backup file to import the key into the Phase 2 environment. + +### Step 2: Import Your EOTS Key into the Keyring +To load your existing EOTS key, use the following command to import it into the +keyring: + +```shell +eotsd keys import +``` + +- ``: The name you want to assign to this key in Phase 2. +- ``: The path to your EOTS key backup file from Phase 1. + +## Starting the EOTS Daemon + +You will need to navigate to the You can start the EOTS daemon using the following command: + +```shell +eotsd start --home +``` + +This command starts the EOTS RPC server at the address specified in eotsd.conf +under the RpcListener field (default: 127.0.0.1:12582). You can override this value +by specifying a custom address with the --rpc-listener flag. + +```shell +2024-10-30T12:42:29.393259Z info Metrics server is starting +{"addr": "127.0.0.1:2113"} +2024-10-30T12:42:29.393278Z info RPC server listening {"address": "127.0.0.1:12582"} +2024-10-30T12:42:29.393363Z info EOTS Manager Daemon is fully active! +EOTS Manager Daemon is fully active! +``` + +>**Note**: It is recommended to run the `eotsd` daemon on a separate machine or +network segment to enhance security. This helps isolate the key management +functionality and reduces the potential attack surface. You can edit +the`EOTSManagerAddress` in the configuration file of the finality provider to +reference the address of the machine where `eotsd` is running. + +## Setting up the Finality Provider + +The Finality Provider Daemon (FPD) is responsible for monitoring new Babylon blocks, +committing public randomness for the blocks it intends to provide finality signatures for, +and submitting finality signatures. For more information on Finality Providers, please see +[here](#). + +### Step 1: Initialize the Finality Provider Daemon + +Use the fpd init command to initialize a home directory for the Finality Provider. +You can set or change the home directory using the `--home` tag. For example, use +`--home ./fpKeys` to specify a custom directory. + +```shell +fpd init --home +``` + +>Note: Running this command may return the message +`service injective.evm.v1beta1.Msg does not have cosmos.msg.v1.service proto annotation`, +which is expected and can be ignored. + +### Step 2: Add a Key for the Finality Provider on the Babylon Chain + +The Finality Provider Daemon uses a keyring to store keys locally, enabling it to sign +transactions on the Babylon chain. + +Add a key for your finality provider: + +```shell +Copy code +fpd keys add --keyname --keyring-backend test --home +--keyring-backend +``` + +Options: +- `test`: Stores keys unencrypted on disk. This is suitable for testing but not recommended +for production. +- `file`: Stores encrypted keys on disk, offering more security than the test option. +- `os`: Uses the operating system's native keyring for the highest level of security, +relying on OS-managed encryption and access controls. + +The command will create a new key pair and store it in your keyring. Sample output: + +```shell +- address: bbn19gulf0a4yz87twpjl8cxnerc2wr2xqm9fsygn9 + name: finality-provider + pubkey: '{"@type":"/cosmos.crypto.secp256k1.PubKey", + "key":"AhZAL00gKplLQKpLMiXPBqaKCoiessoewOaEATKd4Rcy"}' + type: local +``` + +>Note: Verify the chain-id by checking the Babylon RPC node status at +[https://rpc.testnet5.babylonlabs.io/status](https://rpc.testnet5.babylonlabs.io/status). + +### Step 3: Configure fpd.config + +After initializing the Finality Provider Daemon, it will generate an fpd.config file. +Open config.toml to set the necessary parameters as shown below: + +```shell +[Application Options] +EOTSManagerAddress = 127.0.0.1:12582 +RpcListener = 127.0.0.1:12581 + +[babylon] +Key = # the key you used above +ChainID = bbn-test-5 +RPCAddr = http://127.0.0.1:26657 +GRPCAddr = https://127.0.0.1:9090 +KeyDirectory = ./fpKey +``` + +The Key field stores the name of the key used for signing transactions on the +Babylon chain and should match the key name specified during key creation. +KeyDirectory points to the location where the keyring is stored. + +The Finality Provider Daemon is responsible for monitoring for new Babylon +blocks, committing public randomness for the blocks it intends to provide +finality signatures for, and submitting finality signatures. To read more on +Finality Providers please see [here](#) + + +The `fpd init` command initializes a home directory for the EOTS manager. You +can wish to set/change your home directory with the `--home` tag. For the home +`` we have used `./fpKey` + +``` shell +fpd init --home +``` + +Note: will return +`service injective.evm.v1beta1.Msg does not have cosmos.msg.v1.service proto annotation` +which is expected and can be ignored. + +### Step 4: Add key for the finality provider on the Babylon chain + +The keyring is maintained by the finality provider daemon, this is local storage +of the keys that the daemon uses. The account associated with this key exists on +the babylon chain. + +Use the following command to add a key for your finality provider: + +```shell +fpd keys add --keyname --keyring-backend test --home +``` + +We use `--keyring-backend test`, which specifies which backend to use for the +keyring, `test` stores keys unencrypted on disk. For production environments, +use `file` or `os` backend. + + + There are three options for the keyring backend: + + `test`: Stores keys unencrypted on disk. It’s meant for testing purposes and + should never be used in production. `file`: Stores encrypted keys on disk, + which is a more secure option than test but less secure than using the OS + keyring. `os`: Uses the operating system's native keyring, providing the + highest level of security by relying on OS-managed encryption and access + controls. + +This command will create a new key pair and store it in your keyring. The output +should look similar to the below. + +``` shell +- address: bbn19gulf0a4yz87twpjl8cxnerc2wr2xqm9fsygn9 + name: finality-provider pubkey: + '{"@type":"/cosmos.crypto.secp256k1.PubKey", + "key":"AhZAL00gKplLQKpLMiXPBqaKCoiessoewOaEATKd4Rcy"}' + type: local +``` + +>Note: Please verify the `chain-id` from the Babylon RPC +node [https://rpc.testnet5.babylonlabs.io/status] +(https://rpc.testnet5.babylonlabs.io/status) + + >The configuration below requires to point to the path where this keyring is + stored `KeyDirectory`. This `Key` field stores the key name used for + interacting with the babylon chain and will be specified along with + the `KeyringBackend`field in the next step. So we can ignore the setting of the + two fields in this step. + +Once the node is initialized with the above command. It should generate a +`fpd.config` Edit the `config.toml` to set the necessary parameters with the +below + +```shell +[Application Options] EOTSManagerAddress = 127.0.0.1:12582 RpcListener += 127.0.0.1:12581 + +[babylon] Key = // the key you used above +ChainID = bbn-test-5 RPCAddr = http://127.0.0.1:26657 GRPCAddr = +https://127.0.0.1:9090 KeyDirectory = ./fpKey +``` + +### Step 3: Verify the Key Import +After importing, verify that your EOTS key was successfully loaded: + +```shell +eotsd keys list +``` + +You should see your EOTS key listed with the correct details, confirming that +it has been imported correctly. + +>Note: Make sure you're using the same key name and EOTS public key that were +registered in Phase 1. + + +## Starting the Finality provider Daemon + +The finality provider daemon (FPD) needs to be running before proceeding with +registration or voting participation. + +Start the daemon with: + +``` shell +fpd start --home ./fp +``` + +The command flags: +- `start`: Initiates the FPD daemon +- `--home`: Specifies the directory for daemon data and configuration + +The daemon will start the RPC server for CLI communication then begin listening +for incoming requests and finally initialize finality provider services + +You should see logs indicating successful startup: + +``` +[INFO] Starting finality provider daemon... +[INFO] RPC server listening on... +``` + +>Note: Keep this terminal window open as the daemon needs to run continuously. + +The above will start the Finality provider RPC server at the address specified +in `fpd.conf` under the `RpcListener` field, which has a default value +of `127.0.0.1:12581`. You can change this value in the configuration file or +override this value and specify a custom address using +the `--rpc-listener` flag. + +To start the daemon with a specific finality provider instance, use +the `--btc-pk` flag followed by the hex string of the BTC public key of the +finality provider (`btc_pk_hex`) in the next step + +All the available CLI options can be viewed using the `--help` flag. These +options can also be set in the configuration file. + +## Create Finality Provider + +The `create-finality-provider` command initializes a new finality provider +instance locally. This command: + +- Generates a BTC public key that uniquely identifies your finality provider +- Creates a Babylon account to receive staking rewards + +``` shell +fpd create-finality-provider \ --daemon-address 127.0.0.1:12581 \ --chain-id +bbn-test-5 \ --commission 0.05 \ --key-name finality-provider \ --moniker +"MyFinalityProvider" \ --website "https://myfinalityprovider.com" \ +--security-contact "security@myfinalityprovider.com" \ --details "finality +provider for the Babylon network" \ --home ./fp \ --passphrase "passphrase" +``` + +Required parameters: - `--chain-id`: The Babylon chain ID (`bbn-test-5`) - +`--commission`: The commission rate (between 0 and 1) that you'll receive from +delegators - `--key-name`: Name of the key in your keyring for signing +transactions - `--moniker`: A human-readable name for your finality provider + +Optional parameters: - `--website`: Your finality provider's website - +`--security-contact`: Contact email for security issues - `--details`: +Additional description of your finality provider - `--daemon-address`: RPC +address of the finality provider daemon (default: 127.0.0.1:12581) + +Upon successful creation, the command will return a JSON response containing +your finality provider's details: + +``` json +{ + "fp_addr": "bbn1ht2nxa6hlyl89m8xpdde9xsj40n0sxd2f9shsq", + "btc_pk_hex": + "cf0f03b9ee2d4a0f27240e2d8b8c8ef609e24358b2eb3cfd89ae4e4f472e1a41", + "description": + { + "moniker": "MyFinalityProvider", + "website": "https://myfinalityprovider.com", + "security_contact": "security@myfinalityprovider.com", + "details": "finality provider for the Babylon network" + }, + "commission": "0.050000000000000000", + "status": "CREATED" +} +``` + +The response includes: +- `fp_addr`: Your Babylon account address for receiving +rewards +- `btc_pk_hex`: Your unique BTC public key identifier (needed for +registration) +- `description`: Your finality provider's metadata +- `commission`: +Your set commission rate +- `status`: Current status of the finality provider + +## Register Finality Provider + +The `register-finality-provider` command registers your finality provider on the +Babylon chain. This command requires: + +1. The BTC public key (obtained from the `create-finality-provider` command) +2. A funded Babylon account (needs BBN tokens for transaction fees) +3. A running FPD daemon + +``` shell +fpd register-finality-provider \ +cf0f03b9ee2d4a0f27240e2d8b8c8ef609e24358b2eb3cfd89ae4e4f472e1a41 \ +--daemon-address 127.0.0.1:12581 \ --passphrase "Zubu99012" \ --home ./fp \ +``` + +> Note: The BTC public key (`cf0f03...1a41`) is obtained from the previous +`create-finality-provider` command. + +If successful, the command will return a transaction hash: + +``` shell +{ "tx_hash": +"C08377CF289DF0DC5FA462E6409ADCB65A3492C22A112C58EA449F4DC544A3B1" } +``` + + You can query this hash to confirm the transaction was successful by navigating + to the babylon chain and making a query, such as below: + +```shell +babylond query tx --chain-id bbn-test-5 +``` + +>Note: This query must be executed using the Babylon daemon (`babylond`), not +the finality provider daemon (`fpd`), as the registration transaction is +recorded on the Babylon blockchain. + +The hash returned should look something similar to below: + +```shell + type: message +- attributes: + - index: true + key: fp value: + '{ + "addr":"bbn1ht2nxa6hlyl89m8xpdde9xsj40n0sxd2f9shsq", + "description": + { + "moniker":"MyFinalityProvider", + "identity":" + ","website":"https://myfinalityprovider.com", + "security_contact":"security@myfinalityprovider.com", + "details":"Reliablefinality provider for the Babylon + network" + }, + "commission":"0.050000000000000000", + "btc_pk":"cf0f03b9ee2d4a0f27240e2d8b8c8ef609e24358b2eb3cfd89ae4e4f472e1a41", + "pop":{"btc_sig_type":"BIP340", + "btc_sig":"YJgc6NU7Z011imqSfPc9w/Namr1hFj48oTlEjGqbAVvHJv+9h3p/1shTohEb1g0fDWij7Ti9yKZzjAgNVepObA=="}, + "slashed_babylon_height":"0", + "slashed_btc_height":"0", + "jailed":false, + "consumer_id":"euphrates-0.5.0" + }' + - index: true + key: msg_index value: "0" + type: babylon.btcstaking.v1.EventNewFinalityProvider +gas_used: "82063" gas_wanted: "94429" height: "66693" info: "" logs: [] raw_log:"" +``` + +When a finality provider is created, it's associated with two key elements: + +**a) BTC Public Key:** - This serves as the unique identifier for the finality +provider. - It's derived from a Bitcoin private key, likely using the secp256k1 +elliptic curve. - This key is used in the Bitcoin-based security model of +Babylon. + +**b) Babylon Account:** - This is an account on the Babylon blockchain. - It's +where staking rewards for the finality provider are sent. - This account is +controlled by the key you use to create and manage the finality provider (the +one you added with fpd keys add). + +This dual association allows the finality provider to interact with both the +Bitcoin network (for security) and the Babylon network (for rewards and +governance). + +## Slashing Conditions + +Slashing occurs when a finality provider **double signs**. This occurs when a +finality provider signs conflicting blocks at the same height. This results in +the extraction of the provider's private key and automatically triggers shutdown +of the finality provider. + +### Withdrawing Rewards + +When withdrawing rewards, you need to use the Babylon chain's CLI since rewards +are managed by the main chain. + +To withdraw your finality provider rewards: + +``` babylond tx incentive finality_provider ... ``` + + From 980c34a9bf216ffb4c849cea703f136563a7f0eb Mon Sep 17 00:00:00 2001 From: Sam Ricotta Date: Fri, 15 Nov 2024 14:08:30 +0200 Subject: [PATCH 08/53] Update README.md --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index 43079c3..787b843 100644 --- a/README.md +++ b/README.md @@ -32,6 +32,7 @@ It consists of the following programs: The following graphic demonstrates the interconnections between the above programs: + ## Finality Provider Phase 2 Migration Guide From 437e3c494565f4eb9b121df13e1f478e10b36797 Mon Sep 17 00:00:00 2001 From: Sam Ricotta Date: Fri, 15 Nov 2024 15:50:17 +0200 Subject: [PATCH 09/53] Update README.md --- README.md | 167 ++++++++++++------------------------------------------ 1 file changed, 37 insertions(+), 130 deletions(-) diff --git a/README.md b/README.md index 787b843..f5272be 100644 --- a/README.md +++ b/README.md @@ -1,40 +1,4 @@ -# Finality Provider - -A toolset crafted for the creation and -management of Finality Providers. - -## Overview - -Finality providers are responsible for voting -at a finality round on top of [CometBFT](https://github.com/cometbft/cometbft). -Similar to any native PoS validator, -a finality provider can receive voting power delegations from BTC stakers, and -can earn commission from the staking rewards denominated in Babylon tokens. -The core logic of a finality provider instance can be found in -[Finality Provider Core](./docs/fp-core.md). - -The finality provider toolset does not have -any special hardware requirements -and can operate on standard mid-sized machines -running a UNIX-flavored operating system. -It consists of the following programs: - -- *Babylon full node*: An instance of a Babylon node connecting to - the Babylon network. Running one is not a strict requirement, - but it is recommended for security compared to trusting a third-party RPC node. -- *Extractable One-Time Signature (EOTS) manager*: - A daemon responsible for securely maintaining the finality provider’s - private key and producing extractable one time signatures from it. -- *Finality Provider*: A daemon managing the finality provider. - It connects to the EOTS manager to generate EOTS public randomness and - finality votes for Babylon blocks, which it submits to Babylon through - the node connection. - -The following graphic demonstrates the interconnections between the above programs: - - - -## Finality Provider Phase 2 Migration Guide +# Finality Provider Phase 2 Migration Guide This guide covers the Phase 2 launch of the Babylon network, a critical transition that introduces active participation @@ -334,80 +298,7 @@ fpd init --home `service injective.evm.v1beta1.Msg does not have cosmos.msg.v1.service proto annotation`, which is expected and can be ignored. -### Step 2: Add a Key for the Finality Provider on the Babylon Chain - -The Finality Provider Daemon uses a keyring to store keys locally, enabling it to sign -transactions on the Babylon chain. - -Add a key for your finality provider: - -```shell -Copy code -fpd keys add --keyname --keyring-backend test --home ---keyring-backend -``` - -Options: -- `test`: Stores keys unencrypted on disk. This is suitable for testing but not recommended -for production. -- `file`: Stores encrypted keys on disk, offering more security than the test option. -- `os`: Uses the operating system's native keyring for the highest level of security, -relying on OS-managed encryption and access controls. - -The command will create a new key pair and store it in your keyring. Sample output: - -```shell -- address: bbn19gulf0a4yz87twpjl8cxnerc2wr2xqm9fsygn9 - name: finality-provider - pubkey: '{"@type":"/cosmos.crypto.secp256k1.PubKey", - "key":"AhZAL00gKplLQKpLMiXPBqaKCoiessoewOaEATKd4Rcy"}' - type: local -``` - ->Note: Verify the chain-id by checking the Babylon RPC node status at -[https://rpc.testnet5.babylonlabs.io/status](https://rpc.testnet5.babylonlabs.io/status). - -### Step 3: Configure fpd.config - -After initializing the Finality Provider Daemon, it will generate an fpd.config file. -Open config.toml to set the necessary parameters as shown below: - -```shell -[Application Options] -EOTSManagerAddress = 127.0.0.1:12582 -RpcListener = 127.0.0.1:12581 - -[babylon] -Key = # the key you used above -ChainID = bbn-test-5 -RPCAddr = http://127.0.0.1:26657 -GRPCAddr = https://127.0.0.1:9090 -KeyDirectory = ./fpKey -``` - -The Key field stores the name of the key used for signing transactions on the -Babylon chain and should match the key name specified during key creation. -KeyDirectory points to the location where the keyring is stored. - -The Finality Provider Daemon is responsible for monitoring for new Babylon -blocks, committing public randomness for the blocks it intends to provide -finality signatures for, and submitting finality signatures. To read more on -Finality Providers please see [here](#) - - -The `fpd init` command initializes a home directory for the EOTS manager. You -can wish to set/change your home directory with the `--home` tag. For the home -`` we have used `./fpKey` - -``` shell -fpd init --home -``` - -Note: will return -`service injective.evm.v1beta1.Msg does not have cosmos.msg.v1.service proto annotation` -which is expected and can be ignored. - -### Step 4: Add key for the finality provider on the Babylon chain +### Step 2: Add key for the Finality Provider on the Babylon Chain The keyring is maintained by the finality provider daemon, this is local storage of the keys that the daemon uses. The account associated with this key exists on @@ -427,9 +318,11 @@ use `file` or `os` backend. There are three options for the keyring backend: `test`: Stores keys unencrypted on disk. It’s meant for testing purposes and - should never be used in production. `file`: Stores encrypted keys on disk, + should never be used in production. + `file`: Stores encrypted keys on disk, which is a more secure option than test but less secure than using the OS - keyring. `os`: Uses the operating system's native keyring, providing the + keyring. + `os`: Uses the operating system's native keyring, providing the highest level of security by relying on OS-managed encryption and access controls. @@ -489,8 +382,9 @@ registration or voting participation. Start the daemon with: ``` shell -fpd start --home ./fp +fpd start --home ``` +An example of the `--home` flag is `--home ./fpKeys`. The command flags: - `start`: Initiates the FPD daemon @@ -530,21 +424,32 @@ instance locally. This command: - Creates a Babylon account to receive staking rewards ``` shell -fpd create-finality-provider \ --daemon-address 127.0.0.1:12581 \ --chain-id -bbn-test-5 \ --commission 0.05 \ --key-name finality-provider \ --moniker -"MyFinalityProvider" \ --website "https://myfinalityprovider.com" \ ---security-contact "security@myfinalityprovider.com" \ --details "finality -provider for the Babylon network" \ --home ./fp \ --passphrase "passphrase" -``` - -Required parameters: - `--chain-id`: The Babylon chain ID (`bbn-test-5`) - -`--commission`: The commission rate (between 0 and 1) that you'll receive from -delegators - `--key-name`: Name of the key in your keyring for signing -transactions - `--moniker`: A human-readable name for your finality provider - -Optional parameters: - `--website`: Your finality provider's website - -`--security-contact`: Contact email for security issues - `--details`: -Additional description of your finality provider - `--daemon-address`: RPC +fpd create-finality-provider \ +--daemon-address 127.0.0.1:12581 \ +--chain-id bbn-test-5 \ +--commission 0.05 \ +--key-name finality-provider \ +--moniker "MyFinalityProvider" \ +--website "https://myfinalityprovider.com" \ +--security-contact "security@myfinalityprovider.com" \ +--details "finality provider for the Babylon network" \ +--home ./fp \ --passphrase "passphrase" +``` + +Required parameters: +- `--chain-id`: The Babylon chain ID (`bbn-test-5`) +- `--commission`: The commission rate (between 0 and 1) that you'll receive from +delegators +- `--key-name`: Name of the key in your keyring for signing +transactions - +`--moniker`: A human-readable name for your finality provider + +Optional parameters: +- `--website`: Your finality provider's website +- `--security-contact`: Contact email for security issues +- `--details`: +Additional description of your finality provider +- `--daemon-address`: RPC address of the finality provider daemon (default: 127.0.0.1:12581) Upon successful creation, the command will return a JSON response containing @@ -589,7 +494,9 @@ Babylon chain. This command requires: ``` shell fpd register-finality-provider \ cf0f03b9ee2d4a0f27240e2d8b8c8ef609e24358b2eb3cfd89ae4e4f472e1a41 \ ---daemon-address 127.0.0.1:12581 \ --passphrase "Zubu99012" \ --home ./fp \ +--daemon-address 127.0.0.1:12581 \ +--passphrase \ +--home \ ``` > Note: The BTC public key (`cf0f03...1a41`) is obtained from the previous From 261fed86a1c666cd6de7ba73a4b049c739665f5c Mon Sep 17 00:00:00 2001 From: Sam Ricotta Date: Fri, 15 Nov 2024 16:06:20 +0200 Subject: [PATCH 10/53] revert readme and update phase2 --- README.md | 638 ++++--------------------------- docs/finality-provider-phase2.md | 138 ++----- 2 files changed, 123 insertions(+), 653 deletions(-) diff --git a/README.md b/README.md index f5272be..4d10096 100644 --- a/README.md +++ b/README.md @@ -1,589 +1,119 @@ -# Finality Provider Phase 2 Migration Guide +# Finality Provider -This guide covers the Phase 2 launch of the Babylon network, -a critical transition that introduces active participation -in finality voting, rewards distribution, and the Proof of -Stake (PoS) system. This migration represents a shift from -the limited role of finality providers in Phase 1 to a fully -active role in network security and governance in Phase 2. -This guide provides a step-by-step process for operators to -onboard, whether setting up anew or using a pre-existing setup, -with a focus on Phase 2-specific requirements. +A toolset crafted for the creation and +management of Finality Providers. -The following explains the migration from Phase 1 to 2. +## 1. Overview -### Phase 1 (Previous phase) +Finality providers are responsible for voting +at a finality round on top of [CometBFT](https://github.com/cometbft/cometbft). +Similar to any native PoS validator, +a finality provider can receive voting power delegations from BTC stakers, and +can earn commission from the staking rewards denominated in Babylon tokens. +The core logic of a finality provider instance can be found in +[Finality Provider Core](./docs/fp-core.md). -- Only involves Bitcoin holders submitting staking transactions -- No active Proof of Stake (PoS) chain operation -- Finality providers only need EOTS keys registered -- No need to run finality service +The finality provider toolset does not have +any special hardware requirements +and can operate on standard mid-sized machines +running a UNIX-flavored operating system. +It consists of the following programs: -### Phase 2 (New phase) +- *Babylon full node*: An instance of a Babylon node connecting to + the Babylon network. Running one is not a strict requirement, + but it is recommended for security compared to trusting a third-party RPC node. +- *Extractable One-Time Signature (EOTS) manager*: + A daemon responsible for securely maintaining the finality provider’s + private key and producing extractable one time signatures from it. +- *Finality Provider*: A daemon managing the finality provider. + It connects to the EOTS manager to generate EOTS public randomness and + finality votes for Babylon blocks, which it submits to Babylon through + the node connection. -- Active participation in finality voting -- Running the complete finality provider toolset: - - Babylon full node - - EOTS manager daemon - - Finality provider daemon -- Earning commissions from delegations -- Proof of Stake (PoS) and network security -- Rewards distribution -- Participating in governance +The following graphic demonstrates the interconnections between the above programs: -There are 2 different types of paths for Finality providers +![Finality Provider Interconnections](./docs/finality-toolset.png) -1. **New Setup** - - For operators starting fresh - - Need to generate both EOTS and FP keys - - Complete full configuration process +## 2. Installation -If you are a new operator, start with the -[Install Finality Provider Binary](#install-finality-provider-binary) section. +### Prerequisites - 2. **Has existing EOTS Key** - - Already have EOTS key from Phase 1 - - Reference existing EOTS key in setup +This project requires Go version 1.23 or later. -If you have an existing EOTS key from Phase 1 please skip to -[Loading Existing Keys](#loading-existing-keys-only-for-phase-1-finality-providers) -steps +Install Go by following the instructions on +the [official Go installation guide](https://golang.org/doc/install). -## Install Finality Provider Binary - -Download [Golang 1.21](https://go.dev/dl)  +### Downloading the code -Download and install Golang 1.21. Verify the installation with the following command: +To get started, clone the repository to your local machine from Github: -```shell -go version +```bash +git clone https://github.com/babylonlabs-io/finality-provider.git ``` -### Step 1: Clone the Finality Provider Repository +You can choose a specific version from +the [official releases page](https://github.com/babylonlabs-io/finality-provider/releases) -Subsequently Clone the finality provider -[repository](https://github.com/babylonlabs-io/finality-provider) and navigate to the -`bbn-testnet-5` tag. - -```shell -git clone https://github.com/babylonchain/finality-provider.git -cd finality-provider -git checkout +```bash +cd finality-provider # cd into the project directory +git checkout ``` -### Step 2: Build and Install Finality Provider Binaries - -Run: -```shell -make install -``` - -This command will: -- Build and compile all Go packages -- Install binaries to `$GOPATH/bin`: - - `eotsd`: EOTS manager daemon - - `fpd`: Finality provider daemon - - `fpcli`: Finality provider CLI tool -- Make commands globally accessible from your terminal - -### Step 3: Verify Installation +### Building and installing the binary -Run `eotsd` to check the available actions: +At the top-level directory of the project -```shell -eotsd +```bash +make install ``` -Sample output: - -```shell -NAME: - eotsd - Extractable One Time Signature Daemon (eotsd). - -USAGE: - eotsd [global options] command [command options] [arguments...] - -COMMANDS: - start Start the Extractable One Time Signature Daemon. - init Initialize the eotsd home directory. - sign-schnorr Signs a Schnorr signature over arbitrary data with -... -``` +The above command will build and install the following binaries to +`$GOPATH/bin`: -If your shell cannot find the installed binaries, make sure `$GOPATH/bin` is in -the `$PATH` of your shell. Usually these commands will do the job +- `eotsd`: The daemon program for the EOTS manager. +- `fpd`: The daemon program for the finality-provider with overall commands. -```shell -export PATH=$HOME/go/bin:$PATHecho 'export PATH=$HOME/go/bin:$PATH' >> -~/.profile -``` - -## Install Babylon Binary - -Clone the Babylon [repository](https://github.com/babylonlabs-io/babylon) and -checkout the `bbn-testnet-5` tag: - -```shell -git clone git@github.com:babylonlabs-io/babylon.git -cd babylon -git checkout -``` - -### Step 1: Build and Install the Babylon Binary - -Run: -```shell -make install -``` +If your shell cannot find the installed binaries, make sure `$GOPATH/bin` is in +the `$PATH` of your shell. Usually these commands will do the job -This command will: -- Build and compile all Go packages -- Install binary to `$GOPATH/bin`: - - `babylond`: Babylon network daemon -- Make command globally accessible from your terminal - -### Step 2: Verify Installation - -Run `babylond` to see the available commands: - -```shell -babylond -``` - -Sample output: - -```shell -Available Commands: - add-genesis-account Add a genesis account to genesis.json - collect-gentxs Collect genesis txs and output a genesis.json file - comet CometBFT subcommands - config Utilities for managing application configuration ... -``` - -If your shell cannot find the installed binaries, make sure `$GOPATH/bin`  -is in the `$PATH` of your shell. The following command should help this issue. - -```shell +```bash export PATH=$HOME/go/bin:$PATH echo 'export PATH=$HOME/go/bin:$PATH' >> ~/.profile ``` -## Connecting to a Babylon Node - -To operate as a finality provider, the Finality Provider program must be connected -to a Babylon node. It is highly recommended for each finality provider to set up -their own node to ensure network reliability and direct access to network updates. +## 3. Setting up a finality provider -For detailed instructions on setting up a Babylon node, please refer to the -[Setting up a Node](https://github.com/babylonlabs-io/networks/syncing-a-node) -section of the Babylon Networks repository. +### 3.1. Setting up a Babylon Full Node -## Setting up the EOTS Manager +Before setting up the finality provider toolset, +an operator must ensure a working connection with a Babylon full node. +It is highly recommended that operators run their own node to avoid +trusting third parties. Instructions on how to set up a full Babylon node +can be found in +[the Babylon documentation](https://docs.babylonchain.io/docs/user-guides/btc-staking-testnet/setup-node). ->Note: If you have already set up an EOTS Manager, you can skip this section. -The following steps are only for users who have not yet set up an EOTS Manager. -Phase 1 users who already have an EOTS Manager set up can skip to the -[Loading Existing Keys](#loading-existing-keys-only-for-phase-1-finality-providers) -section at the end of this guide for specific instructions -on re-using their Phase 1 EOTS keys. +### 3.2. Setting up the EOTS Manager -After a node and a keyring have been set up, the operator can set up and run the +After a node and a keyring have been set up, +the operator can set up and run the Extractable One Time Signature (EOTS) manager daemon. - -The EOTS daemon is responsible for managing EOTS keys, producing EOTS -randomness, and using them to produce EOTS signatures. To read more on the EOTS -Manager see [here](#) - -### Step 1: Initialize the EOTS Manager - -Use the `eotsd init` command to initialize a home directory for the EOTS Manager. -You can set or change your home directory using the `--home` tag. For example, use -`--home ./eotsKey` to specify a custom directory. - -```shell -eotsd init --home -``` - -### Step 2: Create an EOTS Key - -Once the EOTS Manager is initialized, you need to create an EOTS key: - -``` shell -eotsd keys add --key-name --home -``` - -You will be prompted to enter and confirm a passphrase. -Ensure this is completed before starting the daemon. - -Sample output: - -```json -{ - "name": "eots", - "pub_key_hex": - "e1e72d270b90b24f395e76b417218430a75683bd07cf98b91cf9219d1c777c19", - "mnemonic": "parade hybrid century project toss gun undo ocean exercise - figure decorate basket peace raw spot gap dose daring patch ski purchase - prefer can pair" -} -``` - -## Loading Existing Keys (Only for Phase 1 Finality Providers) - -Note: This section is only for users who participated in Phase 1 and already -have an EOTS key. If you are a new user, you can skip this section. - -If you participated in Phase 1, follow these steps to load your existing EOTS -key and configure it for Phase 2. - -### Step 1: Verify Your EOTS Key Backup -Before proceeding, ensure you have a backup of your Phase 1 EOTS key. -You will need this backup file to import the key into the Phase 2 environment. - -### Step 2: Import Your EOTS Key into the Keyring -To load your existing EOTS key, use the following command to import it into the -keyring: - -```shell -eotsd keys import -``` - -- ``: The name you want to assign to this key in Phase 2. -- ``: The path to your EOTS key backup file from Phase 1. - -## Starting the EOTS Daemon - -You will need to navigate to the You can start the EOTS daemon using the following command: - -```shell -eotsd start --home -``` - -This command starts the EOTS RPC server at the address specified in eotsd.conf -under the RpcListener field (default: 127.0.0.1:12582). You can override this value -by specifying a custom address with the --rpc-listener flag. - -```shell -2024-10-30T12:42:29.393259Z info Metrics server is starting -{"addr": "127.0.0.1:2113"} -2024-10-30T12:42:29.393278Z info RPC server listening {"address": "127.0.0.1:12582"} -2024-10-30T12:42:29.393363Z info EOTS Manager Daemon is fully active! -EOTS Manager Daemon is fully active! -``` - ->**Note**: It is recommended to run the `eotsd` daemon on a separate machine or -network segment to enhance security. This helps isolate the key management -functionality and reduces the potential attack surface. You can edit -the`EOTSManagerAddress` in the configuration file of the finality provider to -reference the address of the machine where `eotsd` is running. - -## Setting up the Finality Provider - -The Finality Provider Daemon (FPD) is responsible for monitoring new Babylon blocks, -committing public randomness for the blocks it intends to provide finality signatures for, -and submitting finality signatures. For more information on Finality Providers, please see -[here](#). - -### Step 1: Initialize the Finality Provider Daemon - -Use the fpd init command to initialize a home directory for the Finality Provider. -You can set or change the home directory using the `--home` tag. For example, use -`--home ./fpKeys` to specify a custom directory. - -```shell -fpd init --home -``` - ->Note: Running this command may return the message -`service injective.evm.v1beta1.Msg does not have cosmos.msg.v1.service proto annotation`, -which is expected and can be ignored. - -### Step 2: Add key for the Finality Provider on the Babylon Chain - -The keyring is maintained by the finality provider daemon, this is local storage -of the keys that the daemon uses. The account associated with this key exists on -the babylon chain. - -Use the following command to add a key for your finality provider: - -```shell -fpd keys add --keyname --keyring-backend test --home -``` - -We use `--keyring-backend test`, which specifies which backend to use for the -keyring, `test` stores keys unencrypted on disk. For production environments, -use `file` or `os` backend. - - - There are three options for the keyring backend: - - `test`: Stores keys unencrypted on disk. It’s meant for testing purposes and - should never be used in production. - `file`: Stores encrypted keys on disk, - which is a more secure option than test but less secure than using the OS - keyring. - `os`: Uses the operating system's native keyring, providing the - highest level of security by relying on OS-managed encryption and access - controls. - -This command will create a new key pair and store it in your keyring. The output -should look similar to the below. - -``` shell -- address: bbn19gulf0a4yz87twpjl8cxnerc2wr2xqm9fsygn9 - name: finality-provider pubkey: - '{"@type":"/cosmos.crypto.secp256k1.PubKey", - "key":"AhZAL00gKplLQKpLMiXPBqaKCoiessoewOaEATKd4Rcy"}' - type: local -``` - ->Note: Please verify the `chain-id` from the Babylon RPC -node [https://rpc.testnet5.babylonlabs.io/status] -(https://rpc.testnet5.babylonlabs.io/status) - - >The configuration below requires to point to the path where this keyring is - stored `KeyDirectory`. This `Key` field stores the key name used for - interacting with the babylon chain and will be specified along with - the `KeyringBackend`field in the next step. So we can ignore the setting of the - two fields in this step. - -Once the node is initialized with the above command. It should generate a -`fpd.config` Edit the `config.toml` to set the necessary parameters with the -below - -```shell -[Application Options] EOTSManagerAddress = 127.0.0.1:12582 RpcListener -= 127.0.0.1:12581 - -[babylon] Key = // the key you used above -ChainID = bbn-test-5 RPCAddr = http://127.0.0.1:26657 GRPCAddr = -https://127.0.0.1:9090 KeyDirectory = ./fpKey -``` - -### Step 3: Verify the Key Import -After importing, verify that your EOTS key was successfully loaded: - -```shell -eotsd keys list -``` - -You should see your EOTS key listed with the correct details, confirming that -it has been imported correctly. - ->Note: Make sure you're using the same key name and EOTS public key that were -registered in Phase 1. - - -## Starting the Finality provider Daemon - -The finality provider daemon (FPD) needs to be running before proceeding with -registration or voting participation. - -Start the daemon with: - -``` shell -fpd start --home -``` -An example of the `--home` flag is `--home ./fpKeys`. - -The command flags: -- `start`: Initiates the FPD daemon -- `--home`: Specifies the directory for daemon data and configuration - -The daemon will start the RPC server for CLI communication then begin listening -for incoming requests and finally initialize finality provider services - -You should see logs indicating successful startup: - -``` -[INFO] Starting finality provider daemon... -[INFO] RPC server listening on... -``` - ->Note: Keep this terminal window open as the daemon needs to run continuously. - -The above will start the Finality provider RPC server at the address specified -in `fpd.conf` under the `RpcListener` field, which has a default value -of `127.0.0.1:12581`. You can change this value in the configuration file or -override this value and specify a custom address using -the `--rpc-listener` flag. - -To start the daemon with a specific finality provider instance, use -the `--btc-pk` flag followed by the hex string of the BTC public key of the -finality provider (`btc_pk_hex`) in the next step - -All the available CLI options can be viewed using the `--help` flag. These -options can also be set in the configuration file. - -## Create Finality Provider - -The `create-finality-provider` command initializes a new finality provider -instance locally. This command: - -- Generates a BTC public key that uniquely identifies your finality provider -- Creates a Babylon account to receive staking rewards - -``` shell -fpd create-finality-provider \ ---daemon-address 127.0.0.1:12581 \ ---chain-id bbn-test-5 \ ---commission 0.05 \ ---key-name finality-provider \ ---moniker "MyFinalityProvider" \ ---website "https://myfinalityprovider.com" \ ---security-contact "security@myfinalityprovider.com" \ ---details "finality provider for the Babylon network" \ ---home ./fp \ --passphrase "passphrase" -``` - -Required parameters: -- `--chain-id`: The Babylon chain ID (`bbn-test-5`) -- `--commission`: The commission rate (between 0 and 1) that you'll receive from -delegators -- `--key-name`: Name of the key in your keyring for signing -transactions - -`--moniker`: A human-readable name for your finality provider - -Optional parameters: -- `--website`: Your finality provider's website -- `--security-contact`: Contact email for security issues -- `--details`: -Additional description of your finality provider -- `--daemon-address`: RPC -address of the finality provider daemon (default: 127.0.0.1:12581) - -Upon successful creation, the command will return a JSON response containing -your finality provider's details: - -``` json -{ - "fp_addr": "bbn1ht2nxa6hlyl89m8xpdde9xsj40n0sxd2f9shsq", - "btc_pk_hex": - "cf0f03b9ee2d4a0f27240e2d8b8c8ef609e24358b2eb3cfd89ae4e4f472e1a41", - "description": - { - "moniker": "MyFinalityProvider", - "website": "https://myfinalityprovider.com", - "security_contact": "security@myfinalityprovider.com", - "details": "finality provider for the Babylon network" - }, - "commission": "0.050000000000000000", - "status": "CREATED" -} -``` - -The response includes: -- `fp_addr`: Your Babylon account address for receiving -rewards -- `btc_pk_hex`: Your unique BTC public key identifier (needed for -registration) -- `description`: Your finality provider's metadata -- `commission`: -Your set commission rate -- `status`: Current status of the finality provider - -## Register Finality Provider - -The `register-finality-provider` command registers your finality provider on the -Babylon chain. This command requires: - -1. The BTC public key (obtained from the `create-finality-provider` command) -2. A funded Babylon account (needs BBN tokens for transaction fees) -3. A running FPD daemon - -``` shell -fpd register-finality-provider \ -cf0f03b9ee2d4a0f27240e2d8b8c8ef609e24358b2eb3cfd89ae4e4f472e1a41 \ ---daemon-address 127.0.0.1:12581 \ ---passphrase \ ---home \ -``` - -> Note: The BTC public key (`cf0f03...1a41`) is obtained from the previous -`create-finality-provider` command. - -If successful, the command will return a transaction hash: - -``` shell -{ "tx_hash": -"C08377CF289DF0DC5FA462E6409ADCB65A3492C22A112C58EA449F4DC544A3B1" } -``` - - You can query this hash to confirm the transaction was successful by navigating - to the babylon chain and making a query, such as below: - -```shell -babylond query tx --chain-id bbn-test-5 -``` - ->Note: This query must be executed using the Babylon daemon (`babylond`), not -the finality provider daemon (`fpd`), as the registration transaction is -recorded on the Babylon blockchain. - -The hash returned should look something similar to below: - -```shell - type: message -- attributes: - - index: true - key: fp value: - '{ - "addr":"bbn1ht2nxa6hlyl89m8xpdde9xsj40n0sxd2f9shsq", - "description": - { - "moniker":"MyFinalityProvider", - "identity":" - ","website":"https://myfinalityprovider.com", - "security_contact":"security@myfinalityprovider.com", - "details":"Reliablefinality provider for the Babylon - network" - }, - "commission":"0.050000000000000000", - "btc_pk":"cf0f03b9ee2d4a0f27240e2d8b8c8ef609e24358b2eb3cfd89ae4e4f472e1a41", - "pop":{"btc_sig_type":"BIP340", - "btc_sig":"YJgc6NU7Z011imqSfPc9w/Namr1hFj48oTlEjGqbAVvHJv+9h3p/1shTohEb1g0fDWij7Ti9yKZzjAgNVepObA=="}, - "slashed_babylon_height":"0", - "slashed_btc_height":"0", - "jailed":false, - "consumer_id":"euphrates-0.5.0" - }' - - index: true - key: msg_index value: "0" - type: babylon.btcstaking.v1.EventNewFinalityProvider -gas_used: "82063" gas_wanted: "94429" height: "66693" info: "" logs: [] raw_log:"" -``` - -When a finality provider is created, it's associated with two key elements: - -**a) BTC Public Key:** - This serves as the unique identifier for the finality -provider. - It's derived from a Bitcoin private key, likely using the secp256k1 -elliptic curve. - This key is used in the Bitcoin-based security model of -Babylon. - -**b) Babylon Account:** - This is an account on the Babylon blockchain. - It's -where staking rewards for the finality provider are sent. - This account is -controlled by the key you use to create and manage the finality provider (the -one you added with fpd keys add). - -This dual association allows the finality provider to interact with both the -Bitcoin network (for security) and the Babylon network (for rewards and -governance). - -## Slashing Conditions - -Slashing occurs when a finality provider **double signs**. This occurs when a -finality provider signs conflicting blocks at the same height. This results in -the extraction of the provider's private key and automatically triggers shutdown -of the finality provider. - -### Withdrawing Rewards - -When withdrawing rewards, you need to use the Babylon chain's CLI since rewards -are managed by the main chain. - -To withdraw your finality provider rewards: - -``` babylond tx incentive finality_provider ... ``` - - +A complete overview of the EOTS manager, its operation, and +its configuration options can be found in the +[EOTS Manager page](docs/eots.md) + +### 3.3. Setting up a Finality Provider + +The last step is to set up and run +the finality daemon. +A complete overview of the finality daemon, its operation, and +its configuration options can be found in the +[Finality page](docs/finality-provider.md). + +## 4. Delegations & Rewards + +A finality provider receives BTC delegations through delegators +interacting with Babylon and choosing it as the recipient of their delegations. +To perform a self-delegation, +the operator can either visit the staking web app we provide, +or run the Babylon [BTC Staker program](https://github.com/babylonlabs-io/btc-staker) once. +The BTC staker connects to a Bitcoin wallet and Babylon to perform delegations. diff --git a/docs/finality-provider-phase2.md b/docs/finality-provider-phase2.md index 1ed54e5..f5272be 100644 --- a/docs/finality-provider-phase2.md +++ b/docs/finality-provider-phase2.md @@ -12,14 +12,14 @@ with a focus on Phase 2-specific requirements. The following explains the migration from Phase 1 to 2. -## Phase 1 (Previous phase) +### Phase 1 (Previous phase) - Only involves Bitcoin holders submitting staking transactions - No active Proof of Stake (PoS) chain operation - Finality providers only need EOTS keys registered - No need to run finality service -## Phase 2 (New phase) +### Phase 2 (New phase) - Active participation in finality voting - Running the complete finality provider toolset: @@ -49,9 +49,6 @@ If you have an existing EOTS key from Phase 1 please skip to [Loading Existing Keys](#loading-existing-keys-only-for-phase-1-finality-providers) steps -For an introduction on the finality providers see (here) - - ## Install Finality Provider Binary Download [Golang 1.21](https://go.dev/dl)  @@ -301,80 +298,7 @@ fpd init --home `service injective.evm.v1beta1.Msg does not have cosmos.msg.v1.service proto annotation`, which is expected and can be ignored. -### Step 2: Add a Key for the Finality Provider on the Babylon Chain - -The Finality Provider Daemon uses a keyring to store keys locally, enabling it to sign -transactions on the Babylon chain. - -Add a key for your finality provider: - -```shell -Copy code -fpd keys add --keyname --keyring-backend test --home ---keyring-backend -``` - -Options: -- `test`: Stores keys unencrypted on disk. This is suitable for testing but not recommended -for production. -- `file`: Stores encrypted keys on disk, offering more security than the test option. -- `os`: Uses the operating system's native keyring for the highest level of security, -relying on OS-managed encryption and access controls. - -The command will create a new key pair and store it in your keyring. Sample output: - -```shell -- address: bbn19gulf0a4yz87twpjl8cxnerc2wr2xqm9fsygn9 - name: finality-provider - pubkey: '{"@type":"/cosmos.crypto.secp256k1.PubKey", - "key":"AhZAL00gKplLQKpLMiXPBqaKCoiessoewOaEATKd4Rcy"}' - type: local -``` - ->Note: Verify the chain-id by checking the Babylon RPC node status at -[https://rpc.testnet5.babylonlabs.io/status](https://rpc.testnet5.babylonlabs.io/status). - -### Step 3: Configure fpd.config - -After initializing the Finality Provider Daemon, it will generate an fpd.config file. -Open config.toml to set the necessary parameters as shown below: - -```shell -[Application Options] -EOTSManagerAddress = 127.0.0.1:12582 -RpcListener = 127.0.0.1:12581 - -[babylon] -Key = # the key you used above -ChainID = bbn-test-5 -RPCAddr = http://127.0.0.1:26657 -GRPCAddr = https://127.0.0.1:9090 -KeyDirectory = ./fpKey -``` - -The Key field stores the name of the key used for signing transactions on the -Babylon chain and should match the key name specified during key creation. -KeyDirectory points to the location where the keyring is stored. - -The Finality Provider Daemon is responsible for monitoring for new Babylon -blocks, committing public randomness for the blocks it intends to provide -finality signatures for, and submitting finality signatures. To read more on -Finality Providers please see [here](#) - - -The `fpd init` command initializes a home directory for the EOTS manager. You -can wish to set/change your home directory with the `--home` tag. For the home -`` we have used `./fpKey` - -``` shell -fpd init --home -``` - -Note: will return -`service injective.evm.v1beta1.Msg does not have cosmos.msg.v1.service proto annotation` -which is expected and can be ignored. - -### Step 4: Add key for the finality provider on the Babylon chain +### Step 2: Add key for the Finality Provider on the Babylon Chain The keyring is maintained by the finality provider daemon, this is local storage of the keys that the daemon uses. The account associated with this key exists on @@ -394,9 +318,11 @@ use `file` or `os` backend. There are three options for the keyring backend: `test`: Stores keys unencrypted on disk. It’s meant for testing purposes and - should never be used in production. `file`: Stores encrypted keys on disk, + should never be used in production. + `file`: Stores encrypted keys on disk, which is a more secure option than test but less secure than using the OS - keyring. `os`: Uses the operating system's native keyring, providing the + keyring. + `os`: Uses the operating system's native keyring, providing the highest level of security by relying on OS-managed encryption and access controls. @@ -456,8 +382,9 @@ registration or voting participation. Start the daemon with: ``` shell -fpd start --home ./fp +fpd start --home ``` +An example of the `--home` flag is `--home ./fpKeys`. The command flags: - `start`: Initiates the FPD daemon @@ -497,21 +424,32 @@ instance locally. This command: - Creates a Babylon account to receive staking rewards ``` shell -fpd create-finality-provider \ --daemon-address 127.0.0.1:12581 \ --chain-id -bbn-test-5 \ --commission 0.05 \ --key-name finality-provider \ --moniker -"MyFinalityProvider" \ --website "https://myfinalityprovider.com" \ ---security-contact "security@myfinalityprovider.com" \ --details "finality -provider for the Babylon network" \ --home ./fp \ --passphrase "passphrase" -``` - -Required parameters: - `--chain-id`: The Babylon chain ID (`bbn-test-5`) - -`--commission`: The commission rate (between 0 and 1) that you'll receive from -delegators - `--key-name`: Name of the key in your keyring for signing -transactions - `--moniker`: A human-readable name for your finality provider - -Optional parameters: - `--website`: Your finality provider's website - -`--security-contact`: Contact email for security issues - `--details`: -Additional description of your finality provider - `--daemon-address`: RPC +fpd create-finality-provider \ +--daemon-address 127.0.0.1:12581 \ +--chain-id bbn-test-5 \ +--commission 0.05 \ +--key-name finality-provider \ +--moniker "MyFinalityProvider" \ +--website "https://myfinalityprovider.com" \ +--security-contact "security@myfinalityprovider.com" \ +--details "finality provider for the Babylon network" \ +--home ./fp \ --passphrase "passphrase" +``` + +Required parameters: +- `--chain-id`: The Babylon chain ID (`bbn-test-5`) +- `--commission`: The commission rate (between 0 and 1) that you'll receive from +delegators +- `--key-name`: Name of the key in your keyring for signing +transactions - +`--moniker`: A human-readable name for your finality provider + +Optional parameters: +- `--website`: Your finality provider's website +- `--security-contact`: Contact email for security issues +- `--details`: +Additional description of your finality provider +- `--daemon-address`: RPC address of the finality provider daemon (default: 127.0.0.1:12581) Upon successful creation, the command will return a JSON response containing @@ -524,7 +462,7 @@ your finality provider's details: "cf0f03b9ee2d4a0f27240e2d8b8c8ef609e24358b2eb3cfd89ae4e4f472e1a41", "description": { - "moniker": "MyFinalityProvider", + "moniker": "MyFinalityProvider", "website": "https://myfinalityprovider.com", "security_contact": "security@myfinalityprovider.com", "details": "finality provider for the Babylon network" @@ -556,7 +494,9 @@ Babylon chain. This command requires: ``` shell fpd register-finality-provider \ cf0f03b9ee2d4a0f27240e2d8b8c8ef609e24358b2eb3cfd89ae4e4f472e1a41 \ ---daemon-address 127.0.0.1:12581 \ --passphrase "Zubu99012" \ --home ./fp \ +--daemon-address 127.0.0.1:12581 \ +--passphrase \ +--home \ ``` > Note: The BTC public key (`cf0f03...1a41`) is obtained from the previous From 59b380978f0028bf193149c746f415a475e4f0d8 Mon Sep 17 00:00:00 2001 From: Sam Ricotta Date: Fri, 15 Nov 2024 16:08:44 +0200 Subject: [PATCH 11/53] Update finality-provider-phase2.md --- docs/finality-provider-phase2.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/finality-provider-phase2.md b/docs/finality-provider-phase2.md index f5272be..095c2d0 100644 --- a/docs/finality-provider-phase2.md +++ b/docs/finality-provider-phase2.md @@ -12,14 +12,14 @@ with a focus on Phase 2-specific requirements. The following explains the migration from Phase 1 to 2. -### Phase 1 (Previous phase) +**Phase 1 (Previous phase)** - Only involves Bitcoin holders submitting staking transactions - No active Proof of Stake (PoS) chain operation - Finality providers only need EOTS keys registered - No need to run finality service -### Phase 2 (New phase) +**Phase 2 (New phase)** - Active participation in finality voting - Running the complete finality provider toolset: From 13ae97bd9de4daa140d6001139b58b1b874ed4e9 Mon Sep 17 00:00:00 2001 From: Sam Ricotta Date: Mon, 18 Nov 2024 11:20:34 +0200 Subject: [PATCH 12/53] Part 1 - review comments --- docs/finality-provider-phase2.md | 198 ++++++++++++------------------- 1 file changed, 75 insertions(+), 123 deletions(-) diff --git a/docs/finality-provider-phase2.md b/docs/finality-provider-phase2.md index 095c2d0..890cacd 100644 --- a/docs/finality-provider-phase2.md +++ b/docs/finality-provider-phase2.md @@ -1,13 +1,14 @@ -# Finality Provider Phase 2 Migration Guide - -This guide covers the Phase 2 launch of the Babylon network, -a critical transition that introduces active participation -in finality voting, rewards distribution, and the Proof of -Stake (PoS) system. This migration represents a shift from -the limited role of finality providers in Phase 1 to a fully -active role in network security and governance in Phase 2. +# Finality Provider Registration + +This guide covers the ongoing operation of the Babylonchain +but in this guide we cover the registration process for +finality providers in Phase 2. + +Phase 2 launch of the Babylon network is a critical transition +that introduces active participation in finality voting, +rewards distribution, and the Proof of Stake (PoS) system. This guide provides a step-by-step process for operators to -onboard, whether setting up anew or using a pre-existing setup, +onboard, whether setting up a new or pre-existing setup, with a focus on Phase 2-specific requirements. The following explains the migration from Phase 1 to 2. @@ -16,7 +17,7 @@ The following explains the migration from Phase 1 to 2. - Only involves Bitcoin holders submitting staking transactions - No active Proof of Stake (PoS) chain operation -- Finality providers only need EOTS keys registered +- Finality providers only need EOTS keys generated - No need to run finality service **Phase 2 (New phase)** @@ -26,14 +27,22 @@ The following explains the migration from Phase 1 to 2. - Babylon full node - EOTS manager daemon - Finality provider daemon -- Earning commissions from delegations -- Proof of Stake (PoS) and network security +- Earning commissions from Bitcoin Stake delegations - Rewards distribution -- Participating in governance There are 2 different types of paths for Finality providers -1. **New Setup** +1. **Has existing EOTS Key** + - Already have EOTS key from [Phase 1](https://github.com/babylonlabs-io/networks/tree/main/bbn-1/finality-providers) + - Reference existing EOTS key in setup + +If you have an existing EOTS key from Phase 1, please skip to +[Loading Existing Keys](#loading-existing-keys-only-for-phase-1-finality-providers) +steps + +>Note: Any finality providers from phase-1 that do not transition their existing key, will not have any of their delegations from phase-1. + +2. **New Setup** - For operators starting fresh - Need to generate both EOTS and FP keys - Complete full configuration process @@ -41,19 +50,11 @@ There are 2 different types of paths for Finality providers If you are a new operator, start with the [Install Finality Provider Binary](#install-finality-provider-binary) section. - 2. **Has existing EOTS Key** - - Already have EOTS key from Phase 1 - - Reference existing EOTS key in setup - -If you have an existing EOTS key from Phase 1 please skip to -[Loading Existing Keys](#loading-existing-keys-only-for-phase-1-finality-providers) -steps - ## Install Finality Provider Binary - -Download [Golang 1.21](https://go.dev/dl)  + -Download and install Golang 1.21. Verify the installation with the following command: +Download and install [Golang 1.23](https://go.dev/dl). +Verify the installation with the following command: ```shell go version @@ -61,9 +62,10 @@ go version ### Step 1: Clone the Finality Provider Repository -Subsequently Clone the finality provider +Subsequently clone the finality provider [repository](https://github.com/babylonlabs-io/finality-provider) and navigate to the -`bbn-testnet-5` tag. +`bbn-test-5` tag. + ```shell git clone https://github.com/babylonchain/finality-provider.git @@ -88,10 +90,10 @@ This command will: ### Step 3: Verify Installation -Run `eotsd` to check the available actions: +Run `eotsd --help` to check the available actions: ```shell -eotsd +eotsd --help ``` Sample output: @@ -118,65 +120,15 @@ export PATH=$HOME/go/bin:$PATHecho 'export PATH=$HOME/go/bin:$PATH' >> ~/.profile ``` -## Install Babylon Binary +## Run Babylon Full Node -Clone the Babylon [repository](https://github.com/babylonlabs-io/babylon) and -checkout the `bbn-testnet-5` tag: - -```shell -git clone git@github.com:babylonlabs-io/babylon.git -cd babylon -git checkout -``` - -### Step 1: Build and Install the Babylon Binary - -Run: -```shell -make install -``` - -This command will: -- Build and compile all Go packages -- Install binary to `$GOPATH/bin`: - - `babylond`: Babylon network daemon -- Make command globally accessible from your terminal +Before proceeding with the finality provider setup, you'll need to have a Babylon +full node running. Please follow the instructions at: -### Step 2: Verify Installation +[Babylon Node Setup Guide](https://github.com/babylonlabs-io/networks/blob/main/bbn-test-5/babylon-node/README.md) -Run `babylond` to see the available commands: - -```shell -babylond -``` - -Sample output: - -```shell -Available Commands: - add-genesis-account Add a genesis account to genesis.json - collect-gentxs Collect genesis txs and output a genesis.json file - comet CometBFT subcommands - config Utilities for managing application configuration ... -``` - -If your shell cannot find the installed binaries, make sure `$GOPATH/bin`  -is in the `$PATH` of your shell. The following command should help this issue. - -```shell -export PATH=$HOME/go/bin:$PATH -echo 'export PATH=$HOME/go/bin:$PATH' >> ~/.profile -``` - -## Connecting to a Babylon Node - -To operate as a finality provider, the Finality Provider program must be connected -to a Babylon node. It is highly recommended for each finality provider to set up -their own node to ensure network reliability and direct access to network updates. - -For detailed instructions on setting up a Babylon node, please refer to the -[Setting up a Node](https://github.com/babylonlabs-io/networks/syncing-a-node) -section of the Babylon Networks repository. +Once you have completed the node setup and it is fully synced, return here +to continue with the finality provider configuration. ## Setting up the EOTS Manager @@ -228,17 +180,17 @@ Sample output: } ``` -## Loading Existing Keys (Only for Phase 1 Finality Providers) - -Note: This section is only for users who participated in Phase 1 and already -have an EOTS key. If you are a new user, you can skip this section. +## Loading Existing Keys -If you participated in Phase 1, follow these steps to load your existing EOTS +>Note: If you participated in Phase 1, follow these steps to load your existing EOTS key and configure it for Phase 2. +>This section is only for Finality Providers who participated in Phase 1 and already +have an EOTS key. If you are a new user, you can skip this section. + ### Step 1: Verify Your EOTS Key Backup -Before proceeding, ensure you have a backup of your Phase 1 EOTS key. -You will need this backup file to import the key into the Phase 2 environment. +Before proceeding, ensure you have access to your original EOTS key from Phase 1. +This is the same key that was registered in the [Phase 1 registration](https://github.com/babylonlabs-io/networks/tree/main/bbn-1/finality-providers). ### Step 2: Import Your EOTS Key into the Keyring To load your existing EOTS key, use the following command to import it into the @@ -253,15 +205,15 @@ eotsd keys import ## Starting the EOTS Daemon -You will need to navigate to the You can start the EOTS daemon using the following command: +You can start the EOTS daemon using the following command: ```shell eotsd start --home ``` This command starts the EOTS RPC server at the address specified in eotsd.conf -under the RpcListener field (default: 127.0.0.1:12582). You can override this value -by specifying a custom address with the --rpc-listener flag. +under the `RPCListener` field (default: `127.0.0.1:12582`). You can override this value +by specifying a custom address with the `--rpc-listener` flag. ```shell 2024-10-30T12:42:29.393259Z info Metrics server is starting @@ -274,7 +226,7 @@ EOTS Manager Daemon is fully active! >**Note**: It is recommended to run the `eotsd` daemon on a separate machine or network segment to enhance security. This helps isolate the key management functionality and reduces the potential attack surface. You can edit -the`EOTSManagerAddress` in the configuration file of the finality provider to +the `EOTSManagerAddress` in the configuration file of the finality provider to reference the address of the machine where `eotsd` is running. ## Setting up the Finality Provider @@ -286,7 +238,7 @@ and submitting finality signatures. For more information on Finality Providers, ### Step 1: Initialize the Finality Provider Daemon -Use the fpd init command to initialize a home directory for the Finality Provider. +Use the `fpd init` command to initialize a home directory for the Finality Provider. You can set or change the home directory using the `--home` tag. For example, use `--home ./fpKeys` to specify a custom directory. @@ -314,7 +266,6 @@ We use `--keyring-backend test`, which specifies which backend to use for the keyring, `test` stores keys unencrypted on disk. For production environments, use `file` or `os` backend. - There are three options for the keyring backend: `test`: Stores keys unencrypted on disk. It’s meant for testing purposes and @@ -352,12 +303,16 @@ Once the node is initialized with the above command. It should generate a below ```shell -[Application Options] EOTSManagerAddress = 127.0.0.1:12582 RpcListener -= 127.0.0.1:12581 - -[babylon] Key = // the key you used above -ChainID = bbn-test-5 RPCAddr = http://127.0.0.1:26657 GRPCAddr = -https://127.0.0.1:9090 KeyDirectory = ./fpKey +[Application Options] +EOTSManagerAddress = 127.0.0.1:12582 +RpcListener = 127.0.0.1:12581 + +[babylon] +Key = // the key you used above +ChainID = bbn-test-5 +RPCAddr = http://127.0.0.1:26657 +GRPCAddr = https://127.0.0.1:9090 +KeyDirectory = ./fpKey ``` ### Step 3: Verify the Key Import @@ -373,7 +328,6 @@ it has been imported correctly. >Note: Make sure you're using the same key name and EOTS public key that were registered in Phase 1. - ## Starting the Finality provider Daemon The finality provider daemon (FPD) needs to be running before proceeding with @@ -400,7 +354,11 @@ You should see logs indicating successful startup: [INFO] RPC server listening on... ``` ->Note: Keep this terminal window open as the daemon needs to run continuously. +>Note: The daemon needs to run continuously. It's recommended to set up a system +service (like `systemd` on Linux or `launchd` on macOS) to manage the daemon +process, handle automatic restarts, and collect logs. For testing purposes, +you can run the daemon directly in a terminal, but remember it must stay +running to function properly. The above will start the Finality provider RPC server at the address specified in `fpd.conf` under the `RpcListener` field, which has a default value @@ -421,7 +379,6 @@ The `create-finality-provider` command initializes a new finality provider instance locally. This command: - Generates a BTC public key that uniquely identifies your finality provider -- Creates a Babylon account to receive staking rewards ``` shell fpd create-finality-provider \ @@ -488,7 +445,8 @@ The `register-finality-provider` command registers your finality provider on the Babylon chain. This command requires: 1. The BTC public key (obtained from the `create-finality-provider` command) -2. A funded Babylon account (needs BBN tokens for transaction fees) +2. A funded Babylon account (needs BBN tokens for transaction fees). +This account will be bonded to your finality provider and used to claim rewards. 3. A running FPD daemon ``` shell @@ -509,16 +467,8 @@ If successful, the command will return a transaction hash: "C08377CF289DF0DC5FA462E6409ADCB65A3492C22A112C58EA449F4DC544A3B1" } ``` - You can query this hash to confirm the transaction was successful by navigating - to the babylon chain and making a query, such as below: - -```shell -babylond query tx --chain-id bbn-test-5 -``` - ->Note: This query must be executed using the Babylon daemon (`babylond`), not -the finality provider daemon (`fpd`), as the registration transaction is -recorded on the Babylon blockchain. +You can verify the transaction was successful by looking up this transaction +hash on the Babylon chain. The hash returned should look something similar to below: @@ -556,14 +506,16 @@ gas_used: "82063" gas_wanted: "94429" height: "66693" info: "" logs: [] raw_log: When a finality provider is created, it's associated with two key elements: **a) BTC Public Key:** - This serves as the unique identifier for the finality -provider. - It's derived from a Bitcoin private key, likely using the secp256k1 -elliptic curve. - This key is used in the Bitcoin-based security model of +provider. +- It's derived from a Bitcoin private key, likely using the secp256k1 +elliptic curve. +- This key is used in the Bitcoin-based security model of Babylon. **b) Babylon Account:** - This is an account on the Babylon blockchain. - It's -where staking rewards for the finality provider are sent. - This account is -controlled by the key you use to create and manage the finality provider (the -one you added with fpd keys add). +where staking rewards for the finality provider are sent. +- This account is controlled by the key you use to create and manage the +finality provider (the one you added with fpd keys add). This dual association allows the finality provider to interact with both the Bitcoin network (for security) and the Babylon network (for rewards and From beea4ae24db7c4158ecbb4a87b00229cc287b8b2 Mon Sep 17 00:00:00 2001 From: Sam Ricotta Date: Mon, 18 Nov 2024 19:58:07 +0200 Subject: [PATCH 13/53] Part 2: review comments --- README.md | 2 +- docs/FP.png | Bin 0 -> 106333 bytes docs/finality-provider-phase2.md | 103 +++++++++++++++++++++++++------ 3 files changed, 85 insertions(+), 20 deletions(-) create mode 100644 docs/FP.png diff --git a/README.md b/README.md index 4d10096..d82e88c 100644 --- a/README.md +++ b/README.md @@ -32,7 +32,7 @@ It consists of the following programs: The following graphic demonstrates the interconnections between the above programs: -![Finality Provider Interconnections](./docs/finality-toolset.png) +![Finality Provider Interconnections](./docs/FP.png) ## 2. Installation diff --git a/docs/FP.png b/docs/FP.png new file mode 100644 index 0000000000000000000000000000000000000000..2f202e9ae057de8df5ee1e1f0422d17a1261e50a GIT binary patch literal 106333 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¥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: Any finality providers from phase-1 that do not transition their existing key, will not have any of their delegations from phase-1. @@ -50,6 +50,37 @@ steps If you are a new operator, start with the [Install Finality Provider Binary](#install-finality-provider-binary) section. +## Overview of Keys for Finality Provider and EOTS Manager + +There are two distinct keys you'll be working with: + +- **EOTS Key**: + - Used for generating EOTS signatures + - Used to generate the BTC public key for the finality provider + - Stored in the EOTS manager daemon's keyring + - Example of the EOTS key output: + ```json + { + "name": "eots", + "pub_key_hex": + "e1e72d270b90b24f395e76b417218430a75683bd07cf98b91cf9219d1c777c19", + "mnemonic": "parade hybrid century project toss gun undo ocean exercise + figure decorate basket peace raw spot gap dose daring patch ski purchase + prefer can pair" + } + ``` + +- **Finality Provider Key**: + - Used for signing transactions on Babylon + - Associated with a Babylon account that receives rewards + - Stored in the finality provider daemon's keyring + + - Example of the finality provider key output: + ```shell + - address: bbn19gulf0a4yz87twpjl8cxnerc2wr2xqm9fsygn9 + name: finality-provider + ``` + ## Install Finality Provider Binary @@ -116,8 +147,7 @@ If your shell cannot find the installed binaries, make sure `$GOPATH/bin` is i the `$PATH` of your shell. Usually these commands will do the job ```shell -export PATH=$HOME/go/bin:$PATHecho 'export PATH=$HOME/go/bin:$PATH' >> -~/.profile +echo 'export PATH=$HOME/go/bin:$PATH' >> ~/.profile ``` ## Run Babylon Full Node @@ -189,8 +219,8 @@ key and configure it for Phase 2. have an EOTS key. If you are a new user, you can skip this section. ### Step 1: Verify Your EOTS Key Backup -Before proceeding, ensure you have access to your original EOTS key from Phase 1. -This is the same key that was registered in the [Phase 1 registration](https://github.com/babylonlabs-io/networks/tree/main/bbn-1/finality-providers). +>Note: Before proceeding, ensure you have access to your original EOTS key from Phase 1. +This is the same key that was registered in the [Phase 1 registration](https://github.com/babylonlabs-io/networks/tree/main/bbn-test-5/finality-providers). ### Step 2: Import Your EOTS Key into the Keyring To load your existing EOTS key, use the following command to import it into the @@ -277,22 +307,31 @@ use `file` or `os` backend. highest level of security by relying on OS-managed encryption and access controls. -This command will create a new key pair and store it in your keyring. The output -should look similar to the below. +This command will create a new key pair and store it in your keyring. +The output should look similar to the below: -``` shell -- address: bbn19gulf0a4yz87twpjl8cxnerc2wr2xqm9fsygn9 - name: finality-provider pubkey: - '{"@type":"/cosmos.crypto.secp256k1.PubKey", - "key":"AhZAL00gKplLQKpLMiXPBqaKCoiessoewOaEATKd4Rcy"}' - type: local + +``` json +{ + "address": "bbn19gulf0a4yz87twpjl8cxnerc2wr2xqm9fsygn9", + "name": "finality-provider", + "pubkey": { + "@type": "/cosmos.crypto.secp256k1.PubKey", + "key": "AhZAL00gKplLQKpLMiXPBqaKCoiessoewOaEATKd4Rcy" + }, + "type": "local" +} ``` ->Note: Please verify the `chain-id` from the Babylon RPC -node [https://rpc.testnet5.babylonlabs.io/status] -(https://rpc.testnet5.babylonlabs.io/status) +>Note: This command will automatically update the `Key` field in +the config file to use this key name. This key will be used for all interactions +with the Babylon chain, including finality provider registration and transaction +signing. - >The configuration below requires to point to the path where this keyring is +>Note: Please verify the `chain-id` and other network parameters from the official +Babylon Networks repository at [https://github.com/babylonlabs-io/networks/tree/main/bbn-test-5/finality-providers](https://github.com/babylonlabs-io/networks/tree/main/bbn-test-5/finality-providers) + +>The configuration below requires to point to the path where this keyring is stored `KeyDirectory`. This `Key` field stores the key name used for interacting with the babylon chain and will be specified along with the `KeyringBackend`field in the next step. So we can ignore the setting of the @@ -528,7 +567,33 @@ finality provider signs conflicting blocks at the same height. This results in the extraction of the provider's private key and automatically triggers shutdown of the finality provider. -### Withdrawing Rewards +## Jailing and Unjailing + +As mentioned above, a finality provider can be jailed for various reasons, +including not signing for a certain number of blocks, not committing public +randomness for a certain number of blocks, or not being responsive to the +finality provider daemon. + +When jailed, the following happens to a finality provider: +- Their voting power becomes 0 +- Status is set to `JAILED` +- Delegator rewards stop + +To unjail a finality provider, you must complete the following steps: +- Fix the underlying issue that caused jailing +- Wait for the jailing period to pass (if it was due to downtime) +- Then send the unjail transaction to the Babylon chain. + +So while slashing is permanent, jailing is a temporary state that can be recovered +from through the unjailing process, as long as the finality provider wasn't slashed. + +## Public Randomness Submission + + +## Reading the logs + + +## Withdrawing Rewards When withdrawing rewards, you need to use the Babylon chain's CLI since rewards are managed by the main chain. From c091e76e4290262fe13187f0a866ed8f719dbbbd Mon Sep 17 00:00:00 2001 From: Sam Ricotta Date: Tue, 19 Nov 2024 19:49:20 +0200 Subject: [PATCH 14/53] Update finality-provider-phase2.md --- docs/finality-provider-phase2.md | 38 ++++++++++++++++++++++++++++---- 1 file changed, 34 insertions(+), 4 deletions(-) diff --git a/docs/finality-provider-phase2.md b/docs/finality-provider-phase2.md index 8e0cea6..1c041a6 100644 --- a/docs/finality-provider-phase2.md +++ b/docs/finality-provider-phase2.md @@ -165,7 +165,7 @@ to continue with the finality provider configuration. >Note: If you have already set up an EOTS Manager, you can skip this section. The following steps are only for users who have not yet set up an EOTS Manager. Phase 1 users who already have an EOTS Manager set up can skip to the -[Loading Existing Keys](#loading-existing-keys-only-for-phase-1-finality-providers) +[Loading Existing Keys](#loading-existing-keys) section at the end of this guide for specific instructions on re-using their Phase 1 EOTS keys. @@ -222,16 +222,46 @@ have an EOTS key. If you are a new user, you can skip this section. >Note: Before proceeding, ensure you have access to your original EOTS key from Phase 1. This is the same key that was registered in the [Phase 1 registration](https://github.com/babylonlabs-io/networks/tree/main/bbn-test-5/finality-providers). +To export your EOTS key, use the following command: + +```shell +eotsd keys export --home --keyring-backend test > key.asc +``` + +- ``: Your EOTS key name from Phase 1 +- `--home`: Path to your EOTS daemon home directory +- `--keyring-backend`: Type of keyring backend (use `test` for testing) +- `key.asc`: Output file for the exported key + +If successful your private key will be saved in `key.asc` + +The exported key will look like: + +``` +-----BEGIN TENDERMINT PRIVATE KEY----- +salt: 35ED0BBC00376EC7FC696838F34A7C36 +type: secp256k1 +kdf: argon2 + +8VOGhpuaZhTPZrKHysx24OhaxuBhVnKqb3WcTwJY+jvfNv/EJRoqmrHZfCnNgd13 +VP88GFE= +=D87O +-----END TENDERMINT PRIVATE KEY----- +``` + ### Step 2: Import Your EOTS Key into the Keyring + To load your existing EOTS key, use the following command to import it into the keyring: ```shell -eotsd keys import +eotsd keys import --home --keyring-backend test ``` -- ``: The name you want to assign to this key in Phase 2. -- ``: The path to your EOTS key backup file from Phase 1. +- ``: New name for your key in Phase 2 +- ``: Path to the exported key file +- `--home`: EOTS daemon home directory for Phase 2 +- `--keyring-backend`: Keyring backend type (use `test` for testing) ## Starting the EOTS Daemon From acf8c9215faad3a48fcda09154b3524c6bd78f55 Mon Sep 17 00:00:00 2001 From: Sam Ricotta Date: Wed, 20 Nov 2024 13:25:53 +0200 Subject: [PATCH 15/53] Part 3: review comments --- docs/finality-provider-phase2.md | 125 ++++++++++++++++++++++--------- 1 file changed, 90 insertions(+), 35 deletions(-) diff --git a/docs/finality-provider-phase2.md b/docs/finality-provider-phase2.md index 1c041a6..c89f6e7 100644 --- a/docs/finality-provider-phase2.md +++ b/docs/finality-provider-phase2.md @@ -76,10 +76,10 @@ There are two distinct keys you'll be working with: - Stored in the finality provider daemon's keyring - Example of the finality provider key output: - ```shell - - address: bbn19gulf0a4yz87twpjl8cxnerc2wr2xqm9fsygn9 - name: finality-provider - ``` +```shell +- address: bbn19gulf0a4yz87twpjl8cxnerc2wr2xqm9fsygn9 +name: finality-provider +``` ## Install Finality Provider Binary @@ -169,7 +169,7 @@ Phase 1 users who already have an EOTS Manager set up can skip to the section at the end of this guide for specific instructions on re-using their Phase 1 EOTS keys. -After a node and a keyring have been set up, the operator can set up and run the +After the full node has been setup, the operator can set up and run the Extractable One Time Signature (EOTS) manager daemon. The EOTS daemon is responsible for managing EOTS keys, producing EOTS @@ -194,6 +194,11 @@ Once the EOTS Manager is initialized, you need to create an EOTS key: eotsd keys add --key-name --home ``` +- ``: Name for your EOTS key (e.g., "eots-key-1") +- `--home`: Path to your EOTS daemon home directory (e.g., "~/.eotsd") +- `--keyring-backend`: Type of keyring storage (use "test" for testing) + + You will be prompted to enter and confirm a passphrase. Ensure this is completed before starting the daemon. @@ -222,22 +227,11 @@ have an EOTS key. If you are a new user, you can skip this section. >Note: Before proceeding, ensure you have access to your original EOTS key from Phase 1. This is the same key that was registered in the [Phase 1 registration](https://github.com/babylonlabs-io/networks/tree/main/bbn-test-5/finality-providers). -To export your EOTS key, use the following command: - -```shell -eotsd keys export --home --keyring-backend test > key.asc -``` - -- ``: Your EOTS key name from Phase 1 -- `--home`: Path to your EOTS daemon home directory -- `--keyring-backend`: Type of keyring backend (use `test` for testing) -- `key.asc`: Output file for the exported key - -If successful your private key will be saved in `key.asc` +### Step 2: Import Your EOTS Key into the Keyring -The exported key will look like: +Before importing the key, it should be in a file in the following format. -``` +`````` -----BEGIN TENDERMINT PRIVATE KEY----- salt: 35ED0BBC00376EC7FC696838F34A7C36 type: secp256k1 @@ -247,19 +241,17 @@ kdf: argon2 VP88GFE= =D87O -----END TENDERMINT PRIVATE KEY----- -``` - -### Step 2: Import Your EOTS Key into the Keyring +``` To load your existing EOTS key, use the following command to import it into the keyring: ```shell -eotsd keys import --home --keyring-backend test +eotsd keys import --home --keyring-backend test ``` - ``: New name for your key in Phase 2 -- ``: Path to the exported key file +- ``: Path to the exported key file - `--home`: EOTS daemon home directory for Phase 2 - `--keyring-backend`: Keyring backend type (use `test` for testing) @@ -294,7 +286,7 @@ reference the address of the machine where `eotsd` is running. The Finality Provider Daemon (FPD) is responsible for monitoring new Babylon blocks, committing public randomness for the blocks it intends to provide finality signatures for, and submitting finality signatures. For more information on Finality Providers, please see -[here](#). +[here](./finality-provider.md). ### Step 1: Initialize the Finality Provider Daemon @@ -381,14 +373,14 @@ Key = // the key you used above ChainID = bbn-test-5 RPCAddr = http://127.0.0.1:26657 GRPCAddr = https://127.0.0.1:9090 -KeyDirectory = ./fpKey +KeyDirectory = # The `--home`path to the directory where the keyring is stored ``` ### Step 3: Verify the Key Import After importing, verify that your EOTS key was successfully loaded: ```shell -eotsd keys list +eotsd keys list --keyring-backend test --home ``` You should see your EOTS key listed with the correct details, confirming that @@ -445,9 +437,9 @@ options can also be set in the configuration file. ## Create Finality Provider The `create-finality-provider` command initializes a new finality provider -instance locally. This command: +instance locally. -- Generates a BTC public key that uniquely identifies your finality provider +This command generates a BTC public key that uniquely identifies your finality provider. ``` shell fpd create-finality-provider \ @@ -520,12 +512,28 @@ This account will be bonded to your finality provider and used to claim rewards. ``` shell fpd register-finality-provider \ -cf0f03b9ee2d4a0f27240e2d8b8c8ef609e24358b2eb3cfd89ae4e4f472e1a41 \ ---daemon-address 127.0.0.1:12581 \ + \ +--daemon-address \ --passphrase \ --home \ ``` +- ``: Your BTC public key from create-finality-provider (e.g., "cf0f03b9ee2d4a0f27240e2d8b8c8ef609e24358b2eb3cfd89ae4e4f472e1a41") +- `--daemon-address`: RPC address of your finality provider daemon (default: "127.0.0.1:12581") +- `--passphrase`: Passphrase for your key +- `--home`: Path to your finality provider daemon home directory (e.g., "~/.fpd") +- `--keyring-backend`: Type of keyring storage (use "test" for testing, "file" for production) + +Example: +```shell +fpd register-finality-provider \ + cf0f03b9ee2d4a0f27240e2d8b8c8ef609e24358b2eb3cfd89ae4e4f472e1a41 \ + --daemon-address 127.0.0.1:12581 \ + --passphrase "my-secure-passphrase" \ + --home ~/.fpd \ + --keyring-backend test +``` + > Note: The BTC public key (`cf0f03...1a41`) is obtained from the previous `create-finality-provider` command. @@ -581,10 +589,10 @@ elliptic curve. - This key is used in the Bitcoin-based security model of Babylon. -**b) Babylon Account:** - This is an account on the Babylon blockchain. - It's -where staking rewards for the finality provider are sent. +**b) Babylon Account:** - This is an account on the Babylon blockchain. +- It's where staking rewards for the finality provider are sent. - This account is controlled by the key you use to create and manage the -finality provider (the one you added with fpd keys add). +finality provider (the one you added with `fpd keys add`). This dual association allows the finality provider to interact with both the Bitcoin network (for security) and the Babylon network (for rewards and @@ -621,7 +629,54 @@ from through the unjailing process, as long as the finality provider wasn't slas ## Reading the logs - + +The logs are stored based on your daemon home directories: + +- EOTS Daemon logs +/logs/eotsd.log + +- Finality Provider Daemon logs +/logs/fpd.log + +You also can access the logs via flags when starting the daemon: + +``` +fpd start --home --log_level debug +``` + Important Log Events to Monitor + +**Status Changes:** +```shell +DEBUG "the finality-provider status is changed to ACTIVE" +DEBUG "the finality-provider is slashed" +DEBUG "the finality-provider status is changed to INACTIVE" +``` + +**Block Finalization Logs:** +```shell +INFO "successfully committed public randomness to the consumer chain" +DEBUG "failed to commit public randomness to the consumer chain" +DEBUG "checking randomness" +``` + +**Finality Votes:** +```shell +DEBUG "the block is already finalized, skip submission" +DEBUG "the finality-provider instance is closing" +``` + +You can also review the logs in real-time using standard Unix tools: + +```shell +# Follow EOTS daemon logs +tail -f /logs/eotsd.log + +# Follow Finality Provider daemon logs +tail -f /logs/fpd.log + +# Filter for specific events (example: status changes) +tail -f /logs/fpd.log | grep "status is changed" +``` ## Withdrawing Rewards From 15bffb1950074e5c16711c9ce59931352c0880bc Mon Sep 17 00:00:00 2001 From: Sam Ricotta Date: Wed, 20 Nov 2024 14:59:00 +0200 Subject: [PATCH 16/53] update to high level docs --- README.md | 58 +++++++++++++++++++++------------------ docs/finality-provider.md | 18 +++++++++--- 2 files changed, 46 insertions(+), 30 deletions(-) diff --git a/README.md b/README.md index d82e88c..8319b71 100644 --- a/README.md +++ b/README.md @@ -5,32 +5,38 @@ management of Finality Providers. ## 1. Overview -Finality providers are responsible for voting -at a finality round on top of [CometBFT](https://github.com/cometbft/cometbft). -Similar to any native PoS validator, -a finality provider can receive voting power delegations from BTC stakers, and -can earn commission from the staking rewards denominated in Babylon tokens. -The core logic of a finality provider instance can be found in -[Finality Provider Core](./docs/fp-core.md). - -The finality provider toolset does not have -any special hardware requirements -and can operate on standard mid-sized machines -running a UNIX-flavored operating system. -It consists of the following programs: - -- *Babylon full node*: An instance of a Babylon node connecting to - the Babylon network. Running one is not a strict requirement, - but it is recommended for security compared to trusting a third-party RPC node. -- *Extractable One-Time Signature (EOTS) manager*: - A daemon responsible for securely maintaining the finality provider’s - private key and producing extractable one time signatures from it. -- *Finality Provider*: A daemon managing the finality provider. - It connects to the EOTS manager to generate EOTS public randomness and - finality votes for Babylon blocks, which it submits to Babylon through - the node connection. - -The following graphic demonstrates the interconnections between the above programs: +Finality providers are key participants in Babylon's consensus +mechanism. They provide finality votes on top of +[CometBFT](https://github.com/cometbft/cometbft), manage public randomness +commitments, and participate in the Proof of Stake (PoS) system. Through these +activities, they can earn commissions from BTC staking delegations. + +The finality provider toolset operates on standard UNIX-based +systems and consists of three core components: + +### 1. Babylon Full Node +A Babylon network node that provides chain data and transaction +submission capabilities. While not mandatory, running your own node is +strongly recommended for security rather than relying on third-party RPC nodes. +See the [Setup Node Guide](https://docs.babylonchain.io/docs/user-guides/btc-staking-testnet/setup-node) for details. + +### 2. Extractable One-Time Signature (EOTS) Manager +A secure key management daemon that handles private key operations, +generates extractable one-time signatures, and produces public randomness. +For enhanced security, this component should run on a separate machine or +network segment. Full details are available in the [EOTS Manager Guide](docs/eots.md). + +### 3. Finality Provider Daemon +The main daemon that monitors Babylon blocks, commits public randomness, and +submits finality signatures. It manages provider status transitions and handles +rewards distribution. See the [Finality Provider Guide](docs/finality-provider.md) +for complete documentation. + +### Component Interactions +The Finality Provider daemon communicates with the Babylon Node to monitor blocks +and submit transactions. It interacts with the EOTS Manager for signature and +randomness generation. The EOTS Manager maintains secure key storage and handles +all private key operations. ![Finality Provider Interconnections](./docs/FP.png) diff --git a/docs/finality-provider.md b/docs/finality-provider.md index 527eafc..1fd1ebb 100644 --- a/docs/finality-provider.md +++ b/docs/finality-provider.md @@ -11,16 +11,26 @@ providers: 1. **Creation and Registration**: Creates and registers finality providers to Babylon. + 2. **EOTS Randomness Commitment**: The daemon monitors the Babylon chain and commits EOTS public randomness for every Babylon block each finality provider intends to - vote for. The commit intervals can be specified in the configuration. The EOTS - public randomness is retrieved through the finality provider daemon's connection - with the [EOTS daemon](eots.md). + vote for. The commit intervals can be specified in the configuration. + 3. **Finality Votes Submission**: The daemon monitors the Babylon chain and produces finality votes for each block each maintained finality provider has committed to vote for. -The daemon is controlled by the `fpd` tool, which has overall commands for +4. **Status Management**: The daemon continuously monitors voting power and overall + provider status. It manages state transitions between `ACTIVE`, `INACTIVE`, + `JAILED`, and `SLASHED` states, while enforcing slashing conditions and handling + the jailing process when violations occur. + +5. **Security and Key Management**: The system manages EOTS keys for signature + generation and Babylon keys for transaction processing and rewards distribution. + It maintains secure coordination with the EOTS daemon for all key-related + operations. + +The daemon is controlled by the `fpd` tool, which provides commands for interacting with the running daemon. ## 2. Configuration From d88e0ee779524920653abc924d7f9fd9621ac01d Mon Sep 17 00:00:00 2001 From: Sam Ricotta Date: Wed, 20 Nov 2024 17:11:56 +0200 Subject: [PATCH 17/53] fix code block --- docs/finality-provider-phase2.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/finality-provider-phase2.md b/docs/finality-provider-phase2.md index c89f6e7..738f93d 100644 --- a/docs/finality-provider-phase2.md +++ b/docs/finality-provider-phase2.md @@ -231,7 +231,7 @@ This is the same key that was registered in the [Phase 1 registration](https://g Before importing the key, it should be in a file in the following format. -`````` +``` -----BEGIN TENDERMINT PRIVATE KEY----- salt: 35ED0BBC00376EC7FC696838F34A7C36 type: secp256k1 From c7cc0477310d0396e91500cc9245194bca39328c Mon Sep 17 00:00:00 2001 From: Sam Ricotta Date: Thu, 21 Nov 2024 13:21:45 +0200 Subject: [PATCH 18/53] Part 4: review comments --- README.md | 16 +-- docs/finality-provider-phase2.md | 163 +++++++++++++------------------ 2 files changed, 76 insertions(+), 103 deletions(-) diff --git a/README.md b/README.md index 8319b71..91f7faf 100644 --- a/README.md +++ b/README.md @@ -5,11 +5,10 @@ management of Finality Providers. ## 1. Overview -Finality providers are key participants in Babylon's consensus -mechanism. They provide finality votes on top of -[CometBFT](https://github.com/cometbft/cometbft), manage public randomness -commitments, and participate in the Proof of Stake (PoS) system. Through these -activities, they can earn commissions from BTC staking delegations. +Finality providers are key participants in Babylon BTC staking protocol. +They provide finality votes on top of +[CometBFT](https://github.com/cometbft/cometbft), Babylon's consensus mechanism. +Through these activities, they can earn commissions from BTC staking delegations. The finality provider toolset operates on standard UNIX-based systems and consists of three core components: @@ -21,13 +20,13 @@ strongly recommended for security rather than relying on third-party RPC nodes. See the [Setup Node Guide](https://docs.babylonchain.io/docs/user-guides/btc-staking-testnet/setup-node) for details. ### 2. Extractable One-Time Signature (EOTS) Manager -A secure key management daemon that handles private key operations, +A secure key management daemon that handles EOTS key operations, generates extractable one-time signatures, and produces public randomness. For enhanced security, this component should run on a separate machine or network segment. Full details are available in the [EOTS Manager Guide](docs/eots.md). ### 3. Finality Provider Daemon -The main daemon that monitors Babylon blocks, commits public randomness, and +The core daemon that polls Babylon blocks, commits public randomness, and submits finality signatures. It manages provider status transitions and handles rewards distribution. See the [Finality Provider Guide](docs/finality-provider.md) for complete documentation. @@ -36,7 +35,7 @@ for complete documentation. The Finality Provider daemon communicates with the Babylon Node to monitor blocks and submit transactions. It interacts with the EOTS Manager for signature and randomness generation. The EOTS Manager maintains secure key storage and handles -all private key operations. +all EOTS key operations. ![Finality Provider Interconnections](./docs/FP.png) @@ -97,6 +96,7 @@ It is highly recommended that operators run their own node to avoid trusting third parties. Instructions on how to set up a full Babylon node can be found in [the Babylon documentation](https://docs.babylonchain.io/docs/user-guides/btc-staking-testnet/setup-node). + ### 3.2. Setting up the EOTS Manager diff --git a/docs/finality-provider-phase2.md b/docs/finality-provider-phase2.md index 738f93d..8601bbb 100644 --- a/docs/finality-provider-phase2.md +++ b/docs/finality-provider-phase2.md @@ -1,50 +1,46 @@ # Finality Provider Registration -This guide covers the ongoing operation of the Babylonchain -but in this guide we cover the registration process for -finality providers in Phase 2. - -Phase 2 launch of the Babylon network is a critical transition +Phase-2 launch of the Babylon network is a critical transition that introduces active participation in finality voting, rewards distribution, and the Proof of Stake (PoS) system. This guide provides a step-by-step process for operators to onboard, whether setting up a new or pre-existing setup, -with a focus on Phase 2-specific requirements. +with a focus on Phase-2 specific requirements. -The following explains the migration from Phase 1 to 2. +The following explains the migration from Phase-1 to Phase-2. -**Phase 1 (Previous phase)** +**Phase-1 (Previous phase)** -- Only involves Bitcoin holders submitting staking transactions +- Only involves Bitcoin holders locking their assets on the Bitcoin chain - No active Proof of Stake (PoS) chain operation - Finality providers only need EOTS keys generated - No need to run finality service -**Phase 2 (New phase)** +**Phase-2 (New phase)** - Active participation in finality voting - Running the complete finality provider toolset: - Babylon full node - EOTS manager daemon - Finality provider daemon -- Earning commissions from Bitcoin Stake delegations -- Rewards distribution +- Earning rewards from Bitcoin delegations -There are 2 different types of paths for Finality providers +There are 2 paths for setting up a finality provider: 1. **Has existing EOTS Key** - - Already have EOTS key from [Phase 1](https://github.com/babylonlabs-io/networks/tree/main/bbn-test-5/finality-providers) - - Reference existing EOTS key in setup + - Already generated a EOTS key pair from [Phase-1](https://github.com/babylonlabs-io/networks/tree/main/bbn-test-5/finality-providers) + + - Reference the existing EOTS key in setup -If you have an existing EOTS key from Phase 1, please skip to +If you have an existing EOTS key from Phase-1, please skip to [Loading Existing Keys](#loading-existing-keys) steps ->Note: Any finality providers from phase-1 that do not transition their existing key, will not have any of their delegations from phase-1. +>Note: Any finality providers from Phase-1 that do not transition their existing key, cannot claim any rewards if they dont have their Finality Provider setup on Phase-2 2. **New Setup** - For operators starting fresh - - Need to generate both EOTS and FP keys + - Need to generate the EOTS key first - Complete full configuration process If you are a new operator, start with the @@ -55,31 +51,27 @@ If you are a new operator, start with the There are two distinct keys you'll be working with: - **EOTS Key**: - - Used for generating EOTS signatures - - Used to generate the BTC public key for the finality provider + - Used for generating EOTS signatures, Schnorr signatures, and randomness pairs + - This serves as the unique identifier for the finality provider + - It's derived from a Bitcoin private key, likely using the secp256k1 + elliptic curve. - Stored in the EOTS manager daemon's keyring - - Example of the EOTS key output: - ```json - { - "name": "eots", - "pub_key_hex": - "e1e72d270b90b24f395e76b417218430a75683bd07cf98b91cf9219d1c777c19", - "mnemonic": "parade hybrid century project toss gun undo ocean exercise - figure decorate basket peace raw spot gap dose daring patch ski purchase - prefer can pair" - } - ``` - -- **Finality Provider Key**: + - This key is used in the Bitcoin-based security model of Babylon. + +- **Babylon Key**: - Used for signing transactions on Babylon + - It's where staking rewards for the finality provider are sent. - Associated with a Babylon account that receives rewards - Stored in the finality provider daemon's keyring + - This account is controlled by the key you use to create and manage the +finality provider (the one you added with `fpd keys add`). - - Example of the finality provider key output: -```shell -- address: bbn19gulf0a4yz87twpjl8cxnerc2wr2xqm9fsygn9 -name: finality-provider -``` +This dual association allows the finality provider to interact with both the +Bitcoin network (for security) and the Babylon network (for rewards and +governance). + +Once a finality provider is created, neither key can be rotated or changed - +they are permanently associated with that specific finality provider instance. ## Install Finality Provider Binary @@ -116,7 +108,6 @@ This command will: - Install binaries to `$GOPATH/bin`: - `eotsd`: EOTS manager daemon - `fpd`: Finality provider daemon - - `fpcli`: Finality provider CLI tool - Make commands globally accessible from your terminal ### Step 3: Verify Installation @@ -164,10 +155,10 @@ to continue with the finality provider configuration. >Note: If you have already set up an EOTS Manager, you can skip this section. The following steps are only for users who have not yet set up an EOTS Manager. -Phase 1 users who already have an EOTS Manager set up can skip to the +Phase-1 users who already had an EOTS Manager set up can skip to the [Loading Existing Keys](#loading-existing-keys) section at the end of this guide for specific instructions -on re-using their Phase 1 EOTS keys. +on re-using their Phase-1 EOTS keys. After the full node has been setup, the operator can set up and run the Extractable One Time Signature (EOTS) manager daemon. @@ -180,7 +171,7 @@ Manager see [here](#) Use the `eotsd init` command to initialize a home directory for the EOTS Manager. You can set or change your home directory using the `--home` tag. For example, use -`--home ./eotsKey` to specify a custom directory. +`--home ./eotsHome` to specify a custom directory. ```shell eotsd init --home @@ -191,17 +182,14 @@ eotsd init --home Once the EOTS Manager is initialized, you need to create an EOTS key: ``` shell -eotsd keys add --key-name --home +eotsd keys add --key-name --home --keyring-backend test ``` -- ``: Name for your EOTS key (e.g., "eots-key-1") +- ``: Name for your EOTS key (e.g., "eots-key-1"). We do not allow the same +`keyname` for an existing keyname. - `--home`: Path to your EOTS daemon home directory (e.g., "~/.eotsd") - `--keyring-backend`: Type of keyring storage (use "test" for testing) - -You will be prompted to enter and confirm a passphrase. -Ensure this is completed before starting the daemon. - Sample output: ```json @@ -215,21 +203,28 @@ Sample output: } ``` +>**Important**: The mnemonic phrase must be stored securely and kept private, as it is the +only way to recover your EOTS key if access is lost and is critical for maintaining control +of your finality provider operations. + ## Loading Existing Keys ->Note: If you participated in Phase 1, follow these steps to load your existing EOTS -key and configure it for Phase 2. +>Note: If you participated in Phase-1, follow these steps to load your existing EOTS +key and configure it for Phase-2. ->This section is only for Finality Providers who participated in Phase 1 and already -have an EOTS key. If you are a new user, you can skip this section. +>This section is only for Finality Providers who participated in Phase-1 and already +had an EOTS key. If you are a new user, you can skip this section unless you would like to +familiarlize yourself with the backup and recovery process. ### Step 1: Verify Your EOTS Key Backup ->Note: Before proceeding, ensure you have access to your original EOTS key from Phase 1. -This is the same key that was registered in the [Phase 1 registration](https://github.com/babylonlabs-io/networks/tree/main/bbn-test-5/finality-providers). +>Note: Before proceeding, ensure you have access to your original EOTS key from Phase-1. +This is the same key that was registered in the [Phase-1 registration](https://github.com/babylonlabs-io/networks/tree/main/bbn-test-5/finality-providers). + ### Step 2: Import Your EOTS Key into the Keyring -Before importing the key, it should be in a file in the following format. +Before importing the key, it should be in a file (the file will be named `key.asc`) +in the following format. ``` -----BEGIN TENDERMINT PRIVATE KEY----- @@ -250,9 +245,10 @@ keyring: eotsd keys import --home --keyring-backend test ``` -- ``: New name for your key in Phase 2 +- ``: New name for your key in Phase-2. This should be unique from the keyname +used in Phase-1. - ``: Path to the exported key file -- `--home`: EOTS daemon home directory for Phase 2 +- `--home`: EOTS daemon home directory for Phase-2 - `--keyring-backend`: Keyring backend type (use `test` for testing) ## Starting the EOTS Daemon @@ -283,16 +279,11 @@ reference the address of the machine where `eotsd` is running. ## Setting up the Finality Provider -The Finality Provider Daemon (FPD) is responsible for monitoring new Babylon blocks, -committing public randomness for the blocks it intends to provide finality signatures for, -and submitting finality signatures. For more information on Finality Providers, please see -[here](./finality-provider.md). - ### Step 1: Initialize the Finality Provider Daemon Use the `fpd init` command to initialize a home directory for the Finality Provider. You can set or change the home directory using the `--home` tag. For example, use -`--home ./fpKeys` to specify a custom directory. +`--home ./fpHome` to specify a custom directory. ```shell fpd init --home @@ -302,13 +293,13 @@ fpd init --home `service injective.evm.v1beta1.Msg does not have cosmos.msg.v1.service proto annotation`, which is expected and can be ignored. -### Step 2: Add key for the Finality Provider on the Babylon Chain +### Step 2: Add key for the Babylon account -The keyring is maintained by the finality provider daemon, this is local storage -of the keys that the daemon uses. The account associated with this key exists on -the babylon chain. +The keyring is kept in the local storage of the finality provider daemon. +The key associates a Babylon account with the finality provider to receive BTC +delegation rewards. -Use the following command to add a key for your finality provider: +Use the following command to add the Babylonkey for your finality provider: ```shell fpd keys add --keyname --keyring-backend test --home @@ -387,9 +378,9 @@ You should see your EOTS key listed with the correct details, confirming that it has been imported correctly. >Note: Make sure you're using the same key name and EOTS public key that were -registered in Phase 1. +registered in Phase-1. -## Starting the Finality provider Daemon +## Starting the Finality Provider Daemon The finality provider daemon (FPD) needs to be running before proceeding with registration or voting participation. @@ -399,10 +390,10 @@ Start the daemon with: ``` shell fpd start --home ``` -An example of the `--home` flag is `--home ./fpKeys`. +An example of the `--home` flag is `--home ./fpHome`. The command flags: -- `start`: Initiates the FPD daemon +- `start`: Runs the FPD daemon - `--home`: Specifies the directory for daemon data and configuration The daemon will start the RPC server for CLI communication then begin listening @@ -427,9 +418,9 @@ of `127.0.0.1:12581`. You can change this value in the configuration file or override this value and specify a custom address using the `--rpc-listener` flag. -To start the daemon with a specific finality provider instance, use -the `--btc-pk` flag followed by the hex string of the BTC public key of the -finality provider (`btc_pk_hex`) in the next step +To start the daemon with a specific finality provider instance after +registration, use the `--eots_pk_hex` flag followed by the hex string of the EOTS +public key of the finality provider. All the available CLI options can be viewed using the `--help` flag. These options can also be set in the configuration file. @@ -505,7 +496,7 @@ Your set commission rate The `register-finality-provider` command registers your finality provider on the Babylon chain. This command requires: -1. The BTC public key (obtained from the `create-finality-provider` command) +1. The EOTS public key 2. A funded Babylon account (needs BBN tokens for transaction fees). This account will be bonded to your finality provider and used to claim rewards. 3. A running FPD daemon @@ -535,7 +526,7 @@ fpd register-finality-provider \ ``` > Note: The BTC public key (`cf0f03...1a41`) is obtained from the previous -`create-finality-provider` command. +`eotsd keys add` command. If successful, the command will return a transaction hash: @@ -580,24 +571,6 @@ The hash returned should look something similar to below: gas_used: "82063" gas_wanted: "94429" height: "66693" info: "" logs: [] raw_log:"" ``` -When a finality provider is created, it's associated with two key elements: - -**a) BTC Public Key:** - This serves as the unique identifier for the finality -provider. -- It's derived from a Bitcoin private key, likely using the secp256k1 -elliptic curve. -- This key is used in the Bitcoin-based security model of -Babylon. - -**b) Babylon Account:** - This is an account on the Babylon blockchain. -- It's where staking rewards for the finality provider are sent. -- This account is controlled by the key you use to create and manage the -finality provider (the one you added with `fpd keys add`). - -This dual association allows the finality provider to interact with both the -Bitcoin network (for security) and the Babylon network (for rewards and -governance). - ## Slashing Conditions Slashing occurs when a finality provider **double signs**. This occurs when a From 3ac7d77a1e402d2b6f43fa9c8ecfe9b81f514598 Mon Sep 17 00:00:00 2001 From: Sam Ricotta Date: Thu, 21 Nov 2024 14:55:09 +0200 Subject: [PATCH 19/53] Part 5: review comments --- docs/finality-provider-phase2.md | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/docs/finality-provider-phase2.md b/docs/finality-provider-phase2.md index 8601bbb..ad0e446 100644 --- a/docs/finality-provider-phase2.md +++ b/docs/finality-provider-phase2.md @@ -171,7 +171,8 @@ Manager see [here](#) Use the `eotsd init` command to initialize a home directory for the EOTS Manager. You can set or change your home directory using the `--home` tag. For example, use -`--home ./eotsHome` to specify a custom directory. +`--home ./eotsHome` to specify a custom directory. The application default home directory is +`/Users//Library/Application Support/Eotsd`. ```shell eotsd init --home @@ -283,7 +284,8 @@ reference the address of the machine where `eotsd` is running. Use the `fpd init` command to initialize a home directory for the Finality Provider. You can set or change the home directory using the `--home` tag. For example, use -`--home ./fpHome` to specify a custom directory. +`--home ./fpHome` to specify a custom directory. The application default home directory is +`/Users//Library/Application Support/Fpd`. ```shell fpd init --home @@ -430,12 +432,11 @@ options can also be set in the configuration file. The `create-finality-provider` command initializes a new finality provider instance locally. -This command generates a BTC public key that uniquely identifies your finality provider. - ``` shell fpd create-finality-provider \ --daemon-address 127.0.0.1:12581 \ --chain-id bbn-test-5 \ +--eots-pk \ //this is the EOTS public key of the finality provider which was generated in `eotsd keys add` --commission 0.05 \ --key-name finality-provider \ --moniker "MyFinalityProvider" \ @@ -509,7 +510,8 @@ fpd register-finality-provider \ --home \ ``` -- ``: Your BTC public key from create-finality-provider (e.g., "cf0f03b9ee2d4a0f27240e2d8b8c8ef609e24358b2eb3cfd89ae4e4f472e1a41") +- ``: Your BTC public key from create-finality-provider +(e.g., "cf0f03b9ee2d4a0f27240e2d8b8c8ef609e24358b2eb3cfd89ae4e4f472e1a41") - `--daemon-address`: RPC address of your finality provider daemon (default: "127.0.0.1:12581") - `--passphrase`: Passphrase for your key - `--home`: Path to your finality provider daemon home directory (e.g., "~/.fpd") From cb82ba3f4f75e000a6423e99c1cd7468454df68b Mon Sep 17 00:00:00 2001 From: Sam Ricotta Date: Thu, 21 Nov 2024 15:01:23 +0200 Subject: [PATCH 20/53] small fixes --- docs/finality-provider-phase2.md | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/docs/finality-provider-phase2.md b/docs/finality-provider-phase2.md index ad0e446..86f5d78 100644 --- a/docs/finality-provider-phase2.md +++ b/docs/finality-provider-phase2.md @@ -455,6 +455,7 @@ transactions - `--moniker`: A human-readable name for your finality provider Optional parameters: +- `--eots-pk`: The EOTS public key of the finality provider which was generated in `eotsd keys add` - `--website`: Your finality provider's website - `--security-contact`: Contact email for security issues - `--details`: @@ -468,7 +469,7 @@ your finality provider's details: ``` json { "fp_addr": "bbn1ht2nxa6hlyl89m8xpdde9xsj40n0sxd2f9shsq", - "btc_pk_hex": + "eots_pk_hex": "cf0f03b9ee2d4a0f27240e2d8b8c8ef609e24358b2eb3cfd89ae4e4f472e1a41", "description": { @@ -485,7 +486,7 @@ your finality provider's details: The response includes: - `fp_addr`: Your Babylon account address for receiving rewards -- `btc_pk_hex`: Your unique BTC public key identifier (needed for +- `eots_pk_hex`: Your unique BTC public key identifier (needed for registration) - `description`: Your finality provider's metadata - `commission`: From c73b74988987597d4817859c6fa70cb215b2a04e Mon Sep 17 00:00:00 2001 From: Vitalis Salis Date: Thu, 21 Nov 2024 15:16:06 +0200 Subject: [PATCH 21/53] Static folder for images --- README.md | 12 +++++------- docs/finality-toolset.png | Bin 75814 -> 0 bytes docs/fp-core.md | 2 +- .../finality-provider-arch.png} | Bin docs/{ => static}/fp-status-transition.png | Bin 5 files changed, 6 insertions(+), 8 deletions(-) delete mode 100644 docs/finality-toolset.png rename docs/{FP.png => static/finality-provider-arch.png} (100%) rename docs/{ => static}/fp-status-transition.png (100%) diff --git a/README.md b/README.md index 91f7faf..ad9348c 100644 --- a/README.md +++ b/README.md @@ -13,31 +13,29 @@ Through these activities, they can earn commissions from BTC staking delegations The finality provider toolset operates on standard UNIX-based systems and consists of three core components: -### 1. Babylon Full Node +1. **Babylon Node**: A Babylon network node that provides chain data and transaction submission capabilities. While not mandatory, running your own node is strongly recommended for security rather than relying on third-party RPC nodes. See the [Setup Node Guide](https://docs.babylonchain.io/docs/user-guides/btc-staking-testnet/setup-node) for details. - -### 2. Extractable One-Time Signature (EOTS) Manager +2. **Extractable One-Time Signature (EOTS) Manager**: A secure key management daemon that handles EOTS key operations, generates extractable one-time signatures, and produces public randomness. For enhanced security, this component should run on a separate machine or network segment. Full details are available in the [EOTS Manager Guide](docs/eots.md). - -### 3. Finality Provider Daemon +3. **Finality Provider Daemon**: The core daemon that polls Babylon blocks, commits public randomness, and submits finality signatures. It manages provider status transitions and handles rewards distribution. See the [Finality Provider Guide](docs/finality-provider.md) for complete documentation. -### Component Interactions +**Component Interactions**: The Finality Provider daemon communicates with the Babylon Node to monitor blocks and submit transactions. It interacts with the EOTS Manager for signature and randomness generation. The EOTS Manager maintains secure key storage and handles all EOTS key operations. -![Finality Provider Interconnections](./docs/FP.png) +![Finality Provider Architecture Diagram](./docs/static/finality-provider-arch.png) ## 2. Installation diff --git a/docs/finality-toolset.png b/docs/finality-toolset.png deleted file mode 100644 index c165ba2159ecc3fdfd42f7e6f520147c0090e05c..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 75814 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¦ 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 Ti=}#kf|trIO{Fpgi=h7jm$!DQ diff --git a/docs/fp-core.md b/docs/fp-core.md index d522749..9917368 100644 --- a/docs/fp-core.md +++ b/docs/fp-core.md @@ -10,7 +10,7 @@ A finality provider has the following 5 possible states: `Registered`, `Inactive`, `Active`, `Jailed`, `Slashed`. The state transition is depicted in the following diagram. -![Finality Provider Status Transition](./fp-status-transition.png). +![Finality Provider Status Transition](./static/fp-status-transition.png). ## Invariants diff --git a/docs/FP.png b/docs/static/finality-provider-arch.png similarity index 100% rename from docs/FP.png rename to docs/static/finality-provider-arch.png diff --git a/docs/fp-status-transition.png b/docs/static/fp-status-transition.png similarity index 100% rename from docs/fp-status-transition.png rename to docs/static/fp-status-transition.png From ae64bc8cd9b96b4142a8565477c77869cbc0b34a Mon Sep 17 00:00:00 2001 From: Vitalis Salis Date: Thu, 21 Nov 2024 15:50:57 +0200 Subject: [PATCH 22/53] Clean up some docs, mess up others more --- README.md | 168 +++++------ docs/eots.md | 188 ------------ ...ase2.md => finality-provider-operation.md} | 130 ++++----- docs/finality-provider.md | 272 ------------------ 4 files changed, 139 insertions(+), 619 deletions(-) delete mode 100644 docs/eots.md rename docs/{finality-provider-phase2.md => finality-provider-operation.md} (86%) delete mode 100644 docs/finality-provider.md diff --git a/README.md b/README.md index ad9348c..114fadc 100644 --- a/README.md +++ b/README.md @@ -1,10 +1,5 @@ # Finality Provider -A toolset crafted for the creation and -management of Finality Providers. - -## 1. Overview - Finality providers are key participants in Babylon BTC staking protocol. They provide finality votes on top of [CometBFT](https://github.com/cometbft/cometbft), Babylon's consensus mechanism. @@ -37,87 +32,82 @@ all EOTS key operations. ![Finality Provider Architecture Diagram](./docs/static/finality-provider-arch.png) -## 2. Installation - -### Prerequisites - -This project requires Go version 1.23 or later. - -Install Go by following the instructions on -the [official Go installation guide](https://golang.org/doc/install). - -### Downloading the code - -To get started, clone the repository to your local machine from Github: - -```bash -git clone https://github.com/babylonlabs-io/finality-provider.git -``` - -You can choose a specific version from -the [official releases page](https://github.com/babylonlabs-io/finality-provider/releases) - -```bash -cd finality-provider # cd into the project directory -git checkout -``` - -### Building and installing the binary - -At the top-level directory of the project - -```bash -make install -``` - -The above command will build and install the following binaries to -`$GOPATH/bin`: - -- `eotsd`: The daemon program for the EOTS manager. -- `fpd`: The daemon program for the finality-provider with overall commands. - -If your shell cannot find the installed binaries, make sure `$GOPATH/bin` is in -the `$PATH` of your shell. Usually these commands will do the job - -```bash -export PATH=$HOME/go/bin:$PATH -echo 'export PATH=$HOME/go/bin:$PATH' >> ~/.profile -``` - -## 3. Setting up a finality provider - -### 3.1. Setting up a Babylon Full Node - -Before setting up the finality provider toolset, -an operator must ensure a working connection with a Babylon full node. -It is highly recommended that operators run their own node to avoid -trusting third parties. Instructions on how to set up a full Babylon node -can be found in -[the Babylon documentation](https://docs.babylonchain.io/docs/user-guides/btc-staking-testnet/setup-node). - - -### 3.2. Setting up the EOTS Manager - -After a node and a keyring have been set up, -the operator can set up and run the -Extractable One Time Signature (EOTS) manager daemon. -A complete overview of the EOTS manager, its operation, and -its configuration options can be found in the -[EOTS Manager page](docs/eots.md) - -### 3.3. Setting up a Finality Provider - -The last step is to set up and run -the finality daemon. -A complete overview of the finality daemon, its operation, and -its configuration options can be found in the -[Finality page](docs/finality-provider.md). - -## 4. Delegations & Rewards - -A finality provider receives BTC delegations through delegators -interacting with Babylon and choosing it as the recipient of their delegations. -To perform a self-delegation, -the operator can either visit the staking web app we provide, -or run the Babylon [BTC Staker program](https://github.com/babylonlabs-io/btc-staker) once. -The BTC staker connects to a Bitcoin wallet and Babylon to perform delegations. +## Become a Finality Provider + +If you are interested in becoming a finality provider +you can find more details [here](./docs/finality-provider-operation.md) + +## Technical Documentation + +You can find more about the internals of the finality provider +toolset operation in the following docs: +* [Core Heuristics](./docs/fp-core.md) +* [Public Randomness Commits](./docs/commit-pub-rand.md) + +## High Level Descriptions of EOTS and Finality Provider + + +### EOTS Manager + +The EOTS daemon is responsible for managing EOTS keys, producing EOTS randomness, and +using them to produce EOTS signatures. + +**Note:** EOTS stands for Extractable One Time Signature. You can read more about it +in +the [Babylon BTC Staking Litepaper](https://docs.babylonchain.io/assets/files/btc_staking_litepaper-32bfea0c243773f0bfac63e148387aef.pdf). +In short, the EOTS manager produces EOTS public/private randomness pairs. The +finality provider commits the public part of these pairs to Babylon for every future +block height that they intend to provide a finality signature for. If the finality +provider votes for two different blocks on the same height, they will have to reuse +the same private randomness which will lead to their underlying private key being +exposed, leading to the slashing of them and all their delegators. + +The EOTS manager is responsible for the following operations: + +1. **EOTS Key Management:** + - Generates [Schnorr](https://en.wikipedia.org/wiki/Schnorr_signature) key pairs + for a given finality provider using the + [BIP-340](https://github.com/bitcoin/bips/blob/master/bip-0340.mediawiki) + standard. + - Persists generated key pairs in the internal Cosmos keyring. +2. **Randomness Generation:** + - Generates lists of EOTS randomness pairs based on the EOTS key, chainID, and + block height. + - The randomness is deterministically generated and tied to specific parameters. +3. **Signature Generation:** + - Signs EOTS using the private key of the finality provider and the corresponding + secret randomness for a given chain at a specified height. + - Signs Schnorr signatures using the private key of the finality provider. + +### Finality Provider + +The Finality Provider Daemon is responsible for monitoring for new Babylon blocks, +committing public randomness for the blocks it intends to provide finality signatures +for, and submitting finality signatures. + +The daemon can manage and perform the following operations for multiple finality +providers: + +1. **Creation and Registration**: Creates and registers finality providers to + Babylon. + +2. **EOTS Randomness Commitment**: The daemon monitors the Babylon chain and commits + EOTS public randomness for every Babylon block each finality provider intends to + vote for. The commit intervals can be specified in the configuration. + +3. **Finality Votes Submission**: The daemon monitors the Babylon chain and produces + finality votes for each block each maintained finality provider has committed to + vote for. + +4. **Status Management**: The daemon continuously monitors voting power and overall + provider status. It manages state transitions between `ACTIVE`, `INACTIVE`, + `JAILED`, and `SLASHED` states, while enforcing slashing conditions and handling + the jailing process when violations occur. + +5. **Security and Key Management**: The system manages EOTS keys for signature + generation and Babylon keys for transaction processing and rewards distribution. + It maintains secure coordination with the EOTS daemon for all key-related + operations. + +The daemon is controlled by the `fpd` tool, which provides commands for +interacting with the running daemon. diff --git a/docs/eots.md b/docs/eots.md deleted file mode 100644 index 8b20cb0..0000000 --- a/docs/eots.md +++ /dev/null @@ -1,188 +0,0 @@ -# EOTS Manager - -## 1. Overview - -The EOTS daemon is responsible for managing EOTS keys, producing EOTS randomness, and -using them to produce EOTS signatures. - -**Note:** EOTS stands for Extractable One Time Signature. You can read more about it -in -the [Babylon BTC Staking Litepaper](https://docs.babylonchain.io/assets/files/btc_staking_litepaper-32bfea0c243773f0bfac63e148387aef.pdf). -In short, the EOTS manager produces EOTS public/private randomness pairs. The -finality provider commits the public part of these pairs to Babylon for every future -block height that they intend to provide a finality signature for. If the finality -provider votes for two different blocks on the same height, they will have to reuse -the same private randomness which will lead to their underlying private key being -exposed, leading to the slashing of them and all their delegators. - -The EOTS manager is responsible for the following operations: - -1. **EOTS Key Management:** - - Generates [Schnorr](https://en.wikipedia.org/wiki/Schnorr_signature) key pairs - for a given finality provider using the - [BIP-340](https://github.com/bitcoin/bips/blob/master/bip-0340.mediawiki) - standard. - - Persists generated key pairs in the internal Cosmos keyring. -2. **Randomness Generation:** - - Generates lists of EOTS randomness pairs based on the EOTS key, chainID, and - block height. - - The randomness is deterministically generated and tied to specific parameters. -3. **Signature Generation:** - - Signs EOTS using the private key of the finality provider and the corresponding - secret randomness for a given chain at a specified height. - - Signs Schnorr signatures using the private key of the finality provider. - -The EOTS manager functions as a daemon controlled by the `eotsd` tool. - -## 2. Configuration - -The `eotsd init` command initializes a home directory for the EOTS manager. This -directory is created in the default home location or in a location specified by -the `--home` flag. - -```bash -eotsd init --home /path/to/eotsd/home/ -``` - -After initialization, the home directory will have the following structure - -```bash -ls /path/to/eotsd/home/ - ├── eotsd.conf # Eotsd-specific configuration file. - ├── logs # Eotsd logs -``` - -If the `--home` flag is not specified, then the default home location will be used. -For different operating systems, those are: - -- **MacOS** `~/Users//Library/Application Support/Eotsd` -- **Linux** `~/.Eotsd` -- **Windows** `C:\Users\\AppData\Local\Eotsd` - -## 3. Keys Management - -Handles the keys for EOTS. - -### 3.1. Create EOTS Keys - -The binary `eotsd` has the option to add a new key to the keyring for -later usage with signing EOTS and Schnorr signatures. Keep in mind -that new keys can be created on demand by the GRPC call from `fpd`. -But, if you would like to add a new EOTS key manually, run `eotsd keys add`. - -This command has several flag options: - -- `--home` specifies the home directory of the `eotsd` in which -the new key will be stored. -- `--key-name` mandatory flag and identifies the name of the key to be generated. -- `--passphrase` specifies the password used to encrypt the key, if such a -passphrase is required. -- `--hd-path` the hd derivation path of the private key. -- `--keyring-backend` specifies the keyring backend, any of `[file, os, kwallet, test, pass, memory]` -are available, by default `test` is used. -- `--recover` indicates whether the user wants to provide a seed phrase to recover -the existing key instead of randomly creating. - -```shell -eotsd keys add --home /path/to/eotsd/home/ --key-name my-key-name --keyring-backend file - -Enter keyring passphrase (attempt 1/3): -... - -2024-04-25T17:11:09.369163Z info successfully created an EOTS key {"key name": "my-key-name", "pk": "50b106208c921b5e8a1c45494306fe1fc2cf68f33b8996420867dc7667fde383"} -New key for the BTC chain is created (mnemonic should be kept in a safe place for recovery): -{ - "name": "my-key-name", - "pub_key_hex": "50b106208c921b5e8a1c45494306fe1fc2cf68f33b8996420867dc7667fde383", - "mnemonic": "bad mnemonic private tilt wish bulb miss plate achieve manage feel word safe dash vanish little miss hockey connect tail certain spread urban series" -} -``` - -> Store the mnemonic in a safe place. With the mnemonic only it is possible to -recover the generated keys by using the `--recover` flag. - -### 3.2. Recover Keys - -To recover the keys from a mnemonic, run: - -```shell -eotsd keys add --home /path/to/eotsd/home/ --key-name my-key-name --keyring-backend file --recover - -> Enter your mnemonic -bad mnemonic private tilt wish bulb miss plate achieve manage feel word safe dash vanish little miss hockey connect tail certain spread urban series -2024-04-25T17:13:29.681324Z info successfully created an EOTS key {"key name": "my-key-name", "pk": "50b106208c921b5e8a1c45494306fe1fc2cf68f33b8996420867dc7667fde383"} -New key for the BTC chain is created (mnemonic should be kept in a safe place for recovery): -{ - "name": "my-key-name", - "pub_key_hex": "50b106208c921b5e8a1c45494306fe1fc2cf68f33b8996420867dc7667fde383", - "mnemonic": "noise measure tuition inform battle swallow slender bundle horn pigeon wage mule average bicycle claim solve home swamp banner idle chapter surround edit gossip" -} -``` - -You will be prompted to provide the mnemonic on key creation. - -### 3.3. Sign Schnorr Signatures - -You can use your key to create a Schnorr signature over arbitrary data -through the `eotsd sign-schnorr` command. -The command takes as an argument the file path, hashes the file content using -sha256, and signs the hash with the EOTS private key in Schnorr format by the -given `key-name` or `eots-pk`. If both flags `--key-name` and `--eots-pk` are -provided, `eots-pk` takes priority. - -```shell -eotsd sign-schnorr /path/to/data/file --home /path/to/eotsd/home/ --key-name my-key-name --keyring-backend file -{ - "key_name": "my-key-name", - "pub_key_hex": "50b106208c921b5e8a1c45494306fe1fc2cf68f33b8996420867dc7667fde383", - "signed_data_hash_hex": "b123ef5f69545cd07ad505c6d3b4931aa87b6adb361fb492275bb81374d98953", - "schnorr_signature_hex": "b91fc06b30b78c0ca66a7e033184d89b61cd6ab572329b20f6052411ab83502effb5c9a1173ed69f20f6502a741eeb5105519bb3f67d37612bc2bcce411f8d72" -} -``` - -### 3.4. Verify Schnorr Signatures - -You can verify the Schnorr signature signed in the previous step through -the `eptsd veify-schnorr-sig` command. -The command takes as an argument the file path, hashes the file content using -sha256 to generate the signed data, and verifies the signature from the `--signature` -flag using the given public key from the `--eots-pk` flag. -If the signature is valid, you will see `Verification is successful!` in the output. -Otherwise, an error message will be printed out. - -```shell -eotsd verify-schnorr-sig /path/to/data/file --eots-pk 50b106208c921b5e8a1c45494306fe1fc2cf68f33b8996420867dc7667fde383 \ ---signature b91fc06b30b78c0ca66a7e033184d89b61cd6ab572329b20f6052411ab83502effb5c9a1173ed69f20f6502a741eeb5105519bb3f67d37612bc2bcce411f8d72 \ ---keyring-backend file -``` - -## 4. Starting the EOTS Daemon - -You can start the EOTS daemon using the following command: - -```bash -eotsd start --home /path/to/eotsd/home -``` - -If the `--home` flag is not specified, then the default home location will be used. - -This will start the EOTS rpc server at the address specified in `eotsd.conf` under -the `RpcListener` field, which is by default set to `127.0.0.1:12582`. You can change -this value in the configuration file or override this value and specify a custom -address using the `--rpc-listener` flag. - -```bash -eotsd start - -2024-02-08T17:59:11.467212Z info RPC server listening {"address": "127.0.0.1:12582"} -2024-02-08T17:59:11.467660Z info EOTS Manager Daemon is fully active! -``` - -All the available cli options can be viewed using the `--help` flag. These options -can also be set in the configuration file. - -**Note**: It is recommended to run the `eotsd` daemon on a separate machine or -network segment to enhance security. This helps isolate the key management -functionality and reduces the potential attack surface. You can edit the -`EOTSManagerAddress` in the configuration file of the finality provider to reference -the address of the machine where `eotsd` is running. diff --git a/docs/finality-provider-phase2.md b/docs/finality-provider-operation.md similarity index 86% rename from docs/finality-provider-phase2.md rename to docs/finality-provider-operation.md index 86f5d78..3ee4064 100644 --- a/docs/finality-provider-phase2.md +++ b/docs/finality-provider-operation.md @@ -1,77 +1,49 @@ -# Finality Provider Registration +# Finality Provider Operation -Phase-2 launch of the Babylon network is a critical transition -that introduces active participation in finality voting, -rewards distribution, and the Proof of Stake (PoS) system. -This guide provides a step-by-step process for operators to -onboard, whether setting up a new or pre-existing setup, -with a focus on Phase-2 specific requirements. +This document describes the +* setup of the finality provider toolset +* creation of your EOTS keys as well as the Babylon keyring +that will be receiving your rewards +* the registration of a finality provider on Babylon +* the operation of a finality provider and its lifecycle +* withdrawing your rewards -The following explains the migration from Phase-1 to Phase-2. + -**Phase-1 (Previous phase)** +## Preliminaries -- Only involves Bitcoin holders locking their assets on the Bitcoin chain -- No active Proof of Stake (PoS) chain operation -- Finality providers only need EOTS keys generated -- No need to run finality service -**Phase-2 (New phase)** -- Active participation in finality voting -- Running the complete finality provider toolset: - - Babylon full node - - EOTS manager daemon - - Finality provider daemon -- Earning rewards from Bitcoin delegations +### Finality Provider -There are 2 paths for setting up a finality provider: +* Finality provider and EOTS manager -> we can link to them from the README. +* -1. **Has existing EOTS Key** - - Already generated a EOTS key pair from [Phase-1](https://github.com/babylonlabs-io/networks/tree/main/bbn-test-5/finality-providers) - - - Reference the existing EOTS key in setup -If you have an existing EOTS key from Phase-1, please skip to -[Loading Existing Keys](#loading-existing-keys) -steps - ->Note: Any finality providers from Phase-1 that do not transition their existing key, cannot claim any rewards if they dont have their Finality Provider setup on Phase-2 +## Prerequisites -2. **New Setup** - - For operators starting fresh - - Need to generate the EOTS key first - - Complete full configuration process +1. Babylon Full Node: Operating a finality provider requires a connection + with a Babylon blockchain node in order to receive new blocks to vote for + and submitting votes and public randomness. It is highly recommended for finality + providers to operate their own Babylon full node instead of relying on third parties. + You can find instructions on how to set up a Babylon node + [here](https://github.com/babylonlabs-io/networks/tree/main/bbn-1/node-setup) +2. Funded Babylon keyring: You need to have a keyring to submit transactions. + Note that successful block votes get their gas refunded, while randomness submissions + come out of your pocket. + You can find more details on the required funds for operating a finality provider [here](). + If you are operating a finality provider for the testnet, you can get funds from our [faucet](). + -If you are a new operator, start with the -[Install Finality Provider Binary](#install-finality-provider-binary) section. +## Phase-1 Finality Providers -## Overview of Keys for Finality Provider and EOTS Manager + +* If you were an fp on phase-1, you don't need to create new keys. +* All your delegations are associated with your existing EOTS key, + so you need to import that instead of creating a new one. (highlight this as its dangerous) +* If you participated in both the testnet and the mainnet, + make sure that you transition the finality provider key you used on the respective network. (highlight this as its dangerous) -There are two distinct keys you'll be working with: - -- **EOTS Key**: - - Used for generating EOTS signatures, Schnorr signatures, and randomness pairs - - This serves as the unique identifier for the finality provider - - It's derived from a Bitcoin private key, likely using the secp256k1 - elliptic curve. - - Stored in the EOTS manager daemon's keyring - - This key is used in the Bitcoin-based security model of Babylon. - -- **Babylon Key**: - - Used for signing transactions on Babylon - - It's where staking rewards for the finality provider are sent. - - Associated with a Babylon account that receives rewards - - Stored in the finality provider daemon's keyring - - This account is controlled by the key you use to create and manage the -finality provider (the one you added with `fpd keys add`). - -This dual association allows the finality provider to interact with both the -Bitcoin network (for security) and the Babylon network (for rewards and -governance). - -Once a finality provider is created, neither key can be rotated or changed - -they are permanently associated with that specific finality provider instance. ## Install Finality Provider Binary @@ -141,15 +113,6 @@ the `$PATH` of your shell. Usually these commands will do the job echo 'export PATH=$HOME/go/bin:$PATH' >> ~/.profile ``` -## Run Babylon Full Node - -Before proceeding with the finality provider setup, you'll need to have a Babylon -full node running. Please follow the instructions at: - -[Babylon Node Setup Guide](https://github.com/babylonlabs-io/networks/blob/main/bbn-test-5/babylon-node/README.md) - -Once you have completed the node setup and it is fully synced, return here -to continue with the finality provider configuration. ## Setting up the EOTS Manager @@ -665,3 +628,30 @@ To withdraw your finality provider rewards: + +## Overview of Keys for Finality Provider and EOTS Manager + +There are two distinct keys you'll be working with: + +- **EOTS Key**: + - Used for generating EOTS signatures, Schnorr signatures, and randomness pairs + - This serves as the unique identifier for the finality provider + - It's derived from a Bitcoin private key, likely using the secp256k1 + elliptic curve. + - Stored in the EOTS manager daemon's keyring + - This key is used in the Bitcoin-based security model of Babylon. + +- **Babylon Key**: + - Used for signing transactions on Babylon + - It's where staking rewards for the finality provider are sent. + - Associated with a Babylon account that receives rewards + - Stored in the finality provider daemon's keyring + - This account is controlled by the key you use to create and manage the + finality provider (the one you added with `fpd keys add`). + +This dual association allows the finality provider to interact with both the +Bitcoin network (for security) and the Babylon network (for rewards and +governance). + +Once a finality provider is created, neither key can be rotated or changed - +they are permanently associated with that specific finality provider instance. diff --git a/docs/finality-provider.md b/docs/finality-provider.md deleted file mode 100644 index 1fd1ebb..0000000 --- a/docs/finality-provider.md +++ /dev/null @@ -1,272 +0,0 @@ -# Finality Provider - -## 1. Overview - -The Finality Provider Daemon is responsible for monitoring for new Babylon blocks, -committing public randomness for the blocks it intends to provide finality signatures -for, and submitting finality signatures. - -The daemon can manage and perform the following operations for multiple finality -providers: - -1. **Creation and Registration**: Creates and registers finality providers to - Babylon. - -2. **EOTS Randomness Commitment**: The daemon monitors the Babylon chain and commits - EOTS public randomness for every Babylon block each finality provider intends to - vote for. The commit intervals can be specified in the configuration. - -3. **Finality Votes Submission**: The daemon monitors the Babylon chain and produces - finality votes for each block each maintained finality provider has committed to - vote for. - -4. **Status Management**: The daemon continuously monitors voting power and overall - provider status. It manages state transitions between `ACTIVE`, `INACTIVE`, - `JAILED`, and `SLASHED` states, while enforcing slashing conditions and handling - the jailing process when violations occur. - -5. **Security and Key Management**: The system manages EOTS keys for signature - generation and Babylon keys for transaction processing and rewards distribution. - It maintains secure coordination with the EOTS daemon for all key-related - operations. - -The daemon is controlled by the `fpd` tool, which provides commands for -interacting with the running daemon. - -## 2. Configuration - -The `fpd init` command initializes a home directory for the finality provider daemon. -This directory is created in the default home location or in a location specified by -the `--home` flag. - -```bash -fpd init --home /path/to/fpd/home/ -``` - -After initialization, the home directory will have the following structure - -```bash -ls /path/to/fpd/home/ - ├── fpd.conf # Fpd-specific configuration file. - ├── logs # Fpd logs -``` - -If the `--home` flag is not specified, then the default home directory will be used. -For different operating systems, those are: - -- **MacOS** `~/Users//Library/Application Support/Fpd` -- **Linux** `~/.Fpd` -- **Windows** `C:\Users\\AppData\Local\Fpd` - -Below are some important parameters of the `fpd.conf` file. - -**Note**: -The configuration below requires pointing to the path where this keyring is -stored `KeyDirectory`. This `Key` field stores the key name of the finality -provider wallet that is going to be used for interacting with the consumer -chain and to sign the messages of your finality provider. It will be specified -along with the `KeyringBackend` field in the next -[step](#3-add-key-for-the-consumer-chain). So we can ignore the setting of the -two fields in this step. - -```bash -[Application Options] -# RPC Address of the EOTS Daemon -EOTSManagerAddress = 127.0.0.1:12582 - -# RPC Address of the Finality Provider Daemon -RpcListener = 127.0.0.1:12581 - -[babylon] -# Name of the key of the finality provider to sign transactions with -Key = - -# Chain id of the chain to connect to -# Please verify the `ChainID` from the Babylon RPC node https://rpc.testnet3.babylonchain.io/status -ChainID = bbn-test-3 - -# RPC Address of Babylon node -RPCAddr = http://127.0.0.1:26657 - -# GRPC Address of Babylon node -GRPCAddr = https://127.0.0.1:9090 - -# Directory to store keys in -KeyDirectory = /path/to/fpd/home -``` - -To see the complete list of configuration options, check the `fpd.conf` file. - -**Additional Notes:** - -If you encounter any gas-related errors while performing staking operations, consider -adjusting the `GasAdjustment` and `GasPrices` parameters. For example, you can set: - -```bash -GasAdjustment = 1.5 -GasPrices = 0.002ubbn -``` - -## 3. Add key for the consumer chain - -The finality provider daemon requires the existence of a keyring that contains an -account for the finality provider with Babylon token funds to pay and sign -transactions. This key identifies the finality provider and will be also used -to pay for fees of transactions to the consumer chain. - -Use the following command to add the key: - -```bash -fpd keys add my-finality-provider -``` - -After executing the above command, the key name will be saved in the config file -created in [step](#2-configuration). - -## 4. Starting the Finality Provider Daemon - -You can start the finality provider daemon using the following command: - -```bash -fpd start --home /path/to/fpd/home -``` - -If the `--home` flag is not specified, then the default home location will be used. - -This will start the Finality provider RPC server at the address specified -in `fpd.conf` under the `RpcListener` field, which has a default value -of `127.0.0.1:12581`. You can change this value in the configuration file or override -this value and specify a custom address using the `--rpc-listener` flag. - -This will also start all the registered finality provider instances except for -slashed ones added in [step](#5-create-and-register-a-finality-provider). To start -the daemon with a specific finality provider instance, use the -`--eots-pk` flag followed by the hex string of the BTC public key of the finality -provider (`btc_pk_hex`) obtained -in [step](#5-create-and-register-a-finality-provider). - -```bash -fpd start - -2024-02-08T18:43:00.705008Z info successfully connected to a remote EOTS manager {"address": "127.0.0.1:12582"} -2024-02-08T18:43:00.712995Z info Starting FinalityProviderApp -2024-02-08T18:43:00.716682Z info RPC server listening {"address": "127.0.0.1:12581"} -2024-02-08T18:43:00.716979Z info Finality Provider Daemon is fully active! -``` - -All the available CLI options can be viewed using the `--help` flag. These options -can also be set in the configuration file. - -## 5. Create and Register a Finality Provider - -We create a finality provider instance through the -`fpd create-finality-provider` or `fpd cfp` command. The created instance is -associated with a BTC public key which serves as its unique identifier and a Babylon -account to which staking rewards will be directed. Note that if the `--key-name` flag -is not specified, the `Key` field of config specified -in [step](#3-add-key-for-the-consumer-chain) will be used. - -```bash -fpd create-finality-provider --key-name my-finality-provider \ - --chain-id bbn-test-3 --moniker my-name -{ - "fp_addr": "bbn19khdh5vf8zv9x49f84cfuxx5t45m7klwq827mp", - "btc_pk_hex": "d0fc4db48643fbb4339dc4bbf15f272411716b0d60f18bdfeb3861544bf5ef63", - "description": { - "moniker": "my-name" - }, - "status": "CREATED" -} -``` - -We register a created finality provider in Babylon through -the `fpd register-finality-provider` or `fpd rfp` command. The output contains -the hash of the Babylon finality provider registration transaction. - -```bash -fpd register-finality-provider \ - --eots-pk d0fc4db48643fbb4339dc4bbf15f272411716b0d60f18bdfeb3861544bf5ef63 -{ - "tx_hash": "800AE5BBDADE974C5FA5BD44336C7F1A952FAB9F5F9B43F7D4850BA449319BAA" -} - -``` - -A finality provider instance will be initiated and start running right after the -finality provider is successfully registered in Babylon. - -We can view the status of all the running finality providers through -the `fpd list-finality-providers` or `fpd ls` command. The `status` field can -receive the following values: - -- `CREATED`: The finality provider is created but not registered yet -- `REGISTERED`: The finality provider is registered but has not received any active - delegations yet -- `ACTIVE`: The finality provider has active delegations and is empowered to send - finality signatures -- `INACTIVE`: The finality provider used to be ACTIVE but the voting power is reduced - to zero -- `SLASHED`: The finality provider is slashed due to malicious behavior - -```bash -fpd list-finality-providers -{ - "finality-providers": [ - ... - { - "fp_addr": "bbn19khdh5vf8zv9x49f84cfuxx5t45m7klwq827mp", - "btc_pk_hex": "d0fc4db48643fbb4339dc4bbf15f272411716b0d60f18bdfeb3861544bf5ef63", - "description": { - "moniker": "my-name" - }, - "last_vote_height": 1 - "status": "REGISTERED" - } - ] -} -``` - -After the creation of the finality provider in the local db, it is possible -to export the finality provider information through the `fpd export-finality-provider` command. -This command connects with the `fpd` daemon to retrieve the finality -provider previously created using the flag `--eots-pk` as key. - -This command also has several flag options: - -- `--eots-pk` the hex string of the BTC public key. -- `--daemon-address` the RPC server address of `fpd` daemon. -- `--signed` signs the finality provider with the chain key of the PoS -chain secured as a proof of untempered exported data. -- `--key-name` identifies the name of the key to use to sign the finality provider. -- `--home` specifies the home directory of the finality provider daemon in which -the finality provider db is stored. -- `--passphrase` specifies the password used to encrypt the key, if such a -passphrase is required. -- `--hd-path` the hd derivation path of the private key. - -```shell -$ fpd export-finality-provider --eots-pk 02face5996b2792114677604ec9dfad4fe66eeace3df92dab834754add5bdd7077 \ ---home ./export-fp/fpd --key-name finality-provider --signed -``` - -The expected result is a JSON object corresponding to the finality provider information. - -```json -{ - "description": { - "moniker": "my-fp-nickname", - "identity": "anyIdentity", - "website": "www.my-public-available-website.com", - "security_contact": "your.email@gmail.com", - "details": "other overall info" - }, - "commission": "0.050000000000000000", - "fp_addr": "bbn19khdh5vf8zv9x49f84cfuxx5t45m7klwq827mp", - "btc_pk": "02face5996b2792114677604ec9dfad4fe66eeace3df92dab834754add5bdd7077", - "pop": { - "btc_sig": "sHLpEHVTyTp9K55oeHxnPlkV4unc/r1obqzKn5S1gq95oXA3AgL1jyCzd/mGb23RfKbEyABjYUdcIBtZ02l5jg==" - }, - "master_pub_rand": "xpub661MyMwAqRbcFLhUq9uPM7GncSytVZvoNg4w7LLx1Y74GeeAZerkpV1amvGBTcw4ECmrwFsTNMNf1LFBKkA2pmd8aJ5Jmp8uKD5xgVSezBq", - "fp_sig_hex": "8ded8158bf65d492c5c6d1ff61c04a2176da9c55ea92dcce5638d11a177b999732a094db186964ab1b73c6a69aaa664672a36620dedb9da41c05e88ad981edda" -} -``` From fd2df484faa4cb7da8f345663725a02b2768d31f Mon Sep 17 00:00:00 2001 From: Vitalis Salis Date: Thu, 21 Nov 2024 15:59:28 +0200 Subject: [PATCH 23/53] more mess --- docs/finality-provider-operation.md | 58 +++++++++++++++++------------ 1 file changed, 34 insertions(+), 24 deletions(-) diff --git a/docs/finality-provider-operation.md b/docs/finality-provider-operation.md index 3ee4064..05358af 100644 --- a/docs/finality-provider-operation.md +++ b/docs/finality-provider-operation.md @@ -10,30 +10,26 @@ that will be receiving your rewards -## Preliminaries - - - -### Finality Provider - -* Finality provider and EOTS manager -> we can link to them from the README. -* - - -## Prerequisites - -1. Babylon Full Node: Operating a finality provider requires a connection - with a Babylon blockchain node in order to receive new blocks to vote for - and submitting votes and public randomness. It is highly recommended for finality - providers to operate their own Babylon full node instead of relying on third parties. - You can find instructions on how to set up a Babylon node - [here](https://github.com/babylonlabs-io/networks/tree/main/bbn-1/node-setup) -2. Funded Babylon keyring: You need to have a keyring to submit transactions. - Note that successful block votes get their gas refunded, while randomness submissions - come out of your pocket. - You can find more details on the required funds for operating a finality provider [here](). - If you are operating a finality provider for the testnet, you can get funds from our [faucet](). - + ## Phase-1 Finality Providers @@ -308,6 +304,13 @@ signing. >Note: Please verify the `chain-id` and other network parameters from the official Babylon Networks repository at [https://github.com/babylonlabs-io/networks/tree/main/bbn-test-5/finality-providers](https://github.com/babylonlabs-io/networks/tree/main/bbn-test-5/finality-providers) + +Funded Babylon keyring: You need to have a keyring to submit transactions. + Note that successful block votes get their gas refunded, while randomness submissions + come out of your pocket. + You can find more details on the required funds for operating a finality provider [here](). + If you are operating a finality provider for the testnet, you can get funds from our [faucet](). + >The configuration below requires to point to the path where this keyring is stored `KeyDirectory`. This `Key` field stores the key name used for @@ -332,6 +335,13 @@ GRPCAddr = https://127.0.0.1:9090 KeyDirectory = # The `--home`path to the directory where the keyring is stored ``` +RPC Address: Operating a finality provider requires a connection +with a Babylon blockchain node in order to receive new blocks to vote for +and submitting votes and public randomness. It is highly recommended for finality +providers to operate their own Babylon full node instead of relying on third parties. +You can find instructions on how to set up a Babylon node +[here](https://github.com/babylonlabs-io/networks/tree/main/bbn-1/node-setup) + ### Step 3: Verify the Key Import After importing, verify that your EOTS key was successfully loaded: From 6a14d2377b47846276c3993a1c5494329cef53f1 Mon Sep 17 00:00:00 2001 From: Sam Ricotta Date: Thu, 21 Nov 2024 18:16:45 +0200 Subject: [PATCH 24/53] wip --- README.md | 34 +++++- docs/finality-provider-operation.md | 154 +++++++++++++++------------- 2 files changed, 110 insertions(+), 78 deletions(-) diff --git a/README.md b/README.md index 114fadc..1234ecc 100644 --- a/README.md +++ b/README.md @@ -34,13 +34,11 @@ all EOTS key operations. ## Become a Finality Provider -If you are interested in becoming a finality provider -you can find more details [here](./docs/finality-provider-operation.md) +For instructions on becoming a finality provider, see our [Finality Provider Guide](./docs/finality-provider-phase2.md). ## Technical Documentation -You can find more about the internals of the finality provider -toolset operation in the following docs: +For detailed technical information about the finality provider's internal operations, see: * [Core Heuristics](./docs/fp-core.md) * [Public Randomness Commits](./docs/commit-pub-rand.md) @@ -111,3 +109,31 @@ providers: The daemon is controlled by the `fpd` tool, which provides commands for interacting with the running daemon. + + +## Overview of Keys for Finality Provider and EOTS Manager + +There are two distinct keys you'll be working with: + +- **EOTS Key**: + - Used for generating EOTS signatures, Schnorr signatures, and randomness pairs + - This serves as the unique identifier for the finality provider + - It's derived from a Bitcoin private key, likely using the secp256k1 + elliptic curve. + - Stored in the EOTS manager daemon's keyring + - This key is used in the Bitcoin-based security model of Babylon. + +- **Babylon Key**: + - Used for signing transactions on Babylon + - It's where staking rewards for the finality provider are sent. + - Associated with a Babylon account that receives rewards + - Stored in the finality provider daemon's keyring + - This account is controlled by the key you use to create and manage the + finality provider (the one you added with `fpd keys add`). + +This dual association allows the finality provider to interact with both the +Bitcoin network (for security) and the Babylon network (for rewards and +governance). + +Once a finality provider is created, neither key can be rotated or changed - +they are permanently associated with that specific finality provider instance. diff --git a/docs/finality-provider-operation.md b/docs/finality-provider-operation.md index 05358af..d7828eb 100644 --- a/docs/finality-provider-operation.md +++ b/docs/finality-provider-operation.md @@ -1,14 +1,29 @@ # Finality Provider Operation -This document describes the -* setup of the finality provider toolset -* creation of your EOTS keys as well as the Babylon keyring -that will be receiving your rewards -* the registration of a finality provider on Babylon -* the operation of a finality provider and its lifecycle -* withdrawing your rewards - - +This document covers the operation and lifecycle of a finality provider, including: +* Installation and configuration +* Key management and security +* Provider registration process +* Operational monitoring and maintenance +* Rewards management + +## Table of Contents + +1. [Phase-1 Finality Providers](#phase-1-finality-providers) +2. [Install Finality Provider Binary](#install-finality-provider-binary) +3. [Setting up the EOTS Manager](#setting-up-the-eots-manager) +4. [Loading Existing Keys](#loading-existing-keys) +5. [Starting the EOTS Daemon](#starting-the-eots-daemon) +6. [Setting up the Finality Provider](#setting-up-the-finality-provider) +7. [Starting the Finality Provider Daemon](#starting-the-finality-provider-daemon) +8. [Create Finality Provider](#create-finality-provider) +9. [Register Finality Provider](#register-finality-provider) +10. [Slashing Conditions](#slashing-conditions) +11. [Jailing and Unjailing](#jailing-and-unjailing) +12. [Public Randomness Submission](#public-randomness-submission) +13. [Reading the logs](#reading-the-logs) +14. [Withdrawing Rewards](#withdrawing-rewards) +15. [Overview of Keys for Finality Provider and EOTS Manager](#overview-of-keys-for-finality-provider-and-eots-manager) -* If you were an fp on phase-1, you don't need to create new keys. +* `Phase-1` operators should use their existing EOTS keys for `Phase-2` participation. +* All your delegations are associated with your existing EOTS key - you must import your existing key instead of creating a new one, as **creating new keys will result in loss of delegations**. +* For those who participated in both testnet and mainnet, ensure you **use the correct key for each network to avoid delegation loss and potential slashing**. +* Locate your `Phase-1` EOTS key backup and proceed to the [Loading Existing Keys](#loading-existing-keys) section for import instructions. + + + + + +## Security Requirements + +> ⚠️ **Critical**: Implement these measures before starting daemons or handling keys + +* EOTS Manager: Restrict access to RPC (127.0.0.1:12582) +* FP Daemon: Secure RPC listener (127.0.0.1:12581) +* Keys: + - EOTS: Secure offline backup required + - Babylon: Use `os` or `file` backend for production +* Monitor: + - Double-signing attempts + - Status changes (Active/Inactive/Jailed) + - Public randomness commits + +> ⚠️ **Warning**: Security breaches can result in slashing and permanent loss of provider status ## Install Finality Provider Binary @@ -78,28 +115,17 @@ This command will: - `fpd`: Finality provider daemon - Make commands globally accessible from your terminal -### Step 3: Verify Installation - -Run `eotsd --help` to check the available actions: +### Step 3: Verify Installation + +Run `fpd version` to verify the installation: ```shell -eotsd --help -``` - -Sample output: - +fpd version +``` +The output should be: ```shell -NAME: - eotsd - Extractable One Time Signature Daemon (eotsd). - -USAGE: - eotsd [global options] command [command options] [arguments...] - -COMMANDS: - start Start the Extractable One Time Signature Daemon. - init Initialize the eotsd home directory. - sign-schnorr Signs a Schnorr signature over arbitrary data with -... +version: +build: ``` If your shell cannot find the installed binaries, make sure `$GOPATH/bin` is in @@ -109,7 +135,6 @@ the `$PATH` of your shell. Usually these commands will do the job echo 'export PATH=$HOME/go/bin:$PATH' >> ~/.profile ``` - ## Setting up the EOTS Manager >Note: If you have already set up an EOTS Manager, you can skip this section. @@ -297,13 +322,20 @@ The output should look similar to the below: } ``` ->Note: This command will automatically update the `Key` field in +This command will automatically update the `Key` field in the config file to use this key name. This key will be used for all interactions with the Babylon chain, including finality provider registration and transaction signing. ->Note: Please verify the `chain-id` and other network parameters from the official +Please verify the `chain-id` and other network parameters from the official Babylon Networks repository at [https://github.com/babylonlabs-io/networks/tree/main/bbn-test-5/finality-providers](https://github.com/babylonlabs-io/networks/tree/main/bbn-test-5/finality-providers) + +> **Important**: Funding Your Babylon Account +> * You need to have funds in your Babylon account to submit transactions +> * Block vote transactions get their gas refunded +> * Public randomness submissions require you to pay gas fees +> * For testnet operations, you can get funds from our [faucet]() +> * For mainnet operations, see the required funds documentation [here]() Funded Babylon keyring: You need to have a keyring to submit transactions. Note that successful block votes get their gas refunded, while randomness submissions @@ -312,15 +344,10 @@ Funded Babylon keyring: You need to have a keyring to submit transactions. If you are operating a finality provider for the testnet, you can get funds from our [faucet](). ->The configuration below requires to point to the path where this keyring is - stored `KeyDirectory`. This `Key` field stores the key name used for - interacting with the babylon chain and will be specified along with - the `KeyringBackend`field in the next step. So we can ignore the setting of the - two fields in this step. -Once the node is initialized with the above command. It should generate a -`fpd.config` Edit the `config.toml` to set the necessary parameters with the -below +### Step 3: Configure Your Finality Provider + +Edit the `config.toml` file in your finality provider home directory with the following parameters: ```shell [Application Options] @@ -335,12 +362,17 @@ GRPCAddr = https://127.0.0.1:9090 KeyDirectory = # The `--home`path to the directory where the keyring is stored ``` -RPC Address: Operating a finality provider requires a connection -with a Babylon blockchain node in order to receive new blocks to vote for -and submitting votes and public randomness. It is highly recommended for finality -providers to operate their own Babylon full node instead of relying on third parties. -You can find instructions on how to set up a Babylon node -[here](https://github.com/babylonlabs-io/networks/tree/main/bbn-1/node-setup) +> **Important**: Operating a finality provider requires a connection to a Babylon blockchain node. It is **highly recommended** to operate your own Babylon full node instead of relying on third parties. You can find instructions on setting up a Babylon node [here](https://github.com/babylonlabs-io/networks/tree/main/bbn-1/node-setup). + +Configuration parameters explained: +* `EOTSManagerAddress`: Address where your EOTS daemon is running +* `RpcListener`: Address for the finality provider RPC server +* `Key`: Your Babylon key name from Step 2 +* `ChainID`: The Babylon network chain ID +* `RPCAddr`: Your Babylon node's RPC endpoint +* `GRPCAddr`: Your Babylon node's GRPC endpoint +* `KeyDirectory`: Path to your keyring directory (same as --home path) + ### Step 3: Verify the Key Import After importing, verify that your EOTS key was successfully loaded: @@ -639,29 +671,3 @@ To withdraw your finality provider rewards: -## Overview of Keys for Finality Provider and EOTS Manager - -There are two distinct keys you'll be working with: - -- **EOTS Key**: - - Used for generating EOTS signatures, Schnorr signatures, and randomness pairs - - This serves as the unique identifier for the finality provider - - It's derived from a Bitcoin private key, likely using the secp256k1 - elliptic curve. - - Stored in the EOTS manager daemon's keyring - - This key is used in the Bitcoin-based security model of Babylon. - -- **Babylon Key**: - - Used for signing transactions on Babylon - - It's where staking rewards for the finality provider are sent. - - Associated with a Babylon account that receives rewards - - Stored in the finality provider daemon's keyring - - This account is controlled by the key you use to create and manage the - finality provider (the one you added with `fpd keys add`). - -This dual association allows the finality provider to interact with both the -Bitcoin network (for security) and the Babylon network (for rewards and -governance). - -Once a finality provider is created, neither key can be rotated or changed - -they are permanently associated with that specific finality provider instance. From 22be88e45b8f9f85297807c407a7b9d4b5b44c5a Mon Sep 17 00:00:00 2001 From: Sam Ricotta Date: Thu, 21 Nov 2024 18:25:07 +0200 Subject: [PATCH 25/53] Update first paragraph --- docs/finality-provider-operation.md | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/docs/finality-provider-operation.md b/docs/finality-provider-operation.md index d7828eb..cbccb0d 100644 --- a/docs/finality-provider-operation.md +++ b/docs/finality-provider-operation.md @@ -1,11 +1,14 @@ # Finality Provider Operation -This document covers the operation and lifecycle of a finality provider, including: -* Installation and configuration -* Key management and security -* Provider registration process -* Operational monitoring and maintenance -* Rewards management +This document guides operators through the complete lifecycle of running a finality provider, including: + +* Installing and configuring the finality provider components (EOTS Manager and FP daemon) +* Managing keys (EOTS key for signatures and Babylon key for rewards) +* Registering your finality provider on the Babylon network +* Operating and maintaining your finality provider +* Collecting rewards + +This is an operational guide intended for DevOps teams running finality providers. For conceptual understanding, see our [Technical Documentation](./docs/fp-core.md). ## Table of Contents @@ -23,7 +26,6 @@ This document covers the operation and lifecycle of a finality provider, includi 12. [Public Randomness Submission](#public-randomness-submission) 13. [Reading the logs](#reading-the-logs) 14. [Withdrawing Rewards](#withdrawing-rewards) -15. [Overview of Keys for Finality Provider and EOTS Manager](#overview-of-keys-for-finality-provider-and-eots-manager) - ### Step 3: Configure Your Finality Provider @@ -364,7 +357,7 @@ GRPCAddr = https://127.0.0.1:9090 KeyDirectory = # The `--home`path to the directory where the keyring is stored ``` -> **Important**: Operating a finality provider requires a connection to a Babylon blockchain node. It is **highly recommended** to operate your own Babylon full node instead of relying on third parties. You can find instructions on setting up a Babylon node [here](https://github.com/babylonlabs-io/networks/tree/main/bbn-1/node-setup). +> ⚠️ **Important**: Operating a finality provider requires a connection to a Babylon blockchain node. It is **highly recommended** to operate your own Babylon full node instead of relying on third parties. You can find instructions on setting up a Babylon node [here](https://github.com/babylonlabs-io/networks/tree/main/bbn-1/node-setup). Configuration parameters explained: * `EOTSManagerAddress`: Address where your EOTS daemon is running @@ -609,8 +602,10 @@ So while slashing is permanent, jailing is a temporary state that can be recover from through the unjailing process, as long as the finality provider wasn't slashed. ## Public Randomness Submission - +For detailed information about public randomness commits, see: +* [Technical Overview](./docs/commit-pub-rand.md) +* [Core Implementation Details](./docs/fp-core.md#committing-public-randomness) ## Reading the logs The logs are stored based on your daemon home directories: From 0c90c2ee8ffb67acc69e586a0d9cb8fe8445cc90 Mon Sep 17 00:00:00 2001 From: Sam Ricotta Date: Thu, 21 Nov 2024 18:33:05 +0200 Subject: [PATCH 27/53] formatting --- docs/finality-provider-operation.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/finality-provider-operation.md b/docs/finality-provider-operation.md index 879241e..834dfa2 100644 --- a/docs/finality-provider-operation.md +++ b/docs/finality-provider-operation.md @@ -611,10 +611,10 @@ For detailed information about public randomness commits, see: The logs are stored based on your daemon home directories: - EOTS Daemon logs -/logs/eotsd.log +`/logs/eotsd.log` - Finality Provider Daemon logs -/logs/fpd.log +`/logs/fpd.log` You also can access the logs via flags when starting the daemon: From c83cb4903c36fef2208ed7f8ac8f580bbe3ed0be Mon Sep 17 00:00:00 2001 From: Sam Ricotta Date: Fri, 22 Nov 2024 11:23:17 +0200 Subject: [PATCH 28/53] small cosmetic changes --- docs/finality-provider-operation.md | 81 ++++++++++++++++++++--------- 1 file changed, 57 insertions(+), 24 deletions(-) diff --git a/docs/finality-provider-operation.md b/docs/finality-provider-operation.md index 834dfa2..82604e7 100644 --- a/docs/finality-provider-operation.md +++ b/docs/finality-provider-operation.md @@ -8,7 +8,10 @@ This document guides operators through the complete lifecycle of running a final * Operating and maintaining your finality provider * Collecting rewards -This is an operational guide intended for DevOps teams running finality providers. For conceptual understanding, see our [Technical Documentation](./docs/fp-core.md). +This is an operational guide intended for DevOps teams running finality providers. +For conceptual understanding, see our [Technical Documentation](./docs/fp-core.md). +Please review the [high-level](./README.md) documentation before proceeding to +gain an overall understanding of the finality provider. ## Table of Contents @@ -74,7 +77,7 @@ These people need to know the following: - Babylon: Use `os` or `file` backend for production * Monitor: - Double-signing attempts - - Status changes (Active/Inactive/Jailed) + - Status changes (`Active`/`Inactive`/`Jailed`) - Public randomness commits > ⚠️ **Warning**: Security breaches can result in slashing and permanent loss of provider status @@ -105,7 +108,7 @@ git checkout ### Step 2: Build and Install Finality Provider Binaries -Run: +Run to build the binaries and install them to your `$GOPATH/bin` directory: ```shell make install ``` @@ -124,14 +127,14 @@ Run `fpd version` to verify the installation: ```shell fpd version ``` -The output should be: -```shell -version: -build: +The expected output should be: +```shell +version: v0.11.0 +commit: 7d37c88e9a33c0b6a86614f743e9426ce6e31d4a ``` If your shell cannot find the installed binaries, make sure `$GOPATH/bin` is in -the `$PATH` of your shell. Usually these commands will do the job +the `$PATH` of your shell. Use the following command to add it to your profile. ```shell echo 'export PATH=$HOME/go/bin:$PATH' >> ~/.profile @@ -139,12 +142,13 @@ echo 'export PATH=$HOME/go/bin:$PATH' >> ~/.profile ## Setting up the EOTS Manager ->Note: If you have already set up an EOTS Manager, you can skip this section. +>If you have already set up an EOTS Manager, you can skip this section. The following steps are only for users who have not yet set up an EOTS Manager. Phase-1 users who already had an EOTS Manager set up can skip to the -[Loading Existing Keys](#loading-existing-keys) +[Loading Existing Keys](#loading-existing-keys) section at the end of this guide for specific instructions -on re-using their Phase-1 EOTS keys. +on re-using their Phase-1 EOTS keys unless you would like to familiarlize yourself +with the backup and recovery process. After the full node has been setup, the operator can set up and run the Extractable One Time Signature (EOTS) manager daemon. @@ -155,15 +159,17 @@ Manager see [here](#) ### Step 1: Initialize the EOTS Manager -Use the `eotsd init` command to initialize a home directory for the EOTS Manager. -You can set or change your home directory using the `--home` tag. For example, use -`--home ./eotsHome` to specify a custom directory. The application default home directory is -`/Users//Library/Application Support/Eotsd`. +Initialize a home directory for the EOTS Manager with the following command: -```shell -eotsd init --home +```shell +eotsd init --home ``` +Parameters: +* `--home`: Directory for EOTS Manager configuration and data + - Default: `/Users//Library/Application Support/Eotsd` + - Example: `--home ./eotsHome` + ### Step 2: Create an EOTS Key Once the EOTS Manager is initialized, you need to create an EOTS key: @@ -196,15 +202,15 @@ of your finality provider operations. ## Loading Existing Keys ->Note: If you participated in Phase-1, follow these steps to load your existing EOTS +If you participated in Phase-1, follow these steps to load your existing EOTS key and configure it for Phase-2. ->This section is only for Finality Providers who participated in Phase-1 and already +This section is only for Finality Providers who participated in Phase-1 and already had an EOTS key. If you are a new user, you can skip this section unless you would like to familiarlize yourself with the backup and recovery process. ### Step 1: Verify Your EOTS Key Backup ->Note: Before proceeding, ensure you have access to your original EOTS key from Phase-1. +>⚠️ **Important**: Before proceeding, ensure you have access to your original EOTS key from Phase-1. This is the same key that was registered in the [Phase-1 registration](https://github.com/babylonlabs-io/networks/tree/main/bbn-test-5/finality-providers). @@ -376,10 +382,14 @@ After importing, verify that your EOTS key was successfully loaded: eotsd keys list --keyring-backend test --home ``` +* ``: Name of the EOTS key to verify +* `--keyring-backend`: Type of keyring backend to use (default: test) +* `--home`: Directory containing EOTS Manager configuration and data + You should see your EOTS key listed with the correct details, confirming that it has been imported correctly. ->Note: Make sure you're using the same key name and EOTS public key that were +>⚠️ **Important**: Make sure you're using the same key name and EOTS public key that were registered in Phase-1. ## Starting the Finality Provider Daemon @@ -512,7 +522,7 @@ fpd register-finality-provider \ ``` - ``: Your BTC public key from create-finality-provider -(e.g., "cf0f03b9ee2d4a0f27240e2d8b8c8ef609e24358b2eb3cfd89ae4e4f472e1a41") +(e.g., `cf0f03b9ee2d4a0f27240e2d8b8c8ef609e24358b2eb3cfd89ae4e4f472e1a41`) - `--daemon-address`: RPC address of your finality provider daemon (default: "127.0.0.1:12581") - `--passphrase`: Passphrase for your key - `--home`: Path to your finality provider daemon home directory (e.g., "~/.fpd") @@ -596,7 +606,30 @@ When jailed, the following happens to a finality provider: To unjail a finality provider, you must complete the following steps: - Fix the underlying issue that caused jailing - Wait for the jailing period to pass (if it was due to downtime) -- Then send the unjail transaction to the Babylon chain. +- Then send the unjail transaction to the Babylon chain (not the finality provider daemon). + +You can use the following command to send the unjail transaction: +```shell +babylond tx slashing unjail \ +--from= \ +--chain-id="euphrates-0.5.0" \ +--gas="auto" \ +--gas-adjustment=1.5 \ +--gas-prices=0.025ubbn \ +--keyring-backend=test \ +--home=./nodeDir +``` + +Parameters: +* `--from`: Your Babylon key name +* `--chain-id`: Current Babylon network chain ID +* `--gas`: Gas limit for transaction (auto recommended) +* `--gas-adjustment`: Multiplier for auto gas calculation +* `--gas-prices`: Gas price in ubbn +* `--keyring-backend`: Keyring backend type +* `--home`: Babylon node home directory + +> ⚠️ **Important**: Before unjailing, ensure you've fixed the underlying issue that caused jailing So while slashing is permanent, jailing is a temporary state that can be recovered from through the unjailing process, as long as the finality provider wasn't slashed. @@ -605,7 +638,7 @@ from through the unjailing process, as long as the finality provider wasn't slas For detailed information about public randomness commits, see: * [Technical Overview](./docs/commit-pub-rand.md) -* [Core Implementation Details](./docs/fp-core.md#committing-public-randomness) +* [Core Implementation Details](./fp-core.md#committing-public-randomness) ## Reading the logs The logs are stored based on your daemon home directories: From 5748743f226dd52e2fec434d1e307e8200228e89 Mon Sep 17 00:00:00 2001 From: Sam Ricotta Date: Fri, 22 Nov 2024 12:50:17 +0200 Subject: [PATCH 29/53] Update finality-provider-operation.md --- docs/finality-provider-operation.md | 36 +++++++++++++++++++++++------ 1 file changed, 29 insertions(+), 7 deletions(-) diff --git a/docs/finality-provider-operation.md b/docs/finality-provider-operation.md index 82604e7..1ce4542 100644 --- a/docs/finality-provider-operation.md +++ b/docs/finality-provider-operation.md @@ -54,9 +54,13 @@ These people need to know the following: ## Phase-1 Finality Providers * `Phase-1` operators should use their existing EOTS keys for `Phase-2` participation. -* All your delegations are associated with your existing EOTS key - you must import your existing key instead of creating a new one, as **creating new keys will result in loss of delegations**. -* For those who participated in both testnet and mainnet, ensure you **use the correct key for each network to avoid delegation loss and potential slashing**. -* Locate your `Phase-1` EOTS key backup and proceed to the [Loading Existing Keys](#loading-existing-keys) section for import instructions. +* All your delegations are associated with your existing EOTS key - you must import +your existing key instead of creating a new one, as +**creating new keys will result in loss of delegations**. +* For those who participated in both testnet and mainnet, ensure you +**use the correct key for each network to avoid delegation loss and potential slashing**. +* Locate your `Phase-1` EOTS key backup and proceed to the [Loading Existing Keys](#loading-existing-keys) +section for import instructions. - ## Security Requirements > ⚠️ **Critical**: Implement these measures before starting daemons or handling keys @@ -80,8 +83,24 @@ These people need to know the following: - Status changes (`Active`/`Inactive`/`Jailed`) - Public randomness commits -> ⚠️ **Warning**: Security breaches can result in slashing and permanent loss of provider status +> ⚠️ **Important Note on Keyring Security**: +The finality provider daemon uses the `--keyring-backend test` which stores keys unencrypted on disk. +While this is generally not secure, it's necessary for the finality provider service because: + +* The daemon needs to automatically sign and send transactions frequently +* If transactions stop for too long, the provider gets jailed +* Using encrypted keystores would require manual password entry after every restart +* Service availability is critical to avoid jailing +For other Babylon services that don't require automatic transaction signing, we recommend: +* Use `os` backend (most secure, uses system keyring) +* Or use `file` backend (encrypted storage) +* Never use `test` backend outside of automated services + +We are actively working on implementing more secure keyring solutions that maintain both security +and high availability. + +> ⚠️ **Warning**: Security breaches can result in slashing and permanent loss of provider status ## Install Finality Provider Binary @@ -363,7 +382,9 @@ GRPCAddr = https://127.0.0.1:9090 KeyDirectory = # The `--home`path to the directory where the keyring is stored ``` -> ⚠️ **Important**: Operating a finality provider requires a connection to a Babylon blockchain node. It is **highly recommended** to operate your own Babylon full node instead of relying on third parties. You can find instructions on setting up a Babylon node [here](https://github.com/babylonlabs-io/networks/tree/main/bbn-1/node-setup). +> ⚠️ **Important**: Operating a finality provider requires a connection to a Babylon blockchain node. +It is **highly recommended** to operate your own Babylon full node instead of relying on third parties. +You can find instructions on setting up a Babylon node [here](https://github.com/babylonlabs-io/networks/tree/main/bbn-1/node-setup). Configuration parameters explained: * `EOTSManagerAddress`: Address where your EOTS daemon is running @@ -446,7 +467,8 @@ instance locally. fpd create-finality-provider \ --daemon-address 127.0.0.1:12581 \ --chain-id bbn-test-5 \ ---eots-pk \ //this is the EOTS public key of the finality provider which was generated in `eotsd keys add` +--eots-pk \ //this is the EOTS public key of the finality provider which was generated in +`eotsd keys add` --commission 0.05 \ --key-name finality-provider \ --moniker "MyFinalityProvider" \ From eea399004835f00cfb3049f4f1f3a29baae154ab Mon Sep 17 00:00:00 2001 From: Sam Ricotta Date: Fri, 22 Nov 2024 12:52:57 +0200 Subject: [PATCH 30/53] formatting --- docs/finality-provider-operation.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/finality-provider-operation.md b/docs/finality-provider-operation.md index 1ce4542..bf1d856 100644 --- a/docs/finality-provider-operation.md +++ b/docs/finality-provider-operation.md @@ -73,8 +73,8 @@ section for import instructions. > ⚠️ **Critical**: Implement these measures before starting daemons or handling keys -* EOTS Manager: Restrict access to RPC (127.0.0.1:12582) -* FP Daemon: Secure RPC listener (127.0.0.1:12581) +* EOTS Manager: Restrict access to RPC (`127.0.0.1:12582`) +* FP Daemon: Secure RPC listener (`127.0.0.1:12581`) * Keys: - EOTS: Secure offline backup required - Babylon: Use `os` or `file` backend for production From d898ab2eb75d8a190544df2d77477630789f7c3a Mon Sep 17 00:00:00 2001 From: Sam Ricotta Date: Fri, 22 Nov 2024 13:14:06 +0200 Subject: [PATCH 31/53] Update finality-provider-operation.md --- docs/finality-provider-operation.md | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/docs/finality-provider-operation.md b/docs/finality-provider-operation.md index bf1d856..84d4e19 100644 --- a/docs/finality-provider-operation.md +++ b/docs/finality-provider-operation.md @@ -8,7 +8,7 @@ This document guides operators through the complete lifecycle of running a final * Operating and maintaining your finality provider * Collecting rewards -This is an operational guide intended for DevOps teams running finality providers. +This is an operational guide intended for DevOps teams running finality providers. For conceptual understanding, see our [Technical Documentation](./docs/fp-core.md). Please review the [high-level](./README.md) documentation before proceeding to gain an overall understanding of the finality provider. @@ -148,7 +148,8 @@ fpd version ``` The expected output should be: ```shell -version: v0.11.0 +# example output +version: v0.11.0 commit: 7d37c88e9a33c0b6a86614f743e9426ce6e31d4a ``` From 8a9bf29a5ce2eddad035bde867630d168f61daa3 Mon Sep 17 00:00:00 2001 From: Vitalis Salis Date: Fri, 22 Nov 2024 15:14:13 +0200 Subject: [PATCH 32/53] more mess --- README.md | 8 +- docs/finality-provider-operation.md | 396 ++++++++++++++++------------ 2 files changed, 229 insertions(+), 175 deletions(-) diff --git a/README.md b/README.md index 1234ecc..2885d7d 100644 --- a/README.md +++ b/README.md @@ -17,12 +17,11 @@ See the [Setup Node Guide](https://docs.babylonchain.io/docs/user-guides/btc-sta A secure key management daemon that handles EOTS key operations, generates extractable one-time signatures, and produces public randomness. For enhanced security, this component should run on a separate machine or -network segment. Full details are available in the [EOTS Manager Guide](docs/eots.md). +network segment. 3. **Finality Provider Daemon**: The core daemon that polls Babylon blocks, commits public randomness, and submits finality signatures. It manages provider status transitions and handles -rewards distribution. See the [Finality Provider Guide](docs/finality-provider.md) -for complete documentation. +rewards distribution. **Component Interactions**: The Finality Provider daemon communicates with the Babylon Node to monitor blocks @@ -34,7 +33,8 @@ all EOTS key operations. ## Become a Finality Provider -For instructions on becoming a finality provider, see our [Finality Provider Guide](./docs/finality-provider-phase2.md). +For instructions on creating and operating a finality provider, +see our [Finality Provider Guide](./docs/finality-provider-operation.md). ## Technical Documentation diff --git a/docs/finality-provider-operation.md b/docs/finality-provider-operation.md index 84d4e19..d49c548 100644 --- a/docs/finality-provider-operation.md +++ b/docs/finality-provider-operation.md @@ -1,34 +1,40 @@ # Finality Provider Operation -This document guides operators through the complete lifecycle of running a finality provider, including: +This document guides operators through the complete +lifecycle of running a finality provider, including: -* Installing and configuring the finality provider components (EOTS Manager and FP daemon) +* Installing and configuring the finality provider + toolset (EOTS Manager and FP daemon) * Managing keys (EOTS key for signatures and Babylon key for rewards) * Registering your finality provider on the Babylon network * Operating and maintaining your finality provider * Collecting rewards -This is an operational guide intended for DevOps teams running finality providers. +This is an operational guide intended for technical finality provider administrators. For conceptual understanding, see our [Technical Documentation](./docs/fp-core.md). -Please review the [high-level](./README.md) documentation before proceeding to +Please review the [high-level explainer](./README.md) before proceeding to gain an overall understanding of the finality provider. ## Table of Contents -1. [Phase-1 Finality Providers](#phase-1-finality-providers) -2. [Install Finality Provider Binary](#install-finality-provider-binary) +1. [A note about Phase-1 Finality Providers](#phase-1-finality-providers) +2. [Install Finality Provider Toolset](#install-finality-provider-binary) 3. [Setting up the EOTS Manager](#setting-up-the-eots-manager) -4. [Loading Existing Keys](#loading-existing-keys) -5. [Starting the EOTS Daemon](#starting-the-eots-daemon) -6. [Setting up the Finality Provider](#setting-up-the-finality-provider) -7. [Starting the Finality Provider Daemon](#starting-the-finality-provider-daemon) -8. [Create Finality Provider](#create-finality-provider) -9. [Register Finality Provider](#register-finality-provider) -10. [Slashing Conditions](#slashing-conditions) -11. [Jailing and Unjailing](#jailing-and-unjailing) -12. [Public Randomness Submission](#public-randomness-submission) -13. [Reading the logs](#reading-the-logs) -14. [Withdrawing Rewards](#withdrawing-rewards) + 1. [Loading Existing Keys](#loading-existing-keys) + 2. [Starting the EOTS Daemon](#starting-the-eots-daemon) +4. [Setting up the Finality Provider](#setting-up-the-finality-provider) + 1. [Starting the Finality Provider Daemon](#starting-the-finality-provider-daemon) +5. [Finality Provider Operation]() + 1. [Create Finality Provider](#create-finality-provider) + 2. [Register Finality Provider](#register-finality-provider) + 3. [Public Randomness Submission](#public-randomness-submission) + 4. [Submission of votes]() + 5. [Keyring maintenance and gas requirements]() + 6. [Reading the logs](#reading-the-logs) + 7. [Withdrawing Rewards](#withdrawing-rewards) + 8. [Jailing and Unjailing](#jailing-and-unjailing) + 9. [Monitoring]() +6. [Security and Slashing]() -## Phase-1 Finality Providers +## 1. A note about Phase-1 Finality Providers + + + +Thank you for being a participant in the first phase of the Babylon launch. +This guide involves instructions for setting up the full finality provider +toolset that you will be required to operate for your participation in the +second phase of the Babylon launch. + +* use the same keys -- ur delegations associated with only the key +* migrate mainnet to mainnet and testnet to testnet +* how to proceed with the guide. + +> ⚠️ **Critical**: Ensure that you use + +Finality providers that participated in the first phase of the Babylon mainnet, +should use the same EOTS keys for the second phase instead of creating new ones, +as all their BTC stake delegations are associated with the keys they used on phase-1. * `Phase-1` operators should use their existing EOTS keys for `Phase-2` participation. * All your delegations are associated with your existing EOTS key - you must import @@ -62,47 +85,14 @@ your existing key instead of creating a new one, as * Locate your `Phase-1` EOTS key backup and proceed to the [Loading Existing Keys](#loading-existing-keys) section for import instructions. - -## Security Requirements - -> ⚠️ **Critical**: Implement these measures before starting daemons or handling keys - -* EOTS Manager: Restrict access to RPC (`127.0.0.1:12582`) -* FP Daemon: Secure RPC listener (`127.0.0.1:12581`) -* Keys: - - EOTS: Secure offline backup required - - Babylon: Use `os` or `file` backend for production -* Monitor: - - Double-signing attempts - - Status changes (`Active`/`Inactive`/`Jailed`) - - Public randomness commits - -> ⚠️ **Important Note on Keyring Security**: -The finality provider daemon uses the `--keyring-backend test` which stores keys unencrypted on disk. -While this is generally not secure, it's necessary for the finality provider service because: - -* The daemon needs to automatically sign and send transactions frequently -* If transactions stop for too long, the provider gets jailed -* Using encrypted keystores would require manual password entry after every restart -* Service availability is critical to avoid jailing - -For other Babylon services that don't require automatic transaction signing, we recommend: -* Use `os` backend (most secure, uses system keyring) -* Or use `file` backend (encrypted storage) -* Never use `test` backend outside of automated services - -We are actively working on implementing more secure keyring solutions that maintain both security -and high availability. - -> ⚠️ **Warning**: Security breaches can result in slashing and permanent loss of provider status -## Install Finality Provider Binary +## 2. Install Finality Provider Toolset Download and install [Golang 1.23](https://go.dev/dl). @@ -112,7 +102,7 @@ Verify the installation with the following command: go version ``` -### Step 1: Clone the Finality Provider Repository +### 2.1. Clone the Finality Provider Repository Subsequently clone the finality provider [repository](https://github.com/babylonlabs-io/finality-provider) and navigate to the @@ -125,7 +115,7 @@ cd finality-provider git checkout ``` -### Step 2: Build and Install Finality Provider Binaries +### 2.2. Build and Install Finality Provider Toolset Binaries Run to build the binaries and install them to your `$GOPATH/bin` directory: ```shell @@ -139,7 +129,7 @@ This command will: - `fpd`: Finality provider daemon - Make commands globally accessible from your terminal -### Step 3: Verify Installation +### 2.3. Verify Installation Run `fpd version` to verify the installation: @@ -153,33 +143,30 @@ version: v0.11.0 commit: 7d37c88e9a33c0b6a86614f743e9426ce6e31d4a ``` -If your shell cannot find the installed binaries, make sure `$GOPATH/bin` is in -the `$PATH` of your shell. Use the following command to add it to your profile. +If your shell cannot find the installed binaries, make sure `$GOPATH/bin` is in +the `$PATH` of your shell. Use the following command to add it to your profile. ```shell echo 'export PATH=$HOME/go/bin:$PATH' >> ~/.profile ``` -## Setting up the EOTS Manager - ->If you have already set up an EOTS Manager, you can skip this section. -The following steps are only for users who have not yet set up an EOTS Manager. -Phase-1 users who already had an EOTS Manager set up can skip to the -[Loading Existing Keys](#loading-existing-keys) -section at the end of this guide for specific instructions -on re-using their Phase-1 EOTS keys unless you would like to familiarlize yourself -with the backup and recovery process. +## 3. Setting up the EOTS Manager Daemon -After the full node has been setup, the operator can set up and run the -Extractable One Time Signature (EOTS) manager daemon. +The EOTS manager daemon is a core component of the finality provider +stack responsible for managing your EOTS keys and producing EOTS signatures +to be used for votes. In this section, we are going to go through +its setup and key generation process. -The EOTS daemon is responsible for managing EOTS keys, producing EOTS -randomness, and using them to produce EOTS signatures. To read more on the EOTS -Manager see [here](#) +> Note: If you were a participant of a phase-1 Babylon launch network +> intending to transition your finality provider to a later phase, +> you do not need to create a new EOTS key. Please follow this section +> as it will guide you in transitioning your existing keys to the +> phase-2 and beyond finality provider stack. -### Step 1: Initialize the EOTS Manager +### 3.1. Initialize the EOTS Manager -Initialize a home directory for the EOTS Manager with the following command: +If you haven't already, +initialize a home directory for the EOTS Manager with the following command: ```shell eotsd init --home @@ -190,53 +177,38 @@ Parameters: - Default: `/Users//Library/Application Support/Eotsd` - Example: `--home ./eotsHome` -### Step 2: Create an EOTS Key +### 3.2. Create/Add an EOTS Key -Once the EOTS Manager is initialized, you need to create an EOTS key: +#### 3.2.1. Import an existing EOTS key -``` shell -eotsd keys add --key-name --home --keyring-backend test -``` - -- ``: Name for your EOTS key (e.g., "eots-key-1"). We do not allow the same -`keyname` for an existing keyname. -- `--home`: Path to your EOTS daemon home directory (e.g., "~/.eotsd") -- `--keyring-backend`: Type of keyring storage (use "test" for testing) - -Sample output: + -```json -{ - "name": "eots", - "pub_key_hex": - "e1e72d270b90b24f395e76b417218430a75683bd07cf98b91cf9219d1c777c19", - "mnemonic": "parade hybrid century project toss gun undo ocean exercise - figure decorate basket peace raw spot gap dose daring patch ski purchase - prefer can pair" -} -``` - ->⚠️ **Important**: The mnemonic phrase must be stored securely and kept private, as it is the -only way to recover your EOTS key if access is lost and is critical for maintaining control -of your finality provider operations. - -## Loading Existing Keys +>If you have already set up an EOTS Manager, you can skip this section. +The following steps are only for users who have not yet set up an EOTS Manager. +Phase-1 users who already had an EOTS Manager set up can skip to the +[Loading Existing Keys](#loading-existing-keys) +section at the end of this guide for specific instructions +on re-using their Phase-1 EOTS keys unless you would like to familiarize yourself +with the backup and recovery process. -If you participated in Phase-1, follow these steps to load your existing EOTS -key and configure it for Phase-2. +If you participated in Phase-1, follow these steps to load your existing EOTS +key and configure it for Phase-2. -This section is only for Finality Providers who participated in Phase-1 and already -had an EOTS key. If you are a new user, you can skip this section unless you would like to -familiarlize yourself with the backup and recovery process. +This section is only for Finality Providers who participated in Phase-1 and already +had an EOTS key. If you are a new user, you can skip this section unless you would like to +familiarlize yourself with the backup and recovery process. -### Step 1: Verify Your EOTS Key Backup ->⚠️ **Important**: Before proceeding, ensure you have access to your original EOTS key from Phase-1. -This is the same key that was registered in the [Phase-1 registration](https://github.com/babylonlabs-io/networks/tree/main/bbn-test-5/finality-providers). +##### Verify Your EOTS Key Backup +>⚠️ **Important**: Before proceeding, ensure you have access to your original EOTS key from Phase-1. +This is the same key that was registered in the [Phase-1 registration](https://github.com/babylonlabs-io/networks/tree/main/bbn-test-5/finality-providers). -### Step 2: Import Your EOTS Key into the Keyring +##### Import Your EOTS Key into the Keyring -Before importing the key, it should be in a file (the file will be named `key.asc`) +Before importing the key, it should be in a file (the file will be named `key.asc`) in the following format. ``` @@ -251,23 +223,67 @@ VP88GFE= -----END TENDERMINT PRIVATE KEY----- ``` -To load your existing EOTS key, use the following command to import it into the +To load your existing EOTS key, use the following command to import it into the keyring: ```shell eotsd keys import --home --keyring-backend test ``` -- ``: New name for your key in Phase-2. This should be unique from the keyname -used in Phase-1. +- ``: New name for your key in Phase-2. This should be unique from the keyname + used in Phase-1. - ``: Path to the exported key file - `--home`: EOTS daemon home directory for Phase-2 - `--keyring-backend`: Keyring backend type (use `test` for testing) -## Starting the EOTS Daemon +##### Verify the Key Import +After importing, verify that your EOTS key was successfully loaded: -You can start the EOTS daemon using the following command: +```shell +eotsd keys list --keyring-backend test --home +``` + +* ``: Name of the EOTS key to verify +* `--keyring-backend`: Type of keyring backend to use (default: test) +* `--home`: Directory containing EOTS Manager configuration and data + +You should see your EOTS key listed with the correct details, confirming that +it has been imported correctly. + +>⚠️ **Important**: Make sure you're using the same key name and EOTS public key that were +registered in Phase-1. + +#### 3.2.2. Create an EOTS key + +``` shell +eotsd keys add --key-name --home --keyring-backend test +``` + +- ``: Name for your EOTS key (e.g., "eots-key-1"). We do not allow the same +`keyname` for an existing keyname. +- `--home`: Path to your EOTS daemon home directory (e.g., "~/.eotsd") +- `--keyring-backend`: Type of keyring storage (use "test" for testing) + +Sample output: + +```json +{ + "name": "eots", + "pub_key_hex": + "e1e72d270b90b24f395e76b417218430a75683bd07cf98b91cf9219d1c777c19", + "mnemonic": "parade hybrid century project toss gun undo ocean exercise + figure decorate basket peace raw spot gap dose daring patch ski purchase + prefer can pair" +} +``` + +>⚠️ **Important**: The mnemonic phrase must be stored securely and kept private, as it is the +only way to recover your EOTS key if access is lost and is critical for maintaining control +of your finality provider operations. +### 3.3. Starting the EOTS Daemon + +You can start the EOTS daemon using the following command: ```shell eotsd start --home ``` @@ -284,15 +300,20 @@ by specifying a custom address with the `--rpc-listener` flag. EOTS Manager Daemon is fully active! ``` ->**Note**: It is recommended to run the `eotsd` daemon on a separate machine or -network segment to enhance security. This helps isolate the key management -functionality and reduces the potential attack surface. You can edit -the `EOTSManagerAddress` in the configuration file of the finality provider to -reference the address of the machine where `eotsd` is running. +>**Security Tip 🔒**: +> * `eotsd` holds your private keys which are used for signing +> * keep it in a separate machine or network segment with enhanced security +> * only allow access to the RPC server specified by the `RPCListener` port to trusted sources -## Setting up the Finality Provider + -### Step 1: Initialize the Finality Provider Daemon +## 4. Setting up the Finality Provider + +### 4.1. Initialize the Finality Provider Daemon Use the `fpd init` command to initialize a home directory for the Finality Provider. You can set or change the home directory using the `--home` tag. For example, use @@ -307,13 +328,13 @@ fpd init --home `service injective.evm.v1beta1.Msg does not have cosmos.msg.v1.service proto annotation`, which is expected and can be ignored. -### Step 2: Add key for the Babylon account +### 4.2. Add key for the Babylon account The keyring is kept in the local storage of the finality provider daemon. The key associates a Babylon account with the finality provider to receive BTC delegation rewards. -Use the following command to add the Babylonkey for your finality provider: +Use the following command to add the Babylon key for your finality provider: ```shell fpd keys add --keyname --keyring-backend test --home @@ -323,16 +344,16 @@ We use `--keyring-backend test`, which specifies which backend to use for the keyring, `test` stores keys unencrypted on disk. For production environments, use `file` or `os` backend. - There are three options for the keyring backend: + + + - `test`: Stores keys unencrypted on disk. It’s meant for testing purposes and - should never be used in production. - `file`: Stores encrypted keys on disk, - which is a more secure option than test but less secure than using the OS - keyring. - `os`: Uses the operating system's native keyring, providing the - highest level of security by relying on OS-managed encryption and access - controls. This command will create a new key pair and store it in your keyring. The output should look similar to the below: @@ -366,7 +387,7 @@ Babylon Networks repository at [https://github.com/babylonlabs-io/networks/tree/ > * For mainnet operations, see the required funds documentation [here]() -### Step 3: Configure Your Finality Provider +### 4.3. Configure Your Finality Provider Edit the `config.toml` file in your finality provider home directory with the following parameters: @@ -396,25 +417,7 @@ Configuration parameters explained: * `GRPCAddr`: Your Babylon node's GRPC endpoint * `KeyDirectory`: Path to your keyring directory (same as --home path) - -### Step 3: Verify the Key Import -After importing, verify that your EOTS key was successfully loaded: - -```shell -eotsd keys list --keyring-backend test --home -``` - -* ``: Name of the EOTS key to verify -* `--keyring-backend`: Type of keyring backend to use (default: test) -* `--home`: Directory containing EOTS Manager configuration and data - -You should see your EOTS key listed with the correct details, confirming that -it has been imported correctly. - ->⚠️ **Important**: Make sure you're using the same key name and EOTS public key that were -registered in Phase-1. - -## Starting the Finality Provider Daemon +### 4.4. Starting the Finality Provider Daemon The finality provider daemon (FPD) needs to be running before proceeding with registration or voting participation. @@ -447,19 +450,21 @@ you can run the daemon directly in a terminal, but remember it must stay running to function properly. The above will start the Finality provider RPC server at the address specified -in `fpd.conf` under the `RpcListener` field, which has a default value -of `127.0.0.1:12581`. You can change this value in the configuration file or +in `fpd.conf` under the `RpcListener` field, which has a default value +of `127.0.0.1:12581`. You can change this value in the configuration file or override this value and specify a custom address using -the `--rpc-listener` flag. +the `--rpc-listener` flag. To start the daemon with a specific finality provider instance after registration, use the `--eots_pk_hex` flag followed by the hex string of the EOTS public key of the finality provider. -All the available CLI options can be viewed using the `--help` flag. These +All the available CLI options can be viewed using the `--help` flag. These options can also be set in the configuration file. -## Create Finality Provider +## 5. Finality Provider Operations + +### 5.1 Create Finality Provider The `create-finality-provider` command initializes a new finality provider instance locally. @@ -526,7 +531,7 @@ registration) Your set commission rate - `status`: Current status of the finality provider -## Register Finality Provider +### 5.2. Register Finality Provider The `register-finality-provider` command registers your finality provider on the Babylon chain. This command requires: @@ -607,14 +612,7 @@ The hash returned should look something similar to below: gas_used: "82063" gas_wanted: "94429" height: "66693" info: "" logs: [] raw_log:"" ``` -## Slashing Conditions - -Slashing occurs when a finality provider **double signs**. This occurs when a -finality provider signs conflicting blocks at the same height. This results in -the extraction of the provider's private key and automatically triggers shutdown -of the finality provider. - -## Jailing and Unjailing +### 5.3. Jailing and Unjailing As mentioned above, a finality provider can be jailed for various reasons, including not signing for a certain number of blocks, not committing public @@ -657,12 +655,20 @@ Parameters: So while slashing is permanent, jailing is a temporary state that can be recovered from through the unjailing process, as long as the finality provider wasn't slashed. -## Public Randomness Submission +### 5.3. Public Randomness Submission For detailed information about public randomness commits, see: * [Technical Overview](./docs/commit-pub-rand.md) * [Core Implementation Details](./fp-core.md#committing-public-randomness) -## Reading the logs + +### 5.4. Submission of votes + + + +### 5.5. Keyring maintenance and gas requirements + + +### 5.6. Reading the logs The logs are stored based on your daemon home directories: @@ -712,7 +718,7 @@ tail -f /logs/fpd.log tail -f /logs/fpd.log | grep "status is changed" ``` -## Withdrawing Rewards +### 5.7. Withdrawing Rewards When withdrawing rewards, you need to use the Babylon chain's CLI since rewards are managed by the main chain. @@ -724,3 +730,51 @@ To withdraw your finality provider rewards: +### 5.8. Jailing and Unjailing + + + +### 5.9. Monitoring + + + +## 6. Security and Slashing + +Slashing occurs when a finality provider **double signs**. This occurs when a +finality provider signs conflicting blocks at the same height. This results in +the extraction of the provider's private key and automatically triggers shutdown +of the finality provider. + + + +> ⚠️ **Critical**: Implement these measures before starting daemons or handling keys + +* Finality Provider Daemon: Secure RPC listener (`127.0.0.1:12581`) +* Keys: + - EOTS: Secure offline backup required + - Babylon: Use `os` or `file` backend for production +* Monitor: + - Double-signing attempts + - Status changes (`Active`/`Inactive`/`Jailed`) + - Public randomness commits + +> ⚠️ **Important Note on Keyring Security**: +The finality provider daemon uses the `--keyring-backend test` which stores keys unencrypted on disk. +While this is generally not secure, it's necessary for the finality provider service because: + +* The daemon needs to automatically sign and send transactions frequently +* If transactions stop for too long, the provider gets jailed +* Using encrypted keystores would require manual password entry after every restart +* Service availability is critical to avoid jailing + +For other Babylon services that don't require automatic transaction signing, we recommend: +* Use `os` backend (most secure, uses system keyring) +* Or use `file` backend (encrypted storage) +* Never use `test` backend outside of automated services + +We are actively working on implementing more secure keyring solutions that maintain both security +and high availability. + +> ⚠️ **Warning**: Security breaches can result in slashing and permanent loss of provider status From 11d78c7d6d44e50a40d3834331349bcbb49d74b3 Mon Sep 17 00:00:00 2001 From: Sam Ricotta Date: Mon, 25 Nov 2024 15:15:13 +0200 Subject: [PATCH 33/53] Update finality-provider-operation.md --- docs/finality-provider-operation.md | 478 +++++++++++++++------------- 1 file changed, 251 insertions(+), 227 deletions(-) diff --git a/docs/finality-provider-operation.md b/docs/finality-provider-operation.md index d49c548..c14e1d9 100644 --- a/docs/finality-provider-operation.md +++ b/docs/finality-provider-operation.md @@ -3,8 +3,7 @@ This document guides operators through the complete lifecycle of running a finality provider, including: -* Installing and configuring the finality provider - toolset (EOTS Manager and FP daemon) +* Installing and configuring the finality provider toolset (EOTS Manager and Finality Provider daemon) * Managing keys (EOTS key for signatures and Babylon key for rewards) * Registering your finality provider on the Babylon network * Operating and maintaining your finality provider @@ -17,45 +16,30 @@ gain an overall understanding of the finality provider. ## Table of Contents -1. [A note about Phase-1 Finality Providers](#phase-1-finality-providers) -2. [Install Finality Provider Toolset](#install-finality-provider-binary) -3. [Setting up the EOTS Manager](#setting-up-the-eots-manager) - 1. [Loading Existing Keys](#loading-existing-keys) - 2. [Starting the EOTS Daemon](#starting-the-eots-daemon) -4. [Setting up the Finality Provider](#setting-up-the-finality-provider) - 1. [Starting the Finality Provider Daemon](#starting-the-finality-provider-daemon) -5. [Finality Provider Operation]() - 1. [Create Finality Provider](#create-finality-provider) - 2. [Register Finality Provider](#register-finality-provider) - 3. [Public Randomness Submission](#public-randomness-submission) - 4. [Submission of votes]() - 5. [Keyring maintenance and gas requirements]() - 6. [Reading the logs](#reading-the-logs) - 7. [Withdrawing Rewards](#withdrawing-rewards) - 8. [Jailing and Unjailing](#jailing-and-unjailing) - 9. [Monitoring]() -6. [Security and Slashing]() - - +1. [A note about Phase-1 Finality Providers](#1-a-note-about-phase-1-finality-providers) +2. [Install Finality Provider Toolset](#2-install-finality-provider-toolset) +3. [Setting up the EOTS Daemon](#3-setting-up-the-eots-daemon) + 1. [Initialize the EOTS Daemon](#31-initialize-the-eots-daemon) + 2. [Create/Add an EOTS Key](#32-createadd-an-eots-key) + 1. [Import an existing EOTS key](#321-import-an-existing-eots-key) + 2. [Create an EOTS key](#322-create-an-eots-key) + 3. [Starting the EOTS Daemon](#33-starting-the-eots-daemon) +4. [Setting up the Finality Provider](#4-setting-up-the-finality-provider) + 1. [Initialize the Finality Provider Daemon](#41-initialize-the-finality-provider-daemon) + 2. [Add key for the Babylon account](#42-add-key-for-the-babylon-account) + 3. [Configure Your Finality Provider](#43-configure-your-finality-provider) + 4. [Starting the Finality Provider Daemon](#44-starting-the-finality-provider-daemon) +5. [Finality Provider Operation](#5-finality-provider-operations) + 1. [Create Finality Provider](#51-create-finality-provider) + 2. [Register Finality Provider](#52-register-finality-provider) + 3. [Public Randomness Submission](#53-public-randomness-submission) + 4. [Submission of votes](#54-submission-of-votes) + 5. [Keyring maintenance and gas requirements](#55-keyring-maintenance-and-gas-requirements) + 6. [Reading the logs](#56-reading-the-logs) + 7. [Withdrawing Rewards](#57-withdrawing-rewards) + 8. [Jailing and Unjailing](#58-jailing-and-unjailing) + 9. [Monitoring](#59-monitoring) +6. [Security and Slashing](#6-security-and-slashing) ## 1. A note about Phase-1 Finality Providers @@ -72,26 +56,6 @@ second phase of the Babylon launch. > ⚠️ **Critical**: Ensure that you use -Finality providers that participated in the first phase of the Babylon mainnet, -should use the same EOTS keys for the second phase instead of creating new ones, -as all their BTC stake delegations are associated with the keys they used on phase-1. - -* `Phase-1` operators should use their existing EOTS keys for `Phase-2` participation. -* All your delegations are associated with your existing EOTS key - you must import -your existing key instead of creating a new one, as -**creating new keys will result in loss of delegations**. -* For those who participated in both testnet and mainnet, ensure you -**use the correct key for each network to avoid delegation loss and potential slashing**. -* Locate your `Phase-1` EOTS key backup and proceed to the [Loading Existing Keys](#loading-existing-keys) -section for import instructions. - - - - ## 2. Install Finality Provider Toolset @@ -117,7 +81,8 @@ git checkout ### 2.2. Build and Install Finality Provider Toolset Binaries -Run to build the binaries and install them to your `$GOPATH/bin` directory: +Run the following command to build the binaries and install them to your `$GOPATH/bin` directory: + ```shell make install ``` @@ -131,12 +96,14 @@ This command will: ### 2.3. Verify Installation -Run `fpd version` to verify the installation: +Run the following command to verify the installation: ```shell fpd version ``` + The expected output should be: + ```shell # example output version: v0.11.0 @@ -150,30 +117,24 @@ the `$PATH` of your shell. Use the following command to add it to your profile. echo 'export PATH=$HOME/go/bin:$PATH' >> ~/.profile ``` -## 3. Setting up the EOTS Manager Daemon +## 3. Setting up the EOTS Daemon The EOTS manager daemon is a core component of the finality provider stack responsible for managing your EOTS keys and producing EOTS signatures to be used for votes. In this section, we are going to go through its setup and key generation process. -> Note: If you were a participant of a phase-1 Babylon launch network -> intending to transition your finality provider to a later phase, -> you do not need to create a new EOTS key. Please follow this section -> as it will guide you in transitioning your existing keys to the -> phase-2 and beyond finality provider stack. +### 3.1. Initialize the EOTS Daemon -### 3.1. Initialize the EOTS Manager - -If you haven't already, -initialize a home directory for the EOTS Manager with the following command: +If you haven't already, initialize a home directory for the EOTS Manager +with the following command: ```shell eotsd init --home ``` Parameters: -* `--home`: Directory for EOTS Manager configuration and data +- `--home`: Directory for EOTS Manager configuration and data - Default: `/Users//Library/Application Support/Eotsd` - Example: `--home ./eotsHome` @@ -181,35 +142,33 @@ Parameters: #### 3.2.1. Import an existing EOTS key - +>⚠️ **Important**:This section is for Finality Providers who participated in Phase-1 and already posess an EOTS key. +>If you are a new user, you can skip this section unless you would like to familiarize yourself +>with the backup and recovery process. + +There are 3 supported methods of loading your existing EOTS keys: using a mnemonic phrase, +exporting the `.asc` file and backing up your entire home directory. We have outlined +each of these three paths for you below. ->If you have already set up an EOTS Manager, you can skip this section. -The following steps are only for users who have not yet set up an EOTS Manager. -Phase-1 users who already had an EOTS Manager set up can skip to the -[Loading Existing Keys](#loading-existing-keys) -section at the end of this guide for specific instructions -on re-using their Phase-1 EOTS keys unless you would like to familiarize yourself -with the backup and recovery process. +#### Using your Mnemonic Phrase -If you participated in Phase-1, follow these steps to load your existing EOTS -key and configure it for Phase-2. +If you are using your mnemonic seed phrase, use the following command to import your key: + +```shell +eotsd keys add --recover +``` -This section is only for Finality Providers who participated in Phase-1 and already -had an EOTS key. If you are a new user, you can skip this section unless you would like to -familiarlize yourself with the backup and recovery process. +You'll be prompted to enter: +1. Your bip39 mnemonic phrase (24 words) +2. A passphrase to encrypt your key +3. HD path (optional - press Enter to use default) -##### Verify Your EOTS Key Backup ->⚠️ **Important**: Before proceeding, ensure you have access to your original EOTS key from Phase-1. -This is the same key that was registered in the [Phase-1 registration](https://github.com/babylonlabs-io/networks/tree/main/bbn-test-5/finality-providers). - +> ⚠️ **Note**: The HD path is optional. If you used the default path when creating your key, +you can skip this by pressing Enter. -##### Import Your EOTS Key into the Keyring +#### Using your `.asc` file -Before importing the key, it should be in a file (the file will be named `key.asc`) -in the following format. +If you exported your key to a `.asc` file. The `.asc` file should be in the following format: ``` -----BEGIN TENDERMINT PRIVATE KEY----- @@ -223,26 +182,38 @@ VP88GFE= -----END TENDERMINT PRIVATE KEY----- ``` -To load your existing EOTS key, use the following command to import it into the -keyring: +To load your existing EOTS key, use the following command: -```shell +```shell eotsd keys import --home --keyring-backend test ``` -- ``: New name for your key in Phase-2. This should be unique from the keyname - used in Phase-1. -- ``: Path to the exported key file -- `--home`: EOTS daemon home directory for Phase-2 -- `--keyring-backend`: Keyring backend type (use `test` for testing) +#### Using Home Directory Backup + +If you backed up your entire EOTS home directory or are using your `--home` directory. + +1. Check to see if the EOTS daemon is running. If it is, stop it. +2. Copy your backup directory or your old home directory to the new location. + +```shell +# Stop the EOTS daemon if running +# Copy your Phase-1 directory to Phase-2 location +cp -r ~/.eotsd ~/.eotsd-phase2 + +# Initialize it for Phase-2 +eotsd init --home ~/.eotsd-phase2 +``` +>⚠️ **Important**: Please note that the above directory is just an example. +Your directory will be located at the path you specified. ##### Verify the Key Import -After importing, verify that your EOTS key was successfully loaded: +After importing, you can verify that your EOTS key was successfully loaded: ```shell eotsd keys list --keyring-backend test --home ``` +Parameters: * ``: Name of the EOTS key to verify * `--keyring-backend`: Type of keyring backend to use (default: test) * `--home`: Directory containing EOTS Manager configuration and data @@ -255,16 +226,23 @@ registered in Phase-1. #### 3.2.2. Create an EOTS key +If you have not created an EOTS key yet, use the following command to create a new one: + ``` shell eotsd keys add --key-name --home --keyring-backend test ``` +Parameters: - ``: Name for your EOTS key (e.g., "eots-key-1"). We do not allow the same `keyname` for an existing keyname. -- `--home`: Path to your EOTS daemon home directory (e.g., "~/.eotsd") -- `--keyring-backend`: Type of keyring storage (use "test" for testing) +- `--home`: Path to your EOTS daemon home directory (e.g., "~/.eotsHome") +- `--keyring-backend`: Type of keyring storage: + - `test`: Stores keys unencrypted, no passphrase prompts + - `os`: Uses system's secure keyring, requires passphrase at startup + - `file`: Encrypted file storage, requires passphrase at startup -Sample output: + +The command will return a JSON response containing your EOTS key details: ```json { @@ -283,7 +261,8 @@ of your finality provider operations. ### 3.3. Starting the EOTS Daemon -You can start the EOTS daemon using the following command: +To start the EOTS daemon using the following command: + ```shell eotsd start --home ``` @@ -303,34 +282,27 @@ EOTS Manager Daemon is fully active! >**Security Tip 🔒**: > * `eotsd` holds your private keys which are used for signing > * keep it in a separate machine or network segment with enhanced security -> * only allow access to the RPC server specified by the `RPCListener` port to trusted sources - - +reference the address of the machine where `eotsd` is running ## 4. Setting up the Finality Provider ### 4.1. Initialize the Finality Provider Daemon -Use the `fpd init` command to initialize a home directory for the Finality Provider. -You can set or change the home directory using the `--home` tag. For example, use -`--home ./fpHome` to specify a custom directory. The application default home directory is -`/Users//Library/Application Support/Fpd`. +To initialize the finality provider daemon, use the following command: ```shell fpd init --home ``` ->Note: Running this command may return the message +>**Note**: Running this command may return the message `service injective.evm.v1beta1.Msg does not have cosmos.msg.v1.service proto annotation`, which is expected and can be ignored. ### 4.2. Add key for the Babylon account -The keyring is kept in the local storage of the finality provider daemon. +For the Finality Provider Daemon, the keyring is kept in the local storage of the finality provider daemon. The key associates a Babylon account with the finality provider to receive BTC delegation rewards. @@ -340,22 +312,21 @@ Use the following command to add the Babylon key for your finality provider: fpd keys add --keyname --keyring-backend test --home ``` -We use `--keyring-backend test`, which specifies which backend to use for the -keyring, `test` stores keys unencrypted on disk. For production environments, -use `file` or `os` backend. - - - - - - -This command will create a new key pair and store it in your keyring. +>**Important🔒**: +>To operate your Finality Provider, ensure your Babylon account is funded. Block vote transactions +have their gas fees refunded, but public randomness >submissions require gas payments. For testnet, +you can obtain funds from our [faucet](#add-faucet). +> + +>We use the `--keyring-backend test`, which stores keys unencrypted on disk. This backend is suitable +for testing but not recommended for large fund storage. >Rewards from Finality Provider commissions +are stored in this keyring. Other keyring backends are not supported yet, and prolonged inactivity +(missing >transactions) can lead to your Finality Provider being jailed. +> +>Keep only enough funds in the keyring for operations, which you can view [here](#keyring-maintenance-and-gas-requirements). +We are also exploring options to support different withdrawal addresses. + +The above `keys add` command will create a new key pair and store it in your keyring. The output should look similar to the below: @@ -375,18 +346,7 @@ This command will automatically update the `Key` field in the config file to use this key name. This key will be used for all interactions with the Babylon chain, including finality provider registration and transaction signing. - -Please verify the `chain-id` and other network parameters from the official -Babylon Networks repository at [https://github.com/babylonlabs-io/networks/tree/main/bbn-test-5/finality-providers](https://github.com/babylonlabs-io/networks/tree/main/bbn-test-5/finality-providers) - -> ⚠️ **Important**: Funding Your Babylon Account -> * You need to have funds in your Babylon account to submit transactions -> * Block vote transactions get their gas refunded -> * Public randomness submissions require you to pay gas fees -> * For testnet operations, you can get funds from our [faucet]() -> * For mainnet operations, see the required funds documentation [here]() - ### 4.3. Configure Your Finality Provider Edit the `config.toml` file in your finality provider home directory with the following parameters: @@ -417,6 +377,9 @@ Configuration parameters explained: * `GRPCAddr`: Your Babylon node's GRPC endpoint * `KeyDirectory`: Path to your keyring directory (same as --home path) +Please verify the `chain-id` and other network parameters from the official +Babylon Networks repository at [https://github.com/babylonlabs-io/networks/tree/main/bbn-test-5/finality-providers](https://github.com/babylonlabs-io/networks/tree/main/bbn-test-5/finality-providers) + ### 4.4. Starting the Finality Provider Daemon The finality provider daemon (FPD) needs to be running before proceeding with @@ -443,7 +406,7 @@ You should see logs indicating successful startup: [INFO] RPC server listening on... ``` ->Note: The daemon needs to run continuously. It's recommended to set up a system +>⚠️**Important**: The daemon needs to run continuously. It's recommended to set up a system service (like `systemd` on Linux or `launchd` on macOS) to manage the daemon process, handle automatic restarts, and collect logs. For testing purposes, you can run the daemon directly in a terminal, but remember it must stay @@ -549,6 +512,7 @@ fpd register-finality-provider \ --home \ ``` +Parameters: - ``: Your BTC public key from create-finality-provider (e.g., `cf0f03b9ee2d4a0f27240e2d8b8c8ef609e24358b2eb3cfd89ae4e4f472e1a41`) - `--daemon-address`: RPC address of your finality provider daemon (default: "127.0.0.1:12581") @@ -556,16 +520,6 @@ fpd register-finality-provider \ - `--home`: Path to your finality provider daemon home directory (e.g., "~/.fpd") - `--keyring-backend`: Type of keyring storage (use "test" for testing, "file" for production) -Example: -```shell -fpd register-finality-provider \ - cf0f03b9ee2d4a0f27240e2d8b8c8ef609e24358b2eb3cfd89ae4e4f472e1a41 \ - --daemon-address 127.0.0.1:12581 \ - --passphrase "my-secure-passphrase" \ - --home ~/.fpd \ - --keyring-backend test -``` - > Note: The BTC public key (`cf0f03...1a41`) is obtained from the previous `eotsd keys add` command. @@ -612,61 +566,61 @@ The hash returned should look something similar to below: gas_used: "82063" gas_wanted: "94429" height: "66693" info: "" logs: [] raw_log:"" ``` -### 5.3. Jailing and Unjailing +### 5.3. Public Randomness Submission -As mentioned above, a finality provider can be jailed for various reasons, -including not signing for a certain number of blocks, not committing public -randomness for a certain number of blocks, or not being responsive to the -finality provider daemon. +For detailed information about public randomness commits, see: +* [Technical Overview](./docs/commit-pub-rand.md) +* [Core Implementation Details](./fp-core.md#committing-public-randomness) -When jailed, the following happens to a finality provider: -- Their voting power becomes 0 -- Status is set to `JAILED` -- Delegator rewards stop +### 5.4. Submission of votes -To unjail a finality provider, you must complete the following steps: -- Fix the underlying issue that caused jailing -- Wait for the jailing period to pass (if it was due to downtime) -- Then send the unjail transaction to the Babylon chain (not the finality provider daemon). +There is a responsibility for the finality providers to submit votes to finalize blocks on the consumer chain. The finality provider daemon automatically handles vote submission for finality providers. -You can use the following command to send the unjail transaction: -```shell -babylond tx slashing unjail \ ---from= \ ---chain-id="euphrates-0.5.0" \ ---gas="auto" \ ---gas-adjustment=1.5 \ ---gas-prices=0.025ubbn \ ---keyring-backend=test \ ---home=./nodeDir +To see the logs of the finality provider daemon, you can use the following command: + +``` shell +tail -f /logs/fpd.log | grep "successfully submitted a finality signature to the consumer chain" ``` -Parameters: -* `--from`: Your Babylon key name -* `--chain-id`: Current Babylon network chain ID -* `--gas`: Gas limit for transaction (auto recommended) -* `--gas-adjustment`: Multiplier for auto gas calculation -* `--gas-prices`: Gas price in ubbn -* `--keyring-backend`: Keyring backend type -* `--home`: Babylon node home directory +To see the technical documentation for sending finality votes, see: +[send-finality-vote.md](./send-finality-vote.md) -> ⚠️ **Important**: Before unjailing, ensure you've fixed the underlying issue that caused jailing +### 5.5. Keyring maintenance and gas requirements -So while slashing is permanent, jailing is a temporary state that can be recovered -from through the unjailing process, as long as the finality provider wasn't slashed. +The keyring stores funds for gas fees and collects rewards. We recommend not holding a large number of funds here—just enough for operations. We are also exploring ways to support different withdrawal addresses. -### 5.3. Public Randomness Submission +We encourage the following for keyring maintenance: +- Backup Keys: Use mnemonic phrases, export key files, or back up the home directory. +- Monitor and Secure: Regularly check for unauthorized activity. +- Production Transition: Replace the test keyring with a secure backend when available. -For detailed information about public randomness commits, see: -* [Technical Overview](./docs/commit-pub-rand.md) -* [Core Implementation Details](./fp-core.md#committing-public-randomness) +For gas requirements, the finality provider daemon will automatically handle gas fees but we recommend monitoring the gas usage to ensure the finality provider is functioning properly. -### 5.4. Submission of votes +The transaction types that consume gas are: +- `MsgCreateFinalityProvider`: Initial creation (requires gas) +- `MsgRegisterFinalityProvider`: Registration (requires gas) +- `MsgSubmitFinalityVote`: Block vote transactions (gas is refunded) +- `MsgCommitPubRandList`: Public randomness submissions (requires gas) - +As a guide we recommend using the following formula to estimate gas requirements: -### 5.5. Keyring maintenance and gas requirements - +``` +Estimated Gas = (Transaction Size) x (Gas Price) +``` + +We recommend holding 2 x Estimated Gas in your keyring to ensure that the finality provider has enough gas to submit votes and other transactions. + +To get your finality provider address, you can use the following command: + +```shell +fpd keys show --keyring-backend test --home +``` + +To check your current balance, you must navigate to the Babylon chain and use the following command: + +```shell +babylond query bank balances +``` ### 5.6. Reading the logs @@ -680,7 +634,7 @@ The logs are stored based on your daemon home directories: You also can access the logs via flags when starting the daemon: -``` +```shell fpd start --home --log_level debug ``` Important Log Events to Monitor @@ -732,11 +686,102 @@ To withdraw your finality provider rewards: ### 5.8. Jailing and Unjailing - +A finality provider can be jailed for various reasons, +including not signing for a certain number of blocks, not committing public +randomness for a certain number of blocks, or not being responsive to the +finality provider daemon. + +When jailed, the following happens to a finality provider: +- Their voting power becomes 0 +- Status is set to `JAILED` +- Delegator rewards stop + +To unjail a finality provider, you must complete the following steps: +1. Fix the underlying issue that caused jailing +2. Wait for the jailing period to pass (if it was due to downtime) +3. Then send the unjail transaction to the Babylon chain (not the finality provider daemon). + +```shell +fpd unjail-finality-provider --daemon-address --home +``` + +Parameters: +- ``: Your finality provider's EOTS public key in hex format +- `--daemon-address`: RPC server address of fpd (default: "127.0.0.1:12581") +- `--home`: Path to your finality provider daemon home directory + +> ⚠️ **Important**: Before unjailing, ensure you've fixed the underlying issue that caused jailing + +So while slashing is permanent, jailing is a temporary state that can be recovered +from through the unjailing process, as long as the finality provider wasn't slashed. ### 5.9. Monitoring - +We want to monitor the following metrics to ensure the health and performance of your Finality Provider: + +- Public randomness commitment success/failure +- Double-signing attempts +- Status changes (`Active`/`Inactive`/`Jailed`) +- Block vote submission success/failure +- Missing block signatures +- Transaction failures +- RPC endpoint availability +- Gas usage and balance + +There are several ways to monitor these metrics but we suggest using Prometheus. + +First, expose the metrics through the following Prometheus endpoints: + +- `Port 12581`: Finality Provider Daemon metrics +- `Port 12582`: EOTS Manager metrics + +Next we will enable metric collection in `app.toml` for your node and configure Prometheus to scrape the metrics. + +``` toml +[telemetry] +enabled = true +prometheus-retention-time = 600 # 10 minutes +[api] +enable = true +address = "127.0.0.1:12581" # Secure RPC listener for Finality Provider Daemon +``` +Restrict access to the EOTS Manager RPC by configuring it to listen only on `127.0.0.1:12582`. +Restart your Finality Provider node to apply these changes. + +After enabling metrics in the app.toml, configure Prometheus to scrape these endpoints (prometheus.yml): + +``` yaml +scrape_configs: + - job_name: 'finality_provider' + static_configs: + - targets: ['localhost:12581', 'localhost:12582'] + metrics_path: '/metrics' + scrape_interval: 10s +``` + +Next we want you to download and install [Prometheus](https://prometheus.io/download/). +Then create a `prometheus.yml` file and add the following scrape configuration: + +``` yaml +scrape_configs: + - job_name: 'finality_provider' + static_configs: + - targets: ['localhost:12581', 'localhost:12582'] + metrics_path: '/metrics' + scrape_interval: 10s +``` + +Then start Prometheus using the following command: + +``` shell +./prometheus --config.file=prometheus.yml +``` + +Once Prometheus is running: + +- Open the Prometheus web interface in your browser (default: `http://localhost:9090`). +- Navigate to Status > Targets. +- Confirm that the endpoints `localhost:12581` and `localhost:12582` are listed and their status is UP. ## 6. Security and Slashing @@ -745,22 +790,7 @@ finality provider signs conflicting blocks at the same height. This results in the extraction of the provider's private key and automatically triggers shutdown of the finality provider. - - -> ⚠️ **Critical**: Implement these measures before starting daemons or handling keys - -* Finality Provider Daemon: Secure RPC listener (`127.0.0.1:12581`) -* Keys: - - EOTS: Secure offline backup required - - Babylon: Use `os` or `file` backend for production -* Monitor: - - Double-signing attempts - - Status changes (`Active`/`Inactive`/`Jailed`) - - Public randomness commits - -> ⚠️ **Important Note on Keyring Security**: +**Keyring Security**: The finality provider daemon uses the `--keyring-backend test` which stores keys unencrypted on disk. While this is generally not secure, it's necessary for the finality provider service because: @@ -769,12 +799,6 @@ While this is generally not secure, it's necessary for the finality provider ser * Using encrypted keystores would require manual password entry after every restart * Service availability is critical to avoid jailing -For other Babylon services that don't require automatic transaction signing, we recommend: -* Use `os` backend (most secure, uses system keyring) -* Or use `file` backend (encrypted storage) -* Never use `test` backend outside of automated services We are actively working on implementing more secure keyring solutions that maintain both security and high availability. - -> ⚠️ **Warning**: Security breaches can result in slashing and permanent loss of provider status From 8389edb8be66eeb7b1b8c14927745953ada0b53f Mon Sep 17 00:00:00 2001 From: Sam Ricotta Date: Mon, 25 Nov 2024 15:26:30 +0200 Subject: [PATCH 34/53] Update finality-provider-operation.md --- docs/finality-provider-operation.md | 31 +++++++++++++++-------------- 1 file changed, 16 insertions(+), 15 deletions(-) diff --git a/docs/finality-provider-operation.md b/docs/finality-provider-operation.md index c14e1d9..425121c 100644 --- a/docs/finality-provider-operation.md +++ b/docs/finality-provider-operation.md @@ -142,7 +142,7 @@ Parameters: #### 3.2.1. Import an existing EOTS key ->⚠️ **Important**:This section is for Finality Providers who participated in Phase-1 and already posess an EOTS key. +> This section is for Finality Providers who participated in Phase-1 and already posess an EOTS key. >If you are a new user, you can skip this section unless you would like to familiarize yourself >with the backup and recovery process. @@ -163,7 +163,7 @@ You'll be prompted to enter: 2. A passphrase to encrypt your key 3. HD path (optional - press Enter to use default) -> ⚠️ **Note**: The HD path is optional. If you used the default path when creating your key, +> The HD path is optional. If you used the default path when creating your key, you can skip this by pressing Enter. #### Using your `.asc` file @@ -203,7 +203,7 @@ cp -r ~/.eotsd ~/.eotsd-phase2 # Initialize it for Phase-2 eotsd init --home ~/.eotsd-phase2 ``` ->⚠️ **Important**: Please note that the above directory is just an example. +> Please note that the above directory is just an example. Your directory will be located at the path you specified. ##### Verify the Key Import @@ -221,8 +221,9 @@ Parameters: You should see your EOTS key listed with the correct details, confirming that it has been imported correctly. ->⚠️ **Important**: Make sure you're using the same key name and EOTS public key that were -registered in Phase-1. +>**Important ⚠️**: +> Make sure you're using the same key name and EOTS public key that were +> registered in Phase-1. #### 3.2.2. Create an EOTS key @@ -255,7 +256,7 @@ The command will return a JSON response containing your EOTS key details: } ``` ->⚠️ **Important**: The mnemonic phrase must be stored securely and kept private, as it is the +> **Security Tip 🔒**: The mnemonic phrase must be stored securely and kept private, as it is the only way to recover your EOTS key if access is lost and is critical for maintaining control of your finality provider operations. @@ -267,7 +268,7 @@ To start the EOTS daemon using the following command: eotsd start --home ``` -This command starts the EOTS RPC server at the address specified in eotsd.conf +This command starts the EOTS RPC server at the address specified in `eotsd.conf` under the `RPCListener` field (default: `127.0.0.1:12582`). You can override this value by specifying a custom address with the `--rpc-listener` flag. @@ -296,7 +297,7 @@ To initialize the finality provider daemon, use the following command: fpd init --home ``` ->**Note**: Running this command may return the message +> Running this command may return the message `service injective.evm.v1beta1.Msg does not have cosmos.msg.v1.service proto annotation`, which is expected and can be ignored. @@ -364,9 +365,9 @@ GRPCAddr = https://127.0.0.1:9090 KeyDirectory = # The `--home`path to the directory where the keyring is stored ``` -> ⚠️ **Important**: Operating a finality provider requires a connection to a Babylon blockchain node. -It is **highly recommended** to operate your own Babylon full node instead of relying on third parties. -You can find instructions on setting up a Babylon node [here](https://github.com/babylonlabs-io/networks/tree/main/bbn-1/node-setup). +> **Important ⚠️**: Operating a finality provider requires a connection to a Babylon blockchain node. +> It is **highly recommended** to operate your own Babylon full node instead of relying on third parties. +> You can find instructions on setting up a Babylon node [here](https://github.com/babylonlabs-io/networks/tree/main/bbn-1/node-setup). Configuration parameters explained: * `EOTSManagerAddress`: Address where your EOTS daemon is running @@ -406,9 +407,9 @@ You should see logs indicating successful startup: [INFO] RPC server listening on... ``` ->⚠️**Important**: The daemon needs to run continuously. It's recommended to set up a system -service (like `systemd` on Linux or `launchd` on macOS) to manage the daemon -process, handle automatic restarts, and collect logs. For testing purposes, +>**Important ⚠️**: The daemon needs to run continuously. It's recommended to set up a system +>service (like `systemd` on Linux or `launchd` on macOS) to manage the daemon +>process, handle automatic restarts, and collect logs. For testing purposes, you can run the daemon directly in a terminal, but remember it must stay running to function properly. @@ -710,7 +711,7 @@ Parameters: - `--daemon-address`: RPC server address of fpd (default: "127.0.0.1:12581") - `--home`: Path to your finality provider daemon home directory -> ⚠️ **Important**: Before unjailing, ensure you've fixed the underlying issue that caused jailing +> Before unjailing, ensure you've fixed the underlying issue that caused jailing So while slashing is permanent, jailing is a temporary state that can be recovered from through the unjailing process, as long as the finality provider wasn't slashed. From 8c036dafd5c282e86e9f8d906875a4f7e2c418a6 Mon Sep 17 00:00:00 2001 From: Sam Ricotta Date: Mon, 25 Nov 2024 15:29:16 +0200 Subject: [PATCH 35/53] formatting --- docs/finality-provider-operation.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/docs/finality-provider-operation.md b/docs/finality-provider-operation.md index 425121c..3f62bdd 100644 --- a/docs/finality-provider-operation.md +++ b/docs/finality-provider-operation.md @@ -221,7 +221,7 @@ Parameters: You should see your EOTS key listed with the correct details, confirming that it has been imported correctly. ->**Important ⚠️**: +>⚠️ **Important**: > Make sure you're using the same key name and EOTS public key that were > registered in Phase-1. @@ -313,7 +313,7 @@ Use the following command to add the Babylon key for your finality provider: fpd keys add --keyname --keyring-backend test --home ``` ->**Important🔒**: +>⚠️ **Important**: >To operate your Finality Provider, ensure your Babylon account is funded. Block vote transactions have their gas fees refunded, but public randomness >submissions require gas payments. For testnet, you can obtain funds from our [faucet](#add-faucet). @@ -365,7 +365,7 @@ GRPCAddr = https://127.0.0.1:9090 KeyDirectory = # The `--home`path to the directory where the keyring is stored ``` -> **Important ⚠️**: Operating a finality provider requires a connection to a Babylon blockchain node. +> ⚠️ **Important**: Operating a finality provider requires a connection to a Babylon blockchain node. > It is **highly recommended** to operate your own Babylon full node instead of relying on third parties. > You can find instructions on setting up a Babylon node [here](https://github.com/babylonlabs-io/networks/tree/main/bbn-1/node-setup). @@ -407,7 +407,7 @@ You should see logs indicating successful startup: [INFO] RPC server listening on... ``` ->**Important ⚠️**: The daemon needs to run continuously. It's recommended to set up a system +>⚠️ **Important**: The daemon needs to run continuously. It's recommended to set up a system >service (like `systemd` on Linux or `launchd` on macOS) to manage the daemon >process, handle automatic restarts, and collect logs. For testing purposes, you can run the daemon directly in a terminal, but remember it must stay From 1e7d16a9c80d2eb56fc94a5b6f0908bad7826955 Mon Sep 17 00:00:00 2001 From: Sam Ricotta Date: Mon, 25 Nov 2024 15:50:56 +0200 Subject: [PATCH 36/53] formatting --- docs/finality-provider-operation.md | 45 +++++++++++++++++------------ 1 file changed, 27 insertions(+), 18 deletions(-) diff --git a/docs/finality-provider-operation.md b/docs/finality-provider-operation.md index 3f62bdd..9bb80ab 100644 --- a/docs/finality-provider-operation.md +++ b/docs/finality-provider-operation.md @@ -315,15 +315,15 @@ fpd keys add --keyname --keyring-backend test --home >⚠️ **Important**: >To operate your Finality Provider, ensure your Babylon account is funded. Block vote transactions -have their gas fees refunded, but public randomness >submissions require gas payments. For testnet, +have their gas fees refunded, but public randomness submissions require gas payments. For testnet, you can obtain funds from our [faucet](#add-faucet). -> - + + >We use the `--keyring-backend test`, which stores keys unencrypted on disk. This backend is suitable -for testing but not recommended for large fund storage. >Rewards from Finality Provider commissions +for testing but not recommended for large fund storage. Rewards from Finality Provider commissions are stored in this keyring. Other keyring backends are not supported yet, and prolonged inactivity -(missing >transactions) can lead to your Finality Provider being jailed. -> +(missing transactions) can lead to your Finality Provider being jailed. + >Keep only enough funds in the keyring for operations, which you can view [here](#keyring-maintenance-and-gas-requirements). We are also exploring options to support different withdrawal addresses. @@ -462,8 +462,7 @@ Optional parameters: - `--security-contact`: Contact email for security issues - `--details`: Additional description of your finality provider -- `--daemon-address`: RPC -address of the finality provider daemon (default: 127.0.0.1:12581) +- `--daemon-address`: RPC address of the finality provider daemon (default: `127.0.0.1:12581`) Upon successful creation, the command will return a JSON response containing your finality provider's details: @@ -516,10 +515,10 @@ fpd register-finality-provider \ Parameters: - ``: Your BTC public key from create-finality-provider (e.g., `cf0f03b9ee2d4a0f27240e2d8b8c8ef609e24358b2eb3cfd89ae4e4f472e1a41`) -- `--daemon-address`: RPC address of your finality provider daemon (default: "127.0.0.1:12581") +- `--daemon-address`: RPC address of your finality provider daemon (default: `127.0.0.1:12581`) - `--passphrase`: Passphrase for your key -- `--home`: Path to your finality provider daemon home directory (e.g., "~/.fpd") -- `--keyring-backend`: Type of keyring storage (use "test" for testing, "file" for production) +- `--home`: Path to your finality provider daemon home directory (e.g., `~/.fpdHome`) +- `--keyring-backend`: Type of keyring storage (use `test` for testing, `file` for production) > Note: The BTC public key (`cf0f03...1a41`) is obtained from the previous `eotsd keys add` command. @@ -583,8 +582,7 @@ To see the logs of the finality provider daemon, you can use the following comma tail -f /logs/fpd.log | grep "successfully submitted a finality signature to the consumer chain" ``` -To see the technical documentation for sending finality votes, see: -[send-finality-vote.md](./send-finality-vote.md) +To see the technical documentation for [sending finality votes](./send-finality-vote.md) ### 5.5. Keyring maintenance and gas requirements @@ -708,7 +706,7 @@ fpd unjail-finality-provider --daemon-address --home `: Your finality provider's EOTS public key in hex format -- `--daemon-address`: RPC server address of fpd (default: "127.0.0.1:12581") +- `--daemon-address`: RPC server address of fpd (default: `127.0.0.1:12581`) - `--home`: Path to your finality provider daemon home directory > Before unjailing, ensure you've fixed the underlying issue that caused jailing @@ -786,12 +784,14 @@ Once Prometheus is running: ## 6. Security and Slashing -Slashing occurs when a finality provider **double signs**. This occurs when a +**Slashing occurs** when a finality provider **double signs**. This occurs when a finality provider signs conflicting blocks at the same height. This results in the extraction of the provider's private key and automatically triggers shutdown -of the finality provider. +of the finality provider, removal from the active set, jailing and compromised rewards. -**Keyring Security**: +> **Critical**: Slashing is irreversible and results in permanent removal from the network. + +**Keyring Security 🔒**: The finality provider daemon uses the `--keyring-backend test` which stores keys unencrypted on disk. While this is generally not secure, it's necessary for the finality provider service because: @@ -800,6 +800,15 @@ While this is generally not secure, it's necessary for the finality provider ser * Using encrypted keystores would require manual password entry after every restart * Service availability is critical to avoid jailing - We are actively working on implementing more secure keyring solutions that maintain both security and high availability. + +**Security Best Practices 🔒**: +Here are some best practices to secure your finality provider: +* Run EOTS Manager and Finality Provider on separate machine/network segment +* Regular system security audits +* Monitor for unauthorized activities +* Allow only necessary ports (`12581`, `12582`) +* Active monitoring of the logs + + From 578bf506f7a7b32a9fb4570573eab3da1e7717e0 Mon Sep 17 00:00:00 2001 From: Sam Ricotta Date: Mon, 25 Nov 2024 16:22:41 +0200 Subject: [PATCH 37/53] add comments --- docs/finality-provider-operation.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/docs/finality-provider-operation.md b/docs/finality-provider-operation.md index 9bb80ab..7aa984a 100644 --- a/docs/finality-provider-operation.md +++ b/docs/finality-provider-operation.md @@ -43,7 +43,7 @@ gain an overall understanding of the finality provider. ## 1. A note about Phase-1 Finality Providers - + ## 2. Install Finality Provider Toolset @@ -155,7 +155,7 @@ each of these three paths for you below. If you are using your mnemonic seed phrase, use the following command to import your key: ```shell -eotsd keys add --recover +eotsd keys add --home --recover ``` You'll be prompted to enter: From eec3622d909c3b3a24b29126d0ee2c54a59b0b72 Mon Sep 17 00:00:00 2001 From: Sam Ricotta Date: Mon, 25 Nov 2024 16:37:25 +0200 Subject: [PATCH 38/53] formatting, small edits --- docs/finality-provider-operation.md | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/docs/finality-provider-operation.md b/docs/finality-provider-operation.md index 7aa984a..3c388a1 100644 --- a/docs/finality-provider-operation.md +++ b/docs/finality-provider-operation.md @@ -110,6 +110,9 @@ version: v0.11.0 commit: 7d37c88e9a33c0b6a86614f743e9426ce6e31d4a ``` +> You wont be able to run `eots version` as its not supported yet but you can +> run `eotsd` to verify the installation. + If your shell cannot find the installed binaries, make sure `$GOPATH/bin` is in the `$PATH` of your shell. Use the following command to add it to your profile. @@ -358,7 +361,7 @@ EOTSManagerAddress = 127.0.0.1:12582 RpcListener = 127.0.0.1:12581 [babylon] -Key = // the key you used above +Key = # the key you used above ChainID = bbn-test-5 RPCAddr = http://127.0.0.1:26657 GRPCAddr = https://127.0.0.1:9090 @@ -506,21 +509,21 @@ This account will be bonded to your finality provider and used to claim rewards. ``` shell fpd register-finality-provider \ - \ + \ --daemon-address \ --passphrase \ --home \ ``` Parameters: -- ``: Your BTC public key from create-finality-provider +- ``: Your EOTS public key (obtained from running `eotsd keys show `) (e.g., `cf0f03b9ee2d4a0f27240e2d8b8c8ef609e24358b2eb3cfd89ae4e4f472e1a41`) - `--daemon-address`: RPC address of your finality provider daemon (default: `127.0.0.1:12581`) - `--passphrase`: Passphrase for your key - `--home`: Path to your finality provider daemon home directory (e.g., `~/.fpdHome`) - `--keyring-backend`: Type of keyring storage (use `test` for testing, `file` for production) -> Note: The BTC public key (`cf0f03...1a41`) is obtained from the previous +> The BTC public key (`cf0f03...1a41`) is obtained from the previous `eotsd keys add` command. If successful, the command will return a transaction hash: @@ -533,7 +536,7 @@ If successful, the command will return a transaction hash: You can verify the transaction was successful by looking up this transaction hash on the Babylon chain. -The hash returned should look something similar to below: +The hash returned should look similar to below: ```shell type: message From 168b9370c8e4f8baf566f6c6cb6b29e9a61942fc Mon Sep 17 00:00:00 2001 From: Sam Ricotta Date: Mon, 25 Nov 2024 16:44:53 +0200 Subject: [PATCH 39/53] Update finality-provider-operation.md --- docs/finality-provider-operation.md | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/docs/finality-provider-operation.md b/docs/finality-provider-operation.md index 3c388a1..7c184b7 100644 --- a/docs/finality-provider-operation.md +++ b/docs/finality-provider-operation.md @@ -456,8 +456,8 @@ Required parameters: - `--commission`: The commission rate (between 0 and 1) that you'll receive from delegators - `--key-name`: Name of the key in your keyring for signing -transactions - -`--moniker`: A human-readable name for your finality provider +transactions +- `--moniker`: A human-readable name for your finality provider Optional parameters: - `--eots-pk`: The EOTS public key of the finality provider which was generated in `eotsd keys add` @@ -592,14 +592,13 @@ To see the technical documentation for [sending finality votes](./send-finality- The keyring stores funds for gas fees and collects rewards. We recommend not holding a large number of funds here—just enough for operations. We are also exploring ways to support different withdrawal addresses. We encourage the following for keyring maintenance: -- Backup Keys: Use mnemonic phrases, export key files, or back up the home directory. -- Monitor and Secure: Regularly check for unauthorized activity. -- Production Transition: Replace the test keyring with a secure backend when available. +- **Backup Keys**: Use mnemonic phrases, export key files, or back up the home directory. +- **Monitor and Secure**: Regularly check for unauthorized activity. +- **Production Transition**: Replace the test keyring with a secure backend when available. For gas requirements, the finality provider daemon will automatically handle gas fees but we recommend monitoring the gas usage to ensure the finality provider is functioning properly. The transaction types that consume gas are: -- `MsgCreateFinalityProvider`: Initial creation (requires gas) - `MsgRegisterFinalityProvider`: Registration (requires gas) - `MsgSubmitFinalityVote`: Block vote transactions (gas is refunded) - `MsgCommitPubRandList`: Public randomness submissions (requires gas) @@ -639,7 +638,7 @@ You also can access the logs via flags when starting the daemon: ```shell fpd start --home --log_level debug ``` - Important Log Events to Monitor + Important Log Events to Monitor: **Status Changes:** ```shell From aa26c709dbce5a6705678ffbf5b8d0ec31a21bc8 Mon Sep 17 00:00:00 2001 From: Sam Ricotta Date: Mon, 25 Nov 2024 16:50:31 +0200 Subject: [PATCH 40/53] Update finality-provider-operation.md --- docs/finality-provider-operation.md | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/docs/finality-provider-operation.md b/docs/finality-provider-operation.md index 7c184b7..1c514f6 100644 --- a/docs/finality-provider-operation.md +++ b/docs/finality-provider-operation.md @@ -589,12 +589,12 @@ To see the technical documentation for [sending finality votes](./send-finality- ### 5.5. Keyring maintenance and gas requirements -The keyring stores funds for gas fees and collects rewards. We recommend not holding a large number of funds here—just enough for operations. We are also exploring ways to support different withdrawal addresses. +The keyring stores funds for gas fees and collects rewards. We recommend **not** holding a large number of funds here—just enough for operations. We are also exploring ways to support different withdrawal addresses. We encourage the following for keyring maintenance: - **Backup Keys**: Use mnemonic phrases, export key files, or back up the home directory. -- **Monitor and Secure**: Regularly check for unauthorized activity. -- **Production Transition**: Replace the test keyring with a secure backend when available. +- **Monitor Regularly**: Check for unauthorized activity, monitor status changes, balance and gas usage. +- **Keyring Transition**: Replace the test keyring with a secure backend when available. For gas requirements, the finality provider daemon will automatically handle gas fees but we recommend monitoring the gas usage to ensure the finality provider is functioning properly. @@ -609,7 +609,7 @@ As a guide we recommend using the following formula to estimate gas requirements Estimated Gas = (Transaction Size) x (Gas Price) ``` -We recommend holding 2 x Estimated Gas in your keyring to ensure that the finality provider has enough gas to submit votes and other transactions. +We recommend holding `2 x Estimated Gas` worth of funds in your keyring to ensure that the finality provider has enough gas to submit votes and other transactions. To get your finality provider address, you can use the following command: @@ -623,6 +623,8 @@ To check your current balance, you must navigate to the Babylon chain and use th babylond query bank balances ``` +Keep track of your balance and gas usage to ensure your finality provider is functioning properly. + ### 5.6. Reading the logs The logs are stored based on your daemon home directories: @@ -693,7 +695,7 @@ randomness for a certain number of blocks, or not being responsive to the finality provider daemon. When jailed, the following happens to a finality provider: -- Their voting power becomes 0 +- Their voting power becomes `0` - Status is set to `JAILED` - Delegator rewards stop @@ -791,7 +793,7 @@ finality provider signs conflicting blocks at the same height. This results in the extraction of the provider's private key and automatically triggers shutdown of the finality provider, removal from the active set, jailing and compromised rewards. -> **Critical**: Slashing is irreversible and results in permanent removal from the network. +> ⚠️ **Critical**: Slashing is irreversible and results in permanent removal from the network. **Keyring Security 🔒**: The finality provider daemon uses the `--keyring-backend test` which stores keys unencrypted on disk. From 437b13ec0a1817a69be6f10ca5cc03ab9337271b Mon Sep 17 00:00:00 2001 From: Sam Ricotta Date: Mon, 25 Nov 2024 17:04:45 +0200 Subject: [PATCH 41/53] Update finality-provider-operation.md --- docs/finality-provider-operation.md | 21 ++++++++++----------- 1 file changed, 10 insertions(+), 11 deletions(-) diff --git a/docs/finality-provider-operation.md b/docs/finality-provider-operation.md index 1c514f6..44b4f2e 100644 --- a/docs/finality-provider-operation.md +++ b/docs/finality-provider-operation.md @@ -799,20 +799,19 @@ of the finality provider, removal from the active set, jailing and compromised r The finality provider daemon uses the `--keyring-backend test` which stores keys unencrypted on disk. While this is generally not secure, it's necessary for the finality provider service because: -* The daemon needs to automatically sign and send transactions frequently -* If transactions stop for too long, the provider gets jailed -* Using encrypted keystores would require manual password entry after every restart -* Service availability is critical to avoid jailing +- The daemon needs to automatically sign and send transactions frequently +- If transactions stop for too long, the provider gets jailed +- Using encrypted keystores would require manual password entry after every restart +- Service availability is critical to avoid jailing We are actively working on implementing more secure keyring solutions that maintain both security and high availability. **Security Best Practices 🔒**: Here are some best practices to secure your finality provider: -* Run EOTS Manager and Finality Provider on separate machine/network segment -* Regular system security audits -* Monitor for unauthorized activities -* Allow only necessary ports (`12581`, `12582`) -* Active monitoring of the logs - - +- Run EOTS Manager and Finality Provider on separate machine/network segment +- Monitor for unauthorized activities +- Keep track of your balance and gas usage +- Keep track of any status changes including jailing +- Allow only necessary ports (`12581`, `12582`) +- Active monitoring of the logs and installation of prometheus for metrics From 26b942df007b9c2c777d179f39f9a853bda05cfd Mon Sep 17 00:00:00 2001 From: Sam Ricotta Date: Mon, 25 Nov 2024 17:18:28 +0200 Subject: [PATCH 42/53] update monitoring --- docs/finality-provider-operation.md | 26 +++++++++----------------- 1 file changed, 9 insertions(+), 17 deletions(-) diff --git a/docs/finality-provider-operation.md b/docs/finality-provider-operation.md index 44b4f2e..7899858 100644 --- a/docs/finality-provider-operation.md +++ b/docs/finality-provider-operation.md @@ -209,7 +209,7 @@ eotsd init --home ~/.eotsd-phase2 > Please note that the above directory is just an example. Your directory will be located at the path you specified. -##### Verify the Key Import +#### Verify the Key Import After importing, you can verify that your EOTS key was successfully loaded: ```shell @@ -218,7 +218,7 @@ eotsd keys list --keyring-backend test --home Parameters: * ``: Name of the EOTS key to verify -* `--keyring-backend`: Type of keyring backend to use (default: test) +* `--keyring-backend`: Type of keyring backend to use (default: `test`) * `--home`: Directory containing EOTS Manager configuration and data You should see your EOTS key listed with the correct details, confirming that @@ -738,7 +738,7 @@ First, expose the metrics through the following Prometheus endpoints: - `Port 12581`: Finality Provider Daemon metrics - `Port 12582`: EOTS Manager metrics -Next we will enable metric collection in `app.toml` for your node and configure Prometheus to scrape the metrics. +Next we will enable metric collection in `app.toml` in both the finality provider daemon and the eots manager and configure Prometheus to scrape the metrics. ``` toml [telemetry] @@ -746,30 +746,22 @@ enabled = true prometheus-retention-time = 600 # 10 minutes [api] enable = true -address = "127.0.0.1:12581" # Secure RPC listener for Finality Provider Daemon +address = "127.0.0.1:12581" # change this to 127.0.0.1:12582 for the eots manager ``` -Restrict access to the EOTS Manager RPC by configuring it to listen only on `127.0.0.1:12582`. -Restart your Finality Provider node to apply these changes. -After enabling metrics in the app.toml, configure Prometheus to scrape these endpoints (prometheus.yml): +After making these changes: +1. Restart your EOTS Manager: `eotsd start` +2. Restart your Finality Provider Daemon: `fpd start` -``` yaml -scrape_configs: - - job_name: 'finality_provider' - static_configs: - - targets: ['localhost:12581', 'localhost:12582'] - metrics_path: '/metrics' - scrape_interval: 10s -``` Next we want you to download and install [Prometheus](https://prometheus.io/download/). -Then create a `prometheus.yml` file and add the following scrape configuration: +Then create a `prometheus.yml` file in both the finality provider daemon and the eots manager and add the following scrape configuration: ``` yaml scrape_configs: - job_name: 'finality_provider' static_configs: - - targets: ['localhost:12581', 'localhost:12582'] + - targets: ['localhost:12581'] # change this to localhost:12582 for the eots manager metrics_path: '/metrics' scrape_interval: 10s ``` From 6c8431ef19c7213f9a143bcfedcc11bbad31506b Mon Sep 17 00:00:00 2001 From: Sam Ricotta Date: Mon, 25 Nov 2024 17:27:19 +0200 Subject: [PATCH 43/53] Update README.md --- README.md | 3 --- 1 file changed, 3 deletions(-) diff --git a/README.md b/README.md index 2885d7d..4f1b7c3 100644 --- a/README.md +++ b/README.md @@ -110,7 +110,6 @@ providers: The daemon is controlled by the `fpd` tool, which provides commands for interacting with the running daemon. - ## Overview of Keys for Finality Provider and EOTS Manager There are two distinct keys you'll be working with: @@ -128,8 +127,6 @@ There are two distinct keys you'll be working with: - It's where staking rewards for the finality provider are sent. - Associated with a Babylon account that receives rewards - Stored in the finality provider daemon's keyring - - This account is controlled by the key you use to create and manage the - finality provider (the one you added with `fpd keys add`). This dual association allows the finality provider to interact with both the Bitcoin network (for security) and the Babylon network (for rewards and From 2f76fca8e8d5ef50135c80573bee213bcca26295 Mon Sep 17 00:00:00 2001 From: Vitalis Salis Date: Mon, 25 Nov 2024 19:13:59 +0200 Subject: [PATCH 44/53] more mess pt. 3 --- docs/finality-provider-operation.md | 586 ++++++++++++---------------- 1 file changed, 252 insertions(+), 334 deletions(-) diff --git a/docs/finality-provider-operation.md b/docs/finality-provider-operation.md index 7899858..ebe5601 100644 --- a/docs/finality-provider-operation.md +++ b/docs/finality-provider-operation.md @@ -3,7 +3,8 @@ This document guides operators through the complete lifecycle of running a finality provider, including: -* Installing and configuring the finality provider toolset (EOTS Manager and Finality Provider daemon) +* Installing and configuring the finality provider toolset + (EOTS Manager and Finality Provider daemon) * Managing keys (EOTS key for signatures and Babylon key for rewards) * Registering your finality provider on the Babylon network * Operating and maintaining your finality provider @@ -16,6 +17,8 @@ gain an overall understanding of the finality provider. ## Table of Contents + + 1. [A note about Phase-1 Finality Providers](#1-a-note-about-phase-1-finality-providers) 2. [Install Finality Provider Toolset](#2-install-finality-provider-toolset) 3. [Setting up the EOTS Daemon](#3-setting-up-the-eots-daemon) @@ -32,18 +35,18 @@ gain an overall understanding of the finality provider. 5. [Finality Provider Operation](#5-finality-provider-operations) 1. [Create Finality Provider](#51-create-finality-provider) 2. [Register Finality Provider](#52-register-finality-provider) + 3. [Withdrawing Rewards](#53-withdrawing-rewards) + 4. [Jailing and Unjailing](#54-jailing-and-unjailing) 3. [Public Randomness Submission](#53-public-randomness-submission) 4. [Submission of votes](#54-submission-of-votes) 5. [Keyring maintenance and gas requirements](#55-keyring-maintenance-and-gas-requirements) 6. [Reading the logs](#56-reading-the-logs) - 7. [Withdrawing Rewards](#57-withdrawing-rewards) - 8. [Jailing and Unjailing](#58-jailing-and-unjailing) 9. [Monitoring](#59-monitoring) 6. [Security and Slashing](#6-security-and-slashing) ## 1. A note about Phase-1 Finality Providers - +> ⚠️ **Critical**: Ensure that you use --> ## 2. Install Finality Provider Toolset -Download and install [Golang 1.23](https://go.dev/dl). -Verify the installation with the following command: +The finality provider toolset requires Golang 1.23](https://go.dev/dl) +to be installed. +Please follow the installation instructions [here](https://go.dev/dl). +You can verify the installation with the following command: ```shell go version @@ -68,7 +73,7 @@ go version ### 2.1. Clone the Finality Provider Repository -Subsequently clone the finality provider +Subsequently, clone the finality provider [repository](https://github.com/babylonlabs-io/finality-provider) and navigate to the `bbn-test-5` tag. @@ -81,7 +86,8 @@ git checkout ### 2.2. Build and Install Finality Provider Toolset Binaries -Run the following command to build the binaries and install them to your `$GOPATH/bin` directory: +Run the following command to build the binaries and +install them to your `$GOPATH/bin` directory: ```shell make install @@ -95,7 +101,6 @@ This command will: - Make commands globally accessible from your terminal ### 2.3. Verify Installation - Run the following command to verify the installation: ```shell @@ -110,9 +115,6 @@ version: v0.11.0 commit: 7d37c88e9a33c0b6a86614f743e9426ce6e31d4a ``` -> You wont be able to run `eots version` as its not supported yet but you can -> run `eotsd` to verify the installation. - If your shell cannot find the installed binaries, make sure `$GOPATH/bin` is in the `$PATH` of your shell. Use the following command to add it to your profile. @@ -143,33 +145,53 @@ Parameters: ### 3.2. Create/Add an EOTS Key + + #### 3.2.1. Import an existing EOTS key -> This section is for Finality Providers who participated in Phase-1 and already posess an EOTS key. ->If you are a new user, you can skip this section unless you would like to familiarize yourself ->with the backup and recovery process. +> ⚡ This section is for Finality Providers who participated in Phase-1 and +> already possess an EOTS key. If you are a new user, you can skip this section. -There are 3 supported methods of loading your existing EOTS keys: using a mnemonic phrase, -exporting the `.asc` file and backing up your entire home directory. We have outlined -each of these three paths for you below. +There are 3 supported methods of loading your existing EOTS keys: (1) using a mnemonic phrase, +(2) exporting the `.asc` file, or (3) backing up your entire home directory. +We have outlined each of these three paths for you below. -#### Using your Mnemonic Phrase +#### Option 1: Using your Mnemonic Phrase If you are using your mnemonic seed phrase, use the following command to import your key: + ```shell eotsd keys add --home --recover ``` You'll be prompted to enter: -1. Your bip39 mnemonic phrase (24 words) +1. Your BIP39 mnemonic phrase (24 words) 2. A passphrase to encrypt your key -3. HD path (optional - press Enter to use default) +3. HD path (optional - press Enter to use the default) -> The HD path is optional. If you used the default path when creating your key, +> ⚡ The HD path is optional. If you used the default path when creating your key, you can skip this by pressing Enter. -#### Using your `.asc` file +#### Option 2: Using your `.asc` file If you exported your key to a `.asc` file. The `.asc` file should be in the following format: @@ -185,31 +207,20 @@ VP88GFE= -----END TENDERMINT PRIVATE KEY----- ``` -To load your existing EOTS key, use the following command: +To load the key, use the following command: ```shell eotsd keys import --home --keyring-backend test ``` -#### Using Home Directory Backup +#### Option 3: Using Home Directory Backup -If you backed up your entire EOTS home directory or are using your `--home` directory. - -1. Check to see if the EOTS daemon is running. If it is, stop it. -2. Copy your backup directory or your old home directory to the new location. - -```shell -# Stop the EOTS daemon if running -# Copy your Phase-1 directory to Phase-2 location -cp -r ~/.eotsd ~/.eotsd-phase2 - -# Initialize it for Phase-2 -eotsd init --home ~/.eotsd-phase2 -``` -> Please note that the above directory is just an example. -Your directory will be located at the path you specified. +If you backed up your entire EOTS home directory, +you can load it manually to the machine you intend to operate +the EOTS daemon on and specify its location as the `--home` argument. #### Verify the Key Import + After importing, you can verify that your EOTS key was successfully loaded: ```shell @@ -225,15 +236,21 @@ You should see your EOTS key listed with the correct details, confirming that it has been imported correctly. >⚠️ **Important**: -> Make sure you're using the same key name and EOTS public key that were +> If you are a finality provider transitioning your stack from phase-1, +> make sure that you are using the same EOTS key that you +> registered in Phase-1. + + +> Make sure you're using the same key name and EOTS key that were > registered in Phase-1. #### 3.2.2. Create an EOTS key -If you have not created an EOTS key yet, use the following command to create a new one: +If you have not created an EOTS key, +use the following command to create a new one: ``` shell -eotsd keys add --key-name --home --keyring-backend test +eotsd keys add --key-name --home --keyring-backend test ``` Parameters: @@ -248,24 +265,24 @@ Parameters: The command will return a JSON response containing your EOTS key details: -```json +``` { "name": "eots", "pub_key_hex": "e1e72d270b90b24f395e76b417218430a75683bd07cf98b91cf9219d1c777c19", "mnemonic": "parade hybrid century project toss gun undo ocean exercise - figure decorate basket peace raw spot gap dose daring patch ski purchase - prefer can pair" + figure decorate basket peace raw spot gap dose daring patch ski purchase + prefer can pair" } ``` -> **Security Tip 🔒**: The mnemonic phrase must be stored securely and kept private, as it is the -only way to recover your EOTS key if access is lost and is critical for maintaining control -of your finality provider operations. +> **Security Tip 🔒**: The mnemonic phrase must be stored securely and kept private. +> It is the only way to recover your EOTS key if you lose access to it and +> if lost it can be used by third parties to get access to your key. ### 3.3. Starting the EOTS Daemon -To start the EOTS daemon using the following command: +To start the EOTS daemon use the following command: ```shell eotsd start --home @@ -279,16 +296,18 @@ by specifying a custom address with the `--rpc-listener` flag. 2024-10-30T12:42:29.393259Z info Metrics server is starting {"addr": "127.0.0.1:2113"} 2024-10-30T12:42:29.393278Z info RPC server listening {"address": "127.0.0.1:12582"} -2024-10-30T12:42:29.393363Z info EOTS Manager Daemon is fully active! -EOTS Manager Daemon is fully active! +2024-10-30T12:42:29.393363Z info EOTS Manager Daemon is fully active! +EOTS Manager Daemon is fully active! ``` >**Security Tip 🔒**: > * `eotsd` holds your private keys which are used for signing -> * keep it in a separate machine or network segment with enhanced security -> * only allow access to the RPC server specified by the `RPCListener` port to trusted sources. You can edit -the `EOTSManagerAddress` in the configuration file of the finality provider to -reference the address of the machine where `eotsd` is running +> * operate the daemon in a separate machine or network segment +> with enhanced security +> * only allow access to the RPC server specified by the `RPCListener` +> port to trusted sources. You can edit the `EOTSManagerAddress` in +> the configuration file of the finality provider to +> reference the address of the machine where `eotsd` is running ## 4. Setting up the Finality Provider @@ -296,44 +315,97 @@ reference the address of the machine where `eotsd` is running To initialize the finality provider daemon, use the following command: -```shell +```shell fpd init --home ``` -> Running this command may return the message -`service injective.evm.v1beta1.Msg does not have cosmos.msg.v1.service proto annotation`, -which is expected and can be ignored. + +> ⚡ Running this command may return the message +> `service injective.evm.v1beta1.Msg does not have cosmos.msg.v1.service proto annotation`, +> which is expected and can be ignored. ### 4.2. Add key for the Babylon account -For the Finality Provider Daemon, the keyring is kept in the local storage of the finality provider daemon. -The key associates a Babylon account with the finality provider to receive BTC -delegation rewards. +Each finality provider maintains a Babylon keyring containing +an account that is used to receive BTC Staking reward commissions and +pay for fees associated with the submission of the transactions required +for the finality provider's operation. -Use the following command to add the Babylon key for your finality provider: +As this key is used by an automated daemon process, +it is required to be accessed unencrypted on disk +and associated with a `test` keyring backend. +The above is to ensure that the finality provider daemon +can timely submit transactions that are essential for +its liveness and receiving of rewards. -```shell -fpd keys add --keyname --keyring-backend test --home -``` + + + +>Keep only enough funds in the keyring for operations, which you can view [here](#keyring-maintenance-and-gas-requirements). +We are also exploring options to support different withdrawal addresses. + +>We use the `--keyring-backend test`, +> which stores keys unencrypted on disk. This backend is suitable +for testing but not recommended for large fund storage. +> Rewards from Finality Provider commissions +are stored in this keyring. Other keyring backends are not supported yet, +> and prolonged inactivity (missing transactions) can lead to your +> Finality Provider being jailed. +> >⚠️ **Important**: ->To operate your Finality Provider, ensure your Babylon account is funded. Block vote transactions -have their gas fees refunded, but public randomness submissions require gas payments. For testnet, +>To operate your Finality Provider, ensure your Babylon account is funded. Block vote transactions +have their gas fees refunded, but public randomness submissions require gas payments. For testnet, you can obtain funds from our [faucet](#add-faucet). ->We use the `--keyring-backend test`, which stores keys unencrypted on disk. This backend is suitable -for testing but not recommended for large fund storage. Rewards from Finality Provider commissions -are stored in this keyring. Other keyring backends are not supported yet, and prolonged inactivity -(missing transactions) can lead to your Finality Provider being jailed. +We recommend **not** holding a large number of funds here—just enough for operations. +We are also exploring ways to support different withdrawal addresses. ->Keep only enough funds in the keyring for operations, which you can view [here](#keyring-maintenance-and-gas-requirements). -We are also exploring options to support different withdrawal addresses. +We encourage the following for keyring maintenance: +- **Backup Keys**: Use mnemonic phrases, export key files, or back up the home directory. +- **Monitor Regularly**: Check for unauthorized activity, monitor status changes, + balance and gas usage. +- **Keyring Transition**: Replace the test keyring with a secure backend when available. + +For gas requirements, the finality provider daemon will +automatically handle gas fees, but we recommend monitoring +the gas usage to ensure the finality provider is functioning properly. + +The transaction types that consume gas are: +- `MsgRegisterFinalityProvider`: Registration (requires gas) +- `MsgSubmitFinalityVote`: Block vote transactions (gas is refunded) +- `MsgCommitPubRandList`: Public randomness submissions (requires gas) + +**Keyring Security 🔒**: +The finality provider daemon uses the `--keyring-backend test` which stores keys unencrypted on disk. +While this is generally not secure, it's necessary for the finality provider service because: + +- The daemon needs to automatically sign and send transactions frequently +- If transactions stop for too long, the provider gets jailed +- Using encrypted keystores would require manual password entry after every restart +- Service availability is critical to avoid jailing + +We are actively working on implementing more secure keyring solutions that maintain both security +and high availability. + +Use the following command to add the Babylon key for your finality provider: + +```shell +fpd keys add --keyname --keyring-backend test --home +``` The above `keys add` command will create a new key pair and store it in your keyring. The output should look similar to the below: - ``` json { "address": "bbn19gulf0a4yz87twpjl8cxnerc2wr2xqm9fsygn9", @@ -392,7 +464,7 @@ registration or voting participation. Start the daemon with: ``` shell -fpd start --home +fpd start --home ``` An example of the `--home` flag is `--home ./fpHome`. @@ -438,34 +510,35 @@ instance locally. ``` shell fpd create-finality-provider \ ---daemon-address 127.0.0.1:12581 \ ---chain-id bbn-test-5 \ ---eots-pk \ //this is the EOTS public key of the finality provider which was generated in -`eotsd keys add` ---commission 0.05 \ ---key-name finality-provider \ ---moniker "MyFinalityProvider" \ ---website "https://myfinalityprovider.com" \ ---security-contact "security@myfinalityprovider.com" \ ---details "finality provider for the Babylon network" \ ---home ./fp \ --passphrase "passphrase" + --daemon-address 127.0.0.1:12581 \ + --chain-id bbn-test-5 \ + --eots-pk \ + --commission 0.05 \ + --key-name finality-provider \ + --moniker "MyFinalityProvider" \ + --website "https://myfinalityprovider.com" \ + --security-contact "security@myfinalityprovider.com" \ + --details "finality provider for the Babylon network" \ + --home ./fp \ + --passphrase "passphrase" ``` Required parameters: - `--chain-id`: The Babylon chain ID (`bbn-test-5`) - `--commission`: The commission rate (between 0 and 1) that you'll receive from -delegators -- `--key-name`: Name of the key in your keyring for signing -transactions + delegators +- `--key-name`: The key name in your Babylon keyring that your finality + provider will be associated with - `--moniker`: A human-readable name for your finality provider Optional parameters: -- `--eots-pk`: The EOTS public key of the finality provider which was generated in `eotsd keys add` +- `--eots-pk`: The EOTS public key of the finality provider + - - `--website`: Your finality provider's website - `--security-contact`: Contact email for security issues -- `--details`: -Additional description of your finality provider -- `--daemon-address`: RPC address of the finality provider daemon (default: `127.0.0.1:12581`) +- `--details`: Additional description of your finality provider +- `--daemon-address`: RPC address of the finality provider daemon + (default: `127.0.0.1:12581`) Upon successful creation, the command will return a JSON response containing your finality provider's details: @@ -489,13 +562,13 @@ your finality provider's details: The response includes: - `fp_addr`: Your Babylon account address for receiving -rewards + rewards - `eots_pk_hex`: Your unique BTC public key identifier (needed for -registration) + registration) - `description`: Your finality provider's metadata -- `commission`: -Your set commission rate -- `status`: Current status of the finality provider +- `commission`: Your set commission rate +- `status`: Current status of the finality provider. + - ### 5.2. Register Finality Provider @@ -503,28 +576,24 @@ The `register-finality-provider` command registers your finality provider on the Babylon chain. This command requires: 1. The EOTS public key -2. A funded Babylon account (needs BBN tokens for transaction fees). -This account will be bonded to your finality provider and used to claim rewards. -3. A running FPD daemon +2. The Babylon account associated with your finality provider + (the one specified in the creation) having sufficient funds + to pay for the transaction fee. +3. A running fpd daemon ``` shell fpd register-finality-provider \ - \ ---daemon-address \ ---passphrase \ ---home \ + \ + --daemon-address \ + --home ``` Parameters: -- ``: Your EOTS public key (obtained from running `eotsd keys show `) -(e.g., `cf0f03b9ee2d4a0f27240e2d8b8c8ef609e24358b2eb3cfd89ae4e4f472e1a41`) -- `--daemon-address`: RPC address of your finality provider daemon (default: `127.0.0.1:12581`) -- `--passphrase`: Passphrase for your key +- ``: The EOTS public key of the finality provider you want to register + (e.g., `cf0f03b9ee2d4a0f27240e2d8b8c8ef609e24358b2eb3cfd89ae4e4f472e1a41`) +- `--daemon-address`: RPC address of the finality provider daemon + (default: `127.0.0.1:12581`) - `--home`: Path to your finality provider daemon home directory (e.g., `~/.fpdHome`) -- `--keyring-backend`: Type of keyring storage (use `test` for testing, `file` for production) - -> The BTC public key (`cf0f03...1a41`) is obtained from the previous -`eotsd keys add` command. If successful, the command will return a transaction hash: @@ -536,163 +605,32 @@ If successful, the command will return a transaction hash: You can verify the transaction was successful by looking up this transaction hash on the Babylon chain. -The hash returned should look similar to below: - -```shell - type: message -- attributes: - - index: true - key: fp value: - '{ - "addr":"bbn1ht2nxa6hlyl89m8xpdde9xsj40n0sxd2f9shsq", - "description": - { - "moniker":"MyFinalityProvider", - "identity":" - ","website":"https://myfinalityprovider.com", - "security_contact":"security@myfinalityprovider.com", - "details":"Reliablefinality provider for the Babylon - network" - }, - "commission":"0.050000000000000000", - "btc_pk":"cf0f03b9ee2d4a0f27240e2d8b8c8ef609e24358b2eb3cfd89ae4e4f472e1a41", - "pop":{"btc_sig_type":"BIP340", - "btc_sig":"YJgc6NU7Z011imqSfPc9w/Namr1hFj48oTlEjGqbAVvHJv+9h3p/1shTohEb1g0fDWij7Ti9yKZzjAgNVepObA=="}, - "slashed_babylon_height":"0", - "slashed_btc_height":"0", - "jailed":false, - "consumer_id":"euphrates-0.5.0" - }' - - index: true - key: msg_index value: "0" - type: babylon.btcstaking.v1.EventNewFinalityProvider -gas_used: "82063" gas_wanted: "94429" height: "66693" info: "" logs: [] raw_log:"" -``` - -### 5.3. Public Randomness Submission - -For detailed information about public randomness commits, see: -* [Technical Overview](./docs/commit-pub-rand.md) -* [Core Implementation Details](./fp-core.md#committing-public-randomness) - -### 5.4. Submission of votes - -There is a responsibility for the finality providers to submit votes to finalize blocks on the consumer chain. The finality provider daemon automatically handles vote submission for finality providers. - -To see the logs of the finality provider daemon, you can use the following command: - -``` shell -tail -f /logs/fpd.log | grep "successfully submitted a finality signature to the consumer chain" -``` - -To see the technical documentation for [sending finality votes](./send-finality-vote.md) - -### 5.5. Keyring maintenance and gas requirements - -The keyring stores funds for gas fees and collects rewards. We recommend **not** holding a large number of funds here—just enough for operations. We are also exploring ways to support different withdrawal addresses. - -We encourage the following for keyring maintenance: -- **Backup Keys**: Use mnemonic phrases, export key files, or back up the home directory. -- **Monitor Regularly**: Check for unauthorized activity, monitor status changes, balance and gas usage. -- **Keyring Transition**: Replace the test keyring with a secure backend when available. - -For gas requirements, the finality provider daemon will automatically handle gas fees but we recommend monitoring the gas usage to ensure the finality provider is functioning properly. - -The transaction types that consume gas are: -- `MsgRegisterFinalityProvider`: Registration (requires gas) -- `MsgSubmitFinalityVote`: Block vote transactions (gas is refunded) -- `MsgCommitPubRandList`: Public randomness submissions (requires gas) - -As a guide we recommend using the following formula to estimate gas requirements: + -When withdrawing rewards, you need to use the Babylon chain's CLI since rewards -are managed by the main chain. +### 5.3. Withdrawing Rewards -To withdraw your finality provider rewards: + -``` babylond tx incentive finality_provider ... ``` +### 5.4. Jailing and Unjailing - +A finality provider can be jailed for the following reasons: +- Not voting for a certain number of blocks +- Not committing public randomness for a certain number of blocks. -### 5.8. Jailing and Unjailing +The specific parameters specifying the exact metrics that are taken +into account for jailing and the period of unjailing +is controlled by the Babylon chain governance. -A finality provider can be jailed for various reasons, -including not signing for a certain number of blocks, not committing public -randomness for a certain number of blocks, or not being responsive to the -finality provider daemon. + When jailed, the following happens to a finality provider: - Their voting power becomes `0` @@ -713,14 +651,48 @@ Parameters: - `--daemon-address`: RPC server address of fpd (default: `127.0.0.1:12581`) - `--home`: Path to your finality provider daemon home directory -> Before unjailing, ensure you've fixed the underlying issue that caused jailing +> ⚠️ Before unjailing, ensure you've fixed the underlying issue that caused jailing -So while slashing is permanent, jailing is a temporary state that can be recovered -from through the unjailing process, as long as the finality provider wasn't slashed. +### 5.5. Slashing + +**Slashing occurs** when a finality provider **double signs**, meaning that the +finality provider signs conflicting blocks at the same height. This results in +the extraction of the finality provider's private key and their immediate +removal from the active set. -### 5.9. Monitoring +> ⚠️ **Critical**: Slashing is irreversible and results in +> permanent removal from the network. -We want to monitor the following metrics to ensure the health and performance of your Finality Provider: +## 6. Prometheus Metrics + + + +The daemon services of the finality provider stack +export Prometheus metrics to support their monitoring. +In this section, we highlight some key Prometheus metrics +to monitor for. + +To configure the metrics: +.... + +### 7.1. EOTS Daemon +... + +### 7.2. Finality Provider Daemon +... + +The finality provider stack exports Prometheus metrics +to support the monitoring of + +We want to monitor the following metrics to +ensure the health and performance of the Finality Provider: - Public randomness commitment success/failure - Double-signing attempts @@ -731,79 +703,25 @@ We want to monitor the following metrics to ensure the health and performance of - RPC endpoint availability - Gas usage and balance -There are several ways to monitor these metrics but we suggest using Prometheus. +There are several ways to monitor these metrics, +but we suggest using Prometheus. First, expose the metrics through the following Prometheus endpoints: - `Port 12581`: Finality Provider Daemon metrics - `Port 12582`: EOTS Manager metrics -Next we will enable metric collection in `app.toml` in both the finality provider daemon and the eots manager and configure Prometheus to scrape the metrics. + +Next we will enable metric collection in `app.toml` +in both the finality provider daemon and the eots manager and +configure Prometheus to scrape the metrics. -``` toml +```toml [telemetry] enabled = true prometheus-retention-time = 600 # 10 minutes + [api] enable = true address = "127.0.0.1:12581" # change this to 127.0.0.1:12582 for the eots manager -``` - -After making these changes: -1. Restart your EOTS Manager: `eotsd start` -2. Restart your Finality Provider Daemon: `fpd start` - - -Next we want you to download and install [Prometheus](https://prometheus.io/download/). -Then create a `prometheus.yml` file in both the finality provider daemon and the eots manager and add the following scrape configuration: - -``` yaml -scrape_configs: - - job_name: 'finality_provider' - static_configs: - - targets: ['localhost:12581'] # change this to localhost:12582 for the eots manager - metrics_path: '/metrics' - scrape_interval: 10s -``` - -Then start Prometheus using the following command: - -``` shell -./prometheus --config.file=prometheus.yml -``` - -Once Prometheus is running: - -- Open the Prometheus web interface in your browser (default: `http://localhost:9090`). -- Navigate to Status > Targets. -- Confirm that the endpoints `localhost:12581` and `localhost:12582` are listed and their status is UP. - -## 6. Security and Slashing - -**Slashing occurs** when a finality provider **double signs**. This occurs when a -finality provider signs conflicting blocks at the same height. This results in -the extraction of the provider's private key and automatically triggers shutdown -of the finality provider, removal from the active set, jailing and compromised rewards. - -> ⚠️ **Critical**: Slashing is irreversible and results in permanent removal from the network. - -**Keyring Security 🔒**: -The finality provider daemon uses the `--keyring-backend test` which stores keys unencrypted on disk. -While this is generally not secure, it's necessary for the finality provider service because: - -- The daemon needs to automatically sign and send transactions frequently -- If transactions stop for too long, the provider gets jailed -- Using encrypted keystores would require manual password entry after every restart -- Service availability is critical to avoid jailing - -We are actively working on implementing more secure keyring solutions that maintain both security -and high availability. - -**Security Best Practices 🔒**: -Here are some best practices to secure your finality provider: -- Run EOTS Manager and Finality Provider on separate machine/network segment -- Monitor for unauthorized activities -- Keep track of your balance and gas usage -- Keep track of any status changes including jailing -- Allow only necessary ports (`12581`, `12582`) -- Active monitoring of the logs and installation of prometheus for metrics +``` \ No newline at end of file From 9dea21de326c13c5eac165076a3876a0c9233912 Mon Sep 17 00:00:00 2001 From: Sam Ricotta Date: Tue, 26 Nov 2024 14:04:15 +0200 Subject: [PATCH 45/53] wip --- docs/finality-provider-operation.md | 261 +++++++++--------- ...df3a623b30a27735b1fe1fda6c6756fa0c.address | 1 + ...58a6bde1e41865fa1da8485fedeea6f6e1.address | 1 + eotsKey/keyring-file/keyhash | 1 + eotsKey/keyring-file/sam1.info | 1 + eotsKey/keyring-file/sam2.info | 1 + ...42b859ca5ff2cd98602d2177d703560c32.address | 1 + eotsKey/keyring-test/sam5.info | 1 + 8 files changed, 138 insertions(+), 130 deletions(-) create mode 100644 eotsKey/keyring-file/c3cd0bdf3a623b30a27735b1fe1fda6c6756fa0c.address create mode 100644 eotsKey/keyring-file/de3e9658a6bde1e41865fa1da8485fedeea6f6e1.address create mode 100644 eotsKey/keyring-file/keyhash create mode 100644 eotsKey/keyring-file/sam1.info create mode 100644 eotsKey/keyring-file/sam2.info create mode 100644 eotsKey/keyring-test/b8a54342b859ca5ff2cd98602d2177d703560c32.address create mode 100644 eotsKey/keyring-test/sam5.info diff --git a/docs/finality-provider-operation.md b/docs/finality-provider-operation.md index ebe5601..d11cbf5 100644 --- a/docs/finality-provider-operation.md +++ b/docs/finality-provider-operation.md @@ -17,8 +17,6 @@ gain an overall understanding of the finality provider. ## Table of Contents - - 1. [A note about Phase-1 Finality Providers](#1-a-note-about-phase-1-finality-providers) 2. [Install Finality Provider Toolset](#2-install-finality-provider-toolset) 3. [Setting up the EOTS Daemon](#3-setting-up-the-eots-daemon) @@ -37,27 +35,25 @@ gain an overall understanding of the finality provider. 2. [Register Finality Provider](#52-register-finality-provider) 3. [Withdrawing Rewards](#53-withdrawing-rewards) 4. [Jailing and Unjailing](#54-jailing-and-unjailing) - 3. [Public Randomness Submission](#53-public-randomness-submission) - 4. [Submission of votes](#54-submission-of-votes) - 5. [Keyring maintenance and gas requirements](#55-keyring-maintenance-and-gas-requirements) - 6. [Reading the logs](#56-reading-the-logs) - 9. [Monitoring](#59-monitoring) -6. [Security and Slashing](#6-security-and-slashing) + 5. [Slashing](#55-slashing) + 6. [Monitoring](#56-monitoring) +6. [Prometheus Metrics](#6-prometheus-metrics) ## 1. A note about Phase-1 Finality Providers - +- If you already have delegations and have set up a key during Phase-1, + please proceed to [Adding Keys](#32-createadd-an-eots-key) to import your + Phase-1 key. +- If you are just starting out, you can begin with the setup steps outlined below. ## 2. Install Finality Provider Toolset @@ -74,8 +70,8 @@ go version ### 2.1. Clone the Finality Provider Repository Subsequently, clone the finality provider -[repository](https://github.com/babylonlabs-io/finality-provider) and navigate to the -`bbn-test-5` tag. +[repository](https://github.com/babylonlabs-io/finality-provider) and navigate +to the `bbn-test-5` tag. ```shell @@ -145,42 +141,43 @@ Parameters: ### 3.2. Create/Add an EOTS Key - +This section explains the process of setting up the private keys for the +EOTS manager. Operators *must* create an EOTS key before starting the +EOTS daemon. We will be using the [cosmos-sdk](https://docs.cosmos.network/v0.52/user/run-node/keyring) backends for key storage. Below is an overview of the supported keyrings and their + usecases. + +For storing the key, the following keyrings are supported: `test`, `os`, `file`. +- `test` is a password-less keyring and is unencrypted on disk. +- `os` uses the system's secure keyring and will prompt for a passphrase at startup. +- `file` encrypts the keyring with a passphrase and stores it on disk. + +Operators can choose whether to keep the key encrypted or unencrypted on disk +based on their requirements. However, for production workloads, we recommend +using the os or file keyrings for enhanced security. + +For consistency purposes, we will be using the `test` keyring throughout the +rest of the document. + +- If you already have an existing key from Phase-1, proceed to + [Import an existing EOTS key](#321-import-an-existing-eots-key) +- If you need to create a new key, proceed to [Create an EOTS key](#32-createadd-an-eots-key). #### 3.2.1. Import an existing EOTS key > ⚡ This section is for Finality Providers who participated in Phase-1 and > already possess an EOTS key. If you are a new user, you can skip this section. -There are 3 supported methods of loading your existing EOTS keys: (1) using a mnemonic phrase, -(2) exporting the `.asc` file, or (3) backing up your entire home directory. -We have outlined each of these three paths for you below. +There are 3 supported methods of loading your existing EOTS keys: (1) using a +mnemonic phrase, (2) exporting the `.asc` file, or (3) backing up your entire +home directory. We have outlined each of these three paths for you below. #### Option 1: Using your Mnemonic Phrase -If you are using your mnemonic seed phrase, use the following command to import your key: - +If you are using your mnemonic seed phrase, use the following command to import +your key: ```shell -eotsd keys add --home --recover +eotsd keys add --home --recover --keyring-backend test ``` You'll be prompted to enter: @@ -193,7 +190,8 @@ you can skip this by pressing Enter. #### Option 2: Using your `.asc` file -If you exported your key to a `.asc` file. The `.asc` file should be in the following format: +If you exported your key to a `.asc` file. The `.asc` file should be in the +following format: ``` -----BEGIN TENDERMINT PRIVATE KEY----- @@ -224,7 +222,7 @@ the EOTS daemon on and specify its location as the `--home` argument. After importing, you can verify that your EOTS key was successfully loaded: ```shell -eotsd keys list --keyring-backend test --home +eotsd keys list --home --keyring-backend test ``` Parameters: @@ -240,10 +238,6 @@ it has been imported correctly. > make sure that you are using the same EOTS key that you > registered in Phase-1. - -> Make sure you're using the same key name and EOTS key that were -> registered in Phase-1. - #### 3.2.2. Create an EOTS key If you have not created an EOTS key, @@ -254,8 +248,8 @@ eotsd keys add --key-name --home --keyring-backend test ``` Parameters: -- ``: Name for your EOTS key (e.g., "eots-key-1"). We do not allow the same -`keyname` for an existing keyname. +- ``: Name for your EOTS key (e.g., "eots-key-1"). We do not allow +the same `keyname` for an existing keyname. - `--home`: Path to your EOTS daemon home directory (e.g., "~/.eotsHome") - `--keyring-backend`: Type of keyring storage: - `test`: Stores keys unencrypted, no passphrase prompts @@ -289,14 +283,14 @@ eotsd start --home ``` This command starts the EOTS RPC server at the address specified in `eotsd.conf` -under the `RPCListener` field (default: `127.0.0.1:12582`). You can override this value -by specifying a custom address with the `--rpc-listener` flag. +under the `RPCListener` field (default: `127.0.0.1:12582`). You can override +this value by specifying a custom address with the `--rpc-listener` flag. ```shell -2024-10-30T12:42:29.393259Z info Metrics server is starting +2024-10-30T12:42:29.393259Z info Metrics server is starting {"addr": "127.0.0.1:2113"} -2024-10-30T12:42:29.393278Z info RPC server listening {"address": "127.0.0.1:12582"} -2024-10-30T12:42:29.393363Z info EOTS Manager Daemon is fully active! +2024-10-30T12:42:29.393278Z info RPC server listening{"address": "127.0.0.1:12582"} +2024-10-30T12:42:29.393363Z info EOTS Manager Daemon is fully active! EOTS Manager Daemon is fully active! ``` @@ -327,54 +321,43 @@ fpd init --home ### 4.2. Add key for the Babylon account Each finality provider maintains a Babylon keyring containing -an account that is used to receive BTC Staking reward commissions and -pay for fees associated with the submission of the transactions required -for the finality provider's operation. - -As this key is used by an automated daemon process, -it is required to be accessed unencrypted on disk -and associated with a `test` keyring backend. -The above is to ensure that the finality provider daemon -can timely submit transactions that are essential for -its liveness and receiving of rewards. - - - - - ->Keep only enough funds in the keyring for operations, which you can view [here](#keyring-maintenance-and-gas-requirements). -We are also exploring options to support different withdrawal addresses. +an account used to receive BTC Staking reward commissions and pay fees for +transactions necessary for the finality provider's operation. + +Since this key is accessed by an automated daemon process, it must be stored +unencrypted on disk and associated with the `test` keyring backend. +This ensures that the finality provider daemon can promptly submit +transactions, such as block votes and public randomness submissions that are +essential for its liveness and earning rewards. + +For the `fpd` keyring, the `test` backend will be exclusively used, and it is +mandatory that you follow this practice until automated key management becomes +available. Additionally, we are also exploring options to support different +withdrawal addresses. + +It is also important to note that the finality provider daemon will refund +certain fees, such as those for transactions that are required for the +finality provider's operation. As this keyring is used for both earning and +operational purposes, we strongly recommend maintaining only the necessary +funds for operations in the keyring. ->We use the `--keyring-backend test`, -> which stores keys unencrypted on disk. This backend is suitable -for testing but not recommended for large fund storage. -> Rewards from Finality Provider commissions -are stored in this keyring. Other keyring backends are not supported yet, -> and prolonged inactivity (missing transactions) can lead to your -> Finality Provider being jailed. -> >⚠️ **Important**: ->To operate your Finality Provider, ensure your Babylon account is funded. Block vote transactions -have their gas fees refunded, but public randomness submissions require gas payments. For testnet, -you can obtain funds from our [faucet](#add-faucet). +>To operate your Finality Provider, ensure your Babylon account is funded. +>Block vote transactions have their gas fees refunded, but public randomness +>submissions require gas payments. For testnet, you can obtain funds from our +>[faucet](#add-faucet). -We recommend **not** holding a large number of funds here—just enough for operations. -We are also exploring ways to support different withdrawal addresses. +We recommend **not** holding a large number of funds here—just enough for +operations. We are also exploring ways to support different withdrawal addresses. We encourage the following for keyring maintenance: -- **Backup Keys**: Use mnemonic phrases, export key files, or back up the home directory. +- **Backup Keys**: Use mnemonic phrases, export key files, or back up the home +directory. - **Monitor Regularly**: Check for unauthorized activity, monitor status changes, balance and gas usage. -- **Keyring Transition**: Replace the test keyring with a secure backend when available. +- **Keyring Transition**: Replace the test keyring with a secure backend when +available. For gas requirements, the finality provider daemon will automatically handle gas fees, but we recommend monitoring @@ -386,16 +369,17 @@ The transaction types that consume gas are: - `MsgCommitPubRandList`: Public randomness submissions (requires gas) **Keyring Security 🔒**: -The finality provider daemon uses the `--keyring-backend test` which stores keys unencrypted on disk. -While this is generally not secure, it's necessary for the finality provider service because: +The finality provider daemon uses the `--keyring-backend test` which stores keys +unencrypted on disk. While this is generally not secure, it's necessary for the +finality provider service because: - The daemon needs to automatically sign and send transactions frequently - If transactions stop for too long, the provider gets jailed - Using encrypted keystores would require manual password entry after every restart - Service availability is critical to avoid jailing -We are actively working on implementing more secure keyring solutions that maintain both security -and high availability. +We are actively working on implementing more secure keyring solutions that maintain +both security and high availability. Use the following command to add the Babylon key for your finality provider: @@ -425,7 +409,8 @@ signing. ### 4.3. Configure Your Finality Provider -Edit the `config.toml` file in your finality provider home directory with the following parameters: +Edit the `config.toml` file in your finality provider home directory with the +following parameters: ```shell [Application Options] @@ -440,9 +425,11 @@ GRPCAddr = https://127.0.0.1:9090 KeyDirectory = # The `--home`path to the directory where the keyring is stored ``` -> ⚠️ **Important**: Operating a finality provider requires a connection to a Babylon blockchain node. -> It is **highly recommended** to operate your own Babylon full node instead of relying on third parties. -> You can find instructions on setting up a Babylon node [here](https://github.com/babylonlabs-io/networks/tree/main/bbn-1/node-setup). +> ⚠️ **Important**: Operating a finality provider requires a connection to a +> Babylon blockchain node. It is **highly recommended** to operate your own +> Babylon full node instead of relying on third parties. You can find +> instructions on setting up a Babylon node +> [here](https://github.com/babylonlabs-io/networks/tree/main/bbn-1/node-setup). Configuration parameters explained: * `EOTSManagerAddress`: Address where your EOTS daemon is running @@ -482,9 +469,9 @@ You should see logs indicating successful startup: [INFO] RPC server listening on... ``` ->⚠️ **Important**: The daemon needs to run continuously. It's recommended to set up a system ->service (like `systemd` on Linux or `launchd` on macOS) to manage the daemon ->process, handle automatic restarts, and collect logs. For testing purposes, +>⚠️ **Important**: The daemon needs to run continuously. It's recommended to set +>up a system service (like `systemd` on Linux or `launchd` on macOS) to manage +>the daemon process, handle automatic restarts, and collect logs. For testing you can run the daemon directly in a terminal, but remember it must stay running to function properly. @@ -512,14 +499,14 @@ instance locally. fpd create-finality-provider \ --daemon-address 127.0.0.1:12581 \ --chain-id bbn-test-5 \ - --eots-pk \ + --eots-pk \ # this was output in fpd keys add --commission 0.05 \ --key-name finality-provider \ --moniker "MyFinalityProvider" \ --website "https://myfinalityprovider.com" \ --security-contact "security@myfinalityprovider.com" \ --details "finality provider for the Babylon network" \ - --home ./fp \ + --home ./fpHome \ --passphrase "passphrase" ``` @@ -532,8 +519,9 @@ Required parameters: - `--moniker`: A human-readable name for your finality provider Optional parameters: -- `--eots-pk`: The EOTS public key of the finality provider - - +- `--eots-pk`: The EOTS public key of the finality provider. If one is not +provided a new one will be created but please use the same EOTS key that you +generated in `fpd keys add` - `--website`: Your finality provider's website - `--security-contact`: Contact email for security issues - `--details`: Additional description of your finality provider @@ -568,7 +556,20 @@ The response includes: - `description`: Your finality provider's metadata - `commission`: Your set commission rate - `status`: Current status of the finality provider. - - + + +Below you can see a list of the statuses that a finality provider can transition +to: + +``` + - `CREATED`: defines a finality provider that is awaiting registration + - `REGISTERED`: defines a finality provider that has been registered + to the consumer chain but has no delegated stake + - `ACTIVE`: defines a finality provider that is delegated to vote + - `INACTIVE`: defines a finality provider whose delegations are reduced to + zero but not slashed + - `JAILED`: defines a finality provider that has been jailed +``` ### 5.2. Register Finality Provider @@ -589,8 +590,8 @@ fpd register-finality-provider \ ``` Parameters: -- ``: The EOTS public key of the finality provider you want to register - (e.g., `cf0f03b9ee2d4a0f27240e2d8b8c8ef609e24358b2eb3cfd89ae4e4f472e1a41`) +- ``: The EOTS public key of the finality provider you want to +register (e.g., `cf0f03b9ee2d4a0f27240e2d8b8c8ef609e24358b2eb3cfd89ae4e4f472e1a41`) - `--daemon-address`: RPC address of the finality provider daemon (default: `127.0.0.1:12581`) - `--home`: Path to your finality provider daemon home directory (e.g., `~/.fpdHome`) @@ -605,6 +606,9 @@ If successful, the command will return a transaction hash: You can verify the transaction was successful by looking up this transaction hash on the Babylon chain. + + + +As a participant in the Finality Provider Program, you will earn rewards that +can be withdrawn. The functionality for withdrawing rewards is currently under +development and will be available soon. Further updates will be provided once +this feature is implemented. ### 5.4. Jailing and Unjailing A finality provider can be jailed for the following reasons: -- Not voting for a certain number of blocks -- Not committing public randomness for a certain number of blocks. +1. Missing Votes + - Not submitting finality votes for a certain number of blocks + - Missing votes when the FP has positive voting power + +2. Missing Public Randomness + - Not committing public randomness for blocks + - Required before voting can occur The specific parameters specifying the exact metrics that are taken into account for jailing and the period of unjailing is controlled by the Babylon chain governance. - - When jailed, the following happens to a finality provider: - Their voting power becomes `0` - Status is set to `JAILED` @@ -682,12 +689,6 @@ to monitor for. To configure the metrics: .... -### 7.1. EOTS Daemon -... - -### 7.2. Finality Provider Daemon -... - The finality provider stack exports Prometheus metrics to support the monitoring of diff --git a/eotsKey/keyring-file/c3cd0bdf3a623b30a27735b1fe1fda6c6756fa0c.address b/eotsKey/keyring-file/c3cd0bdf3a623b30a27735b1fe1fda6c6756fa0c.address new file mode 100644 index 0000000..5c02764 --- /dev/null +++ b/eotsKey/keyring-file/c3cd0bdf3a623b30a27735b1fe1fda6c6756fa0c.address @@ -0,0 +1 @@ +eyJhbGciOiJQQkVTMi1IUzI1NitBMTI4S1ciLCJjcmVhdGVkIjoiMjAyNC0xMS0yNiAxMToxMjowNi4zOTI2NjUgKzAyMDAgRUVUIG09KzUuMjM4ODY4Mzc2IiwiZW5jIjoiQTI1NkdDTSIsInAyYyI6ODE5MiwicDJzIjoiLTV5RFQ5TEY5NUhWWHQ0cCJ9.T8GPy2zgeLwramglyTJSuKB2KJI7ZSTK_6qdChHnH1BZUGasPhvp8w.zWX1pn7ivyZ7MJlg.gS6CSKsK7_UX3YFdBjxd2RdA1NJQEMce2nxnNJcIoRLQ_r7K1IyyGheibRMsJIWiCz5DpVF5CnQzrCQ2k5c6_FCszD8uG6zY_RaWWvSBUvKfQBEw1jhor3u0OCtKb3UW8AnROnKWpdpvobZh9UKhatGodWyHDx9F1QTFysgnLvA2N3xYz6g1W5gDsi8zPL9b0zNX-k8JSOfdljoRYnkOYeH7MSbyfFe-vx10wEi7XpZFRw.0NxsB0llg6OoLpuz4hZJOw \ No newline at end of file diff --git a/eotsKey/keyring-file/de3e9658a6bde1e41865fa1da8485fedeea6f6e1.address b/eotsKey/keyring-file/de3e9658a6bde1e41865fa1da8485fedeea6f6e1.address new file mode 100644 index 0000000..eccb87e --- /dev/null +++ b/eotsKey/keyring-file/de3e9658a6bde1e41865fa1da8485fedeea6f6e1.address @@ -0,0 +1 @@ +eyJhbGciOiJQQkVTMi1IUzI1NitBMTI4S1ciLCJjcmVhdGVkIjoiMjAyNC0xMS0yNiAxMToxMDo0Ny4zNjkxMzggKzAyMDAgRUVUIG09KzEyLjE1MTcyMDI1MSIsImVuYyI6IkEyNTZHQ00iLCJwMmMiOjgxOTIsInAycyI6Ink2ZEtjSHZicVVIakt4eHYifQ.fgDYZXmbnwox-QMTzneyA5u2N23cZ6gn2Quf0M5plfTrYSuNwE98uA.NQ3UVcJcYTYkHCCj.a8XQs4IXKsl6LI-jgT6PCucU8UV3biS4ZM4QS4dvsF3c2uMi_21a-siN6v1B7FSf4ccHY9_muYrQA7JCQX0YXl5q15KYgy9TNFf9xhyxenbwysX9M5BodhUTtCKiDBaGfN1KyVyEl8qNwUtVUF1cGswF9inrySpPgmUUSCEPCHRFC25oDjvgST5bLIZycH5F8GelCyI25-sp2IF2ACEkiMjznHSkNThFxL16pbJWaIhMDw.3JEgb1VUHo6udHngA63FdQ \ No newline at end of file diff --git a/eotsKey/keyring-file/keyhash b/eotsKey/keyring-file/keyhash new file mode 100644 index 0000000..4b46e56 --- /dev/null +++ b/eotsKey/keyring-file/keyhash @@ -0,0 +1 @@ +$2a$10$FlEshqOGVza5WUU1Ud6T6eiUZ4he5xXMf5puo.a8r/vNoGYPLU43e \ No newline at end of file diff --git a/eotsKey/keyring-file/sam1.info b/eotsKey/keyring-file/sam1.info new file mode 100644 index 0000000..4481397 --- /dev/null +++ b/eotsKey/keyring-file/sam1.info @@ -0,0 +1 @@ +eyJhbGciOiJQQkVTMi1IUzI1NitBMTI4S1ciLCJjcmVhdGVkIjoiMjAyNC0xMS0yNiAxMToxMjowNi4zOTA3MTQgKzAyMDAgRUVUIG09KzUuMjM2OTE2NDE3IiwiZW5jIjoiQTI1NkdDTSIsInAyYyI6ODE5MiwicDJzIjoiNWVmYlJfWmplWGNneG1HYyJ9.f2YqyaxXO8jIASt3BbS2DS8pBFuPikvkmirzaKT_FOvcWZscaE0Ozw.2thPhaclVdBmBntF.njCRlR_AYprLceJz8ZocAKly94fAiXO4UnjrnZiH45GpP_1s1yMfx1cH3FjAlSNMshJ1W9UCBmCYhQMP9YGZpgGANrdRAIT43YuwOsuHliKUCDSdXMk_ynZTnu4F1O_IVcvGC3Ncs3ndz5Zus2xQ7Kj_o8EZW7V3wx0aWTKfdsGF7NnfF49tMMFLzLoPnWOE7teg385AlcIz3pYLXjsUku-65uI7ZmZRsqF8w8Mdg30Iq19EdPXAxK8McOqk9U0KCkZk3YyUravsAmuOhmVdf8vt0xeLcK3oTM7fI0skEW_Z6U547rH0xROzQigAAkLrHpldZ0GD-FmSBd5VkmpuRCMme3-lA3vB4p9whiADmOqtkkOOqTRHEGU6Ij5Upbk2bDc5NpEHnF9oNwuJ5W3pehvy-y5w1AhP5h-5xs5NqPeCeuroNgxg-dkIfQ.wJ-jWfXNUayENs3lD-RZpQ \ No newline at end of file diff --git a/eotsKey/keyring-file/sam2.info b/eotsKey/keyring-file/sam2.info new file mode 100644 index 0000000..c45bed0 --- /dev/null +++ b/eotsKey/keyring-file/sam2.info @@ -0,0 +1 @@ +eyJhbGciOiJQQkVTMi1IUzI1NitBMTI4S1ciLCJjcmVhdGVkIjoiMjAyNC0xMS0yNiAxMToxMDo0Ny4zNjY3MDEgKzAyMDAgRUVUIG09KzEyLjE0OTI4MjI5MyIsImVuYyI6IkEyNTZHQ00iLCJwMmMiOjgxOTIsInAycyI6IkF4b1hlOE1peVZiNUYxOHYifQ.OQfl4SjCBxPELCMlfwxmevLs3-etkYl6B2bqn4isATGKkDPxWiVykw.kNpnI8mssyh91wkA.rkt33omj_31cnuj8ZlP5gwbKZKkmFNRF9lQikl-Kolt0oDJTMDvQ2gGIN6j_Ezy8NbzczLDCqVO__-ZPVieP5hMr5M465YCdgcI11L0-1N14Pr_9tVMbm4peWNzZ0q3l6cWoIj6qsUJQ8XpDOejg8PNwLsSSUOHR6GXrJosJ9iquhwxn5bD8hJhjazm53S9k0S38iJc2j4AKa9t_MpDKSddzDEGkRMaVTrhWc2H6sbDuZX6u2W6PVjiizS21pQEYhF7eBfwx1B5fDiwu2qZcwf265855Qtvb1XCrBohe_Z123agBTKMdCZXvny6_5NkoKtbr7LyP2dE_45eDftX3qnwVY6XDIjs6IrNf4mR_lm8WFilQfTIOXiGogiJStfR7HbBdF6c8bhkU1uBdtk_TDHm7GZXzH1DRYXJ320d1sD5ZKA1xvJi8na3iDg.AO0fvomVHcvGp41glqqZCg \ No newline at end of file diff --git a/eotsKey/keyring-test/b8a54342b859ca5ff2cd98602d2177d703560c32.address b/eotsKey/keyring-test/b8a54342b859ca5ff2cd98602d2177d703560c32.address new file mode 100644 index 0000000..a76d556 --- /dev/null +++ b/eotsKey/keyring-test/b8a54342b859ca5ff2cd98602d2177d703560c32.address @@ -0,0 +1 @@ +eyJhbGciOiJQQkVTMi1IUzI1NitBMTI4S1ciLCJjcmVhdGVkIjoiMjAyNC0xMS0yNiAxMToyMzozMy42NDg2NjkgKzAyMDAgRUVUIG09KzkuNjExNzcyODc2IiwiZW5jIjoiQTI1NkdDTSIsInAyYyI6ODE5MiwicDJzIjoiYXhUbnhGRVNUOXlOZmtxOSJ9.7Qc8LSCWDJ1KaKjLAbkrQI9990IZhph5J1UBgtC88NPKcJ4oEO6Q9g.Cys0fRoUyDyhRZQQ.GSvCjXL1ckxnxRLmFiEzmAlEfEqXayu36auXQl7htwntLx9spWgfqnaSYmvesMXqCz9Npbw3OXocSkYz7B3onJPy8to3RPIb9QJY76_Xhx8rjOkxil-YiJiJCGVn51Zoap_iEhJyDxjA1Qi0XGkko8bgSA9nr9TGLODFb3aidhTIDXzVt108w9nL1K7HqSgDzhSClCg1woFmZmWjvAmpMa-sAMJS6DHRwoNYxfuU1RG7uA.dQocnBhWzNJ5EQdcVWp2LQ \ No newline at end of file diff --git a/eotsKey/keyring-test/sam5.info b/eotsKey/keyring-test/sam5.info new file mode 100644 index 0000000..8ce6d98 --- /dev/null +++ b/eotsKey/keyring-test/sam5.info @@ -0,0 +1 @@ +eyJhbGciOiJQQkVTMi1IUzI1NitBMTI4S1ciLCJjcmVhdGVkIjoiMjAyNC0xMS0yNiAxMToyMzozMy42NDU3NDQgKzAyMDAgRUVUIG09KzkuNjA4ODQ2OTU5IiwiZW5jIjoiQTI1NkdDTSIsInAyYyI6ODE5MiwicDJzIjoiWk1kWGFrRUVTVV9FM0p1cyJ9.EvtPpnwO6d3al59pCUU5uCmydAawbgDhxglFg_v716QFumtbL0Sdbg.steAzdE_m0aXdE7D.bu03RyiGuj6ph_dWtu5k5FD8W5LMzxmoi8FKbvfuG7YQkF3_T_mYV5vJI2Hl1mncY8Ih5SHIE5ddvw_EKWdKmXnvfoaSSZi2nTLLlVDu0eYUSnz3bnmZu1oAxvcfaeKYi_T0QuET7B4cx9vfOI-HY5pgeo7BiDtrjGrv1lAsc5c0rasOB54pI_lFO6pqjAyXLpdxtyf2cEpV7xkzvFu7w6Z4toXixYTznoMJMxseVUSfM4KfjKJH2pxlhPqMlMUFSg9rn3SBvh53BBLwO_WnHDOAJ2Jgxve30hfwOC67lHbqTdrsgGv3zUnKeOrJVYwAUyDxmeHyUzghRL2Xv7ZiXxYXkROC3BY7tqZNHk-kp2n-6TPwtxnRGllTXA_Ut2SRc-Hq5gqYPLtvwQ055C0v_t6MDK3nk0n04nuqQ0MBzeKf9_qpCJj-I1E1AQ.8LxlMjSe1NZFF6LZfypqCg \ No newline at end of file From 1bfcbe7a84e21585724b13e7440ad7374a3e2ff7 Mon Sep 17 00:00:00 2001 From: Sam Ricotta Date: Tue, 26 Nov 2024 14:08:52 +0200 Subject: [PATCH 46/53] Update finality-provider-operation.md --- docs/finality-provider-operation.md | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/docs/finality-provider-operation.md b/docs/finality-provider-operation.md index d11cbf5..79c9045 100644 --- a/docs/finality-provider-operation.md +++ b/docs/finality-provider-operation.md @@ -36,7 +36,6 @@ gain an overall understanding of the finality provider. 3. [Withdrawing Rewards](#53-withdrawing-rewards) 4. [Jailing and Unjailing](#54-jailing-and-unjailing) 5. [Slashing](#55-slashing) - 6. [Monitoring](#56-monitoring) 6. [Prometheus Metrics](#6-prometheus-metrics) ## 1. A note about Phase-1 Finality Providers @@ -681,7 +680,7 @@ removal from the active set. Ask devops --> -The daemon services of the finality provider stack + -Next we will enable metric collection in `app.toml` + --> \ No newline at end of file From 3a1055270fdbb5615f9578bc8d4542c8cef81c3a Mon Sep 17 00:00:00 2001 From: Sam Ricotta Date: Tue, 26 Nov 2024 14:24:02 +0200 Subject: [PATCH 47/53] test --- docs/finality-provider-operation.md | 5 +- fpdhome/fpd.conf | 235 ++++++++++++++++++ ...af8deaa294665247608c4ef4b94f6cfd49.address | 1 + fpdhome/keyring-test/fp1.info | 1 + home/eotsd.conf | 39 +++ ...b70622dcc1be4e9be8e7834407b8eea0b1.address | 1 + home/keyring-test/eots1.info | 1 + home/logs/eotsd.log | 4 + 8 files changed, 285 insertions(+), 2 deletions(-) create mode 100644 fpdhome/fpd.conf create mode 100644 fpdhome/keyring-test/87e243af8deaa294665247608c4ef4b94f6cfd49.address create mode 100644 fpdhome/keyring-test/fp1.info create mode 100644 home/eotsd.conf create mode 100644 home/keyring-test/16e9c4b70622dcc1be4e9be8e7834407b8eea0b1.address create mode 100644 home/keyring-test/eots1.info create mode 100644 home/logs/eotsd.log diff --git a/docs/finality-provider-operation.md b/docs/finality-provider-operation.md index 79c9045..0fc9f73 100644 --- a/docs/finality-provider-operation.md +++ b/docs/finality-provider-operation.md @@ -111,7 +111,8 @@ commit: 7d37c88e9a33c0b6a86614f743e9426ce6e31d4a ``` If your shell cannot find the installed binaries, make sure `$GOPATH/bin` is in -the `$PATH` of your shell. Use the following command to add it to your profile. +the `$PATH` of your shell. Use the following command to add it to your profile +depending on your shell. ```shell echo 'export PATH=$HOME/go/bin:$PATH' >> ~/.profile @@ -383,7 +384,7 @@ both security and high availability. Use the following command to add the Babylon key for your finality provider: ```shell -fpd keys add --keyname --keyring-backend test --home +fpd keys add --keyring-backend test --home ``` The above `keys add` command will create a new key pair and store it in your keyring. diff --git a/fpdhome/fpd.conf b/fpdhome/fpd.conf new file mode 100644 index 0000000..7943c93 --- /dev/null +++ b/fpdhome/fpd.conf @@ -0,0 +1,235 @@ +[Application Options] +; Logging level for all subsystems +LogLevel = info + +; the type of the consumer chain (babylon/OPStackL2/wasm) +ChainType = babylon + +; The number of Schnorr public randomness for each commitment +NumPubRand = 70000 + +; The upper bound of the number of Schnorr public randomness for each commitment +NumPubRandMax = 100000 + +; The minimum gap between the last committed rand height and the current Babylon block height +MinRandHeightGap = 35000 + +; The interval between each update of finality-provider status +StatusUpdateInterval = 20s + +; The interval between each attempt to commit public randomness +RandomnessCommitInterval = 30s + +; The interval between each attempt to submit finality signature or public randomness after a failure +SubmissionRetryInterval = 1s + +; The maximum number of retries to submit finality signature or public randomness +MaxSubmissionRetries = 20 + +; The interval between each try of fast sync, which is disabled if the value is 0 +FastSyncInterval = 10s + +; The maximum number of blocks to catch up for each fast sync +FastSyncLimit = 10 + +; The block gap that will trigger the fast sync +FastSyncGap = 3 + +; The address of the remote EOTS manager; Empty if the EOTS manager is running locally +EOTSManagerAddress = 127.0.0.1:12582 + +; The maximum number of finality-provider instances running concurrently within the daemon +MaxNumFinalityProviders = 3 + +; The duration of time that it should sync FP status with the client blockchain +SyncFpStatusInterval = 30s + +; Bitcoin network to run on +BitcoinNetwork = signet + +; the listener for RPC connections, e.g., 127.0.0.1:1234 +RpcListener = 127.0.0.1:12581 + +[chainpollerconfig] +; The maximum number of Babylon blocks that can be stored in the buffer +BufferSize = 1000 + +; The interval between each polling of consumer chain blocks +PollInterval = 20s + +; The static height from which we start polling the chain +StaticChainScanningStartHeight = 1 + +; Automatically discover the height from which to start polling the chain +AutoChainScanningMode = true + +[dbconfig] +; The directory path in which the database file should be stored. +DBPath = /Users/samricotta/code/finality-provider/fpdhome/data + +; The name of the database file. +DBFileName = finality-provider.db + +; Prevents the database from syncing its freelist to disk, resulting in improved performance at the expense of increased startup time. +NoFreelistSync = true + +; Specifies if a Bolt based database backend should be automatically compacted on startup (if the minimum age of the database file is reached). This will require additional disk space for the compacted copy of the database but will result in an overall lower database size after the compaction. +AutoCompact = false + +; Specifies the minimum time that must have passed since a bolt database file was last compacted for the compaction to be considered again. +AutoCompactMinAge = 168h0m0s + +; Specifies the timeout value to use when opening the wallet database. +DBTimeout = 1m0s + +[babylon] +; name of the key to sign transactions with +Key = fp1 + +; chain id of the chain to connect to +ChainID = chain-test + +; address of the rpc server to connect to +RPCAddr = http://localhost:26657 + +; address of the grpc server to connect to +GRPCAddr = https://localhost:9090 + +; account prefix to use for addresses +AccountPrefix = bbn + +; type of keyring to use +KeyringBackend = test + +; adjustment factor when using gas estimation +GasAdjustment = 1.5 + +; comma separated minimum gas prices to accept for transactions +GasPrices = 0.002ubbn + +; directory to store keys in +KeyDirectory = /Users/samricotta/code/finality-provider/fpdhome + +; flag to print debug output +Debug = true + +; client timeout when doing queries +Timeout = 20s + +; block timeout when waiting for block events +BlockTimeout = 1m0s + +; default output when printint responses +OutputFormat = json + +; sign mode to use +SignModeStr = direct + +[opstackl2] +; the rpc address of the op-stack-l2 node to connect to +OPStackL2RPCAddress = + +; the contract address of the op-finality-gadget +OPFinalityGadgetAddress = + +; the rpc address of babylon op finality gadget +BabylonFinalityGadgetRpc = + +; name of the babylon key to sign transactions with +Key = + +; chain id of the babylon chain to connect to +ChainID = + +; address of the babylon rpc server to connect to +RPCAddr = + +; address of the babylon grpc server to connect to +GRPCAddr = + +; babylon account prefix to use for addresses +AccountPrefix = + +; type of keyring to use +KeyringBackend = + +; adjustment factor when using babylon gas estimation +GasAdjustment = 0 + +; comma separated minimum babylon gas prices to accept for transactions +GasPrices = + +; directory to store babylon keys in +KeyDirectory = + +; flag to print debug output +Debug = false + +; client timeout when doing queries +Timeout = 0s + +; block timeout when waiting for block events +BlockTimeout = 0s + +; default output when printint responses +OutputFormat = + +; sign mode to use +SignModeStr = + +[wasm] +; name of the key to sign transactions with +Key = + +; chain id of the chain to connect to +ChainID = + +; address of the rpc server to connect to +RPCAddr = + +; address of the grpc server to connect to +GRPCAddr = + +; account prefix to use for addresses +AccountPrefix = + +; type of keyring to use +KeyringBackend = + +; adjustment factor when using gas estimation +GasAdjustment = 0 + +; comma separated minimum gas prices to accept for transactions +GasPrices = + +; directory to store keys in +KeyDirectory = + +; flag to print debug output +Debug = false + +; client timeout when doing queries +Timeout = 0s + +; block timeout when waiting for block events +BlockTimeout = 0s + +; default output when printint responses +OutputFormat = + +; sign mode to use +SignModeStr = + +; address of the BTC staking contract +BtcStakingContractAddress = + +[metrics] +; IP of the Prometheus server +Host = 127.0.0.1 + +; Port of the Prometheus server +Port = 2112 + +; The interval of Prometheus metrics updated +UpdateInterval = 100ms + diff --git a/fpdhome/keyring-test/87e243af8deaa294665247608c4ef4b94f6cfd49.address b/fpdhome/keyring-test/87e243af8deaa294665247608c4ef4b94f6cfd49.address new file mode 100644 index 0000000..6bbb2ff --- /dev/null +++ b/fpdhome/keyring-test/87e243af8deaa294665247608c4ef4b94f6cfd49.address @@ -0,0 +1 @@ +eyJhbGciOiJQQkVTMi1IUzI1NitBMTI4S1ciLCJjcmVhdGVkIjoiMjAyNC0xMS0yNiAxNDoyMTo1OC45MTg2MjggKzAyMDAgRUVUIG09KzAuMTE5NjUyMDAxIiwiZW5jIjoiQTI1NkdDTSIsInAyYyI6ODE5MiwicDJzIjoidzlVTHE0TzREZzlzU0EwdSJ9.Y2RPcq_9wanSOo-2go42qHuzum--8WaUhxK2617FK7s0oPx-aFBBqQ.zprUDFbAvpkHTN1u.sCDGts8mTWyPPSWuRjq8QRm26JkKSexO5CaBLLffJkWwQK-PgVXs0QepBTc2JxLIxGaVYeGDA8OaEC9Dyyjn-YccXIcaxB1C7Qz7kV6KOKAIHDgkuiOxvN651E4l1qhm1aalh5CsRhmm8ThfEucQkaGS4sJC0g5A3rKpPh-ygYmwNmUALoFlMA4jkhPQWFYKrH-F4DqP4eEOS8VVFcS5hYRfl9QH4yyxhOp-HmAZ12GzrA.j4N3qP27BDnJlTekVXGgfg \ No newline at end of file diff --git a/fpdhome/keyring-test/fp1.info b/fpdhome/keyring-test/fp1.info new file mode 100644 index 0000000..b3dfdef --- /dev/null +++ b/fpdhome/keyring-test/fp1.info @@ -0,0 +1 @@ +eyJhbGciOiJQQkVTMi1IUzI1NitBMTI4S1ciLCJjcmVhdGVkIjoiMjAyNC0xMS0yNiAxNDoyMTo1OC45MTY0NCArMDIwMCBFRVQgbT0rMC4xMTc0NjQwMDEiLCJlbmMiOiJBMjU2R0NNIiwicDJjIjo4MTkyLCJwMnMiOiJZeE9oSDFYSVQ1WmlheWlTIn0.0J2cVEQ8Phy88sW1xoHRyrcJllZkjxllGtd47o_Ob8j6W07lnXfAlw.iLMfUhBIP0GBndrc.t3WDvdkB8TxKkfr9xTkh1pchk9746XWMLwh3b6hlh7-795yI3rQp-3vUpDDdLdH9dt7Fzml5MLD8NV-gHJximyoBsbOxqfnxB2cNj2hcNRCHWYjBpPVo-vtAIu2g0_RKwyJT2Su13k6mw-H40-qYdxE2RBIeH__8EEwTOdXYOiXYPmvW_pqv4DKnAao-gSVFAbb6_dpvhDjDRZcM2aGaM_BgGY2xEOMdzbpsnlgpti4SL-aaqR4zhCnYdk9CmAD2S9imAbMEDLVqAy0ZYSS8se6N7tuxsvY6GZaG43cs9xAg6LDcSLmBFpfifuR1RiSjdF3c5hLS5i_fF9Xoas2zXhUZrlTOL9rP_mx7qgzcQAdtzlbAm914_EQ-zIsuN6nU30xLaOrBEhhPYEkxnvgAS4qGivK-VxzACmyooUyFbZViwuuZk_aTijjH.Yezo5Po4HNpXtzbxm1aT-Q \ No newline at end of file diff --git a/home/eotsd.conf b/home/eotsd.conf new file mode 100644 index 0000000..e0cafb1 --- /dev/null +++ b/home/eotsd.conf @@ -0,0 +1,39 @@ +[Application Options] +; Logging level for all subsystems +LogLevel = debug + +; Type of keyring to use +KeyringBackend = test + +; the listener for RPC connections, e.g., 127.0.0.1:1234 +RpcListener = 127.0.0.1:12582 + +[metrics] +; IP of the Prometheus server +Host = 127.0.0.1 + +; Port of the Prometheus server +Port = 2113 + +; The interval of Prometheus metrics updated +UpdateInterval = 100ms + +[dbconfig] +; The directory path in which the database file should be stored. +DBPath = /Users/samricotta/code/finality-provider/home/data + +; The name of the database file. +DBFileName = eots.db + +; Prevents the database from syncing its freelist to disk, resulting in improved performance at the expense of increased startup time. +NoFreelistSync = true + +; Specifies if a Bolt based database backend should be automatically compacted on startup (if the minimum age of the database file is reached). This will require additional disk space for the compacted copy of the database but will result in an overall lower database size after the compaction. +AutoCompact = false + +; Specifies the minimum time that must have passed since a bolt database file was last compacted for the compaction to be considered again. +AutoCompactMinAge = 168h0m0s + +; Specifies the timeout value to use when opening the wallet database. +DBTimeout = 1m0s + diff --git a/home/keyring-test/16e9c4b70622dcc1be4e9be8e7834407b8eea0b1.address b/home/keyring-test/16e9c4b70622dcc1be4e9be8e7834407b8eea0b1.address new file mode 100644 index 0000000..d90e5dc --- /dev/null +++ b/home/keyring-test/16e9c4b70622dcc1be4e9be8e7834407b8eea0b1.address @@ -0,0 +1 @@ +eyJhbGciOiJQQkVTMi1IUzI1NitBMTI4S1ciLCJjcmVhdGVkIjoiMjAyNC0xMS0yNiAxNDoxNzoxMS4yNTQyMDQgKzAyMDAgRUVUIG09KzAuMDUzNDM5OTE4IiwiZW5jIjoiQTI1NkdDTSIsInAyYyI6ODE5MiwicDJzIjoibGJwYVVZUkRnY0N2ZmJwRyJ9._Yr5nLKRuWuonkcl6RA3oU7EiCyBwrQj-rpSfBdvdgNopohpVxjh6Q.5iSwGa6V8p7XWPaW.DPvIEIono4CMFLBRWn1jeLYO48puD9FnJr7-A7c5iHKW8AZvLtd8hq-PGjtJrvCLsHcAhhBkmVB-m-U6GypE__Zq-uzuQrs831mGmfrcCFJg3CCRM2Df5bvIhL-Tcf-TCUowklNTavgYa4Ac8ZYuGMfzUNd4iH3-C8eLif2ZBaYp_HUmxUQitzY5c6P0wUIQeiwg0D-H1DnRIISXUnpa21gUseO-K-gq0nFT020a-QEdaHGNKmE.Y4J008rJA8KgDh5QgpFzAg \ No newline at end of file diff --git a/home/keyring-test/eots1.info b/home/keyring-test/eots1.info new file mode 100644 index 0000000..dd222cb --- /dev/null +++ b/home/keyring-test/eots1.info @@ -0,0 +1 @@ +eyJhbGciOiJQQkVTMi1IUzI1NitBMTI4S1ciLCJjcmVhdGVkIjoiMjAyNC0xMS0yNiAxNDoxNzoxMS4yNTIzMDcgKzAyMDAgRUVUIG09KzAuMDUxNTQyNzEwIiwiZW5jIjoiQTI1NkdDTSIsInAyYyI6ODE5MiwicDJzIjoiaXFkVGduWXdJUzdIUHlvViJ9.l-Ubsh2jy1qPUxABXeoSsaLGKcn_Jml5vuQ0OPR_PjObTnvh7WSyow.7ZIwW6D1z6gYIr89.NN31yLFK_hdYIcOxmPn2ZFrCeMmns3st62DMViub4MOff_Qiw7ii-OWsAVYE-BwmV-PBFtPAtGm-0T5BSN2pVoyLtBf8E3kUTxpM6e4gokD_u1d4M7CiIiY3qiBjXoKv7Nxza2-yGhgxReE_nqEnzQTCcGn8b4plSczNBzbJKsrpTQIz88bpgpJtVotwJi0tTlB8cif0Qs45-cmSd4Tok_Xcberd-syBX23tJOtw6ywapqzaP9KkkN7zdDS7GnoWKKxChLFRA7fESJ7y0i5CUQvT6JEUARKAhx_ftWsMxio4JMuk6npYizUf2XHSgRz6st1kkGXuBCC3gMMSBQCxJFLDp_-7PJN2rrpbDsW5CTLLmK_8U7BjyFuho4h6qj-VtOhxG-SPY-9PunXp1iQ0o2rkISlcUR31S5S2LT92niTVE5QCYfwLDJrURMs.ZB6n0dwlTayi9SXR5AENdQ \ No newline at end of file diff --git a/home/logs/eotsd.log b/home/logs/eotsd.log new file mode 100644 index 0000000..c5a9e33 --- /dev/null +++ b/home/logs/eotsd.log @@ -0,0 +1,4 @@ +2024-11-26T12:17:11.276407Z info successfully created an EOTS key {"key name": "eots1", "pk": "64d4fdd7f78950f905b2d957af256e781ed57f790860959a434148aa2e86240f"} +2024-11-26T12:18:05.346154Z info Metrics server is starting {"addr": "127.0.0.1:2113"} +2024-11-26T12:18:05.346421Z info RPC server listening {"address": "127.0.0.1:12582"} +2024-11-26T12:18:05.346476Z info EOTS Manager Daemon is fully active! From 5b846cdc3661560683e036bca72a3738b68fd0fa Mon Sep 17 00:00:00 2001 From: Sam Ricotta Date: Tue, 26 Nov 2024 14:29:26 +0200 Subject: [PATCH 48/53] Update finality-provider-operation.md --- docs/finality-provider-operation.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/finality-provider-operation.md b/docs/finality-provider-operation.md index 0fc9f73..ef0ccfe 100644 --- a/docs/finality-provider-operation.md +++ b/docs/finality-provider-operation.md @@ -409,7 +409,7 @@ signing. ### 4.3. Configure Your Finality Provider -Edit the `config.toml` file in your finality provider home directory with the +Edit the `fpd.conf` file in your finality provider home directory with the following parameters: ```shell From cc935b1d9a61bc8f20a98b4bfb38f67201f47af2 Mon Sep 17 00:00:00 2001 From: Vitalis Salis Date: Tue, 26 Nov 2024 15:04:09 +0200 Subject: [PATCH 49/53] dummy files --- ...df3a623b30a27735b1fe1fda6c6756fa0c.address | 1 - ...58a6bde1e41865fa1da8485fedeea6f6e1.address | 1 - eotsKey/keyring-file/keyhash | 1 - eotsKey/keyring-file/sam1.info | 1 - eotsKey/keyring-file/sam2.info | 1 - ...42b859ca5ff2cd98602d2177d703560c32.address | 1 - eotsKey/keyring-test/sam5.info | 1 - fpdhome/fpd.conf | 235 ------------------ ...af8deaa294665247608c4ef4b94f6cfd49.address | 1 - fpdhome/keyring-test/fp1.info | 1 - home/eotsd.conf | 39 --- ...b70622dcc1be4e9be8e7834407b8eea0b1.address | 1 - home/keyring-test/eots1.info | 1 - home/logs/eotsd.log | 4 - 14 files changed, 289 deletions(-) delete mode 100644 eotsKey/keyring-file/c3cd0bdf3a623b30a27735b1fe1fda6c6756fa0c.address delete mode 100644 eotsKey/keyring-file/de3e9658a6bde1e41865fa1da8485fedeea6f6e1.address delete mode 100644 eotsKey/keyring-file/keyhash delete mode 100644 eotsKey/keyring-file/sam1.info delete mode 100644 eotsKey/keyring-file/sam2.info delete mode 100644 eotsKey/keyring-test/b8a54342b859ca5ff2cd98602d2177d703560c32.address delete mode 100644 eotsKey/keyring-test/sam5.info delete mode 100644 fpdhome/fpd.conf delete mode 100644 fpdhome/keyring-test/87e243af8deaa294665247608c4ef4b94f6cfd49.address delete mode 100644 fpdhome/keyring-test/fp1.info delete mode 100644 home/eotsd.conf delete mode 100644 home/keyring-test/16e9c4b70622dcc1be4e9be8e7834407b8eea0b1.address delete mode 100644 home/keyring-test/eots1.info delete mode 100644 home/logs/eotsd.log diff --git a/eotsKey/keyring-file/c3cd0bdf3a623b30a27735b1fe1fda6c6756fa0c.address b/eotsKey/keyring-file/c3cd0bdf3a623b30a27735b1fe1fda6c6756fa0c.address deleted file mode 100644 index 5c02764..0000000 --- a/eotsKey/keyring-file/c3cd0bdf3a623b30a27735b1fe1fda6c6756fa0c.address +++ /dev/null @@ -1 +0,0 @@ -eyJhbGciOiJQQkVTMi1IUzI1NitBMTI4S1ciLCJjcmVhdGVkIjoiMjAyNC0xMS0yNiAxMToxMjowNi4zOTI2NjUgKzAyMDAgRUVUIG09KzUuMjM4ODY4Mzc2IiwiZW5jIjoiQTI1NkdDTSIsInAyYyI6ODE5MiwicDJzIjoiLTV5RFQ5TEY5NUhWWHQ0cCJ9.T8GPy2zgeLwramglyTJSuKB2KJI7ZSTK_6qdChHnH1BZUGasPhvp8w.zWX1pn7ivyZ7MJlg.gS6CSKsK7_UX3YFdBjxd2RdA1NJQEMce2nxnNJcIoRLQ_r7K1IyyGheibRMsJIWiCz5DpVF5CnQzrCQ2k5c6_FCszD8uG6zY_RaWWvSBUvKfQBEw1jhor3u0OCtKb3UW8AnROnKWpdpvobZh9UKhatGodWyHDx9F1QTFysgnLvA2N3xYz6g1W5gDsi8zPL9b0zNX-k8JSOfdljoRYnkOYeH7MSbyfFe-vx10wEi7XpZFRw.0NxsB0llg6OoLpuz4hZJOw \ No newline at end of file diff --git a/eotsKey/keyring-file/de3e9658a6bde1e41865fa1da8485fedeea6f6e1.address b/eotsKey/keyring-file/de3e9658a6bde1e41865fa1da8485fedeea6f6e1.address deleted file mode 100644 index eccb87e..0000000 --- a/eotsKey/keyring-file/de3e9658a6bde1e41865fa1da8485fedeea6f6e1.address +++ /dev/null @@ -1 +0,0 @@ -eyJhbGciOiJQQkVTMi1IUzI1NitBMTI4S1ciLCJjcmVhdGVkIjoiMjAyNC0xMS0yNiAxMToxMDo0Ny4zNjkxMzggKzAyMDAgRUVUIG09KzEyLjE1MTcyMDI1MSIsImVuYyI6IkEyNTZHQ00iLCJwMmMiOjgxOTIsInAycyI6Ink2ZEtjSHZicVVIakt4eHYifQ.fgDYZXmbnwox-QMTzneyA5u2N23cZ6gn2Quf0M5plfTrYSuNwE98uA.NQ3UVcJcYTYkHCCj.a8XQs4IXKsl6LI-jgT6PCucU8UV3biS4ZM4QS4dvsF3c2uMi_21a-siN6v1B7FSf4ccHY9_muYrQA7JCQX0YXl5q15KYgy9TNFf9xhyxenbwysX9M5BodhUTtCKiDBaGfN1KyVyEl8qNwUtVUF1cGswF9inrySpPgmUUSCEPCHRFC25oDjvgST5bLIZycH5F8GelCyI25-sp2IF2ACEkiMjznHSkNThFxL16pbJWaIhMDw.3JEgb1VUHo6udHngA63FdQ \ No newline at end of file diff --git a/eotsKey/keyring-file/keyhash b/eotsKey/keyring-file/keyhash deleted file mode 100644 index 4b46e56..0000000 --- a/eotsKey/keyring-file/keyhash +++ /dev/null @@ -1 +0,0 @@ -$2a$10$FlEshqOGVza5WUU1Ud6T6eiUZ4he5xXMf5puo.a8r/vNoGYPLU43e \ No newline at end of file diff --git a/eotsKey/keyring-file/sam1.info b/eotsKey/keyring-file/sam1.info deleted file mode 100644 index 4481397..0000000 --- a/eotsKey/keyring-file/sam1.info +++ /dev/null @@ -1 +0,0 @@ -eyJhbGciOiJQQkVTMi1IUzI1NitBMTI4S1ciLCJjcmVhdGVkIjoiMjAyNC0xMS0yNiAxMToxMjowNi4zOTA3MTQgKzAyMDAgRUVUIG09KzUuMjM2OTE2NDE3IiwiZW5jIjoiQTI1NkdDTSIsInAyYyI6ODE5MiwicDJzIjoiNWVmYlJfWmplWGNneG1HYyJ9.f2YqyaxXO8jIASt3BbS2DS8pBFuPikvkmirzaKT_FOvcWZscaE0Ozw.2thPhaclVdBmBntF.njCRlR_AYprLceJz8ZocAKly94fAiXO4UnjrnZiH45GpP_1s1yMfx1cH3FjAlSNMshJ1W9UCBmCYhQMP9YGZpgGANrdRAIT43YuwOsuHliKUCDSdXMk_ynZTnu4F1O_IVcvGC3Ncs3ndz5Zus2xQ7Kj_o8EZW7V3wx0aWTKfdsGF7NnfF49tMMFLzLoPnWOE7teg385AlcIz3pYLXjsUku-65uI7ZmZRsqF8w8Mdg30Iq19EdPXAxK8McOqk9U0KCkZk3YyUravsAmuOhmVdf8vt0xeLcK3oTM7fI0skEW_Z6U547rH0xROzQigAAkLrHpldZ0GD-FmSBd5VkmpuRCMme3-lA3vB4p9whiADmOqtkkOOqTRHEGU6Ij5Upbk2bDc5NpEHnF9oNwuJ5W3pehvy-y5w1AhP5h-5xs5NqPeCeuroNgxg-dkIfQ.wJ-jWfXNUayENs3lD-RZpQ \ No newline at end of file diff --git a/eotsKey/keyring-file/sam2.info b/eotsKey/keyring-file/sam2.info deleted file mode 100644 index c45bed0..0000000 --- a/eotsKey/keyring-file/sam2.info +++ /dev/null @@ -1 +0,0 @@ -eyJhbGciOiJQQkVTMi1IUzI1NitBMTI4S1ciLCJjcmVhdGVkIjoiMjAyNC0xMS0yNiAxMToxMDo0Ny4zNjY3MDEgKzAyMDAgRUVUIG09KzEyLjE0OTI4MjI5MyIsImVuYyI6IkEyNTZHQ00iLCJwMmMiOjgxOTIsInAycyI6IkF4b1hlOE1peVZiNUYxOHYifQ.OQfl4SjCBxPELCMlfwxmevLs3-etkYl6B2bqn4isATGKkDPxWiVykw.kNpnI8mssyh91wkA.rkt33omj_31cnuj8ZlP5gwbKZKkmFNRF9lQikl-Kolt0oDJTMDvQ2gGIN6j_Ezy8NbzczLDCqVO__-ZPVieP5hMr5M465YCdgcI11L0-1N14Pr_9tVMbm4peWNzZ0q3l6cWoIj6qsUJQ8XpDOejg8PNwLsSSUOHR6GXrJosJ9iquhwxn5bD8hJhjazm53S9k0S38iJc2j4AKa9t_MpDKSddzDEGkRMaVTrhWc2H6sbDuZX6u2W6PVjiizS21pQEYhF7eBfwx1B5fDiwu2qZcwf265855Qtvb1XCrBohe_Z123agBTKMdCZXvny6_5NkoKtbr7LyP2dE_45eDftX3qnwVY6XDIjs6IrNf4mR_lm8WFilQfTIOXiGogiJStfR7HbBdF6c8bhkU1uBdtk_TDHm7GZXzH1DRYXJ320d1sD5ZKA1xvJi8na3iDg.AO0fvomVHcvGp41glqqZCg \ No newline at end of file diff --git a/eotsKey/keyring-test/b8a54342b859ca5ff2cd98602d2177d703560c32.address b/eotsKey/keyring-test/b8a54342b859ca5ff2cd98602d2177d703560c32.address deleted file mode 100644 index a76d556..0000000 --- a/eotsKey/keyring-test/b8a54342b859ca5ff2cd98602d2177d703560c32.address +++ /dev/null @@ -1 +0,0 @@ -eyJhbGciOiJQQkVTMi1IUzI1NitBMTI4S1ciLCJjcmVhdGVkIjoiMjAyNC0xMS0yNiAxMToyMzozMy42NDg2NjkgKzAyMDAgRUVUIG09KzkuNjExNzcyODc2IiwiZW5jIjoiQTI1NkdDTSIsInAyYyI6ODE5MiwicDJzIjoiYXhUbnhGRVNUOXlOZmtxOSJ9.7Qc8LSCWDJ1KaKjLAbkrQI9990IZhph5J1UBgtC88NPKcJ4oEO6Q9g.Cys0fRoUyDyhRZQQ.GSvCjXL1ckxnxRLmFiEzmAlEfEqXayu36auXQl7htwntLx9spWgfqnaSYmvesMXqCz9Npbw3OXocSkYz7B3onJPy8to3RPIb9QJY76_Xhx8rjOkxil-YiJiJCGVn51Zoap_iEhJyDxjA1Qi0XGkko8bgSA9nr9TGLODFb3aidhTIDXzVt108w9nL1K7HqSgDzhSClCg1woFmZmWjvAmpMa-sAMJS6DHRwoNYxfuU1RG7uA.dQocnBhWzNJ5EQdcVWp2LQ \ No newline at end of file diff --git a/eotsKey/keyring-test/sam5.info b/eotsKey/keyring-test/sam5.info deleted file mode 100644 index 8ce6d98..0000000 --- a/eotsKey/keyring-test/sam5.info +++ /dev/null @@ -1 +0,0 @@ -eyJhbGciOiJQQkVTMi1IUzI1NitBMTI4S1ciLCJjcmVhdGVkIjoiMjAyNC0xMS0yNiAxMToyMzozMy42NDU3NDQgKzAyMDAgRUVUIG09KzkuNjA4ODQ2OTU5IiwiZW5jIjoiQTI1NkdDTSIsInAyYyI6ODE5MiwicDJzIjoiWk1kWGFrRUVTVV9FM0p1cyJ9.EvtPpnwO6d3al59pCUU5uCmydAawbgDhxglFg_v716QFumtbL0Sdbg.steAzdE_m0aXdE7D.bu03RyiGuj6ph_dWtu5k5FD8W5LMzxmoi8FKbvfuG7YQkF3_T_mYV5vJI2Hl1mncY8Ih5SHIE5ddvw_EKWdKmXnvfoaSSZi2nTLLlVDu0eYUSnz3bnmZu1oAxvcfaeKYi_T0QuET7B4cx9vfOI-HY5pgeo7BiDtrjGrv1lAsc5c0rasOB54pI_lFO6pqjAyXLpdxtyf2cEpV7xkzvFu7w6Z4toXixYTznoMJMxseVUSfM4KfjKJH2pxlhPqMlMUFSg9rn3SBvh53BBLwO_WnHDOAJ2Jgxve30hfwOC67lHbqTdrsgGv3zUnKeOrJVYwAUyDxmeHyUzghRL2Xv7ZiXxYXkROC3BY7tqZNHk-kp2n-6TPwtxnRGllTXA_Ut2SRc-Hq5gqYPLtvwQ055C0v_t6MDK3nk0n04nuqQ0MBzeKf9_qpCJj-I1E1AQ.8LxlMjSe1NZFF6LZfypqCg \ No newline at end of file diff --git a/fpdhome/fpd.conf b/fpdhome/fpd.conf deleted file mode 100644 index 7943c93..0000000 --- a/fpdhome/fpd.conf +++ /dev/null @@ -1,235 +0,0 @@ -[Application Options] -; Logging level for all subsystems -LogLevel = info - -; the type of the consumer chain (babylon/OPStackL2/wasm) -ChainType = babylon - -; The number of Schnorr public randomness for each commitment -NumPubRand = 70000 - -; The upper bound of the number of Schnorr public randomness for each commitment -NumPubRandMax = 100000 - -; The minimum gap between the last committed rand height and the current Babylon block height -MinRandHeightGap = 35000 - -; The interval between each update of finality-provider status -StatusUpdateInterval = 20s - -; The interval between each attempt to commit public randomness -RandomnessCommitInterval = 30s - -; The interval between each attempt to submit finality signature or public randomness after a failure -SubmissionRetryInterval = 1s - -; The maximum number of retries to submit finality signature or public randomness -MaxSubmissionRetries = 20 - -; The interval between each try of fast sync, which is disabled if the value is 0 -FastSyncInterval = 10s - -; The maximum number of blocks to catch up for each fast sync -FastSyncLimit = 10 - -; The block gap that will trigger the fast sync -FastSyncGap = 3 - -; The address of the remote EOTS manager; Empty if the EOTS manager is running locally -EOTSManagerAddress = 127.0.0.1:12582 - -; The maximum number of finality-provider instances running concurrently within the daemon -MaxNumFinalityProviders = 3 - -; The duration of time that it should sync FP status with the client blockchain -SyncFpStatusInterval = 30s - -; Bitcoin network to run on -BitcoinNetwork = signet - -; the listener for RPC connections, e.g., 127.0.0.1:1234 -RpcListener = 127.0.0.1:12581 - -[chainpollerconfig] -; The maximum number of Babylon blocks that can be stored in the buffer -BufferSize = 1000 - -; The interval between each polling of consumer chain blocks -PollInterval = 20s - -; The static height from which we start polling the chain -StaticChainScanningStartHeight = 1 - -; Automatically discover the height from which to start polling the chain -AutoChainScanningMode = true - -[dbconfig] -; The directory path in which the database file should be stored. -DBPath = /Users/samricotta/code/finality-provider/fpdhome/data - -; The name of the database file. -DBFileName = finality-provider.db - -; Prevents the database from syncing its freelist to disk, resulting in improved performance at the expense of increased startup time. -NoFreelistSync = true - -; Specifies if a Bolt based database backend should be automatically compacted on startup (if the minimum age of the database file is reached). This will require additional disk space for the compacted copy of the database but will result in an overall lower database size after the compaction. -AutoCompact = false - -; Specifies the minimum time that must have passed since a bolt database file was last compacted for the compaction to be considered again. -AutoCompactMinAge = 168h0m0s - -; Specifies the timeout value to use when opening the wallet database. -DBTimeout = 1m0s - -[babylon] -; name of the key to sign transactions with -Key = fp1 - -; chain id of the chain to connect to -ChainID = chain-test - -; address of the rpc server to connect to -RPCAddr = http://localhost:26657 - -; address of the grpc server to connect to -GRPCAddr = https://localhost:9090 - -; account prefix to use for addresses -AccountPrefix = bbn - -; type of keyring to use -KeyringBackend = test - -; adjustment factor when using gas estimation -GasAdjustment = 1.5 - -; comma separated minimum gas prices to accept for transactions -GasPrices = 0.002ubbn - -; directory to store keys in -KeyDirectory = /Users/samricotta/code/finality-provider/fpdhome - -; flag to print debug output -Debug = true - -; client timeout when doing queries -Timeout = 20s - -; block timeout when waiting for block events -BlockTimeout = 1m0s - -; default output when printint responses -OutputFormat = json - -; sign mode to use -SignModeStr = direct - -[opstackl2] -; the rpc address of the op-stack-l2 node to connect to -OPStackL2RPCAddress = - -; the contract address of the op-finality-gadget -OPFinalityGadgetAddress = - -; the rpc address of babylon op finality gadget -BabylonFinalityGadgetRpc = - -; name of the babylon key to sign transactions with -Key = - -; chain id of the babylon chain to connect to -ChainID = - -; address of the babylon rpc server to connect to -RPCAddr = - -; address of the babylon grpc server to connect to -GRPCAddr = - -; babylon account prefix to use for addresses -AccountPrefix = - -; type of keyring to use -KeyringBackend = - -; adjustment factor when using babylon gas estimation -GasAdjustment = 0 - -; comma separated minimum babylon gas prices to accept for transactions -GasPrices = - -; directory to store babylon keys in -KeyDirectory = - -; flag to print debug output -Debug = false - -; client timeout when doing queries -Timeout = 0s - -; block timeout when waiting for block events -BlockTimeout = 0s - -; default output when printint responses -OutputFormat = - -; sign mode to use -SignModeStr = - -[wasm] -; name of the key to sign transactions with -Key = - -; chain id of the chain to connect to -ChainID = - -; address of the rpc server to connect to -RPCAddr = - -; address of the grpc server to connect to -GRPCAddr = - -; account prefix to use for addresses -AccountPrefix = - -; type of keyring to use -KeyringBackend = - -; adjustment factor when using gas estimation -GasAdjustment = 0 - -; comma separated minimum gas prices to accept for transactions -GasPrices = - -; directory to store keys in -KeyDirectory = - -; flag to print debug output -Debug = false - -; client timeout when doing queries -Timeout = 0s - -; block timeout when waiting for block events -BlockTimeout = 0s - -; default output when printint responses -OutputFormat = - -; sign mode to use -SignModeStr = - -; address of the BTC staking contract -BtcStakingContractAddress = - -[metrics] -; IP of the Prometheus server -Host = 127.0.0.1 - -; Port of the Prometheus server -Port = 2112 - -; The interval of Prometheus metrics updated -UpdateInterval = 100ms - diff --git a/fpdhome/keyring-test/87e243af8deaa294665247608c4ef4b94f6cfd49.address b/fpdhome/keyring-test/87e243af8deaa294665247608c4ef4b94f6cfd49.address deleted file mode 100644 index 6bbb2ff..0000000 --- a/fpdhome/keyring-test/87e243af8deaa294665247608c4ef4b94f6cfd49.address +++ /dev/null @@ -1 +0,0 @@ -eyJhbGciOiJQQkVTMi1IUzI1NitBMTI4S1ciLCJjcmVhdGVkIjoiMjAyNC0xMS0yNiAxNDoyMTo1OC45MTg2MjggKzAyMDAgRUVUIG09KzAuMTE5NjUyMDAxIiwiZW5jIjoiQTI1NkdDTSIsInAyYyI6ODE5MiwicDJzIjoidzlVTHE0TzREZzlzU0EwdSJ9.Y2RPcq_9wanSOo-2go42qHuzum--8WaUhxK2617FK7s0oPx-aFBBqQ.zprUDFbAvpkHTN1u.sCDGts8mTWyPPSWuRjq8QRm26JkKSexO5CaBLLffJkWwQK-PgVXs0QepBTc2JxLIxGaVYeGDA8OaEC9Dyyjn-YccXIcaxB1C7Qz7kV6KOKAIHDgkuiOxvN651E4l1qhm1aalh5CsRhmm8ThfEucQkaGS4sJC0g5A3rKpPh-ygYmwNmUALoFlMA4jkhPQWFYKrH-F4DqP4eEOS8VVFcS5hYRfl9QH4yyxhOp-HmAZ12GzrA.j4N3qP27BDnJlTekVXGgfg \ No newline at end of file diff --git a/fpdhome/keyring-test/fp1.info b/fpdhome/keyring-test/fp1.info deleted file mode 100644 index b3dfdef..0000000 --- a/fpdhome/keyring-test/fp1.info +++ /dev/null @@ -1 +0,0 @@ -eyJhbGciOiJQQkVTMi1IUzI1NitBMTI4S1ciLCJjcmVhdGVkIjoiMjAyNC0xMS0yNiAxNDoyMTo1OC45MTY0NCArMDIwMCBFRVQgbT0rMC4xMTc0NjQwMDEiLCJlbmMiOiJBMjU2R0NNIiwicDJjIjo4MTkyLCJwMnMiOiJZeE9oSDFYSVQ1WmlheWlTIn0.0J2cVEQ8Phy88sW1xoHRyrcJllZkjxllGtd47o_Ob8j6W07lnXfAlw.iLMfUhBIP0GBndrc.t3WDvdkB8TxKkfr9xTkh1pchk9746XWMLwh3b6hlh7-795yI3rQp-3vUpDDdLdH9dt7Fzml5MLD8NV-gHJximyoBsbOxqfnxB2cNj2hcNRCHWYjBpPVo-vtAIu2g0_RKwyJT2Su13k6mw-H40-qYdxE2RBIeH__8EEwTOdXYOiXYPmvW_pqv4DKnAao-gSVFAbb6_dpvhDjDRZcM2aGaM_BgGY2xEOMdzbpsnlgpti4SL-aaqR4zhCnYdk9CmAD2S9imAbMEDLVqAy0ZYSS8se6N7tuxsvY6GZaG43cs9xAg6LDcSLmBFpfifuR1RiSjdF3c5hLS5i_fF9Xoas2zXhUZrlTOL9rP_mx7qgzcQAdtzlbAm914_EQ-zIsuN6nU30xLaOrBEhhPYEkxnvgAS4qGivK-VxzACmyooUyFbZViwuuZk_aTijjH.Yezo5Po4HNpXtzbxm1aT-Q \ No newline at end of file diff --git a/home/eotsd.conf b/home/eotsd.conf deleted file mode 100644 index e0cafb1..0000000 --- a/home/eotsd.conf +++ /dev/null @@ -1,39 +0,0 @@ -[Application Options] -; Logging level for all subsystems -LogLevel = debug - -; Type of keyring to use -KeyringBackend = test - -; the listener for RPC connections, e.g., 127.0.0.1:1234 -RpcListener = 127.0.0.1:12582 - -[metrics] -; IP of the Prometheus server -Host = 127.0.0.1 - -; Port of the Prometheus server -Port = 2113 - -; The interval of Prometheus metrics updated -UpdateInterval = 100ms - -[dbconfig] -; The directory path in which the database file should be stored. -DBPath = /Users/samricotta/code/finality-provider/home/data - -; The name of the database file. -DBFileName = eots.db - -; Prevents the database from syncing its freelist to disk, resulting in improved performance at the expense of increased startup time. -NoFreelistSync = true - -; Specifies if a Bolt based database backend should be automatically compacted on startup (if the minimum age of the database file is reached). This will require additional disk space for the compacted copy of the database but will result in an overall lower database size after the compaction. -AutoCompact = false - -; Specifies the minimum time that must have passed since a bolt database file was last compacted for the compaction to be considered again. -AutoCompactMinAge = 168h0m0s - -; Specifies the timeout value to use when opening the wallet database. -DBTimeout = 1m0s - diff --git a/home/keyring-test/16e9c4b70622dcc1be4e9be8e7834407b8eea0b1.address b/home/keyring-test/16e9c4b70622dcc1be4e9be8e7834407b8eea0b1.address deleted file mode 100644 index d90e5dc..0000000 --- a/home/keyring-test/16e9c4b70622dcc1be4e9be8e7834407b8eea0b1.address +++ /dev/null @@ -1 +0,0 @@ -eyJhbGciOiJQQkVTMi1IUzI1NitBMTI4S1ciLCJjcmVhdGVkIjoiMjAyNC0xMS0yNiAxNDoxNzoxMS4yNTQyMDQgKzAyMDAgRUVUIG09KzAuMDUzNDM5OTE4IiwiZW5jIjoiQTI1NkdDTSIsInAyYyI6ODE5MiwicDJzIjoibGJwYVVZUkRnY0N2ZmJwRyJ9._Yr5nLKRuWuonkcl6RA3oU7EiCyBwrQj-rpSfBdvdgNopohpVxjh6Q.5iSwGa6V8p7XWPaW.DPvIEIono4CMFLBRWn1jeLYO48puD9FnJr7-A7c5iHKW8AZvLtd8hq-PGjtJrvCLsHcAhhBkmVB-m-U6GypE__Zq-uzuQrs831mGmfrcCFJg3CCRM2Df5bvIhL-Tcf-TCUowklNTavgYa4Ac8ZYuGMfzUNd4iH3-C8eLif2ZBaYp_HUmxUQitzY5c6P0wUIQeiwg0D-H1DnRIISXUnpa21gUseO-K-gq0nFT020a-QEdaHGNKmE.Y4J008rJA8KgDh5QgpFzAg \ No newline at end of file diff --git a/home/keyring-test/eots1.info b/home/keyring-test/eots1.info deleted file mode 100644 index dd222cb..0000000 --- a/home/keyring-test/eots1.info +++ /dev/null @@ -1 +0,0 @@ -eyJhbGciOiJQQkVTMi1IUzI1NitBMTI4S1ciLCJjcmVhdGVkIjoiMjAyNC0xMS0yNiAxNDoxNzoxMS4yNTIzMDcgKzAyMDAgRUVUIG09KzAuMDUxNTQyNzEwIiwiZW5jIjoiQTI1NkdDTSIsInAyYyI6ODE5MiwicDJzIjoiaXFkVGduWXdJUzdIUHlvViJ9.l-Ubsh2jy1qPUxABXeoSsaLGKcn_Jml5vuQ0OPR_PjObTnvh7WSyow.7ZIwW6D1z6gYIr89.NN31yLFK_hdYIcOxmPn2ZFrCeMmns3st62DMViub4MOff_Qiw7ii-OWsAVYE-BwmV-PBFtPAtGm-0T5BSN2pVoyLtBf8E3kUTxpM6e4gokD_u1d4M7CiIiY3qiBjXoKv7Nxza2-yGhgxReE_nqEnzQTCcGn8b4plSczNBzbJKsrpTQIz88bpgpJtVotwJi0tTlB8cif0Qs45-cmSd4Tok_Xcberd-syBX23tJOtw6ywapqzaP9KkkN7zdDS7GnoWKKxChLFRA7fESJ7y0i5CUQvT6JEUARKAhx_ftWsMxio4JMuk6npYizUf2XHSgRz6st1kkGXuBCC3gMMSBQCxJFLDp_-7PJN2rrpbDsW5CTLLmK_8U7BjyFuho4h6qj-VtOhxG-SPY-9PunXp1iQ0o2rkISlcUR31S5S2LT92niTVE5QCYfwLDJrURMs.ZB6n0dwlTayi9SXR5AENdQ \ No newline at end of file diff --git a/home/logs/eotsd.log b/home/logs/eotsd.log deleted file mode 100644 index c5a9e33..0000000 --- a/home/logs/eotsd.log +++ /dev/null @@ -1,4 +0,0 @@ -2024-11-26T12:17:11.276407Z info successfully created an EOTS key {"key name": "eots1", "pk": "64d4fdd7f78950f905b2d957af256e781ed57f790860959a434148aa2e86240f"} -2024-11-26T12:18:05.346154Z info Metrics server is starting {"addr": "127.0.0.1:2113"} -2024-11-26T12:18:05.346421Z info RPC server listening {"address": "127.0.0.1:12582"} -2024-11-26T12:18:05.346476Z info EOTS Manager Daemon is fully active! From f6dfff3052dd09517fd74b5874b21a2ee73f5b3e Mon Sep 17 00:00:00 2001 From: Vitalis Salis Date: Tue, 26 Nov 2024 15:59:50 +0200 Subject: [PATCH 50/53] updates --- docs/finality-provider-operation.md | 232 ++++++++++++++-------------- 1 file changed, 118 insertions(+), 114 deletions(-) diff --git a/docs/finality-provider-operation.md b/docs/finality-provider-operation.md index ef0ccfe..53272cf 100644 --- a/docs/finality-provider-operation.md +++ b/docs/finality-provider-operation.md @@ -44,11 +44,16 @@ Thank you for participating in the first phase of the Babylon launch. This guide provides instructions for setting up the full finality provider toolset required for your participation in the second phase of the Babylon launch. -To ensure a safe and seamless transition without any loss of delegations, we -recommend completing the following setup tasks. First and foremost, it is -essential that you use the same key from Phase-1, as your delegations are -exclusively tied to this canonical key. - +Finality providers that received delegations on the first phase of the launch +are required to transition their finality providers to the second phase +using the same EOTS key that they used and registered with during phase-1. +The usage of a different key corresponds to setting up an entirely +different finality provider which will not inherit the phase-1 delegations. +Not transitioning your phase-1 finality provider keys, +will lead to your phase-1 stake delegations not being able to transition +to the second phase. + +How to follow this guide: - If you already have delegations and have set up a key during Phase-1, please proceed to [Adding Keys](#32-createadd-an-eots-key) to import your Phase-1 key. @@ -79,7 +84,7 @@ cd finality-provider git checkout ``` -### 2.2. Build and Install Finality Provider Toolset Binaries +### 2.2. Install Finality Provider Toolset Binaries Run the following command to build the binaries and install them to your `$GOPATH/bin` directory: @@ -143,29 +148,30 @@ Parameters: This section explains the process of setting up the private keys for the EOTS manager. Operators *must* create an EOTS key before starting the -EOTS daemon. We will be using the [cosmos-sdk](https://docs.cosmos.network/v0.52/user/run-node/keyring) backends for key storage. Below is an overview of the supported keyrings and their - usecases. - -For storing the key, the following keyrings are supported: `test`, `os`, `file`. +EOTS daemon.= +We will be using the [cosmos-sdk](https://docs.cosmos.network/v0.52/user/run-node/keyring) +backends for key storage, +which offer support for the following keyrings: - `test` is a password-less keyring and is unencrypted on disk. - `os` uses the system's secure keyring and will prompt for a passphrase at startup. - `file` encrypts the keyring with a passphrase and stores it on disk. Operators can choose whether to keep the key encrypted or unencrypted on disk based on their requirements. However, for production workloads, we recommend -using the os or file keyrings for enhanced security. +using the `os` or `file` keyring backends for enhanced security. -For consistency purposes, we will be using the `test` keyring throughout the +For simplicity, we will be using the `test` keyring throughout the rest of the document. - If you already have an existing key from Phase-1, proceed to [Import an existing EOTS key](#321-import-an-existing-eots-key) -- If you need to create a new key, proceed to [Create an EOTS key](#32-createadd-an-eots-key). +- If you need to create a new key, + proceed to [Create an EOTS key](#32-createadd-an-eots-key). #### 3.2.1. Import an existing EOTS key -> ⚡ This section is for Finality Providers who participated in Phase-1 and -> already possess an EOTS key. If you are a new user, you can skip this section. +> ⚡ This section is for Finality Providers who already possess an EOTS key. +> If you are a new user, you can skip this section. There are 3 supported methods of loading your existing EOTS keys: (1) using a mnemonic phrase, (2) exporting the `.asc` file, or (3) backing up your entire @@ -174,15 +180,15 @@ home directory. We have outlined each of these three paths for you below. #### Option 1: Using your Mnemonic Phrase If you are using your mnemonic seed phrase, use the following command to import -your key: +your key (with a keyring backend of your choice): ```shell -eotsd keys add --home --recover --keyring-backend test +eotsd keys add --home --recover --keyring-backend ``` You'll be prompted to enter: 1. Your BIP39 mnemonic phrase (24 words) -2. A passphrase to encrypt your key +2. A passphrase to encrypt your key if you chose the `os` or `file` keyring backends 3. HD path (optional - press Enter to use the default) > ⚡ The HD path is optional. If you used the default path when creating your key, @@ -208,10 +214,10 @@ VP88GFE= To load the key, use the following command: ```shell -eotsd keys import --home --keyring-backend test +eotsd keys import --home --keyring-backend ``` -#### Option 3: Using Home Directory Backup +#### Option 3: Using a File System Backup If you backed up your entire EOTS home directory, you can load it manually to the machine you intend to operate @@ -222,7 +228,7 @@ the EOTS daemon on and specify its location as the `--home` argument. After importing, you can verify that your EOTS key was successfully loaded: ```shell -eotsd keys list --home --keyring-backend test +eotsd keys list --home --keyring-backend ``` Parameters: @@ -233,7 +239,7 @@ Parameters: You should see your EOTS key listed with the correct details, confirming that it has been imported correctly. ->⚠️ **Important**: +> ⚠️ **Important**: > If you are a finality provider transitioning your stack from phase-1, > make sure that you are using the same EOTS key that you > registered in Phase-1. @@ -244,17 +250,14 @@ If you have not created an EOTS key, use the following command to create a new one: ``` shell -eotsd keys add --key-name --home --keyring-backend test +eotsd keys add --key-name --home --keyring-backend ``` Parameters: - ``: Name for your EOTS key (e.g., "eots-key-1"). We do not allow the same `keyname` for an existing keyname. - `--home`: Path to your EOTS daemon home directory (e.g., "~/.eotsHome") -- `--keyring-backend`: Type of keyring storage: - - `test`: Stores keys unencrypted, no passphrase prompts - - `os`: Uses system's secure keyring, requires passphrase at startup - - `file`: Encrypted file storage, requires passphrase at startup +- `--keyring-backend`: Type of keyring storage The command will return a JSON response containing your EOTS key details: @@ -270,7 +273,7 @@ The command will return a JSON response containing your EOTS key details: } ``` -> **Security Tip 🔒**: The mnemonic phrase must be stored securely and kept private. +> **🔒 Security Tip**: The mnemonic phrase must be stored securely and kept private. > It is the only way to recover your EOTS key if you lose access to it and > if lost it can be used by third parties to get access to your key. @@ -294,7 +297,7 @@ this value by specifying a custom address with the `--rpc-listener` flag. EOTS Manager Daemon is fully active! ``` ->**Security Tip 🔒**: +>**🔒 Security Tip**: > * `eotsd` holds your private keys which are used for signing > * operate the daemon in a separate machine or network segment > with enhanced security @@ -307,7 +310,8 @@ EOTS Manager Daemon is fully active! ### 4.1. Initialize the Finality Provider Daemon -To initialize the finality provider daemon, use the following command: +To initialize the finality provider daemon home directory, +use the following command: ```shell fpd init --home @@ -328,58 +332,27 @@ Since this key is accessed by an automated daemon process, it must be stored unencrypted on disk and associated with the `test` keyring backend. This ensures that the finality provider daemon can promptly submit transactions, such as block votes and public randomness submissions that are -essential for its liveness and earning rewards. +essential for its liveness and earning of rewards. For the `fpd` keyring, the `test` backend will be exclusively used, and it is mandatory that you follow this practice until automated key management becomes available. Additionally, we are also exploring options to support different -withdrawal addresses. +withdrawal addresses, so that rewards can go to a separate address. It is also important to note that the finality provider daemon will refund -certain fees, such as those for transactions that are required for the -finality provider's operation. As this keyring is used for both earning and +fees for the submission of valid votes as those are essential for the protocol. +All other transactions, will require gas, but will be happening infrequently +or only once. As this keyring is used for both earning and operational purposes, we strongly recommend maintaining only the necessary -funds for operations in the keyring. - ->⚠️ **Important**: ->To operate your Finality Provider, ensure your Babylon account is funded. ->Block vote transactions have their gas fees refunded, but public randomness ->submissions require gas payments. For testnet, you can obtain funds from our ->[faucet](#add-faucet). - - -We recommend **not** holding a large number of funds here—just enough for -operations. We are also exploring ways to support different withdrawal addresses. - -We encourage the following for keyring maintenance: -- **Backup Keys**: Use mnemonic phrases, export key files, or back up the home -directory. -- **Monitor Regularly**: Check for unauthorized activity, monitor status changes, - balance and gas usage. -- **Keyring Transition**: Replace the test keyring with a secure backend when -available. - -For gas requirements, the finality provider daemon will -automatically handle gas fees, but we recommend monitoring -the gas usage to ensure the finality provider is functioning properly. - -The transaction types that consume gas are: -- `MsgRegisterFinalityProvider`: Registration (requires gas) -- `MsgSubmitFinalityVote`: Block vote transactions (gas is refunded) -- `MsgCommitPubRandList`: Public randomness submissions (requires gas) - -**Keyring Security 🔒**: -The finality provider daemon uses the `--keyring-backend test` which stores keys -unencrypted on disk. While this is generally not secure, it's necessary for the -finality provider service because: - -- The daemon needs to automatically sign and send transactions frequently -- If transactions stop for too long, the provider gets jailed -- Using encrypted keystores would require manual password entry after every restart -- Service availability is critical to avoid jailing - -We are actively working on implementing more secure keyring solutions that maintain -both security and high availability. +funds for operations in the keyring, and extracting the rest into +more secure locations. + +> ⚠️ **Important**: +> To operate your Finality Provider, ensure your Babylon account is funded. +> Block vote transactions have their gas fees refunded, but public randomness +> submissions require gas payments. For testnet, you can obtain funds from our +> [faucet](#add-faucet). + Use the following command to add the Babylon key for your finality provider: @@ -388,7 +361,7 @@ fpd keys add --keyring-backend test --home ``` The above `keys add` command will create a new key pair and store it in your keyring. -The output should look similar to the below: +The output should look similar to the one below: ``` json { @@ -419,7 +392,7 @@ RpcListener = 127.0.0.1:12581 [babylon] Key = # the key you used above -ChainID = bbn-test-5 +ChainID = bbn-test-5 # chain ID of the Babylon chain RPCAddr = http://127.0.0.1:26657 GRPCAddr = https://127.0.0.1:9090 KeyDirectory = # The `--home`path to the directory where the keyring is stored @@ -441,7 +414,8 @@ Configuration parameters explained: * `KeyDirectory`: Path to your keyring directory (same as --home path) Please verify the `chain-id` and other network parameters from the official -Babylon Networks repository at [https://github.com/babylonlabs-io/networks/tree/main/bbn-test-5/finality-providers](https://github.com/babylonlabs-io/networks/tree/main/bbn-test-5/finality-providers) +[Babylon Networks +repository](https://github.com/babylonlabs-io/networks/tree/main/bbn-test-5/). ### 4.4. Starting the Finality Provider Daemon @@ -459,8 +433,8 @@ The command flags: - `start`: Runs the FPD daemon - `--home`: Specifies the directory for daemon data and configuration -The daemon will start the RPC server for CLI communication then begin listening -for incoming requests and finally initialize finality provider services +The daemon will establish a connection with the Babylon blockchain and +boot up its RPC server for executing CLI requests. You should see logs indicating successful startup: @@ -469,11 +443,9 @@ You should see logs indicating successful startup: [INFO] RPC server listening on... ``` ->⚠️ **Important**: The daemon needs to run continuously. It's recommended to set ->up a system service (like `systemd` on Linux or `launchd` on macOS) to manage ->the daemon process, handle automatic restarts, and collect logs. For testing -you can run the daemon directly in a terminal, but remember it must stay -running to function properly. +> ⚠️ **Important**: The daemon needs to run continuously. It's recommended to set +> up a system service (like `systemd` on Linux or `launchd` on macOS) to manage +> the daemon process, handle automatic restarts, and collect logs. The above will start the Finality provider RPC server at the address specified in `fpd.conf` under the `RpcListener` field, which has a default value @@ -481,13 +453,39 @@ of `127.0.0.1:12581`. You can change this value in the configuration file or override this value and specify a custom address using the `--rpc-listener` flag. -To start the daemon with a specific finality provider instance after -registration, use the `--eots_pk_hex` flag followed by the hex string of the EOTS -public key of the finality provider. - All the available CLI options can be viewed using the `--help` flag. These options can also be set in the configuration file. +### 4.5. Interaction with the EOTS Manager + + + ## 5. Finality Provider Operations ### 5.1 Create Finality Provider @@ -499,29 +497,39 @@ instance locally. fpd create-finality-provider \ --daemon-address 127.0.0.1:12581 \ --chain-id bbn-test-5 \ - --eots-pk \ # this was output in fpd keys add + --eots-pk \ --commission 0.05 \ --key-name finality-provider \ --moniker "MyFinalityProvider" \ --website "https://myfinalityprovider.com" \ --security-contact "security@myfinalityprovider.com" \ --details "finality provider for the Babylon network" \ - --home ./fpHome \ - --passphrase "passphrase" + --home ./fpHome ``` + + Required parameters: -- `--chain-id`: The Babylon chain ID (`bbn-test-5`) +- `--chain-id`: The Babylon chain ID (e.g., for the testnet, `bbn-test-5`) - `--commission`: The commission rate (between 0 and 1) that you'll receive from delegators - `--key-name`: The key name in your Babylon keyring that your finality provider will be associated with - `--moniker`: A human-readable name for your finality provider + Optional parameters: -- `--eots-pk`: The EOTS public key of the finality provider. If one is not -provided a new one will be created but please use the same EOTS key that you -generated in `fpd keys add` +- `--eots-pk`: The EOTS public key maintained by the connected EOTS manager + instance that the finality provider should use. + If one is not provided the finality provider will request + the creation of a new one from the connected EOTS manager instance. - `--website`: Your finality provider's website - `--security-contact`: Contact email for security issues - `--details`: Additional description of your finality provider @@ -551,32 +559,29 @@ your finality provider's details: The response includes: - `fp_addr`: Your Babylon account address for receiving rewards -- `eots_pk_hex`: Your unique BTC public key identifier (needed for - registration) +- `eots_pk_hex`: Your unique BTC public key identifier - `description`: Your finality provider's metadata - `commission`: Your set commission rate - `status`: Current status of the finality provider. + Below you can see a list of the statuses that a finality provider can transition to: - -``` - - `CREATED`: defines a finality provider that is awaiting registration - - `REGISTERED`: defines a finality provider that has been registered - to the consumer chain but has no delegated stake - - `ACTIVE`: defines a finality provider that is delegated to vote - - `INACTIVE`: defines a finality provider whose delegations are reduced to - zero but not slashed - - `JAILED`: defines a finality provider that has been jailed -``` +- `CREATED`: defines a finality provider that is awaiting registration +- `REGISTERED`: defines a finality provider that has been registered + to the consumer chain but has no delegated stake +- `ACTIVE`: defines a finality provider that is delegated to vote +- `INACTIVE`: defines a finality provider whose delegations are reduced to + zero but not slashed +- `JAILED`: defines a finality provider that has been jailed ### 5.2. Register Finality Provider The `register-finality-provider` command registers your finality provider on the -Babylon chain. This command requires: +Babylon chain. This command requires you to specify: -1. The EOTS public key +1. The EOTS public key of the finality provider you wish to register 2. The Babylon account associated with your finality provider (the one specified in the creation) having sufficient funds to pay for the transaction fee. @@ -613,8 +618,6 @@ hash on the Babylon chain. demonstrate that the finality provider has the status `REGISTERED`? That would be a native way to verify the installation, without having to touch Babylon. Natural way to introduce the `CREATED` status. - -Maybe we can find a way to naturally introduce the `ACTIVE` or `INACTIVE` statuses. --> ### 5.3. Withdrawing Rewards @@ -647,7 +650,8 @@ When jailed, the following happens to a finality provider: To unjail a finality provider, you must complete the following steps: 1. Fix the underlying issue that caused jailing 2. Wait for the jailing period to pass (if it was due to downtime) -3. Then send the unjail transaction to the Babylon chain (not the finality provider daemon). +3. Then send the unjail transaction to the + Babylon chain using the following command. ```shell fpd unjail-finality-provider --daemon-address --home @@ -725,4 +729,4 @@ prometheus-retention-time = 600 # 10 minutes [api] enable = true address = "127.0.0.1:12581" # change this to 127.0.0.1:12582 for the eots manager -``` --> --> \ No newline at end of file +``` --> \ No newline at end of file From 6c2c4831d9c639cb6940d63559eedd25f01c45e7 Mon Sep 17 00:00:00 2001 From: Sam Ricotta Date: Tue, 26 Nov 2024 17:57:57 +0200 Subject: [PATCH 51/53] Update finality-provider-operation.md --- docs/finality-provider-operation.md | 70 ++++++++++++++--------------- 1 file changed, 35 insertions(+), 35 deletions(-) diff --git a/docs/finality-provider-operation.md b/docs/finality-provider-operation.md index 53272cf..2120533 100644 --- a/docs/finality-provider-operation.md +++ b/docs/finality-provider-operation.md @@ -458,33 +458,35 @@ options can also be set in the configuration file. ### 4.5. Interaction with the EOTS Manager - +There are 2 pieces to a finality provider entity: the EOTS manager and the +finality provider instance. These components work together and are managed by +separate daemons(`eotsd` and `fpd`). + +The EOTS manager is responsible for managing the keys for finality providers and +handles operations such as key management, signature generation, and randomness +commitments. Where as the finality provider is responsible for creating and +registering finality providers and handling the monitoring of the Babylon chain. +The finality provider daemon is also responsible for coordinating various +operations. + +The interactions between the EOTS Manager and the finality provider happens +through RPC calls. These calls handle key operations, signature generation, +and randomness commitments. An easy way to think about it is the EOTS Manager +maintains the keys while the FP daemon coordinates any interactions with the +Babylon chain. + +The EOTS Manager is designed to handle multiple finality provider keys, operating +as a centralized key management system. When starting a finality provider instance, +you specify which EOTS key to use through the `--eots-pk` flag. This allows you +to run different finality provider instances using different keys from the same +EOTS Manager. + +For example, after registering a finality provider, you can start its daemon by +providing the EOTS public key: + +```shell +fpd start --eots-pk +``` ## 5. Finality Provider Operations @@ -517,14 +519,10 @@ Required parameters: provider will be associated with - `--moniker`: A human-readable name for your finality provider - Optional parameters: - `--eots-pk`: The EOTS public key maintained by the connected EOTS manager instance that the finality provider should use. @@ -565,7 +563,6 @@ The response includes: - `status`: Current status of the finality provider. - Below you can see a list of the statuses that a finality provider can transition to: - `CREATED`: defines a finality provider that is awaiting registration @@ -576,6 +573,9 @@ to: zero but not slashed - `JAILED`: defines a finality provider that has been jailed +For more information on statuses please refer to diagram in the core documentation +[fp-core](./fp-core). + ### 5.2. Register Finality Provider The `register-finality-provider` command registers your finality provider on the From 40e1c0e075004136084a2f80363667d22b82e8c8 Mon Sep 17 00:00:00 2001 From: Sam Ricotta Date: Wed, 27 Nov 2024 12:44:44 +0200 Subject: [PATCH 52/53] last review comments --- README.md | 38 ++++--- docs/finality-provider-operation.md | 151 +++++++++------------------- 2 files changed, 70 insertions(+), 119 deletions(-) diff --git a/README.md b/README.md index 4f1b7c3..12e288f 100644 --- a/README.md +++ b/README.md @@ -3,7 +3,7 @@ Finality providers are key participants in Babylon BTC staking protocol. They provide finality votes on top of [CometBFT](https://github.com/cometbft/cometbft), Babylon's consensus mechanism. -Through these activities, they can earn commissions from BTC staking delegations. +and earn commissions from BTC staking delegations. The finality provider toolset operates on standard UNIX-based systems and consists of three core components: @@ -36,12 +36,6 @@ all EOTS key operations. For instructions on creating and operating a finality provider, see our [Finality Provider Guide](./docs/finality-provider-operation.md). -## Technical Documentation - -For detailed technical information about the finality provider's internal operations, see: -* [Core Heuristics](./docs/fp-core.md) -* [Public Randomness Commits](./docs/commit-pub-rand.md) - ## High Level Descriptions of EOTS and Finality Provider @@ -53,12 +47,20 @@ using them to produce EOTS signatures. **Note:** EOTS stands for Extractable One Time Signature. You can read more about it in the [Babylon BTC Staking Litepaper](https://docs.babylonchain.io/assets/files/btc_staking_litepaper-32bfea0c243773f0bfac63e148387aef.pdf). -In short, the EOTS manager produces EOTS public/private randomness pairs. The +In short, the EOTS manager generates EOTS public/private randomness pairs. The finality provider commits the public part of these pairs to Babylon for every future block height that they intend to provide a finality signature for. If the finality provider votes for two different blocks on the same height, they will have to reuse -the same private randomness which will lead to their underlying private key being -exposed, leading to the slashing of them and all their delegators. +the same private randomness which will lead to their EOTS private key being +exposed, leading to the slashing. In the context of finality providers, slashing +means that once a provider is slashed, its voting power is immediately reduced to +zero following a double sign, and this consequence is permanent. Additionally, +finality providers with an exposed private EOTS key may face a penalty where their +BTC delegations are partially burned according to a globally defined proportion. +For instance, if a finality provider has BTC delegations of 10 BTC and 100 BTC, +and the burn proportion is set to 10%, then after a slashing transaction is +executed on the Bitcoin network, 1 BTC and 10 BTC, respectively, will be burned, +with the remaining amounts returned to the delegators. The EOTS manager is responsible for the following operations: @@ -66,7 +68,7 @@ The EOTS manager is responsible for the following operations: - Generates [Schnorr](https://en.wikipedia.org/wiki/Schnorr_signature) key pairs for a given finality provider using the [BIP-340](https://github.com/bitcoin/bips/blob/master/bip-0340.mediawiki) - standard. + standard as its EOTS key pair - Persists generated key pairs in the internal Cosmos keyring. 2. **Randomness Generation:** - Generates lists of EOTS randomness pairs based on the EOTS key, chainID, and @@ -102,14 +104,20 @@ providers: `JAILED`, and `SLASHED` states, while enforcing slashing conditions and handling the jailing process when violations occur. -5. **Security and Key Management**: The system manages EOTS keys for signature - generation and Babylon keys for transaction processing and rewards distribution. - It maintains secure coordination with the EOTS daemon for all key-related - operations. +5. **Security and Key Management**: The daemon manages Babylon keys for signing + transactions and rewards distribution. It maintains secure coordination with + the EOTS daemon for all key-related operations. The daemon is controlled by the `fpd` tool, which provides commands for interacting with the running daemon. +## Technical Documentation + +For detailed technical information about the finality provider's internal operations, see: +* [Core Heuristics](./docs/fp-core.md) +* [Public Randomness Commits](./docs/commit-pub-rand.md) +* [Send Finality Votes] is also ready at ./docs/send-finality-vote.md. + ## Overview of Keys for Finality Provider and EOTS Manager There are two distinct keys you'll be working with: diff --git a/docs/finality-provider-operation.md b/docs/finality-provider-operation.md index 2120533..0cbe901 100644 --- a/docs/finality-provider-operation.md +++ b/docs/finality-provider-operation.md @@ -36,7 +36,6 @@ gain an overall understanding of the finality provider. 3. [Withdrawing Rewards](#53-withdrawing-rewards) 4. [Jailing and Unjailing](#54-jailing-and-unjailing) 5. [Slashing](#55-slashing) -6. [Prometheus Metrics](#6-prometheus-metrics) ## 1. A note about Phase-1 Finality Providers @@ -46,12 +45,11 @@ for your participation in the second phase of the Babylon launch. Finality providers that received delegations on the first phase of the launch are required to transition their finality providers to the second phase -using the same EOTS key that they used and registered with during phase-1. +using the same EOTS key that they used and registered with during Phase-1. The usage of a different key corresponds to setting up an entirely -different finality provider which will not inherit the phase-1 delegations. -Not transitioning your phase-1 finality provider keys, -will lead to your phase-1 stake delegations not being able to transition -to the second phase. +different finality provider which will not inherit the Phase-1 delegations. +Not transitioning your Phase-1 finality provider prevents your Phase-1 delegations +from transitioning to the second phase. How to follow this guide: - If you already have delegations and have set up a key during Phase-1, @@ -139,29 +137,29 @@ with the following command: eotsd init --home ``` +If `eotsd.conf` already exists `init` will not succeed, if the operator wishes to +overwrite the config file they need to use `--force`. + Parameters: - `--home`: Directory for EOTS Manager configuration and data - - Default: `/Users//Library/Application Support/Eotsd` + - Default: `DefaultEOTSDir` the default EOTS home directory - Example: `--home ./eotsHome` -### 3.2. Create/Add an EOTS Key +### 3.2. Add an EOTS Key This section explains the process of setting up the private keys for the EOTS manager. Operators *must* create an EOTS key before starting the -EOTS daemon.= -We will be using the [cosmos-sdk](https://docs.cosmos.network/v0.52/user/run-node/keyring) -backends for key storage, -which offer support for the following keyrings: -- `test` is a password-less keyring and is unencrypted on disk. -- `os` uses the system's secure keyring and will prompt for a passphrase at startup. -- `file` encrypts the keyring with a passphrase and stores it on disk. +EOTS daemon. -Operators can choose whether to keep the key encrypted or unencrypted on disk -based on their requirements. However, for production workloads, we recommend -using the `os` or `file` keyring backends for enhanced security. +We will be using the [Cosmos SDK](https://docs.cosmos.network/v0.52/user/run-node/keyring) +backends for key storage. At this point in time we are only offering `test` keyring +until further development and testing. -For simplicity, we will be using the `test` keyring throughout the -rest of the document. +Since this key is accessed by an automated daemon process, it must be stored +unencrypted on disk and associated with the `test` keyring backend. +This ensures that the finality provider daemon can promptly submit +transactions, such as block votes and public randomness submissions that are +essential for its liveness and earning of rewards. - If you already have an existing key from Phase-1, proceed to [Import an existing EOTS key](#321-import-an-existing-eots-key) @@ -173,11 +171,13 @@ rest of the document. > ⚡ This section is for Finality Providers who already possess an EOTS key. > If you are a new user, you can skip this section. -There are 3 supported methods of loading your existing EOTS keys: (1) using a -mnemonic phrase, (2) exporting the `.asc` file, or (3) backing up your entire -home directory. We have outlined each of these three paths for you below. +There are 3 supported methods of loading your existing EOTS keys: +1. sing a mnemonic phrase +2. exporting the `.asc` file +3. backing up your entire home directory. We have outlined each of these + three paths for you below. -#### Option 1: Using your Mnemonic Phrase +#### Option 1: Using your mnemonic phrase If you are using your mnemonic seed phrase, use the following command to import your key (with a keyring backend of your choice): @@ -192,7 +192,8 @@ You'll be prompted to enter: 3. HD path (optional - press Enter to use the default) > ⚡ The HD path is optional. If you used the default path when creating your key, -you can skip this by pressing Enter. +you can skip this by pressing `Enter` , which by default uses your original private +key. #### Option 2: Using your `.asc` file @@ -240,7 +241,7 @@ You should see your EOTS key listed with the correct details, confirming that it has been imported correctly. > ⚠️ **Important**: -> If you are a finality provider transitioning your stack from phase-1, +> If you are a finality provider transitioning your stack from Phase-1, > make sure that you are using the same EOTS key that you > registered in Phase-1. @@ -259,7 +260,6 @@ the same `keyname` for an existing keyname. - `--home`: Path to your EOTS daemon home directory (e.g., "~/.eotsHome") - `--keyring-backend`: Type of keyring storage - The command will return a JSON response containing your EOTS key details: ``` @@ -279,7 +279,7 @@ The command will return a JSON response containing your EOTS key details: ### 3.3. Starting the EOTS Daemon -To start the EOTS daemon use the following command: +To start the EOTS daemon, use the following command: ```shell eotsd start --home @@ -317,6 +317,9 @@ use the following command: fpd init --home ``` +If `fpd.conf` already exists `init` will not succeed, if the operator wishes to +overwrite the config file they need to use `--force`. + > ⚡ Running this command may return the message > `service injective.evm.v1beta1.Msg does not have cosmos.msg.v1.service proto annotation`, @@ -374,11 +377,6 @@ The output should look similar to the one below: "type": "local" } ``` - -This command will automatically update the `Key` field in -the config file to use this key name. This key will be used for all interactions -with the Babylon chain, including finality provider registration and transaction -signing. ### 4.3. Configure Your Finality Provider @@ -388,25 +386,25 @@ following parameters: ```shell [Application Options] EOTSManagerAddress = 127.0.0.1:12582 -RpcListener = 127.0.0.1:12581 +RPCListener = 127.0.0.1:12581 [babylon] Key = # the key you used above ChainID = bbn-test-5 # chain ID of the Babylon chain RPCAddr = http://127.0.0.1:26657 GRPCAddr = https://127.0.0.1:9090 -KeyDirectory = # The `--home`path to the directory where the keyring is stored +KeyDirectory = # The `--home` path to the directory where the keyring is stored ``` > ⚠️ **Important**: Operating a finality provider requires a connection to a > Babylon blockchain node. It is **highly recommended** to operate your own > Babylon full node instead of relying on third parties. You can find > instructions on setting up a Babylon node -> [here](https://github.com/babylonlabs-io/networks/tree/main/bbn-1/node-setup). +> [here](https://github.com/babylonlabs-io/networks/tree/main/bbn-test-5/babylon-node/README.md). Configuration parameters explained: * `EOTSManagerAddress`: Address where your EOTS daemon is running -* `RpcListener`: Address for the finality provider RPC server +* `RPCListener`: Address for the finality provider RPC server * `Key`: Your Babylon key name from Step 2 * `ChainID`: The Babylon network chain ID * `RPCAddr`: Your Babylon node's RPC endpoint @@ -433,7 +431,7 @@ The command flags: - `start`: Runs the FPD daemon - `--home`: Specifies the directory for daemon data and configuration -The daemon will establish a connection with the Babylon blockchain and +The daemon will establish a connection with the Babylon node and boot up its RPC server for executing CLI requests. You should see logs indicating successful startup: @@ -448,7 +446,7 @@ You should see logs indicating successful startup: > the daemon process, handle automatic restarts, and collect logs. The above will start the Finality provider RPC server at the address specified -in `fpd.conf` under the `RpcListener` field, which has a default value +in `fpd.conf` under the `RPCListener` field, which has a default value of `127.0.0.1:12581`. You can change this value in the configuration file or override this value and specify a custom address using the `--rpc-listener` flag. @@ -509,10 +507,14 @@ fpd create-finality-provider \ --home ./fpHome ``` - + Required parameters: - `--chain-id`: The Babylon chain ID (e.g., for the testnet, `bbn-test-5`) +- `--eots-pk`: The EOTS public key maintained by the connected EOTS manager + instance that the finality provider should use. + If one is not provided the finality provider will request + the creation of a new one from the connected EOTS manager instance. - `--commission`: The commission rate (between 0 and 1) that you'll receive from delegators - `--key-name`: The key name in your Babylon keyring that your finality @@ -524,10 +526,6 @@ Required parameters: > multiple finality providers. Optional parameters: -- `--eots-pk`: The EOTS public key maintained by the connected EOTS manager - instance that the finality provider should use. - If one is not provided the finality provider will request - the creation of a new one from the connected EOTS manager instance. - `--website`: Your finality provider's website - `--security-contact`: Contact email for security issues - `--details`: Additional description of your finality provider @@ -562,7 +560,6 @@ The response includes: - `commission`: Your set commission rate - `status`: Current status of the finality provider. - Below you can see a list of the statuses that a finality provider can transition to: - `CREATED`: defines a finality provider that is awaiting registration @@ -572,9 +569,12 @@ to: - `INACTIVE`: defines a finality provider whose delegations are reduced to zero but not slashed - `JAILED`: defines a finality provider that has been jailed +- `SLASHED`: Defines a finality provider that has been permanently removed from + the network for double signing (signing conflicting blocks at the same height). + This state is irreversible. For more information on statuses please refer to diagram in the core documentation -[fp-core](./fp-core). +[fp-core](fp-core.md). ### 5.2. Register Finality Provider @@ -612,8 +612,6 @@ You can verify the transaction was successful by looking up this transaction hash on the Babylon chain. - - - - - \ No newline at end of file + \ No newline at end of file From b0fc1f0c60b244573fdc4cd74cafe44d048e2cb9 Mon Sep 17 00:00:00 2001 From: Sam Ricotta Date: Wed, 27 Nov 2024 13:00:05 +0200 Subject: [PATCH 53/53] small comments --- docs/finality-provider-operation.md | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/docs/finality-provider-operation.md b/docs/finality-provider-operation.md index 0cbe901..e039e64 100644 --- a/docs/finality-provider-operation.md +++ b/docs/finality-provider-operation.md @@ -21,7 +21,7 @@ gain an overall understanding of the finality provider. 2. [Install Finality Provider Toolset](#2-install-finality-provider-toolset) 3. [Setting up the EOTS Daemon](#3-setting-up-the-eots-daemon) 1. [Initialize the EOTS Daemon](#31-initialize-the-eots-daemon) - 2. [Create/Add an EOTS Key](#32-createadd-an-eots-key) + 2. [Add an EOTS Key](#32-add-an-eots-key) 1. [Import an existing EOTS key](#321-import-an-existing-eots-key) 2. [Create an EOTS key](#322-create-an-eots-key) 3. [Starting the EOTS Daemon](#33-starting-the-eots-daemon) @@ -53,7 +53,7 @@ from transitioning to the second phase. How to follow this guide: - If you already have delegations and have set up a key during Phase-1, - please proceed to [Adding Keys](#32-createadd-an-eots-key) to import your + please proceed to [Adding Keys](#32-add-an-eots-key) to import your Phase-1 key. - If you are just starting out, you can begin with the setup steps outlined below. @@ -161,10 +161,8 @@ This ensures that the finality provider daemon can promptly submit transactions, such as block votes and public randomness submissions that are essential for its liveness and earning of rewards. -- If you already have an existing key from Phase-1, proceed to - [Import an existing EOTS key](#321-import-an-existing-eots-key) -- If you need to create a new key, - proceed to [Create an EOTS key](#32-createadd-an-eots-key). +If you already have an existing key from Phase-1, proceed to +[Import an existing EOTS key](#321-import-an-existing-eots-key) #### 3.2.1. Import an existing EOTS key @@ -338,7 +336,7 @@ transactions, such as block votes and public randomness submissions that are essential for its liveness and earning of rewards. For the `fpd` keyring, the `test` backend will be exclusively used, and it is -mandatory that you follow this practice until automated key management becomes +mandatory that you follow this practice until automated key management becomes available. Additionally, we are also exploring options to support different withdrawal addresses, so that rewards can go to a separate address.