diff --git a/docs/run-first-validator.md b/docs/run-first-validator.md index eac5cc7..16d25a6 100644 --- a/docs/run-first-validator.md +++ b/docs/run-first-validator.md @@ -7,8 +7,151 @@ - LPS distribution Google spreadsheet URL or CSV file path - Install `gzip` using `sudo apt install gzip` +## Setup node + +- Run the following steps in the machine where the mainnet node is to be setup + +- Copy the example variables file if not already done: + + ```bash + cp ~/cerc/laconicd-stack/playbooks/first-validator/first-validator-vars.example.yml ~/cerc/laconicd-stack/playbooks/first-validator/first-validator-vars.yml + ``` + +- Update `~/cerc/laconicd-stack/playbooks/first-validator/first-validator-vars.yml` with required values: + + ```bash + # Set custom moniker for the node + cerc_moniker: "LaconicMainnetNode" + + # Set desired key name + key_name: "laconic-validator" + ``` + +- Export the data directory and mainnet deployment directory as environment variables: + + ```bash + # Parent directory where the deployment directory will live + export DATA_DIRECTORY= + + # Set mainnet deployment directory + # for eg: mainnet-laconicd-deployment + export MAINNET_DEPLOYMENT_DIR= + ``` + +- Run ansible playbook to setup the node: + + ```bash + ansible-playbook -i localhost, -c local ~/cerc/laconicd-stack/playbooks/first-validator/setup-first-validator.yml + ``` + +- Get the public key of your node: + + ```bash + docker run -it \ + -v ./$MAINNET_DEPLOYMENT_DIR/data/laconicd-data:/root/.laconicd \ + cerc/laconicd:local bash -c "laconicd tendermint show-validator" + ``` + + NOTE: This public key is required in next step to generate the genesis file + +### Setup TMKMS (Optional but Recommended) + + + +- For integrating existing TMKMS with laconicd, follow steps below in the machine where TMKMS is setup + +- Set `$TMKMS_HOME` to the directory path containing TMKMS config files + + ```bash + # Contents of tmkms config directory + ls -l $TMKMS_HOME + drwxrwxr-x 2 ... schema + drwx------ 2 ... secrets + drwxrwxr-x 2 ... state + -rw-rw-r-- 1 ... tmkms.toml + ``` + +- Update the TMKMS configuration file `$TMKMS_HOME/tmkms.toml`: + + ```toml + [[chain]] + id = "laconic-mainnet" + key_format = { type = "cosmos-json", account_key_prefix = "laconicpub", consensus_key_prefix = "laconicvalconspub" } + # Replace with absolute path to tmkms config directory + state_file = "/state/priv_validator_state.json" + + [[validator]] + chain_id = "laconic-mainnet" + # Replace with actual IP address of the laconicd node + addr = "tcp://:26659" + # Replace with absolute path to tmkms config directory + secret_key = "/secrets/kms-identity.key" + protocol_version = "v0.34" + reconnect = true + + [[providers.softsign]] + key_type = "consensus" + # Replace with absolute path to tmkms config directory + path = "/secrets/priv_validator_key" + chain_ids = ["laconic-mainnet"] + ``` + +- Copy your validator key to TMKMS: + + - The validator key in laconicd node deployment is present at `$DATA_DIRECTORY/$MAINNET_DEPLOYMENT_DIR/data/laconicd-data/config/priv_validator_key.json` + + - Place the validator key file in TMKMS config directory at `$TMKMS_HOME/secrets/` + + - Import the private validator key into tmkms: + + ```bash + tmkms softsign import $TMKMS_HOME/secrets/priv_validator_key.json $TMKMS_HOME/secrets/priv_validator_key + ``` + + - Remove the JSON key file + + ```bash + rm $TMKMS_HOME/secrets/priv_validator_key.json + ``` + +- Start TMKMS: + + ```bash + tmkms start --config $TMKMS_HOME/tmkms.toml + ``` + + - Expected example output: + + ```bash + INFO tmkms::commands::start: tmkms 0.14.0 starting up... + INFO tmkms::keyring: [keyring:softsign] added consensus Ed25519 key: {"@type":"/cosmos.crypto.ed25519.PubKey","key":"T24No1A1FmetNRVCOSg2G2XAKWh97oBXuELdAD6DFgw="} + INFO tmkms::connection::tcp: KMS node ID: 7f5fd8dae8953e964e7e56edd4700f597ea0d45c + ERROR tmkms::client: [laconic-mainnet@tcp://localhost:26659] I/O error: Connection refused (os error 111) + ``` + + NOTE: The errors dissapear once the laconicd node starts + + - Note the pubkey logged at start for comparing later with validator pubkey on chain + +- Enable TMKMS in the laconicd node configuration: + + ```bash + # Set TMKMS_ENABLED to true in the node's config.env + echo "TMKMS_ENABLED=true" >> $DATA_DIRECTORY/$MAINNET_DEPLOYMENT_DIR/config.env + ``` + +- Remove the validator key from node deployment as it is no longer required + + ```bash + rm $DATA_DIRECTORY/$MAINNET_DEPLOYMENT_DIR/data/laconicd-data/config/priv_validator_key.json + ``` + + NOTE: Store it safely offline in case of an emergency + ## Export testnet state +- Run the following steps in machine where the testnet node is running + - Get your private key from testnet deployment: ```bash @@ -39,17 +182,19 @@ ## Generate mainnet genesis file -- If mainnet node is to be setup in a new machine, fetch the stack again: +- Run the following steps in secure machine separate from the one where the node is setup + +- Fetch the stack: ```bash laconic-so fetch-stack git.vdb.to/cerc-io/laconicd-stack --git-ssh --pull ``` -- Copy over compressed `testnet-state.gz` file to target machine +- Copy over compressed `testnet-state.gz` file -- Extract the testnet-state JSON file +- Extract the testnet-state JSON file: - ``` + ```bash gzip -dc /testnet-state.gz > testnet-state.json # Remove zip folder @@ -64,66 +209,13 @@ - This will generate the `distribution.json` file -- Copy over the LPS lockup distribution `distribution.json` file to target machine - - Set envs: ```bash export EXPORTED_STATE_PATH= export LPS_DISTRIBUTION_PATH= export EARLY_SUPPORTS_ACC_ADDR= - ``` -- Copy the example variables file: - - ```bash - cp ~/cerc/laconicd-stack/playbooks/first-validator/first-validator-vars.example.yml ~/cerc/laconicd-stack/playbooks/first-validator/first-validator-vars.yml - ``` - -- Run playbook to use exported state for generating mainnet genesis: - - ```bash - ansible-playbook -i localhost, -c local ~/cerc/laconicd-stack/playbooks/first-validator/generate-genesis.yml -e "exported_state_path=$EXPORTED_STATE_PATH" -e "lps_distribution_path=$LPS_DISTRIBUTION_PATH" -e "early_supports_acc_address=$EARLY_SUPPORTS_ACC_ADDR" - ``` - -- Genesis file will be generated in output directory along with a file specifying the staking amount - - ```bash - # List files in output directory - genesis.json and staking-amount.json - ls -l output - ``` - -## Setup node - -- Copy the example variables file if not already done: - - ```bash - cp ~/cerc/laconicd-stack/playbooks/first-validator/first-validator-vars.example.yml ~/cerc/laconicd-stack/playbooks/first-validator/first-validator-vars.yml - ``` - -- Update `~/cerc/laconicd-stack/playbooks/first-validator/first-validator-vars.yml` with required values: - - ```bash - # Use the private key of the existing account that was exported in previous steps - pvt_key: "" - - # Path to the generated mainnet genesis file - # Use the absolute path of generated output directory in the previous steps - genesis_file: "/genesis.json" - - # Path to staking-amount.json generated in previous steps - staking_amount_file: "/staking-amount.json" - - # Set custom moniker for the node - cerc_moniker: "LaconicMainnetNode" - - # Set desired key name - key_name: "laconic-validator" - ``` - -- Export the data directory and mainnet deployment directory as environment variables: - - ```bash # Parent directory where the deployment directory will live export DATA_DIRECTORY= @@ -132,104 +224,43 @@ export MAINNET_DEPLOYMENT_DIR= ``` -- Run ansible playbook to submit gentx and setup the node: +- Copy the example variables file: ```bash - ansible-playbook -i localhost, -c local ~/cerc/laconicd-stack/playbooks/first-validator/setup-first-validator.yml + cp ~/cerc/laconicd-stack/playbooks/first-validator/first-validator-vars.example.yml ~/cerc/laconicd-stack/playbooks/first-validator/first-validator-vars.yml ``` -### Setup TMKMS (Optional but Recommended) - - - -- For integrating existing TMKMS with laconicd, follow steps below in the machine where TMKMS is setup - -- Set `$TMKMS_HOME` to the directory path containing TMKMS config files +- Edit `~/cerc/laconicd-stack/playbooks/first-validator/first-validator-vars.yml` with required values: ```bash - # Contents of tmkms config directory - ls -l $TMKMS_HOME - drwxrwxr-x 2 ... schema - drwx------ 2 ... secrets - drwxrwxr-x 2 ... state - -rw-rw-r-- 1 ... tmkms.toml + # Use the public key exported in previous step (make sure to wrap it with single quotes ['']) + validator_pub_key: '' ``` -- Update the TMKMS configuration file `$TMKMS_HOME/tmkms.toml`: - ```toml - [[chain]] - id = "laconic-mainnet" - key_format = { type = "cosmos-json", account_key_prefix = "laconicpub", consensus_key_prefix = "laconicvalconspub" } - # Replace with absolute path to tmkms config directory - state_file = "/state/priv_validator_state.json" - - [[validator]] - chain_id = "laconic-mainnet" - # Replace with actual IP address of the laconicd node - addr = "tcp://:26659" - # Replace with absolute path to tmkms config directory - secret_key = "/secrets/kms-identity.key" - protocol_version = "v0.34" - reconnect = true - - [[providers.softsign]] - key_type = "consensus" - # Replace with absolute path to tmkms config directory - path = "/secrets/priv_validator_key" - chain_ids = ["laconic-mainnet"] - ``` - -- Copy your validator key to TMKMS: - - - The validator key in laconicd node deployment is present at `$DATA_DIRECTORY/$MAINNET_DEPLOYMENT_DIR/data/laconicd-data/config/priv_validator_key.json` - - - Place the validator key file in TMKMS config directory at `$TMKMS_HOME/secrets/` - - - Import the private validator key into tmkms: - - ```bash - tmkms softsign import $TMKMS_HOME/secrets/priv_validator_key.json $TMKMS_HOME/secrets/priv_validator_key - ``` - - - Remove the JSON key file - - ```bash - rm $TMKMS_HOME/secrets/priv_validator_key.json - ``` - -- Start TMKMS: - ```bash - tmkms start --config $TMKMS_HOME/tmkms.toml - ``` - - - Expected example output: - ```bash - INFO tmkms::commands::start: tmkms 0.14.0 starting up... - INFO tmkms::keyring: [keyring:softsign] added consensus Ed25519 key: {"@type":"/cosmos.crypto.ed25519.PubKey","key":"T24No1A1FmetNRVCOSg2G2XAKWh97oBXuELdAD6DFgw="} - INFO tmkms::connection::tcp: KMS node ID: 7f5fd8dae8953e964e7e56edd4700f597ea0d45c - ERROR tmkms::client: [laconic-mainnet@tcp://localhost:26659] I/O error: Connection refused (os error 111) - ``` - NOTE: The errors dissapear once the laconicd node starts - - - Note the pubkey logged at start for comparing later with validator pubkey on chain - -- Enable TMKMS in the laconicd node configuration: - ```bash - # Set TMKMS_ENABLED to true in the node's config.env - echo "TMKMS_ENABLED=true" >> $DATA_DIRECTORY/$MAINNET_DEPLOYMENT_DIR/config.env - ``` - -- Remove the validator key from node deployment as it is no longer required +- Run playbook to use exported state for generating mainnet genesis: ```bash - rm $DATA_DIRECTORY/$MAINNET_DEPLOYMENT_DIR/data/laconicd-data/config/priv_validator_key.json + ansible-playbook -i localhost, -c local ~/cerc/laconicd-stack/playbooks/first-validator/generate-genesis.yml -e "exported_state_path=$EXPORTED_STATE_PATH" -e "lps_distribution_path=$LPS_DISTRIBUTION_PATH" -e "early_supports_acc_address=$EARLY_SUPPORTS_ACC_ADDR" ``` - NOTE: Store it safely offline in case of an emergency + - Input private key of the existing account that was exported in previous steps when prompted + +- Genesis file will be generated in output directory along with a file specifying the staking amount + + ```bash + # List files in output directory - genesis.json and staking-amount.json + ls -l output + ``` ## Run node -- Command to run node +- Copy the genesis file to the mainnet deployment tmp directory: + + ```bash + cp $DATA_DIRECTORY/$MAINNET_DEPLOYMENT_DIR/data/laconicd-data/tmp/genesis.json + ``` + +- Command to run node: ```bash laconic-so deployment --dir $DATA_DIRECTORY/$MAINNET_DEPLOYMENT_DIR start @@ -241,14 +272,15 @@ laconic-so deployment --dir $DATA_DIRECTORY/$MAINNET_DEPLOYMENT_DIR logs laconicd -f ``` -- If TMKMS has been configured verify that validator and TMKMS pubkeys match +- If TMKMS has been configured verify that validator and TMKMS pubkeys match: - Get validator pubkey on chain + ```bash # Check consensus_pubkey in output laconic-so deployment --dir $DATA_DIRECTORY/$MAINNET_DEPLOYMENT_DIR exec laconicd 'laconicd query staking validators -o json | jq .validators' ``` - + - Compare it with the pubkey noted from logs in TMKMS - Check bonds list to confirm that testnet state was transferred properly: diff --git a/playbooks/first-validator/first-validator-vars.example.yml b/playbooks/first-validator/first-validator-vars.example.yml index c66ff5f..fd788c0 100644 --- a/playbooks/first-validator/first-validator-vars.example.yml +++ b/playbooks/first-validator/first-validator-vars.example.yml @@ -3,6 +3,4 @@ cerc_chain_id: "laconic-mainnet" min_gas_price: 0.001 cerc_loglevel: "info" key_name: "laconic-validator" -pvt_key: "" -genesis_file: "" -staking_amount_file: "" +validator_pub_key: '' diff --git a/playbooks/first-validator/generate-genesis.yml b/playbooks/first-validator/generate-genesis.yml index 4409bf3..c464615 100644 --- a/playbooks/first-validator/generate-genesis.yml +++ b/playbooks/first-validator/generate-genesis.yml @@ -3,13 +3,24 @@ hosts: localhost vars_files: - first-validator-vars.yml + vars: + data_directory: "{{ lookup('env', 'DATA_DIRECTORY') }}" + mainnet_deployment_dir: "{{ lookup('env', 'MAINNET_DEPLOYMENT_DIR') }}" + spec_file: "{{data_directory}}/laconicd-spec.yml" connection: local tasks: + - name: Fail if DATA_DIRECTORY or MAINNET_DEPLOYMENT_DIR env vars are not set + fail: + msg: >- + Required environment variables are not set. + Please export both DATA_DIRECTORY and MAINNET_DEPLOYMENT_DIR before running the playbook. + when: lookup('env', 'DATA_DIRECTORY') == '' or lookup('env', 'MAINNET_DEPLOYMENT_DIR') == '' + - name: Fetch repositories ansible.builtin.shell: cmd: "laconic-so --stack ~/cerc/laconicd-stack/stack-orchestrator/stacks/mainnet-laconicd setup-repositories --git-ssh --pull" - # TODO: Add a playbook flag to control force rebuild + # TODO: Add a flag to control force rebuild - name: Build containers ansible.builtin.shell: cmd: "laconic-so --stack ~/cerc/laconicd-stack/stack-orchestrator/stacks/mainnet-laconicd build-containers --force-rebuild" @@ -43,3 +54,65 @@ - name: Display staking-amount file location ansible.builtin.debug: msg: "Staking amount written to output/staking-amount.json" + + - name: Create deployment spec file + shell: | + laconic-so --stack ~/cerc/laconicd-stack/stack-orchestrator/stacks/mainnet-laconicd deploy init --output {{ spec_file }} + + - name: Create deployment from spec file + shell: | + laconic-so --stack ~/cerc/laconicd-stack/stack-orchestrator/stacks/mainnet-laconicd deploy create --spec-file {{ spec_file }} --deployment-dir {{data_directory}}/{{ mainnet_deployment_dir }} + + - name: Ensure tmp directory exists inside laconicd-data + file: + path: "{{data_directory}}/{{ mainnet_deployment_dir }}/data/laconicd-data/tmp" + state: directory + mode: '0755' + + - name: Copy staking amount file to laconicd-data tmp directory + copy: + src: "{{ lookup('env', 'PWD') }}/output/staking-amount.json" + dest: "{{data_directory}}/{{ mainnet_deployment_dir }}/data/laconicd-data/tmp/staking-amount.json" + mode: '0644' + + - name: Copy genesis file to laconicd-data tmp directory + copy: + src: "{{ lookup('env', 'PWD') }}/output/genesis.json" + dest: "{{data_directory}}/{{ mainnet_deployment_dir }}/data/laconicd-data/tmp/genesis.json" + mode: '0644' + + - name: Prompt for validator private key + vars: + private_key_prompt: "Please enter your validator private key: " + pause: + prompt: "{{ private_key_prompt }}" + echo: no + register: private_key_input + + - name: Fail if private key is not provided + fail: + msg: "Private key is required for creating the gentx." + when: private_key_input.user_input | default('') | trim == '' + + - name: Run script to create and collect gentx + shell: | + docker run -i \ + -v {{data_directory}}/{{ mainnet_deployment_dir }}/data/laconicd-data:/root/.laconicd \ + -v {{data_directory}}/{{ mainnet_deployment_dir }}/config/mainnet-laconicd:/scripts \ + -e "PVT_KEY={{ private_key_input.user_input }}" \ + -e "KEY_NAME={{ key_name }}" \ + -e "CERC_MONIKER={{ cerc_moniker }}" \ + -e "CERC_CHAIN_ID={{ cerc_chain_id }}" \ + -e "VALIDATOR_PUB_KEY={{ validator_pub_key | to_json }}" \ + cerc/laconicd:local bash -c "/scripts/create-and-collect-gentx.sh" + + - name: Update genesis file in output + copy: + src: "{{data_directory}}/{{ mainnet_deployment_dir }}/data/laconicd-data/config/genesis.json" + dest: "{{ lookup('env', 'PWD') }}/output/genesis.json" + mode: '0644' + + - name: Clear tmp directory + file: + path: "{{data_directory}}/{{ mainnet_deployment_dir }}/data/laconicd-data/tmp" + state: absent diff --git a/playbooks/first-validator/setup-first-validator.yml b/playbooks/first-validator/setup-first-validator.yml index 86ce682..5b6171a 100644 --- a/playbooks/first-validator/setup-first-validator.yml +++ b/playbooks/first-validator/setup-first-validator.yml @@ -56,39 +56,3 @@ MIN_GAS_PRICE: "{{ min_gas_price }}" CERC_LOGLEVEL: "{{ cerc_loglevel }}" mode: '0777' - - - name: Ensure tmp directory exists inside laconicd-data - file: - path: "{{data_directory}}/{{ mainnet_deployment_dir }}/data/laconicd-data/tmp" - state: directory - mode: '0755' - - - name: Copy staking amount file to laconicd-data tmp directory - copy: - src: "{{ staking_amount_file }}" - dest: "{{data_directory}}/{{ mainnet_deployment_dir }}/data/laconicd-data/tmp/staking-amount.json" - mode: '0644' - - - name: Copy genesis file to laconicd-data tmp directory - copy: - src: "{{ genesis_file }}" - dest: "{{data_directory}}/{{ mainnet_deployment_dir }}/data/laconicd-data/tmp/genesis.json" - mode: '0644' - - - name: Fail if pvt_key is not set - fail: - msg: >- - Private key (pvt_key) is not set in first-validator-vars.yml. - This is required for creating the gentx. - when: not pvt_key - - - name: Run script to create and collect gentx - shell: | - docker run -i \ - -v {{data_directory}}/{{ mainnet_deployment_dir }}/data/laconicd-data:/root/.laconicd \ - -v {{data_directory}}/{{ mainnet_deployment_dir }}/config/mainnet-laconicd:/scripts \ - -e "PVT_KEY={{ pvt_key }}" \ - -e "KEY_NAME={{ key_name }}" \ - -e "CERC_MONIKER={{ cerc_moniker }}" \ - -e "CERC_CHAIN_ID={{ cerc_chain_id }}" \ - cerc/laconicd:local bash -c "/scripts/create-and-collect-gentx.sh" diff --git a/stack-orchestrator/config/mainnet-laconicd/create-and-collect-gentx.sh b/stack-orchestrator/config/mainnet-laconicd/create-and-collect-gentx.sh index d2fcd9c..6de2ee3 100755 --- a/stack-orchestrator/config/mainnet-laconicd/create-and-collect-gentx.sh +++ b/stack-orchestrator/config/mainnet-laconicd/create-and-collect-gentx.sh @@ -4,6 +4,7 @@ set -e NODE_HOME=/root/.laconicd genesis_file_path=$NODE_HOME/config/genesis.json +# TODO: Set to OS keyring backend KEYRING="test" if [ -f "$genesis_file_path" ]; then @@ -21,6 +22,11 @@ if [ -z "$KEY_NAME" ]; then exit 1 fi +if [ -z "$VALIDATOR_PUB_KEY" ]; then + echo "VALIDATOR_PUB_KEY environment variable not set, exiting..." + exit 1 +fi + input_genesis_file=$NODE_HOME/tmp/genesis.json if [ ! -f ${input_genesis_file} ]; then echo "Genesis file not provided, exiting..." @@ -66,7 +72,7 @@ fi stake_amount=$(jq -r '.common_staking_amount' "$staking_amount_file") # Create gentx with staked amount equal to allocated balance -laconicd genesis gentx $KEY_NAME $stake_amount$DENOM --chain-id $CHAIN_ID --keyring-backend $KEYRING +laconicd genesis gentx $KEY_NAME $stake_amount$DENOM --chain-id $CHAIN_ID --keyring-backend $KEYRING --pubkey "$VALIDATOR_PUB_KEY" # Collect the gentx and validate laconicd genesis collect-gentxs @@ -74,5 +80,5 @@ laconicd genesis validate chmod 777 $genesis_file_path -# Update the input genesis file -cp $genesis_file_path $input_genesis_file +# Clear tmp directory +rm -rf $NODE_HOME/tmp