├── ansible.cfg ├── .gitignore ├── hashicorp.gpg ├── gaia.yml ├── node.yml ├── images └── seedling.gif ├── faucet.yml ├── roles ├── reboot │ └── tasks │ │ └── main.yml ├── docker │ ├── vars │ │ └── main.yml │ └── tasks │ │ └── main.yml ├── faucet │ ├── tasks │ │ ├── main.yml │ │ ├── base.yml │ │ └── faucet.yml │ ├── templates │ │ ├── faucet.service.j2 │ │ └── faucet_config.toml.j2 │ └── defaults │ │ └── main.yml ├── blockscout │ ├── tasks │ │ ├── main.yml │ │ └── blockscout.yml │ ├── templates │ │ └── blockscout.service.j2 │ └── defaults │ │ └── main.yml ├── consensus-monitor │ ├── tasks │ │ ├── main.yml │ │ ├── base.yml │ │ └── consensus.yml │ ├── templates │ │ ├── consensus-monitor-ui.service.j2 │ │ └── consensus-monitor-ws.service.j2 │ └── defaults │ │ └── main.yml ├── node │ ├── files │ │ ├── get_trust_hash.sh │ │ ├── get_trust_height.sh │ │ └── copy_config_vars.py │ ├── templates │ │ ├── chain.service.j2 │ │ ├── cosmovisor.service.j2 │ │ ├── nginx-site.j2 │ │ └── ansible_vars.json.j2 │ ├── tasks │ │ ├── monitoring.yml │ │ ├── main.yml │ │ ├── faucet.yml │ │ ├── services.yml │ │ ├── apis.yml │ │ └── join.yml │ └── defaults │ │ └── main.yml ├── cascadia │ ├── files │ │ ├── get_trust_hash.sh │ │ ├── get_trust_height.sh │ │ └── copy_config_vars.py │ ├── templates │ │ ├── faucet.service.j2 │ │ ├── cascadiad.service.j2 │ │ ├── faucet_config.toml.j2 │ │ ├── cosmovisor.service.j2 │ │ ├── nginx-site.j2 │ │ └── ansible_vars.json.j2 │ ├── tasks │ │ ├── monitoring.yml │ │ ├── main.yml │ │ ├── install_cosmovisor.yml │ │ ├── apis.yml │ │ ├── services.yml │ │ ├── faucet.yml │ │ ├── install_gaiad.yml │ │ ├── genesis.yml │ │ ├── setup.yml │ │ └── config_gaiad.yml │ └── defaults │ │ └── main.yml ├── statesync │ └── tasks │ │ └── main.yml ├── configure-prometheus │ ├── templates │ │ ├── blackbox.json.j2 │ │ └── prometheus.json.j2 │ └── tasks │ │ └── main.yml ├── bigdipper │ ├── tasks │ │ ├── main.yml │ │ ├── hasura.yml │ │ ├── bdui.yml │ │ ├── base.yml │ │ └── bdjuno.yml │ ├── templates │ │ ├── bigdipper-general_config.json.j2 │ │ ├── bigdipper.env.j2 │ │ ├── bdjuno.service.j2 │ │ ├── bigdipper.service.j2 │ │ ├── bigdipper-codegen.yml.j2 │ │ ├── bigdipper-chain_config.json.j2 │ │ └── bdjuno-config.yaml.j2 │ └── defaults │ │ └── main.yml ├── provision-digitalocean │ ├── defaults │ │ └── main.yml │ └── tasks │ │ └── main.yml ├── node-exporter │ ├── templates │ │ └── node_exporter.service.j2 │ └── tasks │ │ └── main.yml ├── hermes │ ├── templates │ │ ├── hermes.service.j2 │ │ └── config.toml.j2 │ ├── tasks │ │ ├── main.yml │ │ ├── base.yml │ │ └── config.yml │ └── defaults │ │ └── main.yml ├── mkswap │ └── tasks │ │ └── main.yml ├── configure-panic │ ├── tasks │ │ └── main.yml │ └── files │ │ └── config_panic_nodes.py ├── export-genesis │ └── tasks │ │ └── main.yml ├── common │ └── tasks │ │ └── main.yml └── nginx-ssl │ └── tasks │ └── main.yml ├── bigdipper.yml ├── blockscout.yml ├── hosts ├── consensus-monitor.yml ├── gaia-mainnet-export.yml ├── examples ├── validator-keys │ ├── validator-28 │ │ ├── node_key.json │ │ ├── self-delegation-wallet-mnemonic.txt │ │ └── priv_validator_key.json │ ├── validator-32 │ │ ├── node_key.json │ │ ├── self-delegation-wallet-mnemonic.txt │ │ └── priv_validator_key.json │ ├── validator-40 │ │ ├── node_key.json │ │ ├── self-delegation-wallet-mnemonic.txt │ │ └── priv_validator_key.json │ └── local-genesis │ │ ├── self-delegation-wallet-mnemonic.txt │ │ └── priv_validator_key.json ├── chain.json ├── inventory-faucet.yml ├── inventory-local.yml ├── inventory-exporting-genesis-do.yml ├── inventory-consensus.yml ├── inventory-local-genesis.yml ├── inventory-rho-devnet-chain-1.yml ├── inventory-rho-devnet-chain-2.yml ├── inventory-join-provider.yml ├── inventory-cosmos-hub.yml ├── inventory-dev.yml ├── inventory-join-salt.yml ├── inventory-join-pepper.yml ├── inventory-join-sugar.yml ├── inventory-public-testnet.yml ├── inventory-bigdipper.yml ├── inventory-three-node.yml ├── inventory-three-node-scratch.yml ├── inventory-multi-node.yml └── inventory-hermes.yml ├── hermes.yml ├── requirements.yml ├── lint.sh ├── tests ├── test_gaia_response.sh ├── generate_version_matrix.py ├── generate_upgrade_matrix.py ├── test_block_production.sh ├── test_tx_stateful.sh ├── test_tx_fresh.sh └── test_software_upgrade.sh ├── .github └── workflows │ ├── lint.yml │ ├── test-cosmoshub-node.yml │ ├── test-theta-node.yml │ ├── export-mainnet-genesis.yml │ └── test-gaia-versions.yml ├── .config └── yamllint.yml ├── game-of-chains-2022 ├── hero-join.yml ├── neutron-join.yml ├── sputnik-join.yml ├── gopher-join.yml ├── README.md └── provider-join.yml ├── node_control.py ├── docs └── Hermes-Relayer-Setup.md └── README.md /ansible.cfg: -------------------------------------------------------------------------------- 1 | [defaults] 2 | host_key_checking = False 3 | allow_world_readable_tmpfiles = true 4 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | secrets/ 2 | *.log 3 | inventory.yml 4 | releases.json 5 | !logs/*.log 6 | .vscode 7 | .env -------------------------------------------------------------------------------- /hashicorp.gpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/T0psecurity/cosmos-network-deployment/HEAD/hashicorp.gpg -------------------------------------------------------------------------------- /gaia.yml: -------------------------------------------------------------------------------- 1 | --- 2 | # Configure a gaia node 3 | - hosts: gaia 4 | become: true 5 | roles: 6 | - gaia 7 | -------------------------------------------------------------------------------- /node.yml: -------------------------------------------------------------------------------- 1 | --- 2 | # Configure a chain node 3 | - hosts: node 4 | become: true 5 | roles: 6 | - node 7 | -------------------------------------------------------------------------------- /images/seedling.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/T0psecurity/cosmos-network-deployment/HEAD/images/seedling.gif -------------------------------------------------------------------------------- /faucet.yml: -------------------------------------------------------------------------------- 1 | --- 2 | # Configure a faucet server 3 | - hosts: faucet 4 | become: true 5 | roles: 6 | - faucet 7 | -------------------------------------------------------------------------------- /roles/reboot/tasks/main.yml: -------------------------------------------------------------------------------- 1 | --- 2 | 3 | - name: Rebooting the machine 4 | reboot: 5 | tags: 6 | reboot 7 | -------------------------------------------------------------------------------- /bigdipper.yml: -------------------------------------------------------------------------------- 1 | --- 2 | # Configure a bigdipper node 3 | - hosts: bigdipper 4 | become: true 5 | roles: 6 | - bigdipper 7 | -------------------------------------------------------------------------------- /roles/docker/vars/main.yml: -------------------------------------------------------------------------------- 1 | --- 2 | docker_edition: ce 3 | docker_package_state: present 4 | docker_service_state: started 5 | -------------------------------------------------------------------------------- /blockscout.yml: -------------------------------------------------------------------------------- 1 | --- 2 | # Configure a bigdipper node 3 | - hosts: blockscout 4 | become: true 5 | roles: 6 | - blockscout 7 | -------------------------------------------------------------------------------- /hosts: -------------------------------------------------------------------------------- 1 | [hosts] 2 | validator0 ansible_host=3.85.131.44 ansible_user=ubuntu 3 | validator1 ansible_host=54.210.84.15 ansible_user=ubuntu -------------------------------------------------------------------------------- /consensus-monitor.yml: -------------------------------------------------------------------------------- 1 | --- 2 | # Configure a bigdipper node 3 | - hosts: consensus 4 | become: true 5 | roles: 6 | - consensus-monitor 7 | -------------------------------------------------------------------------------- /gaia-mainnet-export.yml: -------------------------------------------------------------------------------- 1 | --- 2 | # Provisions VM and configure scripts to export genesis 3 | - hosts: local 4 | roles: 5 | - export-genesis 6 | -------------------------------------------------------------------------------- /roles/faucet/tasks/main.yml: -------------------------------------------------------------------------------- 1 | --- 2 | - name: Base setup 3 | import_tasks: base.yml 4 | 5 | - name: Faucet setup 6 | import_tasks: faucet.yml 7 | -------------------------------------------------------------------------------- /roles/blockscout/tasks/main.yml: -------------------------------------------------------------------------------- 1 | --- 2 | - name: config 3 | import_tasks: config.yml 4 | 5 | - name: Set up blockscout 6 | import_tasks: blockscout.yml 7 | -------------------------------------------------------------------------------- /roles/docker/tasks/main.yml: -------------------------------------------------------------------------------- 1 | --- 2 | 3 | - name: Install docker Python API 4 | pip: 5 | name: docker 6 | 7 | - include_role: 8 | name: geerlingguy.docker 9 | -------------------------------------------------------------------------------- /roles/consensus-monitor/tasks/main.yml: -------------------------------------------------------------------------------- 1 | --- 2 | - name: Base setup 3 | import_tasks: base.yml 4 | 5 | - name: Consensus monitor setup 6 | import_tasks: consensus.yml 7 | -------------------------------------------------------------------------------- /examples/validator-keys/validator-28/node_key.json: -------------------------------------------------------------------------------- 1 | {"priv_key":{"type":"tendermint/PrivKeyEd25519","value":"Ryt6fbpwrxXhIkG+MgSRH2lXtJFuDmWcC0DIFUf95BGeApmWAK1/WhqQrUBb7y6tuM/wmpwU3yqHYFjTeYP5wQ=="}} -------------------------------------------------------------------------------- /examples/validator-keys/validator-32/node_key.json: -------------------------------------------------------------------------------- 1 | {"priv_key":{"type":"tendermint/PrivKeyEd25519","value":"jsb68JzdNmaGVPIBguEemxBL0hSaD3yPzys+4axsJlQZbqJfkL1NMXYjBGQdIXGYI0XZTYHAdKA16OvPQAkMsg=="}} -------------------------------------------------------------------------------- /examples/validator-keys/validator-40/node_key.json: -------------------------------------------------------------------------------- 1 | {"priv_key":{"type":"tendermint/PrivKeyEd25519","value":"xT9wtNRLVtTjBBlMoLgBtffpmQ459YDCKTb45f69QII22Vt39CiJbsJEN7f9nI/RUlAs9GjEoi6CH+dXVFcvbA=="}} -------------------------------------------------------------------------------- /roles/node/files/get_trust_hash.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | # Retrieve hash ID 4 | # $1: rpc address 5 | # $2: block height 6 | echo -n $(curl -s "$1/block?height=$2" | jq -r .result.block_id.hash) 7 | -------------------------------------------------------------------------------- /roles/cascadia/files/get_trust_hash.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | # Retrieve hash ID 4 | # $1: rpc address 5 | # $2: block height 6 | echo -n $(curl -s "$1/block?height=$2" | jq -r .result.block_id.hash) 7 | -------------------------------------------------------------------------------- /examples/validator-keys/local-genesis/self-delegation-wallet-mnemonic.txt: -------------------------------------------------------------------------------- 1 | junk appear guide guess bar reject vendor illegal script sting shock afraid detect ginger other theory relief dress develop core pull across hen float -------------------------------------------------------------------------------- /hermes.yml: -------------------------------------------------------------------------------- 1 | --- 2 | - name: Set up chains 3 | hosts: node 4 | become: true 5 | roles: 6 | - node 7 | 8 | - name: Set up relayer 9 | hosts: hermes 10 | become: true 11 | roles: 12 | - hermes 13 | -------------------------------------------------------------------------------- /examples/validator-keys/validator-28/self-delegation-wallet-mnemonic.txt: -------------------------------------------------------------------------------- 1 | abandon cash abandon cash abandon cash abandon cash abandon cash abandon cash abandon cash abandon cash abandon cash abandon cash abandon cash abandon earth -------------------------------------------------------------------------------- /roles/statesync/tasks/main.yml: -------------------------------------------------------------------------------- 1 | --- 2 | - name: Configure gaia node 3 | include_role: 4 | name: gaia 5 | vars: 6 | statesync_snapshot_interval: 1000 7 | statesync_snapshot_keep_recent: 2 8 | p2p_upnp: true 9 | -------------------------------------------------------------------------------- /examples/validator-keys/validator-32/self-delegation-wallet-mnemonic.txt: -------------------------------------------------------------------------------- 1 | abandon cabbage abandon cabbage abandon cabbage abandon cabbage abandon cabbage abandon cabbage abandon cabbage abandon cabbage abandon cabbage abandon cabbage abandon cabbage abandon garage -------------------------------------------------------------------------------- /examples/validator-keys/validator-40/self-delegation-wallet-mnemonic.txt: -------------------------------------------------------------------------------- 1 | abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon art -------------------------------------------------------------------------------- /roles/node/files/get_trust_height.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | # Retrieve trust height 4 | # $1: rpc address 5 | INTERVAL=1000 6 | LATEST_HEIGHT=$(curl -s $1/block | jq -r .result.block.header.height) 7 | BLOCK_HEIGHT=$(($LATEST_HEIGHT-$INTERVAL)) 8 | echo -n $BLOCK_HEIGHT 9 | -------------------------------------------------------------------------------- /roles/cascadia/files/get_trust_height.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | # Retrieve trust height 4 | # $1: rpc address 5 | INTERVAL=1000 6 | LATEST_HEIGHT=$(curl -s $1/block | jq -r .result.block.header.height) 7 | BLOCK_HEIGHT=$(($LATEST_HEIGHT-$INTERVAL)) 8 | echo -n $BLOCK_HEIGHT 9 | -------------------------------------------------------------------------------- /roles/configure-prometheus/templates/blackbox.json.j2: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "targets": ["{{ inventory_hostname }}"], 4 | "labels": { 5 | "job": "{{ chain_id }}", 6 | "environment": "icmp-probe", 7 | "service": "icmp-probe" 8 | } 9 | } 10 | ] 11 | 12 | -------------------------------------------------------------------------------- /roles/bigdipper/tasks/main.yml: -------------------------------------------------------------------------------- 1 | --- 2 | - name: base 3 | import_tasks: base.yml 4 | 5 | - name: Set up bdjuno 6 | import_tasks: bdjuno.yml 7 | 8 | - name: Set up Hasura 9 | import_tasks: hasura.yml 10 | 11 | # - name: Set up Big Dipper UI 12 | # import_tasks: bdui.yml 13 | -------------------------------------------------------------------------------- /roles/bigdipper/templates/bigdipper-general_config.json.j2: -------------------------------------------------------------------------------- 1 | { 2 | "maintainer": { 3 | "name": "Hypha Worker Co-operative", 4 | "url": "https://hypha.coop/" 5 | }, 6 | "github": { 7 | "reportIssue": "https://github.com/hyphacoop/cosmos-ansible/issues" 8 | }, 9 | "version": "base-v2.1.0" 10 | } -------------------------------------------------------------------------------- /roles/provision-digitalocean/defaults/main.yml: -------------------------------------------------------------------------------- 1 | --- 2 | ### Digital Ocean API defaults 3 | digitalocean_api_key: '' 4 | digitalocean_ssh_keys: [] 5 | digitalocean_size: s-1vcpu-1gb 6 | digitalocean_hostname: '' 7 | digitalocean_image: debian-11-x64 8 | digitalocean_project: '' 9 | digitalocean_region: tor1 10 | -------------------------------------------------------------------------------- /roles/bigdipper/templates/bigdipper.env.j2: -------------------------------------------------------------------------------- 1 | NEXT_PUBLIC_GRAPHQL_URL={{bdui_graphql_url}} 2 | NEXT_PUBLIC_GRAPHQL_WS={{bdui_graphql_ws_url}} 3 | NEXT_PUBLIC_RPC_WEBSOCKET={{bdui_rpc_websocket}} 4 | NODE_ENV=production 5 | PORT={{bdui_port}} 6 | NEXT_PUBLIC_URL={{bdui_public_url}} 7 | NEXT_PUBLIC_CHAIN_TYPE={{bdui_chain}} 8 | -------------------------------------------------------------------------------- /roles/bigdipper/templates/bdjuno.service.j2: -------------------------------------------------------------------------------- 1 | [Unit] 2 | Description=BDJuno Parser 3 | After=network-online.target 4 | 5 | [Service] 6 | User={{bigdipper_user}} 7 | ExecStart={{bdjuno_bin}} start --home {{bdjuno_home}} 8 | Restart=always 9 | RestartSec=3 10 | LimitNOFILE=4096 11 | 12 | [Install] 13 | WantedBy=multi-user.target 14 | -------------------------------------------------------------------------------- /examples/chain.json: -------------------------------------------------------------------------------- 1 | { 2 | "chain_name": "cascadia", 3 | "chain_id": "cascadia_9000-1", 4 | "website": "https://cascadia.foundation/", 5 | "pretty_name": "Cascadia", 6 | "status": "live", 7 | "network_type": "devnet", 8 | "bech32_prefix": "cascadia", 9 | "daemon_name": "cascadiad", 10 | "node_home": "$HOME/.cascadia" 11 | } -------------------------------------------------------------------------------- /roles/bigdipper/templates/bigdipper.service.j2: -------------------------------------------------------------------------------- 1 | [Unit] 2 | Description=Big Dipper Block Explorer 3 | After=network-online.target bdjuno.service 4 | 5 | [Service] 6 | User={{bigdipper_user}} 7 | Group={{bigdipper_user}} 8 | ExecStart=/usr/bin/npm run start 9 | WorkingDirectory={{bdui_dir}} 10 | Restart=always 11 | 12 | [Install] 13 | WantedBy=multi-user.target 14 | -------------------------------------------------------------------------------- /roles/node-exporter/templates/node_exporter.service.j2: -------------------------------------------------------------------------------- 1 | [Unit] 2 | Description=Node Exporter 3 | 4 | [Service] 5 | User=node_exporter 6 | ExecStart=/opt/node_exporter/node_exporter --web.listen-address=[::]:{{ node_exporter_port }} --collector.systemd --collector.textfile.directory="/opt/node_exporter/textfiles" 7 | 8 | [Install] 9 | WantedBy=multi-user.target 10 | -------------------------------------------------------------------------------- /examples/inventory-faucet.yml: -------------------------------------------------------------------------------- 1 | --- 2 | # yamllint disable rule:line-length 3 | all: 4 | vars: 5 | ansible_user: root 6 | chain_id: "my-testnet" 7 | faucet_address: cosmosabc123 8 | faucet_use_tls_proxy: false 9 | # letsencrypt_email: "user@example.com" # Required for TLS setup 10 | children: 11 | faucet: 12 | hosts: 13 | "{{ target }}": 14 | -------------------------------------------------------------------------------- /roles/faucet/templates/faucet.service.j2: -------------------------------------------------------------------------------- 1 | [Unit] 2 | Description="Cosmos REST faucet" 3 | 4 | [Service] 5 | User={{ node_user }} 6 | Environment="{{ faucet_chain_env }}" 7 | WorkingDirectory={{node_user_home}}/cosmos-rest-faucet 8 | ExecStart={{node_user_home}}/cosmos-rest-faucet/.env/bin/hypercorn cosmos_rest_faucet:app -b [::]:{{ faucet_port }} 9 | 10 | [Install] 11 | WantedBy=multi-user.target 12 | -------------------------------------------------------------------------------- /roles/cascadia/templates/faucet.service.j2: -------------------------------------------------------------------------------- 1 | [Unit] 2 | Description="Cosmos REST faucet" 3 | 4 | [Service] 5 | User={{gaiad_user}} 6 | Environment="PATH={{gaiad_home}}/cosmovisor/current/bin" 7 | WorkingDirectory={{gaiad_user_home}}/cosmos-rest-faucet 8 | ExecStart={{gaiad_user_home}}/cosmos-rest-faucet/.env/bin/hypercorn cosmos_rest_faucet:app -b 0.0.0.0:8000 9 | 10 | [Install] 11 | WantedBy=multi-user.target 12 | -------------------------------------------------------------------------------- /roles/hermes/templates/hermes.service.j2: -------------------------------------------------------------------------------- 1 | [Unit] 2 | Description=hermes 3 | After=network-online.target 4 | 5 | [Service] 6 | User={{ hermes_user }} 7 | ExecStart=/home/{{ hermes_user }}/bin/hermes --config /home/{{ hermes_user }}/.hermes/config.toml start 8 | Restart=always 9 | RestartSec=3 10 | LimitNOFILE=4096 11 | Environment="DAEMON_LOG_BUFFER_SIZE=512" 12 | 13 | [Install] 14 | WantedBy=multi-user.target 15 | -------------------------------------------------------------------------------- /examples/inventory-local.yml: -------------------------------------------------------------------------------- 1 | --- 2 | # yamllint disable rule:line-length 3 | all: 4 | vars: 5 | chain_home_clear: true 6 | chain_version: v7.0.0 7 | chain_create_validator: true 8 | faucet_enabled: true 9 | ansible_user: root 10 | children: 11 | node: 12 | hosts: 13 | "{{ target }}": 14 | fast_sync: false 15 | chain_id: my-testnet 16 | chain_moniker: cosmos-node 17 | -------------------------------------------------------------------------------- /roles/consensus-monitor/templates/consensus-monitor-ui.service.j2: -------------------------------------------------------------------------------- 1 | [Unit] 2 | Description="Cosmos Monitor UI Service" 3 | After=network-online.target 4 | 5 | [Service] 6 | User={{ consensus_user }} 7 | WorkingDirectory={{ consensus_repo_path }}/client 8 | ExecStart={{ consensus_repo_path }}/.env/bin/python -m http.server {{ consensus_ui_port }} 9 | Restart=always 10 | RestartSec=5 11 | 12 | [Install] 13 | WantedBy=multi-user.target 14 | -------------------------------------------------------------------------------- /examples/validator-keys/validator-28/priv_validator_key.json: -------------------------------------------------------------------------------- 1 | { 2 | "address": "DFC2D2621902BD92A244C8C09F2D8F929412E25F", 3 | "pub_key": { 4 | "type": "tendermint/PubKeyEd25519", 5 | "value": "pLe/+jwZgno5JlUU/GfArA1F8/SZ+2lEqLiFkWdVD5s=" 6 | }, 7 | "priv_key": { 8 | "type": "tendermint/PrivKeyEd25519", 9 | "value": "Wrxg3YVIo7nXWgUt1mMe6sRLJi2gZlyy3U5mo2KH7MOkt7/6PBmCejkmVRT8Z8CsDUXz9Jn7aUSouIWRZ1UPmw==" 10 | } 11 | } -------------------------------------------------------------------------------- /examples/validator-keys/validator-32/priv_validator_key.json: -------------------------------------------------------------------------------- 1 | { 2 | "address": "F23E53F61FF52B94C07325ED987A648D9C67ECE3", 3 | "pub_key": { 4 | "type": "tendermint/PubKeyEd25519", 5 | "value": "VZA1ymYk0OhtnVn/Y1wR+Ffrwh1/GFIvKhdTKMt3JNU=" 6 | }, 7 | "priv_key": { 8 | "type": "tendermint/PrivKeyEd25519", 9 | "value": "m3r5xWQQHZxSjfs+JsHIXYq0cDzi79zdUCnNBi8V/p5VkDXKZiTQ6G2dWf9jXBH4V+vCHX8YUi8qF1Moy3ck1Q==" 10 | } 11 | } -------------------------------------------------------------------------------- /examples/validator-keys/validator-40/priv_validator_key.json: -------------------------------------------------------------------------------- 1 | { 2 | "address": "973C48DF8B3356C45E44494723A6E0D45DEB8131", 3 | "pub_key": { 4 | "type": "tendermint/PubKeyEd25519", 5 | "value": "xAqzjs6UkEg8YvoQy60bxytIocODxoDTNRz4+H81tTc=" 6 | }, 7 | "priv_key": { 8 | "type": "tendermint/PrivKeyEd25519", 9 | "value": "V9E2OFJ8ghMu/M15KALuNh0ZafFBDt7aUrGcSPOfP9rECrOOzpSQSDxi+hDLrRvHK0ihw4PGgNM1HPj4fzW1Nw==" 10 | } 11 | } -------------------------------------------------------------------------------- /examples/inventory-exporting-genesis-do.yml: -------------------------------------------------------------------------------- 1 | --- 2 | # yamllint disable rule:line-length 3 | all: 4 | vars: 5 | digitalocean_ssh_keys: ['34666002'] 6 | ansible_connection: local 7 | 8 | children: 9 | export_genesis: 10 | hosts: 11 | local: 12 | digitalocean_hostname: mainnet-export 13 | digitalocean_size: s-8vcpu-16gb 14 | digitalocean_region: tor1 15 | digitalocean_project: Staging 16 | -------------------------------------------------------------------------------- /requirements.yml: -------------------------------------------------------------------------------- 1 | --- 2 | collections: 3 | - name: community.docker 4 | - name: community.postgresql 5 | - name: https://github.com/hyphacoop/ansible-common.git 6 | type: git 7 | version: e862f2c7c4e7b929e3216fa359e954bed9ec98e1 8 | - name: https://github.com/lvrfrc87/git-acp-ansible.git 9 | type: git 10 | version: 8bfa71dd63dde0e7a4d99174fec65ddc23427434 11 | roles: 12 | - src: geerlingguy.docker 13 | - src: geerlingguy.nodejs 14 | -------------------------------------------------------------------------------- /examples/validator-keys/local-genesis/priv_validator_key.json: -------------------------------------------------------------------------------- 1 | { 2 | "address": "D5AB5E458FD9F9964EF50A80451B6F3922E6A4AA", 3 | "pub_key": { 4 | "type": "tendermint/PubKeyEd25519", 5 | "value": "qwiUMxz3llsy45fPvM0a8+XQeAJLvrX3QAEJmRMEEoU=" 6 | }, 7 | "priv_key": { 8 | "type": "tendermint/PrivKeyEd25519", 9 | "value": "2yjw8d1QrgB5afmg/UAvvqZ8B9rcaPXVQpqjabvQNVirCJQzHPeWWzLjl8+8zRrz5dB4Aku+tfdAAQmZEwQShQ==" 10 | } 11 | } -------------------------------------------------------------------------------- /examples/inventory-consensus.yml: -------------------------------------------------------------------------------- 1 | --- 2 | # yamllint disable rule:line-length 3 | 4 | all: 5 | vars: 6 | ansible_user: root 7 | consensus_use_tls_proxy: false # Enables TLS, requires a domain name 8 | # letsencrypt_email: "example@example.com" # Required for TLS setup 9 | children: 10 | consensus: 11 | hosts: 12 | "{{ target }}": 13 | consensus_api_node_url: "http://online-node.example.com:1317" 14 | consensus_rpc_node_url: "http://online-node.example.com:26657" 15 | -------------------------------------------------------------------------------- /roles/consensus-monitor/templates/consensus-monitor-ws.service.j2: -------------------------------------------------------------------------------- 1 | [Unit] 2 | Description="Cosmos Monitor Websockets Service" 3 | After=network-online.target 4 | 5 | [Service] 6 | User={{ consensus_user }} 7 | WorkingDirectory={{ consensus_repo_path }}/server 8 | ExecStart={{ consensus_repo_path }}/.env/bin/python consensus_monitor_server.py -a {{ consensus_api_node_url }} -r {{ consensus_rpc_node_url }} -p {{ consensus_ws_port }} 9 | Restart=always 10 | RestartSec=5 11 | 12 | [Install] 13 | WantedBy=multi-user.target 14 | -------------------------------------------------------------------------------- /roles/configure-prometheus/tasks/main.yml: -------------------------------------------------------------------------------- 1 | --- 2 | - name: Copy over Prometheus configuration 3 | template: 4 | src: prometheus.json.j2 5 | dest: /opt/prometheus/hosts/{{ inventory_hostname }}.json 6 | mode: 0644 7 | owner: prometheus 8 | group: prometheus 9 | 10 | - name: Copy over Blackbox Exporter configuration 11 | template: 12 | src: blackbox.json.j2 13 | dest: /opt/prometheus/blackbox-icmp/{{ inventory_hostname }}.json 14 | mode: 0644 15 | owner: prometheus 16 | group: prometheus 17 | -------------------------------------------------------------------------------- /roles/node/templates/chain.service.j2: -------------------------------------------------------------------------------- 1 | [Unit] 2 | Description=Cosmos Hub Gaia service 3 | After=network-online.target 4 | [Service] 5 | User={{node_user}} 6 | ExecStart={{chain_bin}} start --home {{chain_home}} 7 | Restart=always 8 | RestartSec=3 9 | LimitNOFILE=4096 10 | Environment='DAEMON_NAME=cascadiad' 11 | Environment='DAEMON_HOME={{chain_home}}' 12 | Environment='DAEMON_ALLOW_DOWNLOAD_BINARIES=true' 13 | Environment='DAEMON_RESTART_AFTER_UPGRADE=true' 14 | Environment='DAEMON_LOG_BUFFER_SIZE=512' 15 | [Install] 16 | WantedBy=multi-user.target 17 | -------------------------------------------------------------------------------- /roles/cascadia/templates/cascadiad.service.j2: -------------------------------------------------------------------------------- 1 | [Unit] 2 | Description=Cosmos Hub Cascadia service 3 | After=network-online.target 4 | [Service] 5 | User={{cascadiad_user}} 6 | ExecStart={{cascadiad_bin}} start --home {{cascadiad_home}} 7 | Restart=always 8 | RestartSec=3 9 | LimitNOFILE=4096 10 | Environment='DAEMON_NAME=cascadiad' 11 | Environment='DAEMON_HOME={{cascadiad_home}}' 12 | Environment='DAEMON_ALLOW_DOWNLOAD_BINARIES=true' 13 | Environment='DAEMON_RESTART_AFTER_UPGRADE=true' 14 | Environment='DAEMON_LOG_BUFFER_SIZE=512' 15 | [Install] 16 | WantedBy=multi-user.target 17 | -------------------------------------------------------------------------------- /roles/cascadia/templates/faucet_config.toml.j2: -------------------------------------------------------------------------------- 1 | # Cosmos REST Faucet configuration 2 | 3 | gaia_home_folder = "{{gaiad_home}}" 4 | transactions_log = "transactions.csv" 5 | request_timeout = "86400" 6 | 7 | [cosmos] 8 | prefix = "cosmos" 9 | denomination = "{{gaiad_bond_denom}}" 10 | 11 | [testnets] 12 | [testnets.{{chain_id}}] 13 | node_url = "http://localhost:26657" 14 | chain_id = "{{chain_id}}" 15 | faucet_address = {{faucet_address.stdout}} 16 | daily_cap = "500000000" 17 | amount_to_send = "1000000" 18 | tx_fees = "500" 19 | 20 | -------------------------------------------------------------------------------- /roles/hermes/tasks/main.yml: -------------------------------------------------------------------------------- 1 | --- 2 | - name: Base 3 | import_tasks: base.yml 4 | 5 | - name: Configure Hermes 6 | import_tasks: config.yml 7 | 8 | - name: Install Hermes systemd service 9 | template: 10 | src: hermes.service.j2 11 | dest: /etc/systemd/system/hermes.service 12 | 13 | - name: Start Hermes systemd service 14 | systemd: 15 | daemon_reload: true 16 | state: restarted 17 | enabled: true 18 | name: "hermes" 19 | 20 | - name: Rebooting the machine 21 | include_role: 22 | name: reboot 23 | when: reboot | default(false) | bool 24 | -------------------------------------------------------------------------------- /lint.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | pylint=0 3 | yamllint=0 4 | 5 | if [ ! $CI ] 6 | then 7 | echo "Auto-formatting python" 8 | autopep8 --in-place --recursive . 9 | fi 10 | echo "Linting python" 11 | find . -type f -name "*.py" | xargs python -m pylint --rcfile=.config/pylintrc 12 | if [ $? -ne 0 ] 13 | then 14 | pylint=1 15 | echo "Linting python failed" 16 | fi 17 | echo "Linting yaml" 18 | yamllint -c .config/yamllint.yml . 19 | if [ $? -ne 0 ] 20 | then 21 | yamllint=1 22 | echo "Linting yaml failed" 23 | fi 24 | if [ $pylint -ne 0 ] || [ $yamllint -ne 0 ] 25 | then 26 | exit 1 27 | fi 28 | -------------------------------------------------------------------------------- /roles/cascadia/tasks/monitoring.yml: -------------------------------------------------------------------------------- 1 | --- 2 | - name: Setup node-exporter 3 | include_role: 4 | name: node-exporter 5 | when: monitoring_prometheus | default(false) | bool 6 | 7 | - name: Setup on prometheus server 8 | include_role: 9 | name: configure-prometheus 10 | apply: 11 | delegate_to: "{{ grafana_ssh_url }}" 12 | when: monitoring_prometheus | default(false) | bool 13 | 14 | - name: Setup PANIC on monitoring server 15 | include_role: 16 | name: configure-panic 17 | apply: 18 | delegate_to: "{{ panic_ssh_url }}" 19 | when: monitoring_panic | default(false) | bool 20 | -------------------------------------------------------------------------------- /roles/node/tasks/monitoring.yml: -------------------------------------------------------------------------------- 1 | --- 2 | - name: Setup node-exporter 3 | include_role: 4 | name: node-exporter 5 | when: monitoring_prometheus | default(false) | bool 6 | 7 | - name: Setup on prometheus server 8 | include_role: 9 | name: configure-prometheus 10 | apply: 11 | delegate_to: "{{ grafana_ssh_url }}" 12 | when: monitoring_prometheus | default(false) | bool 13 | 14 | - name: Setup PANIC on monitoring server 15 | include_role: 16 | name: configure-panic 17 | apply: 18 | delegate_to: "{{ panic_ssh_url }}" 19 | when: monitoring_panic | default(false) | bool 20 | -------------------------------------------------------------------------------- /roles/faucet/templates/faucet_config.toml.j2: -------------------------------------------------------------------------------- 1 | # Cosmos REST Faucet configuration 2 | 3 | gaia_home_folder = "{{ chain_home }}" 4 | transactions_log = "{{ transactions_log_path }}" 5 | request_timeout = "{{ request_timeout }}" 6 | 7 | [cosmos] 8 | prefix = "cosmos" 9 | denomination = "{{ chain_denom }}" 10 | 11 | [testnets] 12 | [testnets.{{ chain_id }}] 13 | node_url = "{{ node_url }}" 14 | chain_id = "{{ chain_id }}" 15 | faucet_address = "{{ faucet_address }}" 16 | daily_cap = "{{ daily_cap }}" 17 | amount_to_send = "{{ amount_to_send }}" 18 | tx_fees = "{{ tx_fees }}" 19 | -------------------------------------------------------------------------------- /tests/test_gaia_response.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # Test gaia is online. 3 | 4 | gaia_host=$1 5 | gaia_port=$2 6 | 7 | # Waiting until gaiad responds 8 | attempt_counter=0 9 | max_attempts=2100 10 | echo "Waiting for gaia to come back online..." 11 | until $(curl --output /dev/null --silent --head --fail http://$gaia_host:$gaia_port) 12 | do 13 | if [ ${attempt_counter} -gt ${max_attempts} ] 14 | then 15 | echo "" 16 | echo "Tried connecting to gaiad for $attempt_counter times. Exiting." 17 | exit 3 18 | fi 19 | printf '.' 20 | attempt_counter=$(($attempt_counter+1)) 21 | sleep 1 22 | done 23 | -------------------------------------------------------------------------------- /roles/configure-prometheus/templates/prometheus.json.j2: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "targets": ["{{ inventory_hostname }}:{{ node_exporter_port }}"], 4 | "labels": { 5 | "job": "{{ chain_id }}", 6 | "environment": "{{ inventory_hostname }}_exporter", 7 | "service": "{{ inventory_hostname }}_exporter" 8 | } 9 | }, 10 | { 11 | "targets": ["{{ inventory_hostname }}:{{ prometheus_listen_addr | regex_replace('^:','') }}"], 12 | "labels": { 13 | "job": "{{ chain_id }}_gaiad", 14 | "environment": "{{ inventory_hostname }}_gaiad_exporter", 15 | "service": "{{ inventory_hostname }}_gaiad_exporter" 16 | } 17 | } 18 | ] 19 | 20 | -------------------------------------------------------------------------------- /.github/workflows/lint.yml: -------------------------------------------------------------------------------- 1 | --- 2 | 3 | name: Lint 4 | on: 5 | push 6 | 7 | jobs: 8 | build: 9 | runs-on: ubuntu-22.04 10 | steps: 11 | # Get system info 12 | - run: ifconfig 13 | - run: sudo dmidecode 14 | - run: df -h 15 | - run: free -m 16 | - run: echo "GitHub branch is ${{ github.ref }}" 17 | 18 | # Checks-out your repository under $GITHUB_WORKSPACE, 19 | # so your workflow can access it 20 | - name: Checkout repo 21 | uses: actions/checkout@master 22 | 23 | # install linting 24 | - run: pip3 install autopep8 yamllint pylint 25 | 26 | # run lint.sh 27 | - run: ./lint.sh 28 | -------------------------------------------------------------------------------- /roles/node/templates/cosmovisor.service.j2: -------------------------------------------------------------------------------- 1 | [Unit] 2 | Description=cosmovisor 3 | After=network-online.target 4 | 5 | [Service] 6 | User={{node_user}} 7 | ExecStart={{ cosmovisor_bin }} start {{ cosmovisor_invariants_flag }} --home {{ chain_home }} 8 | Restart=always 9 | RestartSec=3 10 | LimitNOFILE=4096 11 | Environment="DAEMON_NAME={{chain_binary_name}}" 12 | Environment="DAEMON_HOME={{ chain_home }}" 13 | Environment="DAEMON_ALLOW_DOWNLOAD_BINARIES=true" 14 | Environment="DAEMON_RESTART_AFTER_UPGRADE=true" 15 | Environment="DAEMON_LOG_BUFFER_SIZE=512" 16 | {% if cosmovisor_skip_backup %} 17 | Environment="UNSAFE_SKIP_BACKUP=true" 18 | {% endif %} 19 | 20 | [Install] 21 | WantedBy=multi-user.target 22 | -------------------------------------------------------------------------------- /roles/cascadia/templates/cosmovisor.service.j2: -------------------------------------------------------------------------------- 1 | [Unit] 2 | Description=cosmovisor 3 | After=network-online.target 4 | 5 | [Service] 6 | User={{cascadiad_user}} 7 | ExecStart={{ cosmovisor_bin }} start --x-crisis-skip-assert-invariants --home {{ cascadiad_home }} 8 | Restart=always 9 | RestartSec=3 10 | LimitNOFILE=4096 11 | Environment="DAEMON_NAME=cascadiad" 12 | Environment="DAEMON_HOME={{ cascadiad_home }}" 13 | Environment="DAEMON_ALLOW_DOWNLOAD_BINARIES=true" 14 | Environment="DAEMON_RESTART_AFTER_UPGRADE=true" 15 | Environment="DAEMON_LOG_BUFFER_SIZE=512" 16 | {% if cosmovisor_skip_backup %} 17 | Environment="UNSAFE_SKIP_BACKUP=true" 18 | {% endif %} 19 | 20 | [Install] 21 | WantedBy=multi-user.target 22 | -------------------------------------------------------------------------------- /examples/inventory-local-genesis.yml: -------------------------------------------------------------------------------- 1 | --- 2 | # yamllint disable rule:line-length 3 | all: 4 | vars: 5 | chain_home_clear: true 6 | chain_version: v7.0.3 7 | genesis_url: "https://files.polypore.xyz/genesis/mainnet-genesis-tinkered/tinkered-genesis_2022-09-11T07%3A43%3A05.6452382Z_v7.0.3_12010083.json.gz" 8 | ansible_user: root 9 | enable_swap: true # Set this for machines with <32GB RAM 10 | swap_size: 8192 11 | children: 12 | node: 13 | hosts: 14 | "{{ target }}": 15 | fast_sync: false 16 | node_key_file: "examples/validator-keys/validator-40/node_key.json" 17 | priv_validator_key_file: "examples/validator-keys/validator-40/priv_validator_key.json" 18 | -------------------------------------------------------------------------------- /.config/yamllint.yml: -------------------------------------------------------------------------------- 1 | --- 2 | 3 | yaml-files: 4 | - '*.yaml' 5 | - '*.yml' 6 | - '.yamllint' 7 | 8 | rules: 9 | braces: enable 10 | brackets: enable 11 | colons: enable 12 | commas: enable 13 | comments: 14 | level: warning 15 | comments-indentation: 16 | level: warning 17 | document-end: disable 18 | document-start: 19 | level: warning 20 | empty-lines: enable 21 | empty-values: disable 22 | hyphens: enable 23 | indentation: enable 24 | key-duplicates: enable 25 | key-ordering: disable 26 | line-length: disable 27 | new-line-at-end-of-file: enable 28 | new-lines: enable 29 | octal-values: disable 30 | quoted-strings: disable 31 | trailing-spaces: enable 32 | truthy: disable 33 | -------------------------------------------------------------------------------- /examples/inventory-rho-devnet-chain-1.yml: -------------------------------------------------------------------------------- 1 | --- 2 | # yamllint disable rule:line-length 3 | all: 4 | vars: 5 | ansible_user: root 6 | chain_version: main 7 | major_version: 8 8 | patch_version: 0 9 | genesis_url: "https://github.com/cosmos/testnets/raw/master/devnet/rho-chain-1-genesis.json.gz" 10 | chain_id: rho-chain-1 11 | chain_home_clear: true 12 | chain_use_ssl_proxy: false 13 | chain_api_host: "rest" 14 | chain_rpc_host: "rpc" 15 | chain_p2p_host: "p2p" 16 | chain_grpc_host: "grpc" 17 | p2p_persistent_peers: "42c0aa9a5e922ae446fa8537f076854a6c2c5053@sentry.chain-1.rho-devnet.polypore.xyz:26656" 18 | children: 19 | node: 20 | hosts: 21 | "{{ target }}": 22 | fast_sync: true 23 | -------------------------------------------------------------------------------- /examples/inventory-rho-devnet-chain-2.yml: -------------------------------------------------------------------------------- 1 | --- 2 | # yamllint disable rule:line-length 3 | all: 4 | vars: 5 | ansible_user: root 6 | chain_version: main 7 | major_version: 8 8 | patch_version: 0 9 | genesis_url: "https://github.com/cosmos/testnets/raw/master/devnet/rho-chain-2-genesis.json.gz" 10 | chain_id: rho-chain-2 11 | chain_home_clear: true 12 | chain_use_ssl_proxy: false 13 | chain_api_host: "rest" 14 | chain_rpc_host: "rpc" 15 | chain_p2p_host: "p2p" 16 | chain_grpc_host: "grpc" 17 | p2p_persistent_peers: "c45efb232d01df3b2399ef9b4b801fd41f6a89fc@sentry.chain-2.rho-devnet.polypore.xyz:26656" 18 | children: 19 | node: 20 | hosts: 21 | "{{ target }}": 22 | fast_sync: true 23 | -------------------------------------------------------------------------------- /game-of-chains-2022/hero-join.yml: -------------------------------------------------------------------------------- 1 | --- 2 | # yamllint disable rule:line-length 3 | all: 4 | vars: 5 | ansible_user: root 6 | node_user: hero 7 | chain_home: "{{node_user_home}}/.hero" 8 | chain_binary_name: herod 9 | chain_version: tags/v0.0.1 10 | chain_repository: https://github.com/strangelove-ventures/hero.git 11 | genesis_url: https://github.com/hyphacoop/ics-testnets/raw/main/game-of-chains-2022/hero/hero-genesis.json 12 | chain_home_clear: true 13 | chain_id: hero-1 14 | cosmovisor_service_name: "cv-hero" 15 | chain_moniker: "hero" 16 | reboot: false 17 | children: 18 | node: 19 | hosts: 20 | "{{ target }}": 21 | p2p_seeds: "fe7997dd631c2916189dc06f5ee59f27318b708b@tenderseed.ccvalidators.com:29039" 22 | -------------------------------------------------------------------------------- /roles/bigdipper/templates/bigdipper-codegen.yml.j2: -------------------------------------------------------------------------------- 1 | overwrite: true 2 | config: 3 | # omitOperationSuffix: true 4 | skipTypeNameForRoot: true 5 | generates: 6 | ./src/graphql/types.tsx: 7 | documents: 8 | - './src/**/*.graphql' 9 | - './src/**/*_actions.ts' 10 | - './src/**/*_documents.ts' 11 | - '!./src/**/desmos_profile.graphql' 12 | schema: {{bdui_graphql_url}} 13 | plugins: 14 | - "typescript" 15 | - "typescript-operations" 16 | - "typescript-react-apollo" # To generate custom hooks per query 17 | ./src/graphql/desmos_profile.ts: 18 | schema: https://gql.mainnet.desmos.network/v1/graphql 19 | documents: 20 | - 'src/graphql/desmos_profile_graphql.ts' 21 | plugins: 22 | - "typescript" 23 | - "typescript-operations" 24 | -------------------------------------------------------------------------------- /examples/inventory-join-provider.yml: -------------------------------------------------------------------------------- 1 | --- 2 | # yamllint disable rule:line-length 3 | all: 4 | vars: 5 | ansible_user: root 6 | node_user: provider 7 | chain_home: "{{node_user_home}}/.isp" 8 | chain_binary_name: interchain-security-pd 9 | chain_version: tags/v0.1.4 10 | chain_repository: https://github.com/cosmos/interchain-security.git 11 | chain_denom: stake 12 | genesis_url: "https://paste.c-net.org/ScarringAiming" 13 | chain_id: provider 14 | chain_home_clear: true 15 | node_service_name: "provider" 16 | p2p_persistent_peers: "b060c4ad12ade4114a87f9cb1c6bdaf0f4e9db2b@167.172.190.207:26656" 17 | cosmovisor_service_name: "cosmovisor-provider" 18 | reboot: false 19 | children: 20 | node: 21 | hosts: 22 | "{{ target }}": 23 | fast_sync: false 24 | -------------------------------------------------------------------------------- /game-of-chains-2022/neutron-join.yml: -------------------------------------------------------------------------------- 1 | --- 2 | # yamllint disable rule:line-length 3 | all: 4 | vars: 5 | ansible_user: root 6 | node_user: neutron 7 | chain_home: "{{node_user_home}}/.neutron" 8 | chain_binary_name: neutrond 9 | chain_version: f5f1ce84a18d9b274a3caa2719997e26c43d3448 10 | chain_repository: https://github.com/neutron-org/neutron.git 11 | genesis_url: https://github.com/hyphacoop/ics-testnets/raw/main/game-of-chains-2022/neutron/neutron-genesis.json 12 | chain_home_clear: true 13 | chain_id: neutron 14 | cosmovisor_service_name: "cv-neutron" 15 | chain_moniker: "neutron" 16 | reboot: false 17 | children: 18 | node: 19 | hosts: 20 | "{{ target }}": 21 | p2p_seeds: "919167501b299c98dbbb8ad3ed233aa314add27f@tenderseed.ccvalidators.com:29049" 22 | -------------------------------------------------------------------------------- /roles/node/tasks/main.yml: -------------------------------------------------------------------------------- 1 | --- 2 | - name: base 3 | import_tasks: base.yml 4 | 5 | - name: config 6 | import_tasks: config.yml 7 | 8 | - name: Create faucet account 9 | import_tasks: faucet.yml 10 | when: faucet_enabled | default(false) | bool 11 | 12 | # - name: join 13 | # import_tasks: join.yml 14 | # when: genesis_file is defined or genesis_url is defined 15 | 16 | - name: setup systemd services 17 | import_tasks: services.yml 18 | 19 | - name: setup APIs 20 | import_tasks: apis.yml 21 | 22 | # - include_role: 23 | # name: faucet 24 | # when: faucet_enabled | default(false) | bool 25 | 26 | - name: setup monitoring 27 | import_tasks: monitoring.yml 28 | 29 | - name: Rebooting the machine 30 | include_role: 31 | name: reboot 32 | when: reboot | default(false) | bool 33 | tags: 34 | - reboot 35 | -------------------------------------------------------------------------------- /roles/mkswap/tasks/main.yml: -------------------------------------------------------------------------------- 1 | --- 2 | 3 | - name: Creating swap file {{ swap_size }} MB in size 4 | shell: 'dd if\=/dev/zero of\=/swap.swp bs\=1M count\={{ swap_size }}' 5 | args: 6 | creates: /swap.swp 7 | register: created_swap 8 | 9 | - name: Change swap file ownership and premissions 10 | when: created_swap.changed 11 | file: 12 | path: /swap.swp 13 | owner: root 14 | group: root 15 | mode: 0600 16 | 17 | - name: Format swap file 18 | when: created_swap.changed 19 | shell: mkswap /swap.swp 20 | 21 | - name: Add swap to fstab 22 | when: created_swap.changed 23 | mount: 24 | name: swap 25 | src: /swap.swp 26 | fstype: swap 27 | opts: sw 28 | passno: 0 29 | dump: 0 30 | state: present 31 | 32 | - name: Turn on swap 33 | when: created_swap.changed 34 | shell: 'swapon -a' 35 | -------------------------------------------------------------------------------- /examples/inventory-cosmos-hub.yml: -------------------------------------------------------------------------------- 1 | --- 2 | # yamllint disable rule:line-length 3 | all: 4 | vars: 5 | ansible_user: root 6 | chain_registry: "https://registry.ping.pub/cosmoshub/chain.json" 7 | chain_home_clear: false 8 | node_unsafe_reset: true 9 | chain_use_ssl_proxy: false 10 | chain_api_host: "rest" 11 | chain_rpc_host: "rpc" 12 | chain_p2p_host: "p2p" 13 | chain_grpc_host: "grpc" 14 | addrbook_url: "https://quicksync.io/addrbook.cosmos.json" 15 | minimum_gas_prices: "0.0025uatom" 16 | enable_swap: true 17 | swap_size: 8192 18 | reboot: true 19 | children: 20 | node: 21 | hosts: 22 | "{{ target }}": 23 | fast_sync: true 24 | statesync_enabled: true 25 | statesync_rpc_servers: 'https://rpc.cosmos.network:443,https://rpc.cosmos.network:443' 26 | -------------------------------------------------------------------------------- /examples/inventory-dev.yml: -------------------------------------------------------------------------------- 1 | --- 2 | # yamllint disable rule:line-length 3 | all: 4 | vars: 5 | chain_home_clear: true 6 | chain_version: v7.0.0 7 | api_enabled: true 8 | chain_id: "my-devnet" 9 | chain_use_ssl_proxy: true 10 | chain_api_host: "rest" 11 | chain_rpc_host: "rpc" 12 | chain_grpc_host: "grpc" 13 | chain_p2p_host: "p2p" 14 | letsencrypt_email: "validator@devnet.com" 15 | enable_swap: false 16 | swap_size: 8192 17 | monitoring_prometheus: true 18 | grafana_ssh_url: root@monitor.devnet.com 19 | reboot: false 20 | children: 21 | node: 22 | hosts: 23 | "{{ target }}": 24 | ansible_user: root 25 | chain_create_validator: true 26 | chain_airdrop: true 27 | chain_airdrop_accounts: 28 | - cosmos* 29 | - cosmos* 30 | -------------------------------------------------------------------------------- /examples/inventory-join-salt.yml: -------------------------------------------------------------------------------- 1 | --- 2 | # yamllint disable rule:line-length 3 | all: 4 | vars: 5 | ansible_user: root 6 | node_user: salt 7 | chain_home: "{{node_user_home}}/.isc-salt" 8 | chain_binary_name: interchain-security-cd 9 | chain_version: tags/v0.1.4 10 | chain_repository: https://github.com/cosmos/interchain-security.git 11 | genesis_url: "https://raw.githubusercontent.com/hyphacoop/ics-testnets/main/private-testnet/ccv-salt-genesis.json" 12 | chain_id: salt 13 | chain_home_clear: true 14 | p2p_persistent_peers: "2bd4797ad1812fc7c90737e9ddef38114bd77229@68.183.199.144:26656" 15 | chain_moniker: "salty" 16 | node_service_name: "salty" 17 | cosmovisor_service_name: "cv-salty" 18 | reboot: false 19 | children: 20 | node: 21 | hosts: 22 | "{{ target }}": 23 | fast_sync: false 24 | -------------------------------------------------------------------------------- /roles/configure-panic/tasks/main.yml: -------------------------------------------------------------------------------- 1 | --- 2 | - name: Copy over config_panic_nodes.py 3 | copy: 4 | src: config_panic_nodes.py 5 | dest: /usr/local/bin/config_panic_nodes.py 6 | mode: 0755 7 | owner: root 8 | group: root 9 | run_once: true 10 | 11 | - name: Configure PANIC with config_panic_nodes.py 12 | script: 13 | cmd: config_panic_nodes.py --config_file {{ panic_config_file }} add --node_name {{ inventory_hostname }} --node_rpc_url {{ inventory_hostname }} --node_rpc_port {{ rpc_port }} --node_is_validator {{ panic_is_validator }} --include_in_node_monitor {{ panic_include_in_node_monitor }} --include_in_network_monitor {{ panic_include_in_network_monitor }} 14 | become_user: panic 15 | throttle: 1 16 | 17 | - name: Restart PANIC 18 | systemd: 19 | name: panic-cosmos.service 20 | state: restarted 21 | run_once: true 22 | -------------------------------------------------------------------------------- /roles/blockscout/templates/blockscout.service.j2: -------------------------------------------------------------------------------- 1 | [Unit] 2 | Description=EVM explorer 3 | After=network-online.target 4 | 5 | [Service] 6 | User=ubuntu 7 | ExecStart={{blockscout_user_home}}/.asdf/shims/mix phx.server 8 | Environment="SECRET_KEY_BASE={{SECRET_KEY_BASE}}" 9 | Environment="ETHEREUM_JSONRPC_HTTP_URL={{ETHEREUM_JSONRPC_HTTP_URL}}" 10 | Environment="ETHEREUM_JSONRPC_WS_URL={{ETHEREUM_JSONRPC_WS_URL}}" 11 | Environment="COIN={{COIN}}" 12 | Environment="SUBNETWORK={{SUBNETWORK}}" 13 | Environment="NETWORK={{NETWORK}}" 14 | Environment="DATABASE_URL={{DATABASE_URL}}" 15 | Environment="PATH=$PATH:{{blockscout_user_home}}/.asdf/shims/elixir:{{blockscout_user_home}}/.asdf/shims:{{blockscout_user_home}}/.asdf/bin:/usr/bin/" 16 | WorkingDirectory={{blockscout_dir}} 17 | Restart=always 18 | RestartSec=3 19 | LimitNOFILE=4096 20 | 21 | [Install] 22 | WantedBy=multi-user.target -------------------------------------------------------------------------------- /examples/inventory-join-pepper.yml: -------------------------------------------------------------------------------- 1 | --- 2 | # yamllint disable rule:line-length 3 | all: 4 | vars: 5 | ansible_user: root 6 | node_user: pepper 7 | chain_home: "{{node_user_home}}/.isc-pepper" 8 | chain_binary_name: interchain-security-cd 9 | chain_version: tags/v0.1.4 10 | chain_repository: https://github.com/cosmos/interchain-security.git 11 | genesis_url: "https://raw.githubusercontent.com/hyphacoop/ics-testnets/main/private-testnet/ccv-pepper-genesis.json" 12 | chain_id: pepper 13 | chain_home_clear: true 14 | p2p_persistent_peers: "2bd4797ad1812fc7c90737e9ddef38114bd77229@159.89.126.190:26656" 15 | chain_moniker: "peppy" 16 | node_service_name: "peppy" 17 | cosmovisor_service_name: "cv-peppy" 18 | reboot: false 19 | children: 20 | node: 21 | hosts: 22 | "{{ target }}": 23 | fast_sync: false 24 | -------------------------------------------------------------------------------- /roles/export-genesis/tasks/main.yml: -------------------------------------------------------------------------------- 1 | --- 2 | # Provision the DO VM 3 | - include_role: 4 | name: provision-digitalocean 5 | 6 | - name: Modify script with values of the droplet 7 | template: 8 | src: tests/export_genesis.sh 9 | dest: /tmp/export_genesis.sh 10 | mode: 0755 11 | 12 | - name: Store IPv4 address into /tmp/droplet_ipv4.txt 13 | copy: 14 | content="{{ droplet_ipv4}}" 15 | dest="/tmp/droplet_ipv4.txt" 16 | 17 | - name: Store IPv6 address into /tmp/droplet_ipv6.txt 18 | copy: 19 | content="{{ droplet_ipv6}}" 20 | dest="/tmp/droplet_ipv6.txt" 21 | 22 | - name: Set IPv6 in hosts file 23 | lineinfile: 24 | path: /etc/hosts 25 | line: '{{ droplet_ipv6 }} mainnet-export' 26 | become: true 27 | 28 | - name: Set IPv4 in hosts file 29 | lineinfile: 30 | path: /etc/hosts 31 | line: '{{ droplet_ipv4 }} mainnet-export' 32 | become: true 33 | -------------------------------------------------------------------------------- /examples/inventory-join-sugar.yml: -------------------------------------------------------------------------------- 1 | --- 2 | # yamllint disable rule:line-length 3 | all: 4 | vars: 5 | ansible_user: root 6 | node_user: sugar 7 | chain_home: "{{node_user_home}}/.isc-sugar" 8 | chain_binary_name: neutrond 9 | chain_binary_release: https://github.com/neutron-org/neutron/raw/feat/interchain-security-with-governance/neutrond 10 | chain_binary_source: release 11 | genesis_url: "https://raw.githubusercontent.com/hyphacoop/ics-testnets/main/private-testnet/ccv-sugar-genesis.json" 12 | chain_id: sugar 13 | chain_home_clear: true 14 | p2p_persistent_peers: "2bd4797ad1812fc7c90737e9ddef38114bd77229@159.203.29.24:26656" 15 | chain_moniker: "sugary" 16 | node_service_name: "sugary" 17 | cosmovisor_service_name: "cv-sugary" 18 | reboot: false 19 | children: 20 | node: 21 | hosts: 22 | "{{ target }}": 23 | fast_sync: false 24 | -------------------------------------------------------------------------------- /roles/cascadia/tasks/main.yml: -------------------------------------------------------------------------------- 1 | --- 2 | - name: setup 3 | import_tasks: setup.yml 4 | 5 | - name: install go and gaiad 6 | import_tasks: install_gaiad.yml 7 | 8 | - name: configure gaiad 9 | import_tasks: config_gaiad.yml 10 | 11 | - name: set up faucet 12 | import_tasks: faucet.yml 13 | when: faucet_enabled 14 | 15 | - name: add genesis file 16 | import_tasks: genesis.yml 17 | when: genesis_file is defined or genesis_url is defined 18 | 19 | - name: install cosmovisor 20 | import_tasks: install_cosmovisor.yml 21 | when: use_cosmovisor 22 | 23 | - name: setup systemd services 24 | import_tasks: services.yml 25 | 26 | - name: setup APIs 27 | import_tasks: apis.yml 28 | 29 | - name: setup monitoring 30 | import_tasks: monitoring.yml 31 | 32 | - name: Rebooting the machine 33 | include_role: 34 | name: reboot 35 | when: reboot | default(false) | bool 36 | tags: 37 | - reboot 38 | -------------------------------------------------------------------------------- /roles/node/tasks/faucet.yml: -------------------------------------------------------------------------------- 1 | --- 2 | - name: create faucet account 3 | shell: | 4 | echo {{faucet_mnemonic}} | {{chain_bin}} keys add faucet --home {{chain_home}} --keyring-backend {{node_keyring}} --output json --recover 5 | {{chain_bin}} add-genesis-account faucet 10000000000000000000000000{{ chain_denom }} --home {{chain_home}} --keyring-backend="{{node_keyring}}" 6 | register: create_faucet_output 7 | become_user: "{{node_user}}" 8 | 9 | - name: save faucet name, address, and mnemonic 10 | copy: 11 | content: "{{create_faucet_output.stderr}}" 12 | dest: "{{chain_home}}/faucet.json" 13 | become_user: "{{node_user}}" 14 | 15 | - name: collect faucet address 16 | shell: | 17 | jq -r '.address' {{chain_home}}/faucet.json 18 | register: faucet_address 19 | become_user: "{{node_user}}" 20 | 21 | - name: set faucet address 22 | set_fact: 23 | faucet_address: "{{ faucet_address.stdout }}" 24 | -------------------------------------------------------------------------------- /examples/inventory-public-testnet.yml: -------------------------------------------------------------------------------- 1 | --- 2 | # yamllint disable rule:line-length 3 | all: 4 | vars: 5 | ansible_user: root 6 | chain_version: v7.1.0 7 | genesis_url: "https://github.com/cosmos/testnets/raw/master/public/genesis.json.gz" 8 | chain_id: theta-testnet-001 9 | chain_home_clear: false 10 | node_unsafe_reset: true 11 | chain_use_ssl_proxy: false 12 | chain_api_host: "rest" 13 | chain_rpc_host: "rpc" 14 | chain_p2p_host: "p2p" 15 | chain_grpc_host: "grpc" 16 | p2p_seeds: "639d50339d7045436c756a042906b9a69970913f@seed-01.theta-testnet.polypore.xyz:26656,3e506472683ceb7ed75c1578d092c79785c27857@seed-02.theta-testnet.polypore.xyz:26656" 17 | reboot: true 18 | children: 19 | node: 20 | hosts: 21 | "{{ target }}": 22 | fast_sync: true 23 | statesync_enabled: true 24 | statesync_rpc_servers: 'http://rpc.state-sync-01.theta-testnet.polypore.xyz:26657,http://rpc.state-sync-02.theta-testnet.polypore.xyz:26657' 25 | -------------------------------------------------------------------------------- /game-of-chains-2022/sputnik-join.yml: -------------------------------------------------------------------------------- 1 | --- 2 | # yamllint disable rule:line-length 3 | all: 4 | vars: 5 | ansible_user: root 6 | node_user: sputnik 7 | chain_home: "{{node_user_home}}/.sputnik" 8 | chain_binary_name: sputnikd 9 | chain_binary_release: https://github.com/hyphacoop/ics-testnets/raw/main/game-of-chains-2022/sputnik/interchain-security-cd # Linux amd64 10 | chain_binary_source: release # Set to "build" if building from source 11 | # chain_version: tags/v0.2.0 12 | # chain_repository: https://github.com/cosmos/interchain-security.git 13 | # chain_binary_name: interchain-security-cd 14 | genesis_url: https://github.com/hyphacoop/ics-testnets/raw/main/game-of-chains-2022/sputnik/sputnik-genesis.json 15 | chain_home_clear: true 16 | chain_id: sputnik 17 | cosmovisor_service_name: "cv-sputnik" 18 | chain_moniker: "sputnik" 19 | children: 20 | node: 21 | hosts: 22 | "{{ target }}": 23 | p2p_seeds: "3aed29ec1ca96ea52299748c50bf7d908511068f@tenderseed.ccvalidators.com:29019" 24 | -------------------------------------------------------------------------------- /tests/generate_version_matrix.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | import json 4 | import sys 5 | import requests 6 | 7 | 8 | # Must provide a cutoff version, e.g. 'v6.0.4' 9 | starting_version = sys.argv[1] 10 | version_major = int(starting_version[1]) 11 | version_patch = int(starting_version[5]) 12 | 13 | # Read in releases from GitHub API 14 | releases_list = requests.get( 15 | 'https://api.github.com/repos/cosmos/gaia/releases', timeout=30).json() 16 | 17 | # Save release list for upgrade matrix script 18 | with open('releases.json', 'w', encoding='utf-8') as outfile: 19 | json.dump(releases_list, outfile) 20 | 21 | # Trim list to only releases from specified version onwards 22 | trimmed_releases = [release for release in releases_list if 23 | (int(release['name'][1]) == version_major and 24 | int(release['name'][5]) >= version_patch) or 25 | int(release['name'][1]) > version_major] 26 | 27 | start_json = json.dumps( 28 | {'gaia_version': [rel['name'] for rel in trimmed_releases]}) 29 | print(start_json) 30 | -------------------------------------------------------------------------------- /game-of-chains-2022/gopher-join.yml: -------------------------------------------------------------------------------- 1 | --- 2 | # yamllint disable rule:line-length 3 | all: 4 | vars: 5 | ansible_user: root 6 | node_user: gopher 7 | chain_home: "{{node_user_home}}/.gopher" 8 | chain_binary_name: gopherd 9 | chain_binary_release: https://github.com/hyphacoop/ics-testnets/raw/main/game-of-chains-2022/gopher/interchain-security-cd # Linux amd64 10 | chain_binary_source: release # Set to "build" if building from source and uncomment the next three lines 11 | genesis_url: https://github.com/hyphacoop/ics-testnets/raw/main/game-of-chains-2022/gopher/gopher-genesis.json 12 | # chain_version: tags/v0.2.1 13 | # chain_repository: https://github.com/cosmos/interchain-security.git 14 | # chain_binary_name: interchain-security-cd 15 | chain_home_clear: true 16 | chain_id: gopher 17 | cosmovisor_service_name: "cv-gopher" 18 | chain_moniker: "gopher" 19 | children: 20 | node: 21 | hosts: 22 | "{{ target }}": 23 | p2p_seeds: "e0a4a0704bbe72d252c541fa7a0da04e7400f589@tenderseed.ccvalidators.com:29059" 24 | -------------------------------------------------------------------------------- /examples/inventory-bigdipper.yml: -------------------------------------------------------------------------------- 1 | --- 2 | # yamllint disable rule:line-length 3 | 4 | all: 5 | vars: 6 | ansible_user: root 7 | hasura_admin_secret: CHANGE_ME # Any random password will work 8 | # Change if not running a cosmos hub testnet, see branches of bdjuno: 9 | bdjuno_version: "chains/cosmos/testnet" 10 | bdui_chain: testnet # Either testnet or mainnet 11 | bigdipper_use_tls_proxy: false # Enables TLS, requires a domain name 12 | # letsencrypt_email: "example@example.com" # Required for TLS setup 13 | genesis_url: "https://github.com/cosmos/testnets/raw/master/public/genesis.json.gz" 14 | # genesis_file: "genesis.json" # Alternative to genesis_url 15 | chain_id: theta-testnet-001 16 | bigdipper_genesis_time: "2019-12-11T16:11:34Z" 17 | bigdipper_genesis_height: 9034670 18 | children: 19 | bigdipper: 20 | hosts: 21 | "{{ target }}": 22 | bdjuno_rpc_address: "http://archive.theta-testnet.com:{{ bdjuno_rpc_port }}" 23 | bdjuno_grpc_address: "http://archive.theta-testnet.com:{{ bdjuno_grpc_port }}" 24 | -------------------------------------------------------------------------------- /roles/blockscout/defaults/main.yml: -------------------------------------------------------------------------------- 1 | # BlockScout related variables 2 | 3 | ## An address of BlockScout repo to download 4 | blockscout_repo: https://github.com/CascadiaFoundation/evm_explorer.git 5 | branch: dev 6 | blockscout_user: ubuntu 7 | blockscout_user_home: "/home/{{blockscout_user}}" 8 | blockscout_dir: "{{blockscout_user_home}}/blockscout" 9 | blockscout_service_name: blockscout 10 | 11 | # Database 12 | blockscout_db: blockscout 13 | blockscout_db_password: cascadia 14 | blockscout_db_user: "feynman" 15 | 16 | erlang: 24.3.4.1 17 | elixir: 1.13.4-otp-24 18 | 19 | NETWORK: Cascadia # Name of the organization/community that hosts the chain 20 | SUBNETWORK: Testnet # Actual name of the particular network 21 | ETHEREUM_JSONRPC_HTTP_URL: "http://localhost:8545" # Network RPC endpoint 22 | ETHEREUM_JSONRPC_WS_URL: "ws://localhost:8546" # Network RPC endpoint in websocket mode 23 | DATABASE_URL: postgresql://{{blockscout_db_user}}:{{blockscout_db_password}}@localhost:5432/{{blockscout_db}} 24 | COIN: CC 25 | SECRET_KEY_BASE: /irrVYsohe37ixGcTvx7Hd0k3afsaEX+L8nl+7G78vQjAiJNXslG0JgdNYvz/VXh 26 | 27 | 28 | -------------------------------------------------------------------------------- /roles/bigdipper/templates/bigdipper-chain_config.json.j2: -------------------------------------------------------------------------------- 1 | { 2 | "title": "Testnet Block Explorer", 3 | "network": "{{chain_id}}", 4 | "icon": {{ bdui_icon | to_json }}, 5 | "logo": { 6 | "default": {{ bdui_logo | to_json }} 7 | }, 8 | "prefix": { 9 | "consensus": "cosmosvalcons", 10 | "validator": "cosmosvaloper", 11 | "account": "cosmos" 12 | }, 13 | "genesis": { 14 | "time": {{ bigdipper_genesis_time | to_json }}, 15 | "height": {{ bigdipper_genesis_height | to_json }} 16 | }, 17 | "primaryTokenUnit": "uatom", 18 | "votingPowerTokenUnit": "uatom", 19 | "tokenUnits": { 20 | "uatom": { 21 | "display": "atom", 22 | "exponent": 6 23 | }, 24 | "rho": { 25 | "display": "rho", 26 | "exponent": 0 27 | }, 28 | "lambda": { 29 | "display": "lambda", 30 | "exponent": 0 31 | }, 32 | "epsilon": { 33 | "display": "epsilon", 34 | "exponent": 0 35 | }, 36 | "theta": { 37 | "display": "theta", 38 | "exponent": 0 39 | } 40 | }, 41 | "extra": { 42 | "profile": true 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /roles/faucet/defaults/main.yml: -------------------------------------------------------------------------------- 1 | --- 2 | # Chain settings 3 | chain_binary_name: gaiad 4 | node_user: gaia 5 | node_user_home: "/home/{{node_user}}" 6 | chain_home: "{{node_user_home}}/.gaia" 7 | chain_denom: uatom 8 | chain_id: "my-testnet" 9 | node_keyring: "test" 10 | faucet_chain_env: "PATH={{chain_home}}/cosmovisor/current/bin" 11 | 12 | # Faucet settings 13 | faucet_version: v1.0.0 14 | faucet_service_name: token-faucet 15 | faucet_address: cosmosabc123 16 | transactions_log_path: "transactions.csv" 17 | request_timeout: 86400 18 | node_url: "http://localhost:26657" 19 | daily_cap: 500000000 20 | amount_to_send: 1000000 21 | tx_fees: 500 22 | faucet_port: 8000 23 | 24 | # Nginx / SSL settings 25 | faucet_setup_nginx: true 26 | faucet_host: "" 27 | faucet_use_tls_proxy: false 28 | ssl_provider: "" 29 | # nginx_sites: {} 30 | nginx_sites: 31 | "{{ faucet_host }}{{ inventory_hostname }}": 32 | ssl_provider: "{{ ssl_provider }}" 33 | web_hostname: "{{ faucet_host }}{{inventory_hostname}}" 34 | locations: 35 | "/": 36 | proxy_location: "http://127.0.0.1:{{ faucet_port }}" 37 | proxy_websocket: true 38 | -------------------------------------------------------------------------------- /roles/faucet/tasks/base.yml: -------------------------------------------------------------------------------- 1 | --- 2 | - name: Populate service facts 3 | service_facts: 4 | 5 | - include_role: 6 | name: common 7 | 8 | # Set up nginx 9 | - name: Change vars for TLS 10 | when: faucet_setup_nginx and faucet_use_tls_proxy 11 | set_fact: 12 | ssl_provider: "letsencrypt" 13 | 14 | - include_role: 15 | name: hypha.common.nginx 16 | when: faucet_setup_nginx 17 | 18 | - include_role: 19 | name: hypha.common.ssl 20 | when: faucet_setup_nginx and faucet_use_tls_proxy 21 | 22 | - name: Restart nginx to apply new config 23 | systemd: 24 | state: restarted 25 | name: nginx 26 | when: faucet_setup_nginx 27 | 28 | - name: Stop existing faucet systemd service 29 | when: > 30 | (faucet_service_name in ansible_facts.services) or 31 | ((faucet_service_name + '.service') in ansible_facts.services) 32 | systemd: 33 | state: stopped 34 | name: "{{faucet_service_name}}" 35 | tags: 36 | - faucet_stop 37 | - faucet_restart 38 | ignore_errors: true 39 | 40 | - name: Install python 41 | apt: 42 | pkg: 43 | - python3 44 | - python3-venv 45 | - python3-pip 46 | - python-is-python3 47 | -------------------------------------------------------------------------------- /game-of-chains-2022/README.md: -------------------------------------------------------------------------------- 1 | # Game of Chains Playbooks 2 | 3 | Inventory files are provided here as reference and to help participants join different chains. 4 | 5 | These playbooks have been tested with Ubuntu 22.10. 6 | 7 | ## Join the Provider Chain 8 | 9 | * **Inventory file:** [`provider-join.yml`](provider-join.yml) 10 | * Binary: `gaiad` 11 | * [Linux amd64 build](https://github.com/hyphacoop/ics-testnets/raw/main/game-of-chains-2022/provider/gaiad) 12 | * [glnro/ics-sdk45 branch](https://github.com/cosmos/gaia/tree/glnro/ics-sdk45) 13 | * Commit 199f728fc6394bdc3f8816fdb906e12f37493bc5 14 | * Binary SHA256: `d1dc6d31671a56b995cc8fab639a4cae6a88981de05d42163351431b8a6691cf` 15 | * Chain ID: `provider` 16 | * Denom: `uprov` 17 | * Bech32 prefix: `cosmos` 18 | 19 | Run the playbook: 20 | ``` 21 | ansible-playbook node.yml -i game-of-chains-2022/provider-join.yml -e 'target=SERVER_IP_OR_DOMAIN node_key_file= priv_validator_key_file=' 22 | ``` 23 | 24 | After the play has finished running, run `journalctl -fu cv-provider` to check the output of cosmovisor, or `journalctl -fu provider` if you set `use_cosmovisor` to `false`. 25 | 26 | -------------------------------------------------------------------------------- /roles/common/tasks/main.yml: -------------------------------------------------------------------------------- 1 | --- 2 | 3 | - name: Upgrade the system 4 | apt: 5 | update_cache: true 6 | upgrade: dist 7 | register: apt_cache 8 | retries: 50 9 | until: apt_cache is success 10 | 11 | - name: Remove python3-pip apt package 12 | ansible.builtin.apt: 13 | name: python3-pip 14 | state: absent 15 | 16 | - name: Download script to install pip3 17 | get_url: 18 | url: https://bootstrap.pypa.io/get-pip.py 19 | dest: /tmp/get-pip.py 20 | mode: '0644' 21 | 22 | - name: Install pip3 using downloaded script 23 | shell: python3 /tmp/get-pip.py 24 | 25 | - name: Install system required packages 26 | apt: 27 | pkg: 28 | - ntp 29 | - python3 30 | - python3-apt 31 | - curl 32 | - apt-transport-https 33 | - software-properties-common 34 | - wget 35 | - git 36 | - build-essential 37 | - haveged 38 | - python3-openssl 39 | - jq 40 | - rsync 41 | 42 | - name: Install basic utils 43 | apt: 44 | state: present 45 | pkg: 46 | - curl 47 | - htop 48 | - mtr-tiny 49 | 50 | - name: Set timezone to America/Toronto 51 | timezone: 52 | name: America/Toronto 53 | -------------------------------------------------------------------------------- /roles/hermes/defaults/main.yml: -------------------------------------------------------------------------------- 1 | --- 2 | hermes_user: hermes 3 | hermes_group: users 4 | hermes_version: v1.0.0 5 | 6 | # Node connections 7 | hermes_relayer_keys: false 8 | hermes_relayer_mnemonics: false 9 | 10 | # Connections 11 | hermes_set_clients: false 12 | 13 | # Channels 14 | hermes_order: unordered 15 | hermes_set_channel_version: false 16 | hermes_channel_version: '0' 17 | 18 | # Mode 19 | # mode.clients 20 | mode_clients: 'true' 21 | mode_clients_refresh: 'true' 22 | mode_clients_misbehaviour: 'true' 23 | 24 | # mode.connections 25 | mode_connections: 'false' 26 | 27 | # mode.channels 28 | mode_channels: 'false' 29 | 30 | # mode.packets 31 | mode_packets: 'true' 32 | mode_packets_clear_interval: 100 33 | mode_packets_clear_on_start: 'true' 34 | mode_packets_tx_confirmation: 'true' 35 | 36 | # REST API 37 | hermes_rest_api: 'true' 38 | hermes_rest_api_bindhost: "127.0.0.1" 39 | hermes_rest_api_port: 3000 40 | 41 | # Telemetry 42 | hermes_telemetry: 'true' 43 | hermes_telemetry_bindhost: "127.0.0.1" 44 | hermes_telemetry_port: 3001 45 | 46 | # Architecture mapping 47 | binary_arch_map: 48 | aarch64: "aarch64-unknown-linux-gnu" 49 | x86_64: "x86_64-unknown-linux-gnu" 50 | 51 | ### Reboot after setup 52 | reboot: true 53 | -------------------------------------------------------------------------------- /roles/consensus-monitor/defaults/main.yml: -------------------------------------------------------------------------------- 1 | --- 2 | # User and repo settings 3 | consensus_user: consensus 4 | consensus_user_home: "/home/{{ consensus_user }}" 5 | consensus_repo_path: "{{ consensus_user_home }}/cosmos-consensus-monitor" 6 | consensus_repo_url: "https://github.com/hyphacoop/cosmos-consensus-monitor.git" 7 | consensus_monitor_version: v1.0.0 8 | 9 | # Consensus monitor settings 10 | consensus_api_node_url: "http://localhost:1317" 11 | consensus_rpc_node_url: "http://localhost:26657" 12 | consensus_ws_port: 9001 13 | consensus_ui_port: 8000 14 | consensus_ws_service_name: consensus-monitor-ws 15 | consensus_ui_service_name: consensus-monitor-ui 16 | 17 | # Nginx / SSL settings 18 | consensus_setup_nginx: true 19 | consensus_host: "" 20 | consensus_use_tls_proxy: false 21 | ssl_provider: "" 22 | # nginx_sites: {} 23 | nginx_sites: 24 | "{{ consensus_host }}{{ inventory_hostname }}": 25 | ssl_provider: "{{ ssl_provider }}" 26 | web_hostname: "{{ consensus_host }}{{inventory_hostname}}" 27 | locations: 28 | "/": 29 | proxy_location: "http://127.0.0.1:{{ consensus_ui_port }}" 30 | proxy_websocket: true 31 | "/ws/": 32 | proxy_location: "http://127.0.0.1:{{ consensus_ws_port }}" 33 | proxy_websocket: true 34 | -------------------------------------------------------------------------------- /roles/faucet/tasks/faucet.yml: -------------------------------------------------------------------------------- 1 | --- 2 | - name: checkout rest faucet repo 3 | git: 4 | repo: 'https://github.com/hyphacoop/cosmos-rest-faucet.git' 5 | dest: "{{node_user_home}}/cosmos-rest-faucet" 6 | version: "{{faucet_version}}" 7 | force: yes 8 | become_user: "{{node_user}}" 9 | 10 | - name: Set up python virtual environment 11 | shell: | 12 | cd {{node_user_home}}/cosmos-rest-faucet 13 | python -m venv .env 14 | become_user: "{{node_user}}" 15 | 16 | - name: install faucet dependencies 17 | pip: 18 | requirements: "{{node_user_home}}/cosmos-rest-faucet/requirements.txt" 19 | virtualenv: "{{node_user_home}}/cosmos-rest-faucet/.env" 20 | become_user: "{{node_user}}" 21 | 22 | - name: configure faucet 23 | template: 24 | src: faucet_config.toml.j2 25 | dest: "{{node_user_home}}/cosmos-rest-faucet/config.toml" 26 | become_user: "{{node_user}}" 27 | 28 | - name: configure faucet service 29 | template: 30 | src: faucet.service.j2 31 | dest: "/etc/systemd/system/{{faucet_service_name}}.service" 32 | 33 | - name: Start faucet service 34 | systemd: 35 | daemon_reload: true 36 | state: restarted 37 | enabled: true 38 | name: "{{faucet_service_name}}" 39 | tags: 40 | - faucet_start 41 | - faucet_restart 42 | -------------------------------------------------------------------------------- /roles/bigdipper/tasks/hasura.yml: -------------------------------------------------------------------------------- 1 | --- 2 | 3 | # - name: "Run docker image for Hasura" 4 | # community.docker.docker_container: 5 | # state: started 6 | # name: big-dipper-hasura 7 | # image: "hasura/graphql-engine:{{hasura_version}}" 8 | # network_mode: host 9 | # restart_policy: "always" 10 | # env: 11 | # HASURA_GRAPHQL_DATABASE_URL: "{{bigdipper_db_url}}" 12 | # HASURA_GRAPHQL_SERVER_PORT: "{{ hasura_port | string }}" 13 | # HASURA_GRAPHQL_SERVER_HOST: "127.0.0.1" 14 | # HASURA_GRAPHQL_UNAUTHORIZED_ROLE: "anonymous" 15 | # ACTION_BASE_URL: "http://localhost:{{bdjuno_hasura_actions_port}}" 16 | # HASURA_GRAPHQL_ADMIN_SECRET: "{{hasura_admin_secret}}" 17 | 18 | - name: "Set up node+npm" 19 | include_role: 20 | name: geerlingguy.nodejs 21 | 22 | - name: "Set up hasura CLI" 23 | shell: "npm install --unsafe-perm --global hasura-cli@{{hasura_cli_version}}" 24 | 25 | # - name: Wait for docker to be ready 26 | # wait_for: 27 | # port: "{{hasura_port}}" 28 | # delay: 10 29 | 30 | - name: "Apply metadata to hasura" 31 | become_user: "{{bigdipper_user}}" 32 | shell: | 33 | hasura metadata apply --endpoint https://cascadia.hasura.app --admin-secret "{{hasura_admin_secret}}" 34 | args: 35 | chdir: "{{bdjuno_dir}}/hasura" 36 | async: 30 37 | poll: 10 38 | -------------------------------------------------------------------------------- /roles/cascadia/tasks/install_cosmovisor.yml: -------------------------------------------------------------------------------- 1 | --- 2 | - name: Check cosmovisor version 3 | shell: | 4 | PATH=$PATH:/usr/local/go/bin:$HOME/go/bin 5 | cosmovisor version 6 | become_user: "{{gaiad_user}}" 7 | register: cosmovisor_current 8 | ignore_errors: true 9 | 10 | - name: clone and install cosmovisor 11 | when: not cosmovisor_version in cosmovisor_current.stdout 12 | shell: | 13 | PATH=$PATH:/usr/local/go/bin:$HOME/go/bin 14 | go install {{cosmovisor_repository}}@{{cosmovisor_version}} 15 | become_user: "{{gaiad_user}}" 16 | 17 | ## Configure cosmovisor 18 | - name: Prepare cosmovisor folder 19 | file: 20 | path: '{{ cosmovisor_home }}/genesis/bin' 21 | state: directory 22 | owner: '{{gaiad_user}}' 23 | group: '{{gaiad_user}}' 24 | 25 | - name: Copy gaiad bin for cosmovisor genesis 26 | copy: 27 | # force: false 28 | remote_src: true 29 | src: '{{ gaiad_bin }}' 30 | dest: '{{ cosmovisor_home }}/genesis/bin/gaiad' 31 | owner: '{{gaiad_user}}' 32 | group: '{{gaiad_user}}' 33 | mode: '0755' 34 | 35 | - name: Add gaiad bin from cosmovisor to .bashrc PATH 36 | blockinfile: 37 | dest: '{{ gaiad_user_home }}/.bashrc' 38 | block: | 39 | export PATH="$PATH:{{ cosmovisor_home }}/current/bin" 40 | marker: '# {mark} ANSIBLE MANAGED BLOCK - GAIAD PATH' 41 | insertbefore: EOF 42 | create: yes 43 | -------------------------------------------------------------------------------- /tests/generate_upgrade_matrix.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | import json 4 | import sys 5 | 6 | 7 | # Must provide a cutoff version, e.g. 'v6.0.4' 8 | starting_version = sys.argv[1] 9 | version_major = int(starting_version[1]) 10 | version_patch = int(starting_version[5]) 11 | 12 | # Read JSON output from generate_start_matrix.py 13 | with open('releases.json', 'r', encoding='utf-8') as releases_file: 14 | releases_list = json.load(releases_file) 15 | 16 | # Trim list to only releases from specified version onwards 17 | trimmed_releases = [release for release in releases_list if 18 | (int(release['name'][1]) == version_major and 19 | int(release['name'][5]) >= version_patch) or 20 | int(release['name'][1]) > version_major] 21 | 22 | # Set upgrade versions to target for each release 23 | matrix = {release['name']: [] for release in trimmed_releases} 24 | 25 | for start_version, _ in matrix.items(): 26 | matrix[start_version] = [ 27 | release['name'] 28 | for release in trimmed_releases 29 | if int(release['name'][1]) > int(start_version[1])] 30 | 31 | # Assemble matrix include section: 32 | includes = [] 33 | for version, upgrades in matrix.items(): 34 | for upgrade in upgrades: 35 | includes.append({'gaia_version': version, 'upgrade_version': upgrade}) 36 | upgrade_json = json.dumps({'include': includes}) 37 | print(upgrade_json) 38 | -------------------------------------------------------------------------------- /game-of-chains-2022/provider-join.yml: -------------------------------------------------------------------------------- 1 | --- 2 | # yamllint disable rule:line-length 3 | all: 4 | vars: 5 | ansible_user: root 6 | node_user: provider 7 | chain_binary_release: https://github.com/hyphacoop/ics-testnets/raw/main/game-of-chains-2022/provider/gaiad # Linux amd64 8 | chain_binary_source: release # Set to "build" if building from source 9 | # chain_version: glnro/ics-sdk45 10 | # chain_repository: https://github.com/cosmos/gaia.git 11 | genesis_url: https://github.com/hyphacoop/ics-testnets/raw/main/game-of-chains-2022/provider/provider-genesis.json 12 | chain_id: provider 13 | chain_home_clear: true 14 | cosmovisor_service_name: "cv-provider" 15 | use_cosmovisor: true # Set to "false" if you do not want to use cosmovisor 16 | node_service_name: provider 17 | # Uncomment the following lines if setting up TLS 18 | # chain_use_ssl_proxy: true 19 | # chain_api_host: "rest" 20 | # chain_rpc_host: "rpc" 21 | # chain_p2p_host: "p2p" 22 | # chain_grpc_host: "grpc" 23 | # letsencrypt_email: "" 24 | children: 25 | node: 26 | hosts: 27 | "{{ target }}": 28 | fast_sync: false 29 | pruning: nothing 30 | p2p_seeds: "7a86ddc92f56e77a26c4fb4d543412f7175a7c9b@provider-seed-01.goc.earthball.xyz:26656" 31 | statesync_enabled: true 32 | statesync_rpc_servers: 'http://provider-seed-01.goc.earthball.xyz:26657,http://provider-seed-01.goc.earthball.xyz:26657' 33 | -------------------------------------------------------------------------------- /examples/inventory-three-node.yml: -------------------------------------------------------------------------------- 1 | --- 2 | # yamllint disable rule:line-length 3 | all: 4 | vars: 5 | ansible_user: root 6 | chain_version: v7.0.0 7 | genesis_file: "examples/genesis-three-node.json" 8 | chain_id: cosmos-testnet 9 | minimum_gas_prices: '0.001uatom' 10 | chain_home_clear: true 11 | chain_create_validator: false 12 | chain_api_host: "rest" 13 | chain_rpc_host: "rpc" 14 | chain_p2p_host: "p2p" 15 | chain_grpc_host: "grpc" 16 | enable_swap: false 17 | swap_size: 8192 18 | p2p_persistent_peers: "9e3598aa3b09ab90a99180b3987f98d69d37ce37@validator-40.testnet.com:26656,6bf63611fd835136ee1039724d40c9989ffd180c@validator-32.testnet.com:26656,f13f0566f2052a737c402a9928d6f9a703ffd47d@validator-28.testnet.com:26656" 19 | reboot: false 20 | children: 21 | node: 22 | hosts: 23 | validator-40.testnet.com: 24 | node_key_file: "examples/validator-keys/validator-40/node_key.json" 25 | priv_validator_key_file: "examples/validator-keys/validator-40/priv_validator_key.json" 26 | validator-32.testnet.com: 27 | node_key_file: "examples/validator-keys/validator-32/node_key.json" 28 | priv_validator_key_file: "examples/validator-keys/validator-32/priv_validator_key.json" 29 | validator-28.testnet.com: 30 | node_key_file: "examples/validator-keys/validator-28/node_key.json" 31 | priv_validator_key_file: "examples/validator-keys/validator-28/priv_validator_key.json" 32 | -------------------------------------------------------------------------------- /roles/nginx-ssl/tasks/main.yml: -------------------------------------------------------------------------------- 1 | --- 2 | 3 | - name: Install nginx packages 4 | apt: 5 | pkg: 6 | - nginx 7 | - certbot 8 | 9 | - name: Configure certbot to reload nginx on renew 10 | ini_file: 11 | path: /etc/letsencrypt/cli.ini 12 | section: '' 13 | option: deploy-hook 14 | value: 'systemctl reload nginx' 15 | state: present 16 | 17 | - name: Create nginx SSL directory 18 | file: 19 | path: /etc/nginx/ssl 20 | owner: root 21 | group: root 22 | mode: '700' 23 | state: directory 24 | 25 | - name: Download 4096-bit DH params 26 | ansible.builtin.get_url: 27 | url: https://ssl-config.mozilla.org/ffdhe4096.txt 28 | dest: /etc/ssl/dhparam.pem 29 | mode: 0644 30 | 31 | - name: Register Let's Encrypt 32 | command: certbot register --email {{letsencrypt_email}} --agree-tos -n 33 | args: 34 | creates: /etc/letsencrypt/accounts 35 | 36 | - name: Get Let's Encrypt Cert 37 | command: certbot certonly --webroot -w /var/www/html/ -d {{site_hostname}} --rsa-key-size 4096 38 | args: 39 | creates: /etc/letsencrypt/live/{{site_hostname}}/fullchain.pem 40 | 41 | - name: Configure nginx 42 | template: 43 | src: nginx-site.j2 44 | dest: '/etc/nginx/sites-available/{{site_hostname}}' 45 | 46 | - name: Enabling {{site_hostname}} nginx config 47 | file: 48 | src: /etc/nginx/sites-available/{{site_hostname}} 49 | dest: /etc/nginx/sites-enabled/{{site_hostname}} 50 | state: link 51 | 52 | - name: Reload nginx 53 | systemd: 54 | state: reloaded 55 | name: nginx 56 | -------------------------------------------------------------------------------- /tests/test_block_production.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # Check that blocks are being produced. 3 | 4 | gaia_host=$1 5 | gaia_port=$2 6 | stop_height=$3 7 | 8 | # Test gaia response 9 | tests/test_gaia_response.sh $gaia_host $gaia_port 10 | # Exit if test_gaia_response.sh fails 11 | if [ $? != 0 ] 12 | then 13 | exit 1 14 | fi 15 | 16 | # Get the current gaia version and block height from the API 17 | chain_version=$(curl -s http://$gaia_host:$gaia_port/abci_info | jq -r .result.response.version) 18 | echo $chain_version 19 | cur_height=0 20 | until [[ "${cur_height}" -gt 1 ]] 21 | do 22 | cur_height=$(curl -s http://$gaia_host:$gaia_port/block | jq -r .result.block.header.height) 23 | echo $cur_height 24 | sleep 5 25 | done 26 | 27 | # Check if gaia is producing blocks 28 | test_counter=0 29 | max_tests=2100 30 | echo "Current gaiad version: $chain_version" 31 | echo "Block height: $cur_height" 32 | echo "Waiting to reach block height $stop_height..." 33 | height=0 34 | until [ $height -ge $stop_height ] 35 | do 36 | sleep 5 37 | if [ ${test_counter} -gt ${max_tests} ] 38 | then 39 | echo "Queried gaia $test_counter times with a 5s wait between queries. A block height of $stop_height was not reached. Exiting." 40 | exit 2 41 | fi 42 | height=$(curl -s http://$gaia_host:$gaia_port/block | jq -r .result.block.header.height) 43 | if [ -z "$height" ] 44 | then 45 | height=0 46 | fi 47 | echo "Block height: $height" 48 | test_counter=$(($test_counter+1)) 49 | done 50 | echo "Gaia is producing blocks." 51 | -------------------------------------------------------------------------------- /roles/cascadia/tasks/apis.yml: -------------------------------------------------------------------------------- 1 | --- 2 | - name: Set variables for api endpoint 3 | set_fact: 4 | endpoint_port: '{{api_port}}' 5 | site_hostname: '{{gaiad_api_host}}.{{inventory_hostname}}' 6 | when: gaiad_use_ssl_proxy | default(false) | bool 7 | 8 | - name: Setup nginx SSL for gaiad api endpoint 9 | include_role: 10 | name: nginx-ssl 11 | when: gaiad_use_ssl_proxy | default(false) | bool 12 | 13 | - name: Set variables for rpc endpoint 14 | set_fact: 15 | endpoint_port: '{{rpc_port}}' 16 | site_hostname: '{{gaiad_rpc_host}}.{{inventory_hostname}}' 17 | when: gaiad_use_ssl_proxy | default(false) | bool 18 | 19 | - name: Setup nginx SSL for gaiad rpc endpoint 20 | include_role: 21 | name: nginx-ssl 22 | when: gaiad_use_ssl_proxy | default(false) | bool 23 | 24 | - name: Set variables for GRPC endpoint 25 | set_fact: 26 | endpoint_port: '{{grpc_port}}' 27 | site_hostname: '{{gaiad_grpc_host}}.{{inventory_hostname}}' 28 | grpc_vhost: true 29 | when: gaiad_use_ssl_proxy | default(false) | bool 30 | 31 | - name: Setup nginx SSL for gaiad GRPC endpoint 32 | include_role: 33 | name: nginx-ssl 34 | when: gaiad_use_ssl_proxy | default(false) | bool 35 | 36 | - name: Set variables for P2P endpoint 37 | set_fact: 38 | endpoint_port: '{{p2p_port}}' 39 | site_hostname: '{{gaiad_p2p_host}}.{{inventory_hostname}}' 40 | when: gaiad_use_ssl_proxy | default(false) | bool 41 | 42 | - name: Setup nginx SSL for gaiad P2P endpoint 43 | include_role: 44 | name: nginx-ssl 45 | when: gaiad_use_ssl_proxy | default(false) | bool 46 | -------------------------------------------------------------------------------- /.github/workflows/test-cosmoshub-node.yml: -------------------------------------------------------------------------------- 1 | --- 2 | 3 | name: Join Cosmos Hub 4 | on: 5 | workflow_dispatch: 6 | schedule: 7 | # At 15:30 on Monday. 8 | - cron: '30 15 * * 1' 9 | pull_request: 10 | types: 11 | - opened 12 | - closed 13 | jobs: 14 | test-cosmoshub: 15 | runs-on: ubuntu-22.04 16 | steps: 17 | - name: Check out repository code 18 | uses: actions/checkout@v3 19 | - name: Set up Python 20 | uses: actions/setup-python@v3 21 | with: 22 | python-version: '3.10' 23 | - name: Install pip dependencies 24 | run: | 25 | python -m pip install --upgrade pip 26 | python -m pip install ansible toml 27 | - name: Configure ansible.cfg 28 | run: echo "transport = local" >> ansible.cfg 29 | - name: Install ansible-galaxy requirements 30 | run: ansible-galaxy install -r requirements.yml 31 | - name: Run playbook 32 | run: | 33 | ansible-playbook node.yml -i examples/inventory-cosmos-hub.yml --extra-vars "target=local reboot=false chain_home={{ node_user_home }}/.gaia node_user=runner enable_swap=true swap_size=16384 cosmovisor_invariants_flag=''" 34 | - name: Check cosmovisor service 35 | run: systemctl status cosmovisor 36 | - name: Check blocks are being produced 37 | run: | 38 | height=$(curl -s https://rpc.cosmos.network/block | jq -r '.result.block.header.height') 39 | echo "Waiting for block $[ $height + 100 ]..." 40 | tests/test_block_production.sh 127.0.0.1 26657 $[ $height + 100] 41 | -------------------------------------------------------------------------------- /roles/cascadia/tasks/services.yml: -------------------------------------------------------------------------------- 1 | --- 2 | - name: configure systemd service for cascadiad 3 | when: not use_cosmovisor 4 | template: 5 | src: cascadiad.service.j2 6 | dest: "/etc/systemd/system/{{cascadiad_service_name}}.service" 7 | 8 | - name: configure systemd service for cosmovisor 9 | when: use_cosmovisor 10 | template: 11 | src: cosmovisor.service.j2 12 | dest: "/etc/systemd/system/{{cosmovisor_service_name}}.service" 13 | 14 | - name: Restart journalctl so that the logs may flow 15 | systemd: 16 | state: restarted 17 | name: systemd-journald 18 | 19 | - name: Enable cascadiad systemd service 20 | when: not use_cosmovisor 21 | systemd: 22 | daemon_reload: true 23 | state: stopped 24 | enabled: true 25 | name: "{{cascadiad_service_name}}" 26 | 27 | - name: Start cascadiad systemd service 28 | when: (not use_cosmovisor) and (not reboot | default(false) | bool) 29 | systemd: 30 | daemon_reload: true 31 | state: restarted 32 | enabled: true 33 | name: "{{cascadiad_service_name}}" 34 | tags: 35 | - cascadiad_start 36 | - cascadiad_restart 37 | 38 | - name: Enable cosmovisor systemd service 39 | when: use_cosmovisor 40 | systemd: 41 | daemon_reload: true 42 | state: stopped 43 | enabled: true 44 | name: "{{cosmovisor_service_name}}" 45 | 46 | - name: Start cosmovisor systemd service 47 | when: (use_cosmovisor) and (not reboot | default(false) | bool) 48 | systemd: 49 | daemon_reload: true 50 | state: restarted 51 | enabled: true 52 | name: "{{cosmovisor_service_name}}" 53 | tags: 54 | - cascadiad_start 55 | - cascadiad_restart 56 | -------------------------------------------------------------------------------- /roles/node/tasks/services.yml: -------------------------------------------------------------------------------- 1 | --- 2 | - name: configure systemd service for chain 3 | when: not use_cosmovisor 4 | template: 5 | src: chain.service.j2 6 | dest: "/etc/systemd/system/{{node_service_name}}.service" 7 | 8 | - name: configure systemd service for cosmovisor 9 | when: use_cosmovisor 10 | template: 11 | src: cosmovisor.service.j2 12 | dest: "/etc/systemd/system/{{cosmovisor_service_name}}.service" 13 | 14 | - name: Restart journalctl so that the logs may flow 15 | systemd: 16 | state: restarted 17 | name: systemd-journald 18 | 19 | - name: Enable chain systemd service 20 | when: chain_start and not use_cosmovisor 21 | systemd: 22 | daemon_reload: true 23 | state: stopped 24 | enabled: true 25 | name: "{{node_service_name}}" 26 | 27 | - name: Start chain systemd service 28 | when: chain_start and ((not use_cosmovisor) and (not reboot | default(false) | bool)) 29 | systemd: 30 | daemon_reload: true 31 | state: restarted 32 | enabled: true 33 | name: "{{node_service_name}}" 34 | tags: 35 | - chain_start 36 | - chain_restart 37 | 38 | - name: Enable cosmovisor systemd service 39 | when: chain_start and use_cosmovisor 40 | systemd: 41 | daemon_reload: true 42 | state: stopped 43 | enabled: true 44 | name: "{{cosmovisor_service_name}}" 45 | 46 | - name: Start cosmovisor systemd service 47 | when: chain_start and ((use_cosmovisor) and (not reboot | default(false) | bool)) 48 | systemd: 49 | daemon_reload: true 50 | state: restarted 51 | enabled: true 52 | name: "{{cosmovisor_service_name}}" 53 | tags: 54 | - chain_start 55 | - chain_restart 56 | -------------------------------------------------------------------------------- /roles/provision-digitalocean/tasks/main.yml: -------------------------------------------------------------------------------- 1 | --- 2 | - name: Create a new Droplet 3 | community.digitalocean.digital_ocean_droplet: 4 | state: present 5 | oauth_token: "{{ digitalocean_api_key }}" 6 | name: "{{ digitalocean_hostname }}" 7 | unique_name: true 8 | size: "{{ digitalocean_size }}" 9 | region: "{{ digitalocean_region }}" 10 | image: "{{ digitalocean_image }}" 11 | ipv6: true 12 | wait_timeout: 500 13 | project_name: "{{ digitalocean_project }}" 14 | ssh_keys: "{{ digitalocean_ssh_keys }}" 15 | register: droplet_info 16 | 17 | - name: Show Droplet info 18 | debug: 19 | msg: | 20 | Droplet ID is {{ droplet_info.data.droplet.id }} 21 | First Public IPv6 is {{ (droplet_info.data.droplet.networks.v6 | selectattr('type', 'equalto', 'public')).0.ip_address }} 22 | First Public IPv4 is {{ (droplet_info.data.droplet.networks.v4 | selectattr('type', 'equalto', 'public')).0.ip_address }} 23 | First Private IPv4 is {{ (droplet_info.data.droplet.networks.v4 | selectattr('type', 'equalto', 'private')).0.ip_address }} 24 | 25 | - name: Error VM already exists 26 | fail: msg="The host {{ digitalocean_hostname }} already exists." 27 | when: droplet_info.changed == false 28 | 29 | - name: Store IPv6 address 30 | set_fact: 31 | droplet_ipv6: "{{ (droplet_info.data.droplet.networks.v6 | selectattr('type', 'equalto', 'public')).0.ip_address }}" 32 | 33 | - name: Store IPv4 address 34 | set_fact: 35 | droplet_ipv4: "{{ (droplet_info.data.droplet.networks.v4 | selectattr('type', 'equalto', 'public')).0.ip_address }}" 36 | 37 | - name: Store droplet_id 38 | set_fact: 39 | droplet_id: "{{ droplet_info.data.droplet.id }}" 40 | -------------------------------------------------------------------------------- /.github/workflows/test-theta-node.yml: -------------------------------------------------------------------------------- 1 | --- 2 | 3 | name: Join Public Testnet 4 | on: 5 | workflow_dispatch: 6 | schedule: 7 | # At 15:30 on Monday. 8 | - cron: '30 15 * * 1' 9 | pull_request: 10 | types: 11 | - opened 12 | - closed 13 | jobs: 14 | test-public-testnet: 15 | runs-on: ubuntu-22.04 16 | steps: 17 | - name: Check out repository code 18 | uses: actions/checkout@v3 19 | - name: Set up Python 20 | uses: actions/setup-python@v3 21 | with: 22 | python-version: '3.10' 23 | - name: Install dependencies 24 | run: | 25 | python -m pip install --upgrade pip 26 | python -m pip install ansible toml 27 | - name: Configure ansible.cfg 28 | run: echo "transport = local" >> ansible.cfg 29 | - name: Install ansible-galaxy requirements 30 | run: ansible-galaxy install -r requirements.yml 31 | - name: Run playbook 32 | run: | 33 | chain_version=$(curl -s https://rpc.state-sync-01.theta-testnet.polypore.xyz/abci_info? | jq -r '.result.response.version') 34 | ansible-playbook node.yml -i examples/inventory-public-testnet.yml --extra-vars "target=local reboot=false chain_version=$chain_version chain_home={{ node_user_home }}/.gaia node_user=runner enable_swap=true swap_size=16384 cosmovisor_invariants_flag=''" 35 | - name: Check cosmovisor service 36 | run: systemctl status cosmovisor 37 | - name: Check blocks are being produced 38 | run: | 39 | height=$(curl -s http://rpc.state-sync-01.theta-testnet.polypore.xyz:26657/block | jq -r '.result.block.header.height') 40 | echo "Waiting for block $[ $height + 100 ]..." 41 | tests/test_block_production.sh 127.0.0.1 26657 $[ $height + 100] 42 | -------------------------------------------------------------------------------- /roles/consensus-monitor/tasks/base.yml: -------------------------------------------------------------------------------- 1 | --- 2 | - name: Populate service facts 3 | service_facts: 4 | 5 | - include_role: 6 | name: common 7 | 8 | # Set up nginx 9 | - name: Change vars for TLS 10 | when: consensus_setup_nginx and consensus_use_tls_proxy 11 | set_fact: 12 | ssl_provider: "letsencrypt" 13 | 14 | - include_role: 15 | name: hypha.common.nginx 16 | when: consensus_setup_nginx 17 | 18 | - include_role: 19 | name: hypha.common.ssl 20 | when: consensus_setup_nginx and consensus_use_tls_proxy 21 | 22 | - name: Restart nginx to apply new config 23 | systemd: 24 | state: restarted 25 | name: nginx 26 | when: consensus_setup_nginx 27 | 28 | - name: Stop existing Websockets service 29 | when: > 30 | (consensus_ws_service_name in ansible_facts.services) or 31 | ((consensus_ws_service_name + '.service') in ansible_facts.services) 32 | systemd: 33 | state: stopped 34 | name: "{{consensus_ws_service_name}}" 35 | tags: 36 | - consensus_stop 37 | - consensus_restart 38 | ignore_errors: true 39 | 40 | - name: Stop existing UI service 41 | when: > 42 | (consensus_ui_service_name in ansible_facts.services) or 43 | ((consensus_ui_service_name + '.service') in ansible_facts.services) 44 | systemd: 45 | state: stopped 46 | name: "{{consensus_ui_service_name}}" 47 | tags: 48 | - consensus_stop 49 | - consensus_restart 50 | ignore_errors: true 51 | 52 | - name: Install python 53 | apt: 54 | pkg: 55 | - python3 56 | - python3-venv 57 | - python3-pip 58 | - python-is-python3 59 | 60 | - name: Create consensus user 61 | user: 62 | name: "{{ consensus_user }}" 63 | append: true 64 | groups: adm 65 | shell: /bin/bash 66 | comment: User for consensus monitor services 67 | -------------------------------------------------------------------------------- /roles/node/tasks/apis.yml: -------------------------------------------------------------------------------- 1 | --- 2 | - name: Set variables for api endpoint 3 | set_fact: 4 | proxy_location: 'http://127.0.0.1:{{api_port}}' 5 | site_hostname: '{{chain_api_host}}.{{inventory_hostname}}' 6 | websocket: false 7 | grpc_vhost: false 8 | when: chain_use_ssl_proxy | default(false) | bool 9 | 10 | - name: Setup nginx SSL for chain api endpoint 11 | include_role: 12 | name: nginx-ssl 13 | when: chain_use_ssl_proxy | default(false) | bool 14 | 15 | - name: Set variables for rpc endpoint 16 | set_fact: 17 | proxy_location: 'http://127.0.0.1:{{rpc_port}}' 18 | site_hostname: '{{chain_rpc_host}}.{{inventory_hostname}}' 19 | websocket: true 20 | websocket_path: '/websocket' 21 | grpc_vhost: false 22 | when: chain_use_ssl_proxy | default(false) | bool 23 | 24 | - name: Setup nginx SSL for chain rpc endpoint 25 | include_role: 26 | name: nginx-ssl 27 | when: chain_use_ssl_proxy | default(false) | bool 28 | 29 | - name: Set variables for GRPC endpoint 30 | set_fact: 31 | proxy_location: 'grpc://127.0.0.1:{{grpc_port}}' 32 | site_hostname: '{{chain_grpc_host}}.{{inventory_hostname}}' 33 | websocket: false 34 | grpc_vhost: true 35 | when: chain_use_ssl_proxy | default(false) | bool 36 | 37 | - name: Setup nginx SSL for chain GRPC endpoint 38 | include_role: 39 | name: nginx-ssl 40 | when: chain_use_ssl_proxy | default(false) | bool 41 | 42 | - name: Set variables for P2P endpoint 43 | set_fact: 44 | proxy_location: 'http://127.0.0.1:{{p2p_port}}' 45 | site_hostname: '{{chain_p2p_host}}.{{inventory_hostname}}' 46 | grpc_vhost: false 47 | websocket: false 48 | when: chain_use_ssl_proxy | default(false) | bool 49 | 50 | - name: Setup nginx SSL for chain P2P endpoint 51 | include_role: 52 | name: nginx-ssl 53 | when: chain_use_ssl_proxy | default(false) | bool 54 | -------------------------------------------------------------------------------- /roles/bigdipper/tasks/bdui.yml: -------------------------------------------------------------------------------- 1 | --- 2 | 3 | - name: "Clone and checkout big-dipper-ui" 4 | become_user: "{{bigdipper_user}}" 5 | git: 6 | repo: 'https://github.com/forbole/big-dipper-2.0-cosmos.git' 7 | dest: "{{bdui_dir}}" 8 | version: "{{bdui_version}}" 9 | force: yes 10 | 11 | - name: Install deps for big-dipper-ui 12 | become_user: "{{bigdipper_user}}" 13 | shell: | 14 | cd "{{bdui_dir}}" 15 | npm ci 16 | 17 | - name: "General config for big-dipper-ui" 18 | become_user: "{{bigdipper_user}}" 19 | template: 20 | src: bigdipper-general_config.json.j2 21 | dest: "{{bdui_dir}}/src/configs/general_config.json" 22 | 23 | - name: "Chain config for big-dipper-ui" 24 | become_user: "{{bigdipper_user}}" 25 | template: 26 | src: bigdipper-chain_config.json.j2 27 | dest: "{{bdui_dir}}/src/configs/chain_config.{{bdui_chain}}.json" 28 | 29 | - name: "codegen.yml config for big-dipper-ui" 30 | become_user: "{{bigdipper_user}}" 31 | template: 32 | src: bigdipper-codegen.yml.j2 33 | dest: "{{bdui_dir}}/codegen.yml" 34 | 35 | - name: Check Hasura is in sync with our graphql operations 36 | become_user: "{{bigdipper_user}}" 37 | shell: | 38 | cd "{{bdui_dir}}" 39 | npm run graphql:codegen 40 | 41 | - name: Install .env for big-dipper-ui 42 | become_user: "{{bigdipper_user}}" 43 | template: 44 | src: bigdipper.env.j2 45 | dest: "{{bdui_dir}}/.env" 46 | 47 | - name: Build big-dipper-ui 48 | become_user: "{{bigdipper_user}}" 49 | shell: | 50 | cd "{{bdui_dir}}" 51 | npm run build 52 | 53 | - name: "Create systemd service for big-dipper-ui" 54 | template: 55 | src: bigdipper.service.j2 56 | dest: "/etc/systemd/system/{{bdui_service_name}}.service" 57 | 58 | - name: "Run big-dipper-ui" 59 | systemd: 60 | daemon_reload: true 61 | state: restarted 62 | enabled: true 63 | name: "{{bdui_service_name}}" 64 | -------------------------------------------------------------------------------- /roles/hermes/templates/config.toml.j2: -------------------------------------------------------------------------------- 1 | [global] 2 | log_level = 'info' 3 | 4 | [mode] 5 | 6 | [mode.clients] 7 | enabled = {{ mode_clients }} 8 | refresh = {{ mode_clients_refresh }} 9 | misbehaviour = {{ mode_clients_misbehaviour }} 10 | 11 | [mode.connections] 12 | enabled = {{ mode_connections}} 13 | 14 | [mode.channels] 15 | enabled = {{ mode_channels}} 16 | 17 | [mode.packets] 18 | enabled = {{ mode_packets}} 19 | clear_interval = {{ mode_packets_clear_interval }} 20 | clear_on_start = {{ mode_packets_clear_on_start }} 21 | tx_confirmation = {{ mode_packets_tx_confirmation }} 22 | 23 | [rest] 24 | enabled = {{ hermes_rest_api }} 25 | host = '{{ hermes_rest_api_bindhost }}' 26 | port = {{ hermes_rest_api_port }} 27 | 28 | [telemetry] 29 | enabled = {{ hermes_telemetry }} 30 | host = '{{ hermes_telemetry_bindhost }}' 31 | port = {{ hermes_telemetry_port }} 32 | 33 | {% for id, chaindata in hermes_chains.items() %} 34 | [[chains]] 35 | id = '{{ id }}' 36 | rpc_addr = '{{ chaindata.hermes_chain_rpc_url_schema }}://{{ chaindata.hermes_chain_rpc_hostname }}:{{ chaindata.hermes_chain_rpc_port }}' 37 | grpc_addr = '{{ chaindata.hermes_chain_grpc_url_schema }}://{{ chaindata.hermes_chain_grpc_hostname }}:{{ chaindata.hermes_chain_grpc_port }}' 38 | websocket_addr = '{{ chaindata.hermes_chain_websocket_url_schema }}://{{ chaindata.hermes_chain_rpc_hostname }}:{{ chaindata.hermes_chain_rpc_port }}/websocket' 39 | rpc_timeout = '{{ chaindata.hermes_chain_rpc_timeout }}' 40 | account_prefix = '{{ chaindata.hermes_chain_account_prefix }}' 41 | key_name = '{{ chaindata.hermes_chain_key_name }}' 42 | store_prefix = '{{ chaindata.hermes_chain_store_prefix }}' 43 | max_gas = {{ chaindata.hermes_chain_max_gas }} 44 | fee_granter = '{{ chaindata.hermes_chain_fee_granter }}' 45 | gas_price = {{ chaindata.gas_price }} 46 | gas_multiplier = {{ chaindata.hermes_chain_gas_multiplier }} 47 | clock_drift = '{{ chaindata.hermes_chain_clock_drift }}' 48 | trusting_period = '{{ chaindata.hermes_chain_trusting_period }}' 49 | trust_threshold = {{ chaindata.hermes_chain_trust_threshold }} 50 | 51 | {% endfor %} 52 | -------------------------------------------------------------------------------- /.github/workflows/export-mainnet-genesis.yml: -------------------------------------------------------------------------------- 1 | --- 2 | name: Export mainnet genesis 3 | on: 4 | workflow_dispatch: 5 | schedule: 6 | # At 05:30 on day-of-month 1 and 15 7 | - cron: '30 5 1,15 * *' 8 | 9 | jobs: 10 | build: 11 | runs-on: ubuntu-22.04 12 | steps: 13 | # Get system info 14 | - run: ifconfig 15 | - run: arp -a 16 | - run: sudo dmidecode 17 | - run: df -h 18 | - run: free -m 19 | - run: uname -a 20 | - run: lsb_release -a 21 | - run: echo "GitHub branch is ${{ github.ref }}" 22 | - run: whoami 23 | - run: pwd 24 | 25 | - name: Set SSH key 26 | run: | 27 | if [ ! -d ~/.ssh ] 28 | then 29 | mkdir -m 700 ~/.ssh 30 | fi 31 | echo "${{ secrets.SSH_KEY }}" > ~/.ssh/id_rsa 32 | chmod 600 ~/.ssh/id_rsa 33 | 34 | - name: Install dependencies 35 | run: | 36 | python -m pip install --upgrade pip 37 | python -m pip install ansible toml 38 | 39 | - name: Checkout repo 40 | uses: actions/checkout@master 41 | 42 | - name: Install ansible-galaxy requirements 43 | run: ansible-galaxy install -r requirements.yml 44 | 45 | - name: Provision VM 46 | run: ansible-playbook gaia-mainnet-export.yml -i examples/inventory-exporting-genesis-do.yml --extra-vars "digitalocean_api_key=${{ secrets.DO_API_KEY }}" 47 | 48 | - name: Install Gaia and configure for mainnet 49 | run: ansible-playbook node.yml -i examples/inventory-cosmos-hub.yml --extra-vars "target=mainnet-export" 50 | 51 | - name: Copy export_genesis.sh to VM 52 | run: | 53 | scp /tmp/export_genesis.sh root@mainnet-export:/tmp/export_genesis.sh 54 | 55 | - name: Copy SSH key to VM 56 | run: | 57 | scp ~/.ssh/id_rsa root@mainnet-export:/root/.ssh/ 58 | 59 | - name: Run export_genesis.sh on VM in a screen session 60 | run: | 61 | ssh root@mainnet-export screen -L -Logfile /root/export_genesis.log -S export_genesis -d -m bash '/tmp/export_genesis.sh ${{ github.ref_name }}' 62 | -------------------------------------------------------------------------------- /roles/cascadia/templates/nginx-site.j2: -------------------------------------------------------------------------------- 1 | server { 2 | listen [::]:443 http2; 3 | listen 0.0.0.0:443 http2; 4 | 5 | server_name {{site_hostname}}; 6 | 7 | ssl on; 8 | server_tokens off; 9 | ssl_protocols TLSv1.2 TLSv1.3; 10 | ssl_prefer_server_ciphers on; 11 | ssl_session_timeout 5m; 12 | ssl_session_cache builtin:1000 shared:SSL:10m; 13 | add_header Strict-Transport-Security "max-age=63072000;" always; 14 | add_header X-Content-Type-Options nosniff; 15 | add_header X-Frame-Options DENY; 16 | add_header Access-Control-Allow-Origin *; 17 | add_header Access-Control-Allow-Headers *; 18 | ssl_stapling on; 19 | ssl_stapling_verify on; 20 | ssl_trusted_certificate /etc/letsencrypt/live/{{site_hostname}}/fullchain.pem; 21 | ssl_ciphers 'ECDHE-RSA-AES256-GCM-SHA384:ECDHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384:DHE-RSA-AES128-GCM-SHA256:ECDHE-RSA-AES256-SHA384:ECDHE-RSA-AES128-SHA256:ECDHE-RSA-AES256-SHA:ECDHE-RSA-AES128-SHA:DHE-RSA-AES256-SHA256:DHE-RSA-AES128-SHA256:DHE-RSA-AES256-SHA:DHE-RSA-AES128-SHA:ECDHE-RSA-DES-CBC3-SHA:EDH-RSA-DES-CBC3-SHA:AES256-GCM-SHA384:AES128-GCM-SHA256:AES256-SHA256:AES128-SHA256:AES256-SHA:AES128-SHA:DES-CBC3-SHA:HIGH:!aNULL:!eNULL:!EXPORT:!CAMELLIA:!DES:!MD5:!PSK:!RC4:!3DES'; 22 | 23 | ### SSL cert files ### 24 | ssl_dhparam /etc/ssl/dhparam.pem; 25 | ssl_certificate /etc/letsencrypt/live/{{site_hostname}}/fullchain.pem; 26 | ssl_certificate_key /etc/letsencrypt/live/{{site_hostname}}/privkey.pem; 27 | 28 | ### Add SSL specific settings here ### 29 | keepalive_timeout 60; 30 | 31 | {% if grpc_vhost is defined %} 32 | location / { 33 | grpc_pass grpc://127.0.0.1:9090; 34 | proxy_redirect off; 35 | } 36 | {% else %} 37 | location / { 38 | proxy_pass {{proxy_location}}; 39 | proxy_redirect off; 40 | 41 | proxy_set_header Host $host; 42 | proxy_set_header X-Real-IP $remote_addr; 43 | proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; 44 | proxy_max_temp_file_size 0; 45 | proxy_buffering off; 46 | 47 | client_max_body_size 8192M; 48 | proxy_read_timeout 1200; 49 | } 50 | {% endif %} 51 | } 52 | -------------------------------------------------------------------------------- /roles/consensus-monitor/tasks/consensus.yml: -------------------------------------------------------------------------------- 1 | --- 2 | - name: Checkout cosmos-consensus-monitor repo 3 | git: 4 | repo: "{{ consensus_repo_url }}" 5 | dest: "{{ consensus_repo_path }}" 6 | version: "{{ consensus_monitor_version }}" 7 | force: yes 8 | become_user: "{{ consensus_user }}" 9 | 10 | - name: Set up python virtual environment 11 | shell: | 12 | cd {{ consensus_repo_path }} 13 | python -m venv .env 14 | become_user: "{{ consensus_user }}" 15 | 16 | - name: Install consensus dependencies 17 | pip: 18 | requirements: "{{ consensus_repo_path }}/requirements.txt" 19 | virtualenv: "{{ consensus_repo_path }}/.env" 20 | become_user: "{{ consensus_user }}" 21 | 22 | - name: Configure Websockets endpoint in client Javascript 23 | replace: 24 | path: "{{ consensus_repo_path }}/client/js/consensus.js" 25 | regexp: '":" \+ \"9001\" \+ \"/\"' 26 | replace: '"/ws/"' 27 | become_user: "{{ consensus_user }}" 28 | 29 | - name: Configure Websockets service 30 | template: 31 | src: consensus-monitor-ws.service.j2 32 | dest: "/etc/systemd/system/{{ consensus_ws_service_name }}.service" 33 | 34 | - name: Configure UI service 35 | template: 36 | src: consensus-monitor-ui.service.j2 37 | dest: "/etc/systemd/system/{{ consensus_ui_service_name }}.service" 38 | 39 | - name: Enable Websockets service 40 | systemd: 41 | daemon_reload: true 42 | state: stopped 43 | enabled: true 44 | name: "{{ consensus_ws_service_name }}" 45 | 46 | - name: Start Websockets service 47 | systemd: 48 | daemon_reload: true 49 | state: started 50 | enabled: true 51 | name: "{{ consensus_ws_service_name }}" 52 | tags: 53 | - consensus_start 54 | - consensus_restart 55 | 56 | - name: Enable UI service 57 | systemd: 58 | daemon_reload: true 59 | state: stopped 60 | enabled: true 61 | name: "{{ consensus_ui_service_name }}" 62 | 63 | - name: Start UI service 64 | systemd: 65 | daemon_reload: true 66 | state: started 67 | enabled: true 68 | name: "{{ consensus_ui_service_name }}" 69 | tags: 70 | - consensus_start 71 | - consensus_restart 72 | -------------------------------------------------------------------------------- /roles/node/files/copy_config_vars.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | """ 4 | This script takes a JSON config file and patches `.toml` files with its values 5 | """ 6 | 7 | import argparse 8 | import json 9 | import toml 10 | 11 | parser = argparse.ArgumentParser( 12 | description="Patch chain config files") 13 | 14 | parser.add_argument('--chain_home') 15 | parser.add_argument('--config_file') 16 | 17 | args = vars(parser.parse_args()) 18 | 19 | chain_home = args["chain_home"] 20 | config_file = args["config_file"] 21 | 22 | 23 | def update_config_files(source_config, destination_folder): 24 | """ 25 | Loads the config JSON file and updates the config files it references 26 | """ 27 | with open(source_config, "r", encoding="utf8") as file: 28 | config = json.load(file) 29 | for file_name, var_map in config.items(): 30 | file_path = destination_folder + "/config/" + file_name 31 | update_config(file_path, var_map) 32 | 33 | 34 | def update_config(file_path, var_map): 35 | """ 36 | Injects variables into a TOML config file from a map of definitions 37 | The keys in the map are a path within the config file 38 | The values are the value to set it to 39 | """ 40 | config = {} 41 | with open(file_path, "r", encoding="utf8") as file: 42 | config = toml.load(file) 43 | 44 | for config_path, config_value in var_map.items(): 45 | if config_value == "": 46 | continue 47 | set_nested(config, config_path, config_value) 48 | 49 | with open(file_path, "w", encoding="utf8") as file: 50 | toml.dump(config, file) 51 | 52 | 53 | def set_nested(nested_dict, path, value): 54 | """ 55 | Sets a value that's deeply nested within a dict 56 | """ 57 | 58 | segments = path.split('.') 59 | final_field = segments.pop() 60 | current_val = nested_dict 61 | for subpath in segments: 62 | if subpath in current_val: 63 | current_val = current_val[subpath] 64 | else: 65 | current_val[subpath] = {} 66 | current_val = current_val[subpath] 67 | current_val[final_field] = value 68 | 69 | 70 | update_config_files(config_file, chain_home) 71 | -------------------------------------------------------------------------------- /roles/cascadia/files/copy_config_vars.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | """ 4 | This script takes a JSON config file and patches `.toml` files with its values 5 | """ 6 | 7 | import argparse 8 | import json 9 | import toml 10 | 11 | parser = argparse.ArgumentParser( 12 | description="Patch gaiad config files") 13 | 14 | parser.add_argument('--gaiad_home') 15 | parser.add_argument('--config_file') 16 | 17 | args = vars(parser.parse_args()) 18 | 19 | gaiad_home = args["gaiad_home"] 20 | config_file = args["config_file"] 21 | 22 | 23 | def update_config_files(source_config, destination_folder): 24 | """ 25 | Loads the config JSON file and updates the config files it references 26 | """ 27 | with open(source_config, "r", encoding="utf8") as file: 28 | config = json.load(file) 29 | for file_name, var_map in config.items(): 30 | file_path = destination_folder + "/config/" + file_name 31 | update_config(file_path, var_map) 32 | 33 | 34 | def update_config(file_path, var_map): 35 | """ 36 | Injects variables into a TOML config file from a map of definitions 37 | The keys in the map are a path within the config file 38 | The values are the value to set it to 39 | """ 40 | config = {} 41 | with open(file_path, "r", encoding="utf8") as file: 42 | config = toml.load(file) 43 | 44 | for config_path, config_value in var_map.items(): 45 | if config_value == "": 46 | continue 47 | set_nested(config, config_path, config_value) 48 | 49 | with open(file_path, "w", encoding="utf8") as file: 50 | toml.dump(config, file) 51 | 52 | 53 | def set_nested(nested_dict, path, value): 54 | """ 55 | Sets a value that's deeply nested within a dict 56 | """ 57 | 58 | segments = path.split('.') 59 | final_field = segments.pop() 60 | current_val = nested_dict 61 | for subpath in segments: 62 | if subpath in current_val: 63 | current_val = current_val[subpath] 64 | else: 65 | current_val[subpath] = {} 66 | current_val = current_val[subpath] 67 | current_val[final_field] = value 68 | 69 | 70 | update_config_files(config_file, gaiad_home) 71 | -------------------------------------------------------------------------------- /roles/cascadia/tasks/faucet.yml: -------------------------------------------------------------------------------- 1 | --- 2 | - name: create faucet account 3 | shell: | 4 | PATH=$PATH:/usr/local/go/bin:$HOME/go/bin 5 | gaiad keys add faucet --home {{gaiad_home}} --keyring-backend {{gaiad_validator_keyring}} --output json 6 | gaiad add-genesis-account faucet 1000000000000{{ gaiad_bond_denom }} --home {{gaiad_home}} --keyring-backend="{{gaiad_validator_keyring}}" 7 | register: create_faucet_output 8 | become_user: "{{gaiad_user}}" 9 | 10 | - name: save faucet name, address, and mnemonic 11 | copy: 12 | content: "{{create_faucet_output.stderr}}" 13 | dest: "{{gaiad_home}}/faucet.json" 14 | become_user: "{{gaiad_user}}" 15 | 16 | - name: checkout rest faucet repo 17 | git: 18 | repo: 'https://github.com/hyphacoop/cosmos-rest-faucet.git' 19 | dest: "{{gaiad_user_home}}/cosmos-rest-faucet" 20 | version: "{{faucet_version}}" 21 | force: yes 22 | become_user: "{{gaiad_user}}" 23 | 24 | - name: install python for faucet 25 | apt: 26 | pkg: 27 | - python3 28 | - python3-venv 29 | - python3-pip 30 | - python-is-python3 31 | 32 | - name: set up python virtual environment 33 | shell: | 34 | cd {{gaiad_user_home}}/cosmos-rest-faucet 35 | python -m venv .env 36 | become_user: "{{gaiad_user}}" 37 | 38 | - name: install faucet dependencies 39 | pip: 40 | requirements: "{{gaiad_user_home}}/cosmos-rest-faucet/requirements.txt" 41 | virtualenv: "{{gaiad_user_home}}/cosmos-rest-faucet/.env" 42 | become_user: "{{gaiad_user}}" 43 | 44 | - name: set faucet address 45 | shell: | 46 | jq '.address' {{gaiad_home}}/faucet.json 47 | register: faucet_address 48 | become_user: "{{gaiad_user}}" 49 | 50 | - name: configure faucet 51 | template: 52 | src: faucet_config.toml.j2 53 | dest: "{{gaiad_user_home}}/cosmos-rest-faucet/config.toml" 54 | 55 | - name: configure faucet service 56 | template: 57 | src: faucet.service.j2 58 | dest: "/etc/systemd/system/{{faucet_service_name}}.service" 59 | 60 | - name: Start faucet service 61 | systemd: 62 | daemon_reload: true 63 | state: restarted 64 | enabled: true 65 | name: "{{faucet_service_name}}" 66 | tags: 67 | - gaiad_start 68 | - gaiad_restart 69 | -------------------------------------------------------------------------------- /roles/node-exporter/tasks/main.yml: -------------------------------------------------------------------------------- 1 | --- 2 | - name: Create node_exporter group 3 | group: 4 | name: node_exporter 5 | system: yes 6 | state: present 7 | 8 | - name: Create node_exporter user 9 | user: 10 | name: node_exporter 11 | group: node_exporter 12 | append: no 13 | shell: /bin/bash 14 | system: yes 15 | state: present 16 | 17 | - name: Get latest release URL 18 | github_release: 19 | user: prometheus 20 | repo: node_exporter 21 | action: latest_release 22 | register: node_exporter_latest 23 | 24 | - name: Download Node Exporter 25 | unarchive: 26 | src: https://github.com/prometheus/node_exporter/releases/download/{{ node_exporter_latest['tag'] }}/node_exporter-{{ node_exporter_latest['tag'] | regex_replace('^v','') }}.linux-amd64.tar.gz 27 | dest: /opt/ 28 | remote_src: yes 29 | 30 | - name: Create link to Node Exporter version 31 | file: 32 | src: /opt/node_exporter-{{ node_exporter_latest['tag'] | regex_replace('^v','') }}.linux-amd64 33 | dest: /opt/node_exporter 34 | state: link 35 | 36 | - name: Create directory /opt/node_exporter/textfiles 37 | file: 38 | path: /opt/node_exporter/textfiles/ 39 | state: directory 40 | mode: '0700' 41 | owner: node_exporter 42 | group: node_exporter 43 | 44 | - name: Chown /opt/node_exporter to node_exporter 45 | file: 46 | path: /opt/node_exporter 47 | state: directory 48 | owner: node_exporter 49 | group: node_exporter 50 | mode: '0700' 51 | recurse: yes 52 | 53 | - name: Install crontab for monitoring .gaia 54 | cron: 55 | name: monitoring-gaia-disksize 56 | job: echo SIZE_FOLDER_GAIA{src=\"{{chain_home}}\"} $(du --max-depth=1 {{chain_home}} | tail -n 1 | awk '{print $1}') > /opt/node_exporter/textfiles/SIZE_FOLDER_GAIA.prom 57 | minute: "*/1" 58 | user: root 59 | 60 | - name: Install node_exporter systemd service 61 | template: 62 | src: node_exporter.service.j2 63 | dest: /etc/systemd/system/node_exporter.service 64 | mode: 0644 65 | 66 | - name: Reload systemd daemon 67 | systemd: 68 | daemon_reload: yes 69 | 70 | - name: Enable and start node_exporter service 71 | systemd: 72 | name: node_exporter 73 | enabled: yes 74 | state: started 75 | -------------------------------------------------------------------------------- /examples/inventory-three-node-scratch.yml: -------------------------------------------------------------------------------- 1 | --- 2 | # yamllint disable rule:line-length 3 | all: 4 | vars: 5 | ansible_user: ubuntu 6 | chain_version: v0.1.1 7 | chain_id: cascadia_9000-1 8 | minimum_gas_prices: '0.001uCC' 9 | chain_home_clear: true 10 | chain_api_host: "rest" 11 | chain_rpc_host: "rpc" 12 | chain_p2p_host: "p2p" 13 | chain_grpc_host: "grpc" 14 | swap_size: 8192 15 | genesis_node: validator1 16 | validators: [validator1, validator2] 17 | sentries: [sentry1, sentry2] 18 | dynamic_p2p_persistent_peers: true 19 | bonded_tokens_pool: 100000000000000000000000000 20 | bonded_supply_divider: 2 21 | git_token: "" 22 | children: 23 | node: 24 | hosts: 25 | validator1: 26 | chain_create_validator: true 27 | validator_moniker: validator-40 28 | voting_power: 40 29 | chain_gentx_validator: "{{ (bonded_tokens_pool|int * voting_power|int / 100)|int }}" 30 | chain_validator_coins: "{{ (bonded_supply_divider * chain_gentx_validator|int | int +chain_gentx_validator|int)|int }}" 31 | p2p_pex: false 32 | p2p_addr_book_strict: false 33 | validator2: 34 | validator_moniker: validator-32 35 | start_multinode: true 36 | voting_power: 60 37 | chain_gentx_validator: "{{ (bonded_tokens_pool|int * voting_power|int / 100)|int }}" 38 | chain_validator_coins: "{{ (bonded_supply_divider * chain_gentx_validator|int | int +chain_gentx_validator|int)|int }}" 39 | p2p_pex: false 40 | p2p_addr_book_strict: false 41 | # validator2: 42 | # validator_moniker: validator-28 43 | # start_multinode: true 44 | # voting_power: 28 45 | # chain_gentx_validator: "{{ (bonded_tokens_pool|int * voting_power|int / 100)|int }}" 46 | # chain_validator_coins: "{{ (bonded_supply_divider * chain_gentx_validator|int | int +chain_gentx_validator|int)|int }}" 47 | sentry1: 48 | api_enabled: true 49 | api_enabled_unsafe_cors: true 50 | sync_multinode_genesis: true 51 | sentry2: 52 | api_enabled: true 53 | api_enabled_unsafe_cors: true 54 | sync_multinode_genesis: true 55 | -------------------------------------------------------------------------------- /roles/bigdipper/templates/bdjuno-config.yaml.j2: -------------------------------------------------------------------------------- 1 | chain: 2 | bech32_prefix: cascadia 3 | modules: 4 | - actions 5 | - modules 6 | - messages 7 | - auth 8 | - bank 9 | - consensus 10 | - gov 11 | - slashing 12 | - staking 13 | - distribution 14 | - inflation 15 | node: 16 | type: remote 17 | config: 18 | rpc: 19 | client_name: {{ bdjuno_client_name }} 20 | address: {{ bdjuno_rpc_address }} 21 | max_connections: 20 22 | grpc: 23 | address: {{ bdjuno_grpc_address }} 24 | insecure: true 25 | parsing: 26 | workers: {{ bdjuno_workers }} 27 | listen_new_blocks: {{ bdjuno_listen_new_blocks | to_json }} 28 | parse_old_blocks: {{ bdjuno_parse_new_blocks | to_json }} 29 | parse_genesis: {{ bdjuno_parse_genesis | to_json }} 30 | start_height: {{ bigdipper_genesis_height }} 31 | fast_sync: {{ bdjuno_fast_sync | to_json }} 32 | genesis_file_path: {{bdjuno_home}}/genesis.json 33 | average_block_time: {{ bdjuno_avg_block_time }} 34 | database: 35 | name: {{bigdipper_db}} 36 | host: 127.0.0.1 37 | port: 5432 38 | user: {{bigdipper_db_user}} 39 | password: {{bigdipper_db_password}} 40 | schema: public 41 | max_open_connections: 10 42 | max_idle_connections: 10 43 | partition_size: 100000 44 | partition_batch: 1000 45 | logging: 46 | level: debug 47 | format: text 48 | telemetry: 49 | port: {{bigdipper_telemetry_port}} 50 | pricefeed: 51 | tokens: 52 | - name: Cascadia 53 | units: 54 | - denom: uCC 55 | exponent: 0 56 | - denom: CC 57 | exponent: 18 58 | price_id: cascadia 59 | - name: Rho 60 | units: 61 | - denom: rho 62 | exponent: 0 63 | - name: Lambda 64 | units: 65 | - denom: lambda 66 | exponent: 0 67 | - name: Epsilon 68 | units: 69 | - denom: epsilon 70 | exponent: 0 71 | - name: Theta 72 | units: 73 | - denom: theta 74 | exponent: 0 75 | actions: 76 | port: {{bdjuno_hasura_actions_port}} 77 | -------------------------------------------------------------------------------- /roles/bigdipper/tasks/base.yml: -------------------------------------------------------------------------------- 1 | --- 2 | 3 | - include_role: 4 | name: common 5 | 6 | # Set up nginx 7 | 8 | # - name: Change vars for TLS 9 | # when: bigdipper_use_tls_proxy 10 | # set_fact: 11 | # bigdipper_web_scheme: https 12 | # bigdipper_websocket_scheme: wss 13 | # ssl_provider: "letsencrypt" 14 | 15 | # - include_role: 16 | # name: hypha.common.nginx 17 | 18 | # - include_role: 19 | # name: hypha.common.ssl 20 | 21 | # - name: Restart nginx to apply new config 22 | # systemd: 23 | # state: restarted 24 | # name: nginx 25 | 26 | # Set up big dipper 27 | - name: "Install python dependencies" 28 | pip: 29 | name: psycopg2-binary 30 | 31 | # - include_role: 32 | # name: docker 33 | 34 | - name: Remove golang apt package 35 | ansible.builtin.apt: 36 | name: golang 37 | state: absent 38 | 39 | - name: Remove system Go files 40 | file: 41 | state: absent 42 | path: "{{ item }}" 43 | loop: 44 | - /usr/bin/go 45 | - /usr/lib/go 46 | 47 | - name: Check golang version 48 | shell: | 49 | PATH=$PATH:/usr/local/go/bin:$HOME/go/bin 50 | go version 51 | register: go_current_version 52 | ignore_errors: true 53 | 54 | - name: Extract golang 55 | when: not go_version in go_current_version.stdout 56 | unarchive: 57 | src: "https://golang.org/dl/go{{go_version}}.{{go_arch}}.tar.gz" 58 | dest: /usr/local 59 | remote_src: yes 60 | become: true 61 | 62 | - name: Ensure user exists for bigdipper 63 | user: 64 | name: "{{bigdipper_user}}" 65 | append: true 66 | groups: adm 67 | shell: /bin/bash 68 | comment: User for bigdipper block explorer services 69 | 70 | - name: "Register bigdipper db URL" 71 | set_fact: 72 | bigdipper_db_url: "postgres://{{bigdipper_db_user}}:{{bigdipper_db_password}}@127.0.0.1:5432/{{bigdipper_db}}" 73 | 74 | - name: Get the list of services 75 | service_facts: 76 | 77 | - name: "Stop bdjuno systemd service" 78 | systemd: 79 | state: stopped 80 | name: "{{bdjuno_service_name}}" 81 | when: "'{{bdjuno_service_name}}.service' in services" 82 | 83 | # - name: "Stop big-dipper-ui systemd service" 84 | # systemd: 85 | # state: stopped 86 | # name: "{{bdui_service_name}}" 87 | # when: "'{{bdui_service_name}}.service' in services" 88 | 89 | # - name: Remove hasura docker container 90 | # community.docker.docker_container: 91 | # name: big-dipper-hasura 92 | # state: absent 93 | -------------------------------------------------------------------------------- /roles/node/templates/nginx-site.j2: -------------------------------------------------------------------------------- 1 | server { 2 | listen [::]:443 http2; 3 | listen 0.0.0.0:443 http2; 4 | 5 | server_name {{site_hostname}}; 6 | 7 | ssl on; 8 | server_tokens off; 9 | ssl_protocols TLSv1.2 TLSv1.3; 10 | ssl_prefer_server_ciphers on; 11 | ssl_session_timeout 5m; 12 | ssl_session_cache builtin:1000 shared:SSL:10m; 13 | add_header Strict-Transport-Security "max-age=63072000;" always; 14 | add_header X-Content-Type-Options nosniff; 15 | add_header X-Frame-Options DENY; 16 | add_header Access-Control-Allow-Origin *; 17 | add_header Access-Control-Allow-Headers *; 18 | ssl_stapling on; 19 | ssl_stapling_verify on; 20 | ssl_trusted_certificate /etc/letsencrypt/live/{{site_hostname}}/fullchain.pem; 21 | ssl_ciphers 'ECDHE-RSA-AES256-GCM-SHA384:ECDHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384:DHE-RSA-AES128-GCM-SHA256:ECDHE-RSA-AES256-SHA384:ECDHE-RSA-AES128-SHA256:ECDHE-RSA-AES256-SHA:ECDHE-RSA-AES128-SHA:DHE-RSA-AES256-SHA256:DHE-RSA-AES128-SHA256:DHE-RSA-AES256-SHA:DHE-RSA-AES128-SHA:ECDHE-RSA-DES-CBC3-SHA:EDH-RSA-DES-CBC3-SHA:AES256-GCM-SHA384:AES128-GCM-SHA256:AES256-SHA256:AES128-SHA256:AES256-SHA:AES128-SHA:DES-CBC3-SHA:HIGH:!aNULL:!eNULL:!EXPORT:!CAMELLIA:!DES:!MD5:!PSK:!RC4:!3DES'; 22 | 23 | ### SSL cert files ### 24 | ssl_dhparam /etc/ssl/dhparam.pem; 25 | ssl_certificate /etc/letsencrypt/live/{{site_hostname}}/fullchain.pem; 26 | ssl_certificate_key /etc/letsencrypt/live/{{site_hostname}}/privkey.pem; 27 | 28 | ### Add SSL specific settings here ### 29 | keepalive_timeout 60; 30 | 31 | {% if grpc_vhost == true %} 32 | location / { 33 | grpc_pass {{proxy_location}}; 34 | proxy_redirect off; 35 | } 36 | {% else %} 37 | location / { 38 | proxy_pass {{proxy_location}}; 39 | proxy_redirect off; 40 | proxy_set_header Host $host; 41 | proxy_set_header X-Real-IP $remote_addr; 42 | proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; 43 | proxy_max_temp_file_size 0; 44 | proxy_buffering off; 45 | client_max_body_size 8192M; 46 | proxy_read_timeout 1200; 47 | } 48 | 49 | {% if websocket == true %} 50 | location {{ websocket_path }} { 51 | proxy_pass {{proxy_location}}; 52 | proxy_http_version 1.1; 53 | proxy_set_header Upgrade $http_upgrade; 54 | proxy_set_header Connection "Upgrade"; 55 | proxy_set_header Host $host; 56 | proxy_set_header X-Real-IP $remote_addr; 57 | proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; 58 | } 59 | {% endif %} 60 | {% endif %} 61 | 62 | } 63 | -------------------------------------------------------------------------------- /roles/hermes/tasks/base.yml: -------------------------------------------------------------------------------- 1 | --- 2 | - include_role: 3 | name: common 4 | 5 | - name: Create hermes user 6 | user: 7 | name: "{{ hermes_user }}" 8 | group: "{{ hermes_group }}" 9 | shell: /bin/bash 10 | append: no 11 | 12 | - name: chown hermes home directory 13 | file: 14 | path: /home/{{ hermes_user }} 15 | state: directory 16 | owner: "{{ hermes_user }}" 17 | group: "{{ hermes_group }}" 18 | mode: '0755' 19 | 20 | - name: Create ~/.hermes/bin directory 21 | file: 22 | path: /home/{{ hermes_user }}/.hermes/bin 23 | state: directory 24 | owner: "{{ hermes_user }}" 25 | group: "{{ hermes_group }}" 26 | mode: '0755' 27 | 28 | - name: Create ~/bin directory 29 | file: 30 | path: /home/{{ hermes_user }}/bin 31 | state: directory 32 | owner: "{{ hermes_user }}" 33 | group: "{{ hermes_group }}" 34 | mode: '0755' 35 | 36 | - name: Get latest hermes version 37 | when: hermes_version == 'latest' 38 | uri: 39 | url: https://api.github.com/repos/informalsystems/ibc-rs/releases/latest 40 | return_content: true 41 | register: json_reponse 42 | 43 | - name: Download and Extract latest hermes 44 | when: hermes_version == 'latest' 45 | unarchive: 46 | src: https://github.com/informalsystems/ibc-rs/releases/download/{{ json_reponse.json.tag_name }}/hermes-{{ json_reponse.json.tag_name }}-{{ binary_arch_map[ansible_architecture] }}.tar.gz 47 | dest: /home/{{ hermes_user }}/.hermes/bin/ 48 | remote_src: yes 49 | become_user: "{{ hermes_user }}" 50 | 51 | - name: Download and Extract hermes {{ hermes_version }} 52 | when: hermes_version != 'latest' 53 | unarchive: 54 | src: https://github.com/informalsystems/ibc-rs/releases/download/{{ hermes_version }}/hermes-{{ hermes_version }}-{{binary_arch_map[ansible_architecture]}}.tar.gz 55 | dest: /home/{{ hermes_user }}/.hermes/bin/ 56 | remote_src: yes 57 | become_user: "{{ hermes_user }}" 58 | 59 | - name: ln -s /home/{{ hermes_user }}/.hermes/bin/hermes /home/{{ hermes_user }}/bin/hermes 60 | ansible.builtin.file: 61 | src: /home/{{ hermes_user }}/.hermes/bin/hermes 62 | dest: /home/{{ hermes_user }}/bin/hermes 63 | owner: "{{ hermes_user }}" 64 | group: "{{ hermes_group }}" 65 | state: link 66 | 67 | - name: Add hermes bin from ~/bin to .bashrc PATH 68 | blockinfile: 69 | dest: '/home/{{ hermes_user }}/.bashrc' 70 | block: | 71 | export PATH="$PATH:/home/{{ hermes_user }}/bin" 72 | marker: '# {mark} ANSIBLE MANAGED BLOCK - HERMES PATH' 73 | insertbefore: EOF 74 | create: yes 75 | -------------------------------------------------------------------------------- /node_control.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | """ 4 | Ansible-backed node management operations: 5 | ./node-control.py [-i ] [-t target] 6 | -i is optional, it defaults to inventory.yml 7 | The target option is the server IP or domain 8 | Operations: 9 | restart: restarts the chain service 10 | stop: stops the chain service 11 | start: starts the chain service 12 | reset: resets the chain database 13 | reboot: reboots the host 14 | """ 15 | 16 | import sys 17 | import argparse 18 | import os 19 | 20 | parser = argparse.ArgumentParser(description='Single-command node management.') 21 | parser.add_argument('-i', metavar='inventory', help='inventory file (default: inventory.yml)', 22 | required=False, 23 | default='inventory.yml') 24 | parser.add_argument('-t', metavar='target', help='target server', 25 | required=False, 26 | default='') 27 | parser.add_argument('operation', help='the operation to perform') 28 | 29 | args = parser.parse_args() 30 | 31 | operation = args.operation 32 | inventory = args.i 33 | target = args.t 34 | 35 | if operation == "restart": 36 | print(os.popen("ansible-playbook node.yml -i " + 37 | inventory + " -e 'target=" + target + " reboot=false' --tags 'chain_restart'").read()) 38 | sys.exit(0) 39 | 40 | if operation == "stop": 41 | print(os.popen("ansible-playbook node.yml -i " + 42 | inventory + " -e 'target=" + target + "' --tags 'chain_stop'").read()) 43 | sys.exit(0) 44 | 45 | if operation == "start": 46 | print(os.popen("ansible-playbook node.yml -i " + 47 | inventory + " -e 'target=" + target + " reboot=false' --tags 'chain_start'").read()) 48 | sys.exit(0) 49 | 50 | if operation == "reset": 51 | answer = input( 52 | "This will reset chain database on all nodes in inventory. " 53 | "Are you sure you want to continue (yes/no)? ") 54 | if answer.lower() in ["yes"]: 55 | print(os.popen("ansible-playbook node.yml -i " + 56 | inventory + 57 | " --extra-vars 'node_unsafe_reset=true target=" + target + "' " 58 | " --tags 'chain_stop,chain_reset,chain_start'").read()) 59 | sys.exit(0) 60 | else: 61 | print("Aborting...") 62 | sys.exit(2) 63 | 64 | if operation == "reboot": 65 | print(os.popen("ansible-playbook node.yml -i " + inventory + 66 | " --extra-vars 'reboot=true target=" + target + "' --tags 'reboot'").read()) 67 | sys.exit(0) 68 | 69 | else: 70 | print("Invalid operation.") 71 | sys.exit(1) 72 | -------------------------------------------------------------------------------- /tests/test_tx_stateful.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # Test transactions with a stateful state. 4 | # This script assumes: 5 | # - Tinkered genesis with validator-40 for valdator key 6 | # - the bond denom is uatom 7 | # - the home folder is ~/.gaia 8 | 9 | check_code() 10 | { 11 | txhash=$1 12 | code=$(gaiad q tx $txhash -o json | jq '.code') 13 | if [ $code -eq 0 ] 14 | then 15 | return 0 16 | else 17 | return 1 18 | fi 19 | } 20 | 21 | # Add gaiad to PATH 22 | export PATH="$PATH:~/.gaia/cosmovisor/current/bin" 23 | 24 | # Recover validator self-delegation and operator addresses 25 | val_self_del=$(jq -r '.address' ~/.gaia/validator.json) 26 | val1=$(echo $(gaiad q staking delegations $val_self_del -o json) | jq -r '.delegation_responses[0].delegation.validator_address') 27 | echo "validator has self-delegation address $val_self_del." 28 | echo "validator has operator address $val1." 29 | 30 | # Create test account 31 | echo $(gaiad keys add test-account --keyring-backend test --output json 2>&1) > test_account.json 32 | test_account=$(jq -r '.address' ./test_account.json) 33 | echo "test-account has address $test_account." 34 | 35 | # Test tx send 36 | echo "Sending funds from validator to test account..." 37 | TXHASH=$(gaiad tx bank send $val_self_del $test_account 5000000000000uatom --from $val_self_del --keyring-backend test --fees 500uatom --chain-id local-testnet -y -o json | jq '.txhash' | tr -d '"') 38 | echo $TXHASH 39 | echo "Waiting for transaction to go on chain..." 40 | sleep 12 41 | check_code $TXHASH 42 | 43 | # Test delegation 44 | echo "Delgating funds from test account to validator..." 45 | # Delegate from test-account to validator 46 | TXHASH=$(gaiad tx staking delegate $val1 4000000000000uatom --from test-account --keyring-backend test --fees 500uatom --chain-id local-testnet -y -o json | jq '.txhash' | tr -d '"') 47 | echo "Waiting for transaction to go on chain..." 48 | sleep 12 49 | check_code $TXHASH 50 | 51 | # Test withdrawing rewards 52 | starting_balance=$(gaiad q bank balances $test_account -o json | jq -r '.balances[0].amount') 53 | balance_denom=$(gaiad q bank balances $test_account -o json | jq -r '.balances[0].denom') 54 | 55 | echo "Withdrawing rewards for test account..." 56 | TXHASH=$(gaiad tx distribution withdraw-all-rewards --from $test_account --keyring-backend test --fees 500uatom --chain-id local-testnet -y -o json | jq '.txhash' | tr -d '"') 57 | # Wait for rewards to accumulate 58 | echo "Waiting for transaction to go on chain..." 59 | sleep 30 60 | check_code $TXHASH 61 | 62 | # Check the test-account funds 63 | ending_balance=$(gaiad q bank balances $test_account -o json | jq -r '.balances[0].amount') 64 | delta=$[ $ending_balance - $starting_balance] 65 | if [ $delta -gt 0 ] 66 | then 67 | echo "$delta$balance_denom were withdrawn successfully." 68 | else 69 | echo "Rewards could not be withdrawn." 70 | exit 1 71 | fi 72 | -------------------------------------------------------------------------------- /docs/Hermes-Relayer-Setup.md: -------------------------------------------------------------------------------- 1 | # Hermes IBC Relayer Setup Guide 2 | 3 | This guide will assist you in setting up two chains connected through an IBC relayer. 4 | 5 | - It is recommended Debian 11 is used for all host machines. 6 | 7 | ## Overview 8 | 9 | We will use a scenario in which the hosts are set up in the `dev.testnet.com` domain. This is an example domain, you should replace it with your own. 10 | 11 | The hosts listed in the example [inventory file](/examples/inventory-hermes.yml) are: 12 | * Chain 1 host: `my-chain-1.dev.testnet.com` 13 | * Chain 2 host: `my-chain-2.dev.testnet.com` 14 | * Hermes relayer: `hermes.dev.testnet.com` 15 | 16 | Once the relayer is operational, you will be able to send messages between both chains using the `ibc transfer` command. 17 | 18 | See the [Hermes Guide](https://hermes.informal.systems/index.html) for additional information. 19 | 20 | ## Chains Settings 21 | 22 | * **Gaia version:** `v7.0.0` 23 | * **Chain IDs:** `my-chain-1` and `my-chain-2` 24 | * **Hermes version:** `v1.0.0` 25 | 26 | ## Workflow 27 | 28 | 1. Configure the inventory file. 29 | 2. Run the `hermes.yml` playbook. 30 | 3. Test the relayer. 31 | 32 | ## Prerequisites 33 | 34 | ### DNS 35 | 36 | - A/AAAA records must be set up for both chains and the relayer prior to running the playbook. 37 | 38 | ## Deployment 39 | 40 | ### Configure the Inventory File 41 | 42 | Make the following modifications to [inventory-hermes.yml](/examples/inventory-hermes.yml): 43 | - Replace the `dev.testnet.com` address with your own in the `hosts` variable. 44 | - Replace the chain IDs in the `hermes_chains` variable with the IDs of the chains being relayed to. 45 | - Replace the default mnemonic file paths in `hermes_relayer_mnemonic` for both chains. You can replace those with `hermes_relayer_key` and `hermes_relayer_mnemonics` with `hermes_relayer_keys` if you want to use key files instead. 46 | - Replace the hosts in the `hermes_chain_rpc_*` and `hermes_chain_grpc_*` variables with the endpoints that Hermes will connect to. 47 | - A key file in this case is the output from `gaiad keys add --output json`. 48 | 49 | ### Run the Playbook 50 | 51 | If the chains are already set up and you only want to install the relayer, you can comment or delete the `Set up chains` task in the `hermes.yml` play: 52 | ``` 53 | ansible-galaxy install -r requirements.yml 54 | ansible-playbook hermes.yml -i examples/inventory-hermes.yml 55 | ``` 56 | 57 | The channels that are created as part of the play will be saved under `/home/hermes/-.txt` for each chain in the `hermes` machine. 58 | 59 | ### Test the Relayer 60 | 61 | You can now send messages between `my-chain-1` and `my-chain-2` using the `gaiad tx ibc-transfer` command. In the example below, `hermes` created `channel-0`. 62 | ``` 63 | gaiad tx ibc-transfer transfer transfer channel-0 [cosmos address of receiver] 1000uatom --chain-id [chain we are sending from] --from [cosmos address of sender] --fees 500uatom --gas auto -y 64 | ``` 65 | -------------------------------------------------------------------------------- /tests/test_tx_fresh.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # Test transactions with a fresh state. 4 | # This script assumes: 5 | # - a faucet and validator have been created as part of the play 6 | # - the home folder is ~/.gaia 7 | 8 | check_code() 9 | { 10 | txhash=$1 11 | code=$(gaiad q tx $txhash -o json | jq '.code') 12 | if [ $code -eq 0 ] 13 | then 14 | return 0 15 | else 16 | return 1 17 | fi 18 | } 19 | 20 | # Add gaiad to PATH 21 | export PATH="$PATH:~/.gaia/cosmovisor/current/bin" 22 | 23 | # Get bond denom 24 | denom=$(echo $(gaiad q staking params -o json) | jq -r '.bond_denom') 25 | echo "Bond denom is $denom." 26 | 27 | # Recover faucet address 28 | faucet=$(jq -r '.address' ~/.gaia/faucet.json) 29 | echo "faucet has address $faucet." 30 | 31 | # Recover validator self-delegation and operator addresses 32 | val_self_del=$(jq -r '.address' ~/.gaia/validator.json) 33 | val1=$(echo $(gaiad q staking delegations $val_self_del -o json) | jq -r '.delegation_responses[0].delegation.validator_address') 34 | echo "validator has self-delegation address $val_self_del." 35 | echo "validator has operator address $val1." 36 | 37 | # Create test account 38 | echo $(gaiad keys add test-account --keyring-backend test --output json 2>&1) > test_account.json 39 | test_account=$(jq -r '.address' ./test_account.json) 40 | echo "test-account has address $test_account." 41 | 42 | # Test tx send 43 | echo "Sending funds from faucet to test account..." 44 | TXHASH=$(gaiad tx bank send $faucet $test_account 5000100$denom --from $faucet --keyring-backend test --fees 1$denom --chain-id my-testnet -y -o json | jq '.txhash' | tr -d '"') 45 | echo $TXHASH 46 | echo "Waiting for transaction to go on chain..." 47 | sleep 6 48 | check_code $TXHASH 49 | 50 | # Test delegation 51 | echo "Delegating funds from test account to validator..." 52 | # Delegate from test-account to validator 53 | TXHASH=$(gaiad tx staking delegate $val1 4000000$denom --from test-account --keyring-backend test --fees 1$denom --chain-id my-testnet -y -o json | jq '.txhash' | tr -d '"') 54 | echo "Waiting for transaction to go on chain..." 55 | sleep 12 56 | check_code $TXHASH 57 | 58 | # Test withdrawing rewards 59 | starting_balance=$(gaiad q bank balances $test_account -o json | jq -r '.balances[0].amount') 60 | balance_denom=$(gaiad q bank balances $test_account -o json | jq -r '.balances[0].denom') 61 | 62 | echo "Withdrawing rewards for test account..." 63 | TXHASH=$(gaiad tx distribution withdraw-all-rewards --from $test_account --keyring-backend test --fees 1$denom --chain-id my-testnet -y -o json | jq '.txhash' | tr -d '"') 64 | # Wait for rewards to accumulate 65 | echo "Waiting for transaction to go on chain..." 66 | sleep 6 67 | check_code $TXHASH 68 | 69 | # Check the test-account funds 70 | ending_balance=$(gaiad q bank balances $test_account -o json | jq -r '.balances[0].amount') 71 | delta=$[ $ending_balance - $starting_balance] 72 | if [ $delta -gt 0 ] 73 | then 74 | echo "$delta$balance_denom were withdrawn successfully." 75 | else 76 | echo "Rewards could not be withdrawn." 77 | exit 1 78 | fi 79 | -------------------------------------------------------------------------------- /examples/inventory-multi-node.yml: -------------------------------------------------------------------------------- 1 | --- 2 | # yamllint disable rule:line-length 3 | all: 4 | vars: 5 | ansible_user: root 6 | chain_version: v7.0.3 7 | chain_id: cosmos-testnet 8 | minimum_gas_prices: '0.001uatom' 9 | chain_home_clear: true 10 | chain_api_host: "rest" 11 | chain_rpc_host: "rpc" 12 | chain_p2p_host: "p2p" 13 | chain_grpc_host: "grpc" 14 | genesis_node: val1.cosmostest.network 15 | dynamic_p2p_persistent_peers: true 16 | bonded_tokens_pool: 100000000 17 | bonded_supply_divider: 10 18 | letsencrypt_email: "validator@cosmostest.network" 19 | enable_swap: true 20 | swap_size: 8192 21 | # Remove the next four lines if you are not setting up monitoring 22 | monitoring_prometheus: true 23 | grafana_ssh_url: root@monitor.cosmostest.network 24 | monitoring_panic: true 25 | panic_ssh_url: root@monitor.cosmostest.network 26 | 27 | children: 28 | node: 29 | hosts: 30 | val1.cosmostest.network: 31 | chain_create_validator: true 32 | validator_moniker: val1 33 | voting_power: 40 34 | chain_gentx_validator: "{{ (bonded_tokens_pool|int * voting_power|int / 100)|int }}" 35 | chain_validator_coins: "{{ (bonded_supply_divider * chain_gentx_validator|int | int +chain_gentx_validator|int)|int }}" 36 | # Remove the next line if you are not setting up PANIC 37 | panic_is_validator: 'yes' 38 | val2.cosmostest.network: 39 | validator_moniker: val2 40 | start_multinode: true 41 | voting_power: 32 42 | chain_gentx_validator: "{{ (bonded_tokens_pool|int * voting_power|int / 100)|int }}" 43 | chain_validator_coins: "{{ (bonded_supply_divider * chain_gentx_validator|int | int +chain_gentx_validator|int)|int }}" 44 | # Remove the next line if you are not setting up PANIC 45 | panic_is_validator: 'yes' 46 | val3.cosmostest.network: 47 | validator_moniker: validator-28 48 | start_multinode: true 49 | voting_power: 28 50 | chain_gentx_validator: "{{ (bonded_tokens_pool|int * voting_power|int / 100)|int }}" 51 | chain_validator_coins: "{{ (bonded_supply_divider * chain_gentx_validator|int | int +chain_gentx_validator|int)|int }}" 52 | # Remove the next line if you are not setting up PANIC 53 | panic_is_validator: 'yes' 54 | sen1.cosmostest.network: 55 | api_enabled: true 56 | sync_multinode_genesis: true 57 | sen2.cosmostest.network: 58 | api_enabled: true 59 | sync_multinode_genesis: true 60 | sync1.cosmostest.network: 61 | statesync_snapshot_interval: 1000 62 | statesync_snapshot_keep_recent: 2 63 | p2p_upnp: true 64 | api_enabled: true 65 | sync_multinode_genesis: true 66 | sync2.cosmostest.network: 67 | statesync_snapshot_interval: 1000 68 | statesync_snapshot_keep_recent: 2 69 | p2p_upnp: true 70 | api_enabled: true 71 | sync_multinode_genesis: true 72 | -------------------------------------------------------------------------------- /roles/cascadia/templates/ansible_vars.json.j2: -------------------------------------------------------------------------------- 1 | { 2 | "client.toml": { 3 | "keyring-backend": {{ client_keyring_backend | to_json }}, 4 | "broadcast-mode": {{ client_broadcast_mode | to_json }} 5 | }, 6 | "app.toml": { 7 | "minimum-gas-prices": {{ minimum_gas_prices | to_json }}, 8 | "pruning": {{ pruning | to_json }}, 9 | "pruning-keep-recent": {{ pruning_keep_recent | to_json }}, 10 | "pruning-keep-every": {{ pruning_keep_every | to_json }}, 11 | "pruning-interval": {{ pruning_interval | to_json }}, 12 | "halt-height": {{ halt_height | to_json }}, 13 | "halt-time": {{ halt_time | to_json }}, 14 | "min-retain-blocks": {{ min_retain_blocks | to_json }}, 15 | "inter-block-cache": {{ inter_block_cache | to_json }}, 16 | "telemetry.service-name": {{ telemetry_service_name | to_json }}, 17 | "telemetry.enabled": {{ telemetry_enabled | to_json }}, 18 | "telemetry.enable-hostname": {{ telemetry_enable_hostname | to_json }}, 19 | "telemetry.enable-hostname-label": {{ telemetry_enable_hostname_label | to_json }}, 20 | "telemetry.enable-service-label": {{ telemetry_enable_service_label | to_json }}, 21 | "telemetry.prometheus-retention-time": {{ prometheus_retention_time | to_json }}, 22 | "api.enable": {{ api_enabled | to_json }}, 23 | "api.swagger": {{ api_swagger | to_json }}, 24 | "api.address": "0.0.0.0:{{ api_port }}", 25 | "grpc.enable": {{ grpc_enabled | to_json }}, 26 | "grpc.address": "0.0.0.0:{{ grpc_port }}", 27 | "state-sync.snapshot-interval": {{ statesync_snapshot_interval | to_json }}, 28 | "state-sync.snapshot-keep-recent": {{ statesync_snapshot_keep_recent | to_json }} 29 | }, 30 | "config.toml": { 31 | {% if major_version|int >= 8 %} 32 | "blocksync.enable": {{ fast_sync | to_json }}, 33 | "blocksync.version": {{ fastsync_version | to_json }}, 34 | {% else %} 35 | "fast_sync": {{ fast_sync | to_json }}, 36 | "fastsync.version": {{ fastsync_version | to_json }}, 37 | {% endif %} 38 | "abci": {{ abci | to_json }}, 39 | "rpc.laddr": "tcp://0.0.0.0:{{ rpc_port }}", 40 | "p2p.laddr": "tcp://0.0.0.0:{{ p2p_port }}", 41 | "p2p.external_address": {{ p2p_external_address | to_json }}, 42 | "p2p.seeds": {{ p2p_seeds | to_json }}, 43 | "p2p.persistent_peers": {{ p2p_persistent_peers | to_json }}, 44 | "p2p.upnp": {{ p2p_upnp | to_json }}, 45 | "p2p.pex": {{ p2p_pex | to_json }}, 46 | "p2p.seed_mode": {{ p2p_seed_mode | to_json }}, 47 | "p2p.private_peer_ids": {{ p2p_private_peer_ids | to_json }}, 48 | "statesync.enable": {{ statesync_enabled | to_json }}, 49 | "statesync.rpc_servers": {{ statesync_rpc_servers | to_json }}, 50 | "statesync.trust_height": {{ statesync_trust_height | to_json }}, 51 | "statesync.trust_hash": {{ statesync_trust_hash | to_json }}, 52 | "statesync.trust_period": {{ statesync_trust_period | to_json }}, 53 | "statesync.discovery_time": {{ statesync_discovery_time | to_json }}, 54 | "statesync.chunk_request_timeout": {{ statesync_chunk_request_timeout | to_json }}, 55 | "statesync.chunk_fetchers": {{ statesync_chunk_fetchers | to_json }}, 56 | "instrumentation.prometheus": {{ prometheus_enabled | to_json }}, 57 | "instrumentation.prometheus_listen_addr": {{ prometheus_listen_addr | to_json }}, 58 | "instrumentation.namespace": {{ instrumentation_namespace | to_json }} 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /examples/inventory-hermes.yml: -------------------------------------------------------------------------------- 1 | --- 2 | # yamllint disable rule:line-length 3 | all: 4 | vars: 5 | chain_home_clear: true 6 | chain_version: v7.0.2 7 | hermes_version: v1.0.0 8 | ansible_user: root 9 | children: 10 | node: 11 | hosts: 12 | my-chain-1.dev.testnet.com: 13 | chain_id: my-chain-1 14 | chain_create_validator: true 15 | chain_airdrop: true 16 | chain_airdrop_accounts: 17 | - cosmos1r5v5srda7xfth3hn2s26txvrcrntldjumt8mhl # relayer account 18 | my-chain-2.dev.testnet.com: 19 | chain_id: my-chain-2 20 | chain_create_validator: true 21 | chain_airdrop: true 22 | chain_airdrop_accounts: 23 | - cosmos1r5v5srda7xfth3hn2s26txvrcrntldjumt8mhl # relayer account 24 | hermes: 25 | hosts: 26 | hermes.dev.testnet.com: 27 | hermes_relayer_mnemonics: true 28 | hermes_chains: 29 | my-chain-1: 30 | hermes_relayer_mnemonic: 'examples/validator-keys/validator-40/self-delegation-wallet-mnemonic.txt' 31 | hermes_port_name: transfer 32 | hermes_chain_rpc_url_schema: http 33 | hermes_chain_rpc_hostname: my-chain-1.dev.testnet.com 34 | hermes_chain_rpc_port: 26657 35 | hermes_chain_grpc_url_schema: http 36 | hermes_chain_grpc_hostname: my-chain-1.dev.testnet.com 37 | hermes_chain_grpc_port: 9090 38 | hermes_chain_websocket_url_schema: ws 39 | hermes_chain_rpc_timeout: '10s' 40 | hermes_chain_account_prefix: 'cosmos' 41 | hermes_chain_key_name: 'testkey' 42 | hermes_chain_store_prefix: 'ibc' 43 | hermes_chain_max_gas: 2000000 44 | hermes_chain_fee_granter: '' 45 | gas_price: "{ price = 0.001, denom = 'uatom' }" 46 | hermes_chain_gas_multiplier: 1.1 47 | hermes_chain_clock_drift: '5s' 48 | hermes_chain_trusting_period: '1days' 49 | hermes_chain_trust_threshold: "{ numerator = '1', denominator = '3' }" 50 | my-chain-2: 51 | hermes_relayer_mnemonic: 'examples/validator-keys/validator-40/self-delegation-wallet-mnemonic.txt' 52 | hermes_port_name: transfer 53 | hermes_chain_rpc_url_schema: http 54 | hermes_chain_rpc_hostname: my-chain-2.dev.testnet.com 55 | hermes_chain_rpc_port: 26657 56 | hermes_chain_grpc_url_schema: http 57 | hermes_chain_grpc_hostname: my-chain-2.dev.testnet.com 58 | hermes_chain_grpc_port: 9090 59 | hermes_chain_websocket_url_schema: ws 60 | hermes_chain_rpc_timeout: '10s' 61 | hermes_chain_account_prefix: 'cosmos' 62 | hermes_chain_key_name: 'testkey' 63 | hermes_chain_store_prefix: 'ibc' 64 | hermes_chain_max_gas: 2000000 65 | hermes_chain_fee_granter: '' 66 | gas_price: "{ price = 0.001, denom = 'uatom' }" 67 | hermes_chain_gas_multiplier: 1.1 68 | hermes_chain_clock_drift: '5s' 69 | hermes_chain_trusting_period: '1days' 70 | hermes_chain_trust_threshold: "{ numerator = '1', denominator = '3' }" 71 | -------------------------------------------------------------------------------- /roles/cascadia/tasks/install_gaiad.yml: -------------------------------------------------------------------------------- 1 | --- 2 | 3 | # TODO: Firewall 4 | # - name: set up firewall (block by default?) 5 | 6 | - name: Check gaiad version 7 | shell: | 8 | PATH=$PATH:/usr/local/go/bin:$HOME/go/bin 9 | gaiad version 10 | become_user: "{{gaiad_user}}" 11 | register: gaiad_current_version 12 | ignore_errors: true 13 | 14 | ## Create go bin directory 15 | - name: Prepare go folder 16 | when: gaiad_binary_source == "release" 17 | file: 18 | path: '{{ gaiad_user_home }}/go/bin' 19 | state: directory 20 | recurse: true 21 | owner: '{{gaiad_user}}' 22 | group: '{{gaiad_user}}' 23 | 24 | 25 | - name: Download gaiad binary from release 26 | when: not gaiad_version in gaiad_current_version.stdout and gaiad_binary_source == "release" 27 | get_url: 28 | url: "{{ gaiad_binary_release }}" 29 | dest: "{{gaiad_user_home}}/go/bin/gaiad" 30 | mode: "0777" 31 | force: true 32 | become_user: "{{gaiad_user}}" 33 | 34 | - name: Clone gaiad 35 | when: not gaiad_version in gaiad_current_version.stdout and gaiad_binary_source == "build" 36 | git: 37 | repo: "{{gaiad_repository}}" 38 | dest: "{{ gaiad_user_home }}/gaia" 39 | version: "{{gaiad_version}}" 40 | force: yes 41 | become_user: "{{gaiad_user}}" 42 | 43 | - name: Install gaiad 44 | when: not gaiad_version in gaiad_current_version.stdout and gaiad_binary_source == "build" 45 | shell: | 46 | PATH=$PATH:/usr/local/go/bin:$HOME/go/bin 47 | make install 48 | args: 49 | chdir: "{{ gaiad_user_home }}/gaia" 50 | become_user: "{{gaiad_user}}" 51 | 52 | # Clear gaiad_home if it exists 53 | - name: Check if gaiad home folder exists 54 | stat: 55 | path: "{{gaiad_home}}" 56 | register: gaiad_home_exists 57 | 58 | - name: Clear gaiad home 59 | when: gaiad_home_autoclear 60 | file: 61 | state: absent 62 | path: "{{gaiad_home}}" 63 | 64 | # Initialize gaiad home 65 | - name: initialize gaiad 66 | when: gaiad_home_autoclear or not gaiad_home_exists.stat.exists 67 | # TODO: should we overwrite? 68 | shell: | 69 | cd $HOME 70 | PATH=$PATH:/usr/local/go/bin:$HOME/go/bin 71 | gaiad init {{inventory_hostname}} --home {{gaiad_home}} --chain-id {{chain_id}} 72 | become_user: "{{gaiad_user}}" 73 | 74 | - name: reset gaiad database (command for v7.0.0) 85 | when: gaiad_unsafe_reset and ((major_version|int == 7 and patch_version|int >= 1) or major_version|int > 7) 86 | shell: | 87 | cd $HOME 88 | PATH=$PATH:/usr/local/go/bin:$HOME/go/bin 89 | gaiad tendermint unsafe-reset-all --home {{gaiad_home}} 90 | become_user: "{{gaiad_user}}" 91 | tags: 92 | - gaiad_reset 93 | 94 | - name: Add gaiad bin from go/bin to .bashrc PATH 95 | when: not use_cosmovisor 96 | blockinfile: 97 | dest: '{{ gaiad_user_home }}/.bashrc' 98 | block: | 99 | export PATH="$PATH:{{ gaiad_user_home }}/go/bin" 100 | marker: '# {mark} ANSIBLE MANAGED BLOCK - GAIAD PATH' 101 | insertbefore: EOF 102 | create: yes 103 | -------------------------------------------------------------------------------- /roles/cascadia/tasks/genesis.yml: -------------------------------------------------------------------------------- 1 | --- 2 | # Genesis file configuration 3 | # - name: Check stat of local genesis file 4 | # when: genesis_file is defined 5 | # local_action: 6 | # module: stat 7 | # path: "{{genesis_file}}" 8 | # get_checksum: false 9 | # register: local_genesis_file_exists 10 | # - name: Check if remote genesis file exists 11 | # when: genesis_file is defined 12 | # stat: 13 | # path: "{{gaiad_home}}/config/genesis.json" 14 | # get_checksum: false 15 | # register: genesis_file_exists 16 | - name: check if genesis_file is gz or not 17 | when: genesis_file is defined 18 | stat: 19 | path: '{{genesis_file}}' 20 | get_mime: true 21 | delegate_to: localhost 22 | become: false 23 | register: file_type 24 | 25 | - name: File type of {{genesis_file}} 26 | when: genesis_file is defined 27 | debug: 28 | msg: '{{file_type.stat.mimetype}}' 29 | 30 | - name: gzip the file if not zipped 31 | when: 32 | - genesis_file is defined 33 | - file_type.stat.mimetype == "text/plain" 34 | archive: 35 | path: '{{genesis_file}}' 36 | dest: '{{genesis_file}}.gz' 37 | format: gz 38 | delegate_to: localhost 39 | become: false 40 | 41 | - name: set genesis_file to include .gz 42 | when: 43 | - genesis_file is defined 44 | - file_type.stat.mimetype == "text/plain" 45 | set_fact: 46 | genesis_file: '{{ genesis_file }}.gz' 47 | 48 | - name: copy {{genesis_file}} to remote server 49 | when: genesis_file is defined 50 | copy: 51 | src: '{{genesis_file}}' 52 | dest: '{{gaiad_user_home}}/genesis.json.gz' 53 | owner: '{{gaiad_user}}' 54 | group: '{{gaiad_user}}' 55 | 56 | - name: extract {{genesis_file}} to {{gaiad_home}}/config/genesis.json 57 | when: genesis_file is defined 58 | shell: | 59 | gunzip -c $HOME/genesis.json.gz > {{gaiad_home}}/config/genesis.json 60 | become_user: "{{gaiad_user}}" 61 | 62 | - name: download genesis file 63 | when: genesis_url is defined 64 | get_url: 65 | url: "{{genesis_url}}" 66 | dest: "{{ gaiad_user_home }}/genesis.data" 67 | mode: 0644 68 | become_user: "{{gaiad_user}}" 69 | 70 | - name: Check file type of downloaded genesis file 71 | when: genesis_url is defined 72 | stat: 73 | path: '{{gaiad_user_home}}/genesis.data' 74 | get_mime: true 75 | register: file_type 76 | 77 | - name: File type of {{gaiad_user_home}}/genesis.data 78 | when: genesis_url is defined 79 | debug: 80 | msg: '{{file_type.stat.mimetype}}' 81 | 82 | - name: Extract the file if genesis is gzip 83 | when: 84 | - genesis_url is defined 85 | - file_type.stat.mimetype == "application/gzip" 86 | shell: | 87 | gunzip -c $HOME/genesis.data > {{gaiad_home}}/config/genesis.json 88 | become_user: "{{gaiad_user}}" 89 | 90 | - name: Copy non-zipped genesis to genesis config 91 | when: 92 | - genesis_url is defined 93 | - file_type.stat.mimetype == "text/plain" 94 | copy: 95 | src: '{{gaiad_user_home}}/genesis.data' 96 | dest: '{{gaiad_home}}/config/genesis.json' 97 | owner: '{{gaiad_user}}' 98 | group: '{{gaiad_user}}' 99 | remote_src: true 100 | 101 | - name: verify genesis file 102 | when: genesis_shasum is defined 103 | # Throw an error if shasum doesn't match 104 | shell: | 105 | GENESIS_SHASUM="$(sha256sum {{ gaiad_home }}/config/genesis.json)" 106 | if [ $GENESIS_SHASUM != {{ genesis_shasum }} ]; then 107 | exit 1 108 | fi 109 | exit 0 110 | become_user: "{{gaiad_user}}" 111 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Ansible Cosmos Network Creator 2 | ✨ An Ansible toolkit for Cosmos networks 💫 3 | 4 | Use this toolkit to: 5 | 6 | - Join a testnet 7 | - Start a local testnet 8 | - Start a multi-node testnet 9 | 10 | ![Waterdrops feeding seedlings](images/seedling.gif) 11 | 12 | ## 🌰 Requirements 13 | 14 | - Python 3 15 | - Ansible 16 | - Install Ansible with `pip` and not `apt`: 17 | ``` 18 | pip install ansible 19 | ``` 20 | 21 | ## 🌱 Quick Start 22 | 23 | To join the Cosmos Hub [public testnet](https://github.com/cosmos/testnets/tree/master/public): 24 | 25 | 1. Clone this repository 26 | 2. Run `ansible-galaxy install -r requirements.yml` to install dependencies 27 | 3. Set up SSH access to the target machine 28 | 4. Run the playbook 29 | ``` 30 | ansible-playbook node.yml -i examples/inventory-public-testnet.yml -e 'target=SERVER_IP_OR_DOMAIN' 31 | ``` 32 | 5. Log into the target machine to follow the syncing process 33 | ``` 34 | journalctl -fu cosmovisor 35 | ``` 36 | 37 | Watch the video below to see the playbook in action: 38 | 39 | [![Join the Cosmos Hub Public Testnet](https://img.youtube.com/vi/4KkMblQ6wcY/0.jpg)](https://youtu.be/4KkMblQ6wcY) 40 | 41 | ## 🌳 Explore Further 42 | 43 | - See the [examples](examples/README.md) for more command, playbook, and configuration options. 44 | - See the [Playbook Variables Overview](docs/Playbook-Variables.md) for a list of default variables you can override with the `--extra-vars` or `-e` option. 45 | - Visit the [Cosmos testnets repo](https://github.com/cosmos/testnets) for more information. 46 | 47 | ### Playbook Tags 48 | 49 | Use `cascadia_control.py` to run only part of the `cascadia` playbook: 50 | 51 | ``` 52 | ./cascadia-control.py [-i inventory] [-t target] operation 53 | ``` 54 | 55 | The inventory argument is optional and defaults to `inventory.yml` (e.g. `./cascadia-control.py restart`). 56 | 57 | The target option is the server IP or domain. 58 | 59 | The operation will apply to all the nodes in the inventory: 60 | - `restart` restarts the cascadiad/cosmovisor service 61 | - `stop` stops the cascadiad/cosmovisor service 62 | - `start` starts thecascadiad/cosmovisor service 63 | - `reboot` reboots the machine 64 | - `reset` runs `cascadiad unsafe-reset-all` 65 | 66 | ### Role Folder Structure 67 | 68 | - The `cascadia` role provides the core functionality of this toolkit 69 | - Node setup: `roles/cascadia/tasks/main.yml` 70 | - Default variables: `roles/cascadia/defaults/main.yml` 71 | - Systemd services: `roles/cascadia/templates/` 72 | - To add a variable to the cascadia config files, add it to: 73 | - `roles/cascadia/templates/ansible_vars.json.j2` 74 | 75 | ## 🌴 Automatic Tests 76 | 77 | This repository runs different tests automatically as defined below. 78 | 79 | ### Fresh State (weekly) 80 | 81 | The fresh state test is run using GitHub Actions and results are displayed with a badge at the top of this readme. 82 | 83 | ### Mainnet exported genesis (bi-weekly) 84 | 85 | We export a genesis file from `cosmoshub-4` and modify it using our [tinkerer script](https://github.com/hyphacoop/cosmos-genesis-tinkerer). The exported and modified genesis files can be accessed [here](https://files.polypore.xyz/genesis/). 86 | 87 | We run the stateful tests with the modified genesis file when there is a major version of Cascadia that is higher than the major version running on `cosmoshub-4`. 88 | 89 | ### Joining the Public Testnet (weekly) 90 | 91 | We test joining the Cosmos Hub public testnet weekly using GitHub Actions and a badge is displayed at the top of this readme. 92 | 93 | ## 🔎 Code Standards 94 | 95 | - All Python code is formatted to PEP 8 and linted with `pylint`. 96 | - All YAML code is linted with `yamllint`. 97 | - See `lint.sh` and `.config/` for details. 98 | -------------------------------------------------------------------------------- /roles/bigdipper/defaults/main.yml: -------------------------------------------------------------------------------- 1 | --- 2 | ### Golang ### 3 | binary_arch_map: 4 | aarch64: "linux-arm64" 5 | x86_64: "linux-amd64" 6 | go_arch: "{{binary_arch_map[ansible_architecture]}}" 7 | go_version: 1.18.5 8 | 9 | ### Node.js ### 10 | nodejs_version: "14.x" 11 | 12 | ### PostgreSQL ### 13 | postgresql_version: 12 14 | 15 | ### Big Dipper ### 16 | bigdipper_user: "ubuntu" 17 | bigdipper_user_home: "/home/{{bigdipper_user}}" 18 | bigdipper_db: bdjuno 19 | bigdipper_db_user: "feynman" 20 | # This password prevents drive-by malware 21 | # from guessing or in case it's accidentally exposed. 22 | # The DB runs on localhost so the password doesn't need to be secret: 23 | bigdipper_db_password: "1qazxsw23edc" 24 | bigdipper_telemetry_port: 5000 25 | bigdipper_rpc_port: 26657 26 | 27 | ### bdjuno ### 28 | bdjuno_home: "{{bigdipper_user_home}}/.bdjuno" 29 | bdjuno_dir: "{{bigdipper_user_home}}/bdjuno" 30 | bdjuno_bin: "{{bigdipper_user_home}}/go/bin/bdjuno" 31 | bdjuno_service_name: "bdjuno" 32 | bdjuno_client_name: cascadia 33 | bdjuno_rpc_port: 26657 34 | bdjuno_grpc_port: 9090 35 | bdjuno_rpc_address: "http://localhost:{{ bdjuno_rpc_port }}" 36 | bdjuno_grpc_address: "http://localhost:{{ bdjuno_grpc_port }}" 37 | bdjuno_fast_sync: false 38 | bdjuno_workers: 5 39 | bdjuno_listen_new_blocks: true 40 | bdjuno_parse_new_blocks: true 41 | bdjuno_parse_genesis: true 42 | bdjuno_avg_block_time: 5s 43 | # Set depending on the chain: 44 | # bdjuno_version: "chains/cosmos/testnet" 45 | # Set to match genesis info: 46 | # bigdipper_genesis_time: 2021-07-13T08:00:00 47 | bigdipper_genesis_height: 1 48 | 49 | bdjuno_hasura_actions_port: 3000 50 | 51 | ### Hasura ### 52 | hasura_version: v2.9.0 53 | hasura_cli_version: "2.9.0" 54 | hasura_port: 8080 55 | hasura_actions_service_name: hasura-actions 56 | # The following should be private: 57 | hasura_admin_secret: "something" 58 | hasura_host: "hasura." 59 | rpc_host: "rpc." 60 | hasura_cloud_id: "54.176.149.52" 61 | 62 | ### Big Dipper UI ### 63 | bdui_host: "" 64 | bdui_dir: "{{bigdipper_user_home}}/big-dipper" 65 | bdui_version: "base-v2.1.0" 66 | bdui_port: 3001 67 | bdui_graphql_url: "{{bigdipper_web_scheme}}://{{hasura_host}}{{inventory_hostname}}/v1/graphql" 68 | bdui_graphql_ws_url: "{{bigdipper_websocket_scheme}}://{{hasura_host}}{{inventory_hostname}}/v1/graphql" 69 | bdui_rpc_websocket: "{{bigdipper_websocket_scheme}}://{{rpc_host}}{{inventory_hostname}}/websocket" 70 | bdui_public_url: "{{bigdipper_web_scheme}}://{{bdui_host}}{{inventory_hostname}}" 71 | bdui_chain: testnet 72 | bdui_service_name: bigdipper 73 | bdui_icon: "" 74 | bdui_logo: "" 75 | 76 | ### nginx configuration ### 77 | 78 | bigdipper_use_tls_proxy: false 79 | # The following variables are set automatically 80 | # based on bigdipper_use_tls_proxy 81 | bigdipper_web_scheme: http 82 | bigdipper_websocket_scheme: ws 83 | ssl_provider: "" 84 | 85 | nginx_sites: 86 | "{{hasura_host}}{{inventory_hostname}}": 87 | ssl_provider: "{{ssl_provider}}" 88 | web_hostname: "{{hasura_host}}{{inventory_hostname}}" 89 | locations: 90 | "/": 91 | proxy_location: "http://127.0.0.1:{{hasura_port}}" 92 | proxy_websocket: true 93 | "{{rpc_host}}{{inventory_hostname}}": 94 | ssl_provider: "{{ssl_provider}}" 95 | web_hostname: "{{rpc_host}}{{inventory_hostname}}" 96 | locations: 97 | "/": 98 | proxy_location: "http://127.0.0.1:{{bigdipper_rpc_port}}" 99 | proxy_websocket: true 100 | "{{bdui_host}}{{inventory_hostname}}": 101 | ssl_provider: "{{ssl_provider}}" 102 | web_hostname: "{{bdui_host}}{{inventory_hostname}}" 103 | locations: 104 | "/": 105 | proxy_location: "http://127.0.0.1:{{bdui_port}}" 106 | proxy_websocket: true 107 | 108 | ## genesis url 109 | genesis_url: "https://github.com/CascadiaFoundation/chain-configuration/raw/master/devnet/genesis.json.gz" 110 | -------------------------------------------------------------------------------- /roles/node/tasks/join.yml: -------------------------------------------------------------------------------- 1 | --- 2 | # Genesis file configuration 3 | # - name: Check stat of local genesis file 4 | # when: genesis_file is defined 5 | # local_action: 6 | # module: stat 7 | # path: "{{genesis_file}}" 8 | # get_checksum: false 9 | # register: local_genesis_file_exists 10 | # - name: Check if remote genesis file exists 11 | # when: genesis_file is defined 12 | # stat: 13 | # path: "{{chain_home}}/config/genesis.json" 14 | # get_checksum: false 15 | # register: genesis_file_exists 16 | - name: check if genesis_file is gz or not 17 | when: genesis_file is defined 18 | stat: 19 | path: '{{genesis_file}}' 20 | get_mime: true 21 | delegate_to: localhost 22 | become: false 23 | register: file_type 24 | 25 | - name: File type of {{genesis_file}} 26 | when: genesis_file is defined 27 | debug: 28 | msg: '{{file_type.stat.mimetype}}' 29 | 30 | - name: gzip the file if not zipped 31 | when: 32 | - genesis_file is defined 33 | - file_type.stat.mimetype != "application/gzip" 34 | archive: 35 | path: '{{genesis_file}}' 36 | dest: '{{genesis_file}}.gz' 37 | format: gz 38 | delegate_to: localhost 39 | become: false 40 | 41 | - name: set genesis_file to include .gz 42 | when: 43 | - genesis_file is defined 44 | - file_type.stat.mimetype != "application/gzip" 45 | set_fact: 46 | genesis_file: '{{ genesis_file }}.gz' 47 | 48 | - name: copy {{genesis_file}} to remote server 49 | when: genesis_file is defined 50 | copy: 51 | src: '{{genesis_file}}' 52 | dest: '{{node_user_home}}/genesis.json.gz' 53 | owner: '{{node_user}}' 54 | group: '{{node_user}}' 55 | 56 | - name: extract {{genesis_file}} to {{chain_home}}/config/genesis.json 57 | when: genesis_file is defined 58 | shell: | 59 | gunzip -c $HOME/genesis.json.gz > {{chain_home}}/config/genesis.json 60 | become_user: "{{node_user}}" 61 | 62 | - name: download genesis file 63 | when: genesis_url is defined 64 | get_url: 65 | url: "{{genesis_url}}" 66 | dest: "{{ node_user_home }}/genesis.data" 67 | mode: 0644 68 | become_user: "{{node_user}}" 69 | 70 | - name: Check file type of downloaded genesis file 71 | when: genesis_url is defined 72 | stat: 73 | path: '{{node_user_home}}/genesis.data' 74 | get_mime: true 75 | register: file_type 76 | 77 | - name: File type of {{node_user_home}}/genesis.data 78 | when: genesis_url is defined 79 | debug: 80 | msg: '{{file_type.stat.mimetype}}' 81 | 82 | - name: Extract the file if genesis is gzip 83 | when: 84 | - genesis_url is defined 85 | - file_type.stat.mimetype == "application/gzip" 86 | shell: | 87 | gunzip -c $HOME/genesis.data > {{chain_home}}/config/genesis.json 88 | become_user: "{{node_user}}" 89 | 90 | - name: Copy non-zipped genesis to genesis config (plain text) 91 | when: 92 | - genesis_url is defined 93 | - file_type.stat.mimetype != "application/gzip" 94 | copy: 95 | src: '{{node_user_home}}/genesis.data' 96 | dest: '{{chain_home}}/config/genesis.json' 97 | owner: '{{node_user}}' 98 | group: '{{node_user}}' 99 | remote_src: true 100 | 101 | - name: Copy non-zipped genesis to genesis config (json) 102 | when: 103 | - genesis_url is defined 104 | - file_type.stat.mimetype == "application/json" 105 | copy: 106 | src: '{{node_user_home}}/genesis.data' 107 | dest: '{{chain_home}}/config/genesis.json' 108 | owner: '{{node_user}}' 109 | group: '{{node_user}}' 110 | remote_src: true 111 | 112 | - name: verify genesis file 113 | when: genesis_shasum is defined 114 | # Throw an error if shasum doesn't match 115 | shell: | 116 | GENESIS_SHASUM="$(sha256sum {{ chain_home }}/config/genesis.json)" 117 | if [ $GENESIS_SHASUM != {{ genesis_shasum }} ]; then 118 | exit 1 119 | fi 120 | exit 0 121 | become_user: "{{node_user}}" 122 | -------------------------------------------------------------------------------- /roles/cascadia/tasks/setup.yml: -------------------------------------------------------------------------------- 1 | --- 2 | # Save JSON data from RPC API 3 | - name: Get JSON from registry 4 | uri: 5 | url: "{{ chain_registry }}" 6 | method: GET 7 | return_content: yes 8 | status_code: 200 9 | body_format: json 10 | when: chain_registry is defined 11 | register: chain_registry_json 12 | 13 | - name: Set chain_id to {{ chain_registry_json.json.chain_id }} 14 | when: chain_registry is defined 15 | set_fact: 16 | chain_id: '{{ chain_registry_json.json.chain_id }}' 17 | 18 | - name: Set gaiad_version to {{ chain_registry_json.json.codebase.recommended_version }} 19 | when: chain_registry is defined 20 | set_fact: 21 | gaiad_version: '{{ chain_registry_json.json.codebase.recommended_version }}' 22 | 23 | - name: Set genesis_url to {{ chain_registry_json.json.genesis.genesis_url }} 24 | when: chain_registry is defined 25 | set_fact: 26 | genesis_url: '{{ chain_registry_json.json.genesis.genesis_url }}' 27 | 28 | # Get gaiad_version number 29 | - name: parse version 30 | set_fact: 31 | major_version: "{{ gaiad_version[1] }}" 32 | patch_version: "{{ gaiad_version[5] }}" 33 | when: major_version is undefined and patch_version is undefined 34 | tags: 35 | - gaiad_reset 36 | - gaiad_stop 37 | - gaiad_restart 38 | 39 | - include_role: 40 | name: common 41 | 42 | - name: Set value to enable gaiad prometheus 43 | set_fact: 44 | prometheus_enabled: true 45 | when: monitoring_prometheus | default(false) | bool 46 | 47 | - name: Setup and enable swap 48 | include_role: 49 | name: mkswap 50 | when: enable_swap | default(false) | bool 51 | 52 | - name: Set up pip dependencies 53 | pip: 54 | name: 55 | - toml 56 | - github3.py 57 | 58 | - name: Ensure user exists for gaiad 59 | user: 60 | name: "{{gaiad_user}}" 61 | append: true 62 | groups: adm 63 | shell: /bin/bash 64 | comment: User for gaiad and cosmovisor services 65 | 66 | # Stop existing services 67 | - name: Populate service facts 68 | service_facts: 69 | tags: 70 | - gaiad_stop 71 | - gaiad_restart 72 | 73 | - name: Stop existing faucet systemd service 74 | when: > 75 | (faucet_service_name in ansible_facts.services) or 76 | ((faucet_service_name + '.service') in ansible_facts.services) 77 | systemd: 78 | state: stopped 79 | name: "{{faucet_service_name}}" 80 | tags: 81 | - gaiad_stop 82 | - gaiad_restart 83 | 84 | - name: Stop existing gaiad systemd service 85 | # Check for both `SERVICE_NAME` and `SERVICE_NAME.service` 86 | when: > 87 | not use_cosmovisor and ( 88 | (gaiad_service_name in ansible_facts.services) or 89 | ((gaiad_service_name + '.service') in ansible_facts.services)) 90 | systemd: 91 | state: stopped 92 | name: "{{gaiad_service_name}}" 93 | tags: 94 | - gaiad_stop 95 | - gaiad_restart 96 | 97 | - name: Stop existing cosmovisor systemd service 98 | when: > 99 | use_cosmovisor and ( 100 | (cosmovisor_service_name in ansible_facts.services) or 101 | ((cosmovisor_service_name + '.service') in ansible_facts.services)) 102 | systemd: 103 | state: stopped 104 | name: "{{cosmovisor_service_name}}" 105 | tags: 106 | - gaiad_stop 107 | - gaiad_restart 108 | 109 | - name: Remove golang apt package 110 | ansible.builtin.apt: 111 | name: golang 112 | state: absent 113 | 114 | - name: Remove system Go files 115 | file: 116 | state: absent 117 | path: "{{ item }}" 118 | loop: 119 | - /usr/bin/go 120 | - /usr/lib/go 121 | 122 | - name: Check golang version 123 | shell: | 124 | PATH=$PATH:/usr/local/go/bin:$HOME/go/bin 125 | go version 126 | register: go_current_version 127 | ignore_errors: true 128 | 129 | - name: Extract golang 130 | when: not go_version in go_current_version.stdout 131 | unarchive: 132 | src: "https://golang.org/dl/go{{go_version}}.{{go_arch}}.tar.gz" 133 | dest: /usr/local 134 | remote_src: yes 135 | become: true 136 | -------------------------------------------------------------------------------- /roles/cascadia/defaults/main.yml: -------------------------------------------------------------------------------- 1 | --- 2 | 3 | # Go configuration 4 | go_arch: "{{binary_arch_map[ansible_architecture]}}" 5 | go_version: 1.18.5 6 | 7 | # General Cascadiad settings 8 | cascadiad_user: cascadia 9 | cascadiad_user_home: "/home/{{cascadiad_user}}" 10 | cascadiad_home: "{{cascadiad_user_home}}/.cascadiad" 11 | cascadiad_home_autoclear: false 12 | cascadiad_unsafe_reset: false 13 | cascadiad_version: v0.1.1 14 | cascadiad_repository: https://github.com/CascadiaFoundation/cascadia-chain.git 15 | cascadiad_binary_release: "https://github.com/CascadiaFoundation/cascadia-chain/releases/download/{{ cascadiad_version }}/cascadiad-{{ cascadiad_version }}-{{binary_arch_map[ansible_architecture]}}" 16 | cascadiad_binary_source: "build" 17 | cascadiad_bin: "{{ cascadiad_user_home }}/go/bin/cascadiad" 18 | cascadiad_service_name: "cascadiad" 19 | cascadiad_gov_testing: false 20 | cascadiad_voting_period: 10s 21 | cascadiad_bond_denom: uatom 22 | chain_id: "theta-devnet" 23 | 24 | # Default variables for creating a validator 25 | cascadiad_create_validator: false 26 | cascadiad_gentx_validator_stake: "8000000000{{ cascadiad_bond_denom }}" 27 | cascadiad_validator_keyring: "test" 28 | cascadiad_validator_coins: "1000000000000{{ cascadiad_bond_denom }}" 29 | 30 | # Default variables for airdropping tokens 31 | cascadiad_airdrop: false 32 | cascadiad_airdrop_coins: "1000000000{{ cascadiad_bond_denom }}" 33 | cascadiad_airdrop_accounts: [] 34 | 35 | # Cosmovisor settings 36 | ## TODO: Support arbitrary cosmovisor branches 37 | use_cosmovisor: true 38 | cosmovisor_version: v1.0.0 39 | cosmovisor_repository: github.com/cosmos/cosmos-sdk/cosmovisor/cmd/cosmovisor 40 | cosmovisor_bin: "{{cascadiad_user_home}}/go/bin/cosmovisor" 41 | cosmovisor_home: "{{ cascadiad_home }}/cosmovisor" 42 | cosmovisor_service_name: "cosmovisor" 43 | cosmovisor_skip_backup: true 44 | 45 | ## config.toml variables 46 | fast_sync: true 47 | abci: socket 48 | 49 | ### RPC 50 | rpc_port: '26657' 51 | 52 | ### P2P 53 | p2p_port: '26656' 54 | p2p_external_address: '' 55 | p2p_seeds: '' 56 | p2p_persistent_peers: '' 57 | p2p_upnp: false 58 | p2p_pex: true 59 | p2p_seed_mode: false 60 | p2p_private_peer_ids: false 61 | 62 | ### Statesync 63 | statesync_enabled: false 64 | statesync_rpc_servers: '' 65 | statesync_trust_height: 0 66 | statesync_trust_hash: '' 67 | statesync_trust_period: 168h0m0s 68 | statesync_discovery_time: 15s 69 | statesync_chunk_request_timeout: 10s 70 | statesync_auto_populate: true 71 | # TODO: Why does my config say 4 when it isn't default? 72 | statesync_chunk_fetchers: '4' 73 | 74 | ### Fastsync 75 | fastsync_version: v0 76 | # TODO: All the other fastsync versions? 77 | 78 | prometheus_enabled: false 79 | prometheus_listen_addr: :26660 80 | instrumentation_namespace: tendermint 81 | 82 | ## app.toml variables 83 | minimum_gas_prices: '' 84 | pruning: default 85 | pruning_keep_recent: '0' 86 | pruning_keep_every: '0' 87 | pruning_interval: '0' 88 | halt_height: '0' 89 | halt_time: '0' 90 | min_retain_blocks: '0' 91 | inter_block_cache: true 92 | 93 | ### telemetry 94 | telemetry_service_name: '' 95 | telemetry_enabled: false 96 | telemetry_enable_hostname: false 97 | telemetry_enable_hostname_label: false 98 | telemetry_enable_service_label: false 99 | prometheus_retention_time: '0' 100 | 101 | ### API 102 | api_enabled: false 103 | api_swagger: false 104 | api_port: '1317' 105 | 106 | ### grpc 107 | grpc_enabled: true 108 | grpc_port: '9090' 109 | 110 | ### state-sync 111 | statesync_snapshot_interval: 0 112 | statesync_snapshot_keep_recent: 2 113 | 114 | ### client.toml variables 115 | client_keyring_backend: os 116 | client_broadcast_mode: sync 117 | 118 | ### Faucet settings 119 | faucet_enabled: true 120 | faucet_version: v0.1.1 121 | faucet_service_name: token-faucet 122 | 123 | ### node exporter config 124 | node_exporter_port: 9100 125 | 126 | ### Prometheus / Grafana defaults 127 | grafana_ssh_url: root@monitor.polypore.xyz 128 | monitoring_prometheus: false 129 | 130 | ### PANIC monitoring defaults 131 | panic_ssh_url: root@monitor.polypore.xyz 132 | monitoring_panic: false 133 | panic_config_file: /home/panic/panic_cosmos/config/user_config_nodes.ini 134 | panic_is_validator: 'no' 135 | panic_include_in_node_monitor: 'yes' 136 | panic_include_in_network_monitor: 'yes' 137 | 138 | ### Reboot after setup 139 | reboot: true 140 | 141 | # Vars with no defaults (to prevent code from running) 142 | # These don't get put into config files 143 | # genesis_url: "" 144 | # genesis_file: "" 145 | # addrbook_file: "" 146 | # addrbook_url: "https://quicksync.io/addrbook.cosmos.json" 147 | # node_key_file: "" 148 | # priv_validator_key_file 149 | 150 | # Architecture mapping 151 | binary_arch_map: 152 | aarch64: "linux-arm64" 153 | x86_64: "linux-amd64" 154 | -------------------------------------------------------------------------------- /.github/workflows/test-gaia-versions.yml: -------------------------------------------------------------------------------- 1 | --- 2 | 3 | name: Test Gaia Versions 4 | on: 5 | workflow_dispatch: 6 | schedule: 7 | # At 15:30 on Monday. 8 | - cron: '30 15 * * 1' 9 | pull_request: 10 | types: 11 | - opened 12 | - closed 13 | push: 14 | paths-ignore: 15 | - 'docs/**' 16 | - 'examples/**' 17 | - 'logs/**' 18 | - '!examples/inventory-local.yml' 19 | - 'README.md' 20 | jobs: 21 | generate-matrices: 22 | runs-on: ubuntu-22.04 23 | steps: 24 | # Get system info 25 | - run: ifconfig 26 | - run: arp -a 27 | - run: sudo dmidecode 28 | - run: df -h 29 | - run: free -m 30 | - run: uname -a 31 | - run: lsb_release -a 32 | - run: echo "GitHub branch is ${{ github.ref }}" 33 | - run: whoami 34 | - run: pwd 35 | 36 | - name: Check out repository code 37 | uses: actions/checkout@v3 38 | 39 | - name: Set up Python 40 | uses: actions/setup-python@v3 41 | with: 42 | python-version: '3.10' 43 | 44 | - name: Install dependencies 45 | run: | 46 | python -m pip install --upgrade pip 47 | python -m pip install requests 48 | 49 | - name: Generate starting versions 50 | id: generate-start 51 | run: | 52 | start=$(tests/generate_version_matrix.py v6.0.4) 53 | echo $start 54 | echo ::set-output name=start_versions::$start 55 | - name: Generate upgrade versions 56 | id: generate-upgrade 57 | run: | 58 | upgrade=$(tests/generate_upgrade_matrix.py v6.0.4) 59 | echo $upgrade 60 | echo ::set-output name=upgrade_versions::$upgrade 61 | outputs: 62 | start_versions: ${{ steps.generate-start.outputs.start_versions }} 63 | upgrade_versions: ${{ steps.generate-upgrade.outputs.upgrade_versions }} 64 | 65 | test-start: 66 | runs-on: ubuntu-22.04 67 | needs: generate-matrices 68 | strategy: 69 | matrix: 70 | ${{ fromJSON(needs.generate-matrices.outputs.start_versions) }} 71 | steps: 72 | - run: echo "Test ${{matrix.gaia_version}}" 73 | - name: Check out repository code 74 | uses: actions/checkout@v3 75 | - name: Set up Python 76 | uses: actions/setup-python@v3 77 | with: 78 | python-version: '3.10' 79 | - name: Install dependencies 80 | run: | 81 | python -m pip install --upgrade pip 82 | python -m pip install ansible toml 83 | 84 | - name: Configure ansible.cfg 85 | run: echo "transport = local" >> ansible.cfg 86 | - name: Install ansible-galaxy requirements 87 | run: ansible-galaxy install -r requirements.yml 88 | - name: Run playbook 89 | run: ansible-playbook node.yml -i examples/inventory-local.yml --extra-vars "target=local reboot=false chain_version=${{ matrix.gaia_version }} chain_home={{ node_user_home }}/.gaia chain_gov_testing=true node_user=runner cosmovisor_invariants_flag=''" 90 | - name: Check cosmovisor service 91 | run: systemctl status cosmovisor 92 | - name: Check blocks are being produced 93 | run: tests/test_block_production.sh 127.0.0.1 26657 10 94 | - name: Happy path - transaction testing 95 | run: tests/test_tx_fresh.sh 96 | - name: Get RAM usage while chain is running 97 | run: free -m 98 | 99 | test-upgrade: 100 | runs-on: ubuntu-22.04 101 | needs: generate-matrices 102 | strategy: 103 | matrix: 104 | ${{ fromJSON(needs.generate-matrices.outputs.upgrade_versions) }} 105 | steps: 106 | - run: echo "Test upgrading ${{matrix.gaia_version}} to ${{matrix.upgrade_version}}" 107 | - name: Check out repository code 108 | uses: actions/checkout@v3 109 | - name: Set up Python 110 | uses: actions/setup-python@v3 111 | with: 112 | python-version: '3.10' 113 | - name: Install dependencies 114 | run: | 115 | python -m pip install --upgrade pip 116 | python -m pip install ansible toml 117 | 118 | - name: Configure ansible.cfg 119 | run: echo "transport = local" >> ansible.cfg 120 | - name: Install ansible-galaxy requirements 121 | run: ansible-galaxy install -r requirements.yml 122 | - name: Run playbook 123 | run: ansible-playbook node.yml -i examples/inventory-local.yml --extra-vars "target=local reboot=false chain_version=${{ matrix.gaia_version }} chain_home={{ node_user_home }}/.gaia chain_gov_testing=true node_user=runner" 124 | - name: Check cosmovisor service 125 | run: systemctl status cosmovisor 126 | - name: Check blocks are being produced 127 | run: tests/test_block_production.sh 127.0.0.1 26657 10 128 | - name: Test software upgrade 129 | run: tests/test_software_upgrade.sh 127.0.0.1 26657 ${{ matrix.upgrade_version }} 130 | - name: Happy path - transaction testing 131 | run: tests/test_tx_fresh.sh 132 | -------------------------------------------------------------------------------- /roles/blockscout/tasks/blockscout.yml: -------------------------------------------------------------------------------- 1 | - name: Clone BlockScout 2 | become_user: "{{ blockscout_user }}" 3 | git: 4 | repo: "{{ blockscout_repo }}" 5 | dest: "{{ blockscout_dir }}" 6 | version: "{{ branch }}" 7 | update: yes 8 | force: yes 9 | 10 | - name: Ensure user exists for bigdipper 11 | user: 12 | name: "{{blockscout_user}}" 13 | append: true 14 | groups: adm 15 | shell: /bin/bash 16 | comment: User for blockscout block explorer services 17 | 18 | - name: Get the list of services 19 | service_facts: 20 | 21 | - name: "Stop blockscout systemd service" 22 | systemd: 23 | state: stopped 24 | name: "{{blockscout_service_name}}" 25 | when: "'{{blockscout_service_name}}.service' in services" 26 | 27 | - name: Remove static assets from previous deployment, if any 28 | file: 29 | path: "{{ blockscout_repo }}/apps/block_scout_web/priv/static" 30 | state: absent 31 | 32 | - block: 33 | - name: sh env 34 | ansible.builtin.shell: 35 | args: 36 | cmd: "{{ shenv_cmd }}" 37 | chdir: '{{ blockscout_user_home }}/' 38 | register: shenv 39 | 40 | - name: Compile BlockScout 41 | ansible.builtin.shell: | 42 | {{ source }} 43 | {{blockscout_user_home}}/.asdf/shims/mix do {{ item }} 44 | args: 45 | chdir: "{{ blockscout_dir }}" 46 | executable: '{{ ansible_user_shell }}' 47 | with_items: 48 | - deps.get 49 | - local.rebar --force 50 | - deps.compile 51 | - compile 52 | - ecto.drop 53 | - ecto.create 54 | - ecto.migrate 55 | vars: 56 | source: "{{ shenv.stdout_lines | map('regex_replace', '(^)', '. ') | join('\n') }}" 57 | 58 | - name: Install Node modules at apps/block_scout_web/assets 59 | command: npm install 60 | args: 61 | chdir: "{{ blockscout_dir }}/apps/block_scout_web/assets" 62 | 63 | - name: Execute webpack.js at apps/block_scout_web/assets/node_modules/webpack/bin 64 | command: node_modules/webpack/bin/webpack.js --mode production 65 | args: 66 | chdir: "{{ blockscout_dir }}/apps/block_scout_web/assets" 67 | 68 | - name: Install Node modules at apps/explorer 69 | command: npm install 70 | args: 71 | chdir: "{{ blockscout_dir }}/apps/explorer" 72 | 73 | - name: Build static assets 74 | ansible.builtin.shell: | 75 | {{ source }} 76 | {{ blockscout_user_home }}/.asdf/shims/mix phx.digest 77 | args: 78 | chdir: "{{ blockscout_dir }}" 79 | executable: '{{ ansible_user_shell }}' 80 | vars: 81 | source: "{{ shenv.stdout_lines | map('regex_replace', '(^)', '. ') | join('\n') }}" 82 | 83 | # - name: Install SSL certificates 84 | # ansible.builtin.shell: | 85 | # {{ source }} 86 | # {{ blockscout_user_home }}/.asdf/shims/mix phx.gen.cert blockscout blockscout.local --force 87 | # args: 88 | # chdir: "{{ blockscout_dir }}/apps/block_scout_web" 89 | # executable: '{{ ansible_user_shell }}' 90 | # vars: 91 | # source: "{{ shenv.stdout_lines | map('regex_replace', '(^)', '. ') | join('\n') }}" 92 | 93 | environment: 94 | NETWORK: "{{ NETWORK }}" 95 | SUBNETWORK: "{{ SUBNETWORK }}" 96 | ETHEREUM_JSONRPC_HTTP_URL: "{{ ETHEREUM_JSONRPC_HTTP_URL }}" # Network RPC endpoint 97 | ETHEREUM_JSONRPC_WS_URL: "{{ ETHEREUM_JSONRPC_WS_URL }}" # Network RPC endpoint in websocket mode 98 | DATABASE_URL: "{{ DATABASE_URL }}" 99 | COIN: "{{ COIN }}" 100 | SECRET_KEY_BASE: "{{ SECRET_KEY_BASE }}" 101 | MIX_ENV: "prod" 102 | become_user: "{{ blockscout_user }}" 103 | vars: 104 | - asdfsh: "{{ blockscout_user_home | quote }}/.asdf/asdf.sh" 105 | - profile: "{{ blockscout_user_home }}/.profile" 106 | - shprofile: "{{ blockscout_user_home }}/.{{ ansible_user_shell | basename | regex_replace('$', '_') | regex_replace('zsh_', 'z') }}profile" 107 | - shrc: "{{ blockscout_user_home }}/.{{ ansible_user_shell | basename }}rc" 108 | - shenv_cmd: "if [ -e {{ asdfsh }} ]; then echo '{{ asdfsh }}'; fi; if [ -e {{ shprofile }} ]; then echo '{{ shprofile }}'; fi; if [ -e {{ profile }} ]; then echo '{{ profile }}'; fi; if [ -e {{ shrc }} ]; then echo '{{ shrc }}'; fi" 109 | 110 | # - name: Remove dev dependencies 111 | # file: 112 | # state: absent 113 | # path: "{{ item }}" 114 | # with_items: 115 | # - "{{ blockscout_dir }}/_build/" 116 | # - "{{ blockscout_dir }}/deps/" 117 | # - "{{ blockscout_dir }}/apps/block_scout_web/assets/node_modules/" 118 | # - "{{ blockscout_dir }}/apps/explorer/node_modules/" 119 | # - "{{ blockscout_dir }}/logs/dev/" 120 | 121 | - name: "Set up blockscout systemd service" 122 | template: 123 | src: blockscout.service.j2 124 | dest: "/etc/systemd/system/{{blockscout_service_name}}.service" 125 | 126 | - name: "Restart journalctl: the logs must flow" 127 | systemd: 128 | state: restarted 129 | name: systemd-journald 130 | 131 | - name: "Run blockscout systemd service" 132 | systemd: 133 | daemon_reload: true 134 | state: restarted 135 | enabled: true 136 | name: "{{blockscout_service_name}}" -------------------------------------------------------------------------------- /roles/cascadia/tasks/config_gaiad.yml: -------------------------------------------------------------------------------- 1 | --- 2 | - name: create validator 3 | when: gaiad_create_validator 4 | shell: | 5 | cd $HOME 6 | PATH=$PATH:/usr/local/go/bin:$HOME/go/bin 7 | gaiad keys add validator --keyring-backend {{gaiad_validator_keyring}} --home {{gaiad_home}} --output json 8 | gaiad add-genesis-account validator {{gaiad_validator_coins}} --home {{gaiad_home}} --keyring-backend="{{gaiad_validator_keyring}}" 9 | register: gaiad_create_validator_output 10 | become_user: "{{gaiad_user}}" 11 | 12 | - name: save validator name, address, and mnemonic 13 | when: gaiad_create_validator 14 | copy: 15 | content="{{gaiad_create_validator_output.stderr}}" 16 | dest="{{gaiad_home}}/validator.json" 17 | become_user: "{{gaiad_user}}" 18 | 19 | - name: create genesis accounts 20 | when: gaiad_airdrop and gaiad_create_validator 21 | shell: | 22 | cd $HOME 23 | PATH=$PATH:/usr/local/go/bin:$HOME/go/bin 24 | gaiad add-genesis-account {{ item }} {{gaiad_airdrop_coins}} --home {{gaiad_home}} 25 | become_user: "{{gaiad_user}}" 26 | loop: "{{ gaiad_airdrop_accounts }}" 27 | 28 | - name: collect gentx 29 | when: gaiad_create_validator 30 | shell: | 31 | cd $HOME 32 | PATH=$PATH:/usr/local/go/bin:$HOME/go/bin 33 | gaiad gentx validator {{gaiad_gentx_validator_stake}} --keyring-backend="{{gaiad_validator_keyring}}" --home {{gaiad_home}} --chain-id {{chain_id}} 34 | gaiad collect-gentxs --home {{gaiad_home}} 35 | become_user: "{{gaiad_user}}" 36 | 37 | - name: patch genesis file with minimum deposit and short voting period 38 | when: gaiad_gov_testing 39 | shell: | 40 | cd {{gaiad_home}}/config 41 | jq '.app_state.gov.deposit_params.min_deposit[0].amount |= "1"' genesis.json > temp.json 42 | jq '.app_state.gov.voting_params.voting_period |= "{{ gaiad_voting_period }}"' temp.json > genesis.json 43 | rm temp.json 44 | 45 | - name: patch genesis file with specified denom 46 | replace: 47 | path: '{{gaiad_home}}/config/genesis.json' 48 | regexp: 'stake' 49 | replace: '{{gaiad_bond_denom}}' 50 | 51 | # Get trust height automatically 52 | - name: obtain trust height 53 | when: statesync_enabled and statesync_auto_populate 54 | script: 55 | get_trust_height.sh {{ statesync_rpc_servers.split(',')[0] }} 56 | register: trust_height 57 | 58 | - name: obtain trust height block hash ID 59 | when: statesync_enabled and statesync_auto_populate 60 | script: 61 | get_trust_hash.sh {{ statesync_rpc_servers.split(',')[0] }} {{ trust_height.stdout }} 62 | register: trust_hash 63 | 64 | - name: print trust height and hash ID 65 | when: statesync_enabled and statesync_auto_populate 66 | debug: 67 | msg: 'Height {{trust_height.stdout }} has hash ID {{ trust_hash.stdout }}' 68 | become_user: "{{gaiad_user}}" 69 | 70 | - name: set state sync variables 71 | when: statesync_enabled and statesync_auto_populate 72 | set_fact: 73 | statesync_trust_height: "{{ trust_height.stdout }}" 74 | statesync_trust_hash: "{{ trust_hash.stdout }}" 75 | 76 | # Config file generation 77 | - name: copy app.toml 78 | when: app_toml_file is defined 79 | copy: 80 | src: '{{app_toml_file}}' 81 | dest: '{{gaiad_home}}/config/app.toml' 82 | owner: '{{gaiad_user}}' 83 | group: '{{gaiad_user}}' 84 | 85 | - name: copy config.toml 86 | when: config_toml_file is defined 87 | copy: 88 | src: '{{config_toml_file}}' 89 | dest: '{{gaiad_home}}/config/config.toml' 90 | owner: '{{gaiad_user}}' 91 | group: '{{gaiad_user}}' 92 | 93 | - name: copy node_key.json 94 | when: node_key_file is defined 95 | copy: 96 | src: '{{node_key_file}}' 97 | dest: '{{gaiad_home}}/config/node_key.json' 98 | owner: '{{gaiad_user}}' 99 | group: '{{gaiad_user}}' 100 | 101 | - name: copy priv_validator_key.json 102 | when: priv_validator_key_file is defined 103 | copy: 104 | src: '{{priv_validator_key_file}}' 105 | dest: '{{gaiad_home}}/config/priv_validator_key.json' 106 | owner: '{{gaiad_user}}' 107 | group: '{{gaiad_user}}' 108 | 109 | ## Addressbook config 110 | - name: copy addrbook.json 111 | when: addrbook_file is defined 112 | copy: 113 | src: '{{addrbook_file}}' 114 | dest: '{{gaiad_home}}/config/addrbook_file.json' 115 | owner: '{{gaiad_user}}' 116 | group: '{{gaiad_user}}' 117 | 118 | - name: download addrbook.json from URL 119 | when: addrbook_url is defined 120 | get_url: 121 | url: "{{addrbook_url}}" 122 | dest: "{{gaiad_home}}/config/addrbook.json" 123 | owner: '{{gaiad_user}}' 124 | group: '{{gaiad_user}}' 125 | 126 | ## Patching Config files 127 | - name: generate config json for patching toml files 128 | template: 129 | src: ansible_vars.json.j2 130 | dest: '{{gaiad_home}}/config/ansible_vars.json' 131 | owner: '{{gaiad_user}}' 132 | group: '{{gaiad_user}}' 133 | 134 | - name: patch .toml configs with ansible variables 135 | script: | 136 | copy_config_vars.py --gaiad_home=$(echo {{gaiad_home}}) \ 137 | --config_file=$(echo {{gaiad_home}}/config/ansible_vars.json) 138 | become_user: "{{gaiad_user}}" 139 | 140 | - name: delete generated config json 141 | file: 142 | state: absent 143 | path: '{{gaiad_home}}/config/ansible_vars.json' 144 | owner: '{{gaiad_user}}' 145 | group: '{{gaiad_user}}' 146 | -------------------------------------------------------------------------------- /tests/test_software_upgrade.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # Test a gaia software upgrade via governance proposal. 3 | # It assumes gaia is running on the local host. 4 | 5 | gaia_host=$1 6 | gaia_port=$2 7 | upgrade_version=$3 8 | 9 | echo "Attempting upgrade to $upgrade_version." 10 | 11 | # Add gaiad to PATH 12 | echo "Adding gaiad to PATH..." 13 | export PATH="$PATH:~/.gaia/cosmovisor/current/bin" 14 | echo "PATH=$PATH" 15 | 16 | # Auto set denom 17 | echo "Get denom from ~/.gaia/config/genesis.json" 18 | denom=$(jq -r '.app_state.gov.deposit_params.min_deposit[].denom' ~/.gaia/config/genesis.json) 19 | 20 | # Get the current gaia version from the API 21 | echo "Get the current gaia version from the API" 22 | chain_version=$(curl -s http://$gaia_host:$gaia_port/abci_info | jq -r .result.response.version) 23 | 24 | # Get chain-id from the API 25 | echo "Get chain-id from the API" 26 | chain_id=$(curl -s http://$gaia_host:$gaia_port/status | jq -r .result.node_info.network) 27 | 28 | # Submit upgrade proposal 29 | chain_version_major=${chain_version:1:1} 30 | echo "Current major version: $chain_version_major" 31 | 32 | upgrade_version_major=${upgrade_version:1:1} 33 | echo "Upgrade major version: $upgrade_version_major" 34 | major_difference=$[ $upgrade_version_major-$chain_version_major ] 35 | 36 | if [ $major_difference -eq 1 ]; then 37 | if [ $upgrade_version_major -eq 7 ]; then 38 | upgrade_name="v7-Theta" 39 | elif [ $upgrade_version_major -eq 8 ]; then 40 | upgrade_name="v8-Rho" 41 | fi 42 | fi 43 | 44 | if [ -n "$upgrade_name" ]; then 45 | echo "Upgrading to $upgrade_name." 46 | 47 | # Set time to wait for proposal to pass 48 | echo "Get voting_period from genesis file" 49 | voting_period=$(jq -r '.app_state.gov.voting_params.voting_period' ~/.gaia/config/genesis.json) 50 | voting_period_seconds=${voting_period::-1} 51 | echo "Using ($voting_period_seconds)s voting period to calculate the upgrade height." 52 | 53 | # Calculate upgrade height 54 | echo "Calculate upgrade height" 55 | let voting_blocks_delta=$voting_period_seconds/5+3 56 | height=$(curl -s http://$gaia_host:$gaia_port/block | jq -r .result.block.header.height) 57 | upgrade_height=$(($height+$voting_blocks_delta)) 58 | echo "Upgrade block height set to $upgrade_height." 59 | 60 | # Get validator address 61 | echo "Querying gaiad for the validator address..." 62 | validator_address=$(jq -r '.address' ~/.gaia/validator.json) 63 | echo "The validator has address $validator_address." 64 | 65 | # Auto download: Set the binary paths need for the proposal message 66 | download_path="https://github.com/cosmos/gaia/releases/download/$upgrade_version" 67 | upgrade_info="{\"binaries\":{\"linux/amd64\":\"$download_path/gaiad-$upgrade_version-linux-amd64\",\"linux/arm64\":\"$download_path/$upgrade_version/gaiad-$upgrade_version-linux-arm64\",\"darwin/amd64\":\"$download_path/gaiad-$upgrade_version-darwin-amd64\",\"windows/amd64\":\"$download_path/gaiad-$upgrade_version-windows-amd64.exe\"}}" 68 | proposal="gaiad --output json tx gov submit-proposal software-upgrade $upgrade_name --from $validator_address --keyring-backend test --upgrade-height $upgrade_height --upgrade-info $upgrade_info --title gaia-upgrade --description 'test' --chain-id $chain_id --deposit 10$denom --fees 1000$denom --yes" 69 | 70 | # Submit the proposal 71 | echo "Submitting the upgrade proposal." 72 | echo $proposal 73 | txhash=$($proposal | jq -r .txhash) 74 | 75 | # Wait for the proposal to go on chain 76 | sleep 8 77 | 78 | # Get proposal ID from txhash 79 | echo "Get proposal ID from txhash" 80 | proposal_id=$(gaiad --output json q tx $txhash | jq -r '.logs[].events[] | select(.type=="submit_proposal") | .attributes[] | select(.key=="proposal_id") | .value') 81 | 82 | # Vote yes on the proposal 83 | echo "Submitting the \"yes\" vote to proposal $proposal_id" 84 | vote="gaiad tx gov vote $proposal_id yes --from $validator_address --keyring-backend test --chain-id $chain_id --fees 1000$denom --yes" 85 | echo $vote 86 | $vote 87 | 88 | # Wait for the voting period to be over 89 | echo "Waiting for the voting period to end..." 90 | sleep 8 91 | 92 | echo "Upgrade proposal $proposal_id status:" 93 | gaiad q gov proposal $proposal_id --output json | jq '.status' 94 | 95 | # Wait until the right height is reached 96 | echo "Waiting for the upgrade to take place at block height $upgrade_height..." 97 | tests/test_block_production.sh $gaia_host $gaia_port $upgrade_height 98 | echo "The upgrade height was reached." 99 | 100 | # Test gaia response 101 | tests/test_gaia_response.sh $gaia_host $gaia_port 102 | 103 | # Get running version 104 | gaiad_upgraded_version=$(curl -s http://$gaia_host:$gaia_port/abci_info | jq -r .result.response.version) 105 | echo "Current gaiad version: $gaiad_upgraded_version" 106 | 107 | # Check upgraded version is the one we want 108 | if [[ "$gaiad_upgraded_version" != "$upgrade_version" ]]; then 109 | echo "Requested $upgrade_version, but detected $gaiad_upgraded_version." 110 | exit 4 111 | fi 112 | 113 | # Test block production 114 | tests/test_block_production.sh $gaia_host $gaia_port $[$upgrade_height+10] 115 | 116 | else 117 | echo "No upgrade name specified, skipping upgrade." 118 | fi 119 | -------------------------------------------------------------------------------- /roles/hermes/tasks/config.yml: -------------------------------------------------------------------------------- 1 | --- 2 | - name: Get chain IDs 3 | set_fact: 4 | chain_ids: "{{ hermes_chains.keys() | list }}" 5 | 6 | - name: Configure Hermes 7 | template: 8 | src: config.toml.j2 9 | dest: /home/{{ hermes_user }}/.hermes/config.toml 10 | become_user: "{{ hermes_user }}" 11 | 12 | - name: Upload key file from first chain 13 | copy: 14 | src: '{{ hermes_chains[chain_ids[0]].hermes_relayer_key }}' 15 | dest: '/home/{{ hermes_user }}/.hermes/{{ chain_ids[0] }}-relayer.json' 16 | owner: '{{hermes_user}}' 17 | group: '{{hermes_group}}' 18 | when: hermes_relayer_keys 19 | 20 | - name: Upload key file from second chain 21 | copy: 22 | src: '{{ hermes_chains[chain_ids[1]].hermes_relayer_key }}' 23 | dest: '/home/{{ hermes_user }}/.hermes/{{ chain_ids[1] }}-relayer.json' 24 | owner: '{{hermes_user}}' 25 | group: '{{hermes_group}}' 26 | when: hermes_relayer_keys 27 | 28 | - name: Add relayer keys 29 | shell: | 30 | hermes keys add --key-file /home/{{ hermes_user }}/.hermes/{{ chain_ids[0] }}-relayer.json --chain {{ chain_ids[0] }} --overwrite 31 | hermes keys add --key-file /home/{{ hermes_user }}/.hermes/{{ chain_ids[1] }}-relayer.json --chain {{ chain_ids[1] }} --overwrite 32 | environment: 33 | PATH: "/home/{{hermes_user}}/bin:{{ ansible_env.PATH }}" 34 | become_user: hermes 35 | when: hermes_relayer_keys 36 | 37 | - name: Upload mnemonic from first chain 38 | copy: 39 | src: '{{ hermes_chains[chain_ids[0]].hermes_relayer_mnemonic }}' 40 | dest: '/home/{{ hermes_user }}/.hermes/{{ chain_ids[0] }}-relayer.txt' 41 | owner: '{{hermes_user}}' 42 | group: '{{hermes_group}}' 43 | when: hermes_relayer_mnemonics 44 | 45 | - name: Upload mnemonic file from second chain 46 | copy: 47 | src: '{{ hermes_chains[chain_ids[1]].hermes_relayer_mnemonic }}' 48 | dest: '/home/{{ hermes_user }}/.hermes/{{ chain_ids[1] }}-relayer.txt' 49 | owner: '{{hermes_user}}' 50 | group: '{{hermes_group}}' 51 | when: hermes_relayer_mnemonics 52 | 53 | - name: Add relayer keys from mnemonics 54 | shell: | 55 | hermes keys add --mnemonic-file /home/{{ hermes_user }}/.hermes/{{ chain_ids[0] }}-relayer.txt --chain {{ chain_ids[0] }} --overwrite 56 | hermes keys add --mnemonic-file /home/{{ hermes_user }}/.hermes/{{ chain_ids[1] }}-relayer.txt --chain {{ chain_ids[1] }} --overwrite 57 | environment: 58 | PATH: "/home/{{hermes_user}}/bin:{{ ansible_env.PATH }}" 59 | become_user: hermes 60 | when: hermes_relayer_mnemonics 61 | 62 | - name: Create connection over new clients 63 | when: not hermes_set_clients 64 | shell: | 65 | hermes create connection --a-chain {{ chain_ids[0] }} --b-chain {{ chain_ids[1] }} 66 | environment: 67 | PATH: "/home/{{hermes_user}}/bin:{{ ansible_env.PATH }}" 68 | become_user: hermes 69 | 70 | - name: Create connection over existing clients 71 | when: hermes_set_clients 72 | shell: | 73 | hermes create connection --a-chain {{ chain_ids[0] }} --a-client {{ hermes_chains[chain_ids[0]].hermes_client_id }} --b-client {{ hermes_chains[chain_ids[1]].hermes_client_id }} 74 | environment: 75 | PATH: "/home/{{hermes_user}}/bin:{{ ansible_env.PATH }}" 76 | become_user: hermes 77 | 78 | - name: Obtain last connection 79 | shell: | 80 | hermes --json query connections --chain {{ chain_ids[0] }} | jq -r '.result[-1]' 81 | environment: 82 | PATH: "/home/{{hermes_user}}/bin:{{ ansible_env.PATH }}" 83 | register: connection_id 84 | become_user: hermes 85 | 86 | - name: Display last connection 87 | debug: 88 | msg: 89 | - "Last connection: {{ connection_id.stdout }}" 90 | 91 | - name: Create channel using last connection 92 | when: not hermes_set_channel_version 93 | shell: | 94 | hermes create channel --a-chain {{ chain_ids[0] }} \ 95 | --a-port {{ hermes_chains[chain_ids[0]].hermes_port_name}} \ 96 | --b-port {{ hermes_chains[chain_ids[1]].hermes_port_name}} \ 97 | --order {{ hermes_order }} --a-connection {{ connection_id.stdout }} 98 | environment: 99 | PATH: "/home/{{hermes_user}}/bin:{{ ansible_env.PATH }}" 100 | register: channel_creation 101 | become_user: hermes 102 | 103 | - name: Display channel creation output 104 | when: not hermes_set_channel_version 105 | debug: 106 | msg: "{{ channel_creation.stdout }}" 107 | 108 | - name: Create channel using last connection, set channel version 109 | when: hermes_set_channel_version 110 | shell: | 111 | hermes create channel --a-chain {{ chain_ids[0] }} \ 112 | --a-port {{ hermes_chains[chain_ids[0]].hermes_port_name}} \ 113 | --b-port {{ hermes_chains[chain_ids[1]].hermes_port_name}} \ 114 | --order {{ hermes_order }} --a-connection {{ connection_id.stdout }} \ 115 | --channel-version {{ hermes_channel_version }} 116 | environment: 117 | PATH: "/home/{{hermes_user}}/bin:{{ ansible_env.PATH }}" 118 | register: channel_creation_with_version 119 | become_user: hermes 120 | 121 | - name: Display channel creation output, set channel version 122 | when: hermes_set_channel_version 123 | debug: 124 | msg: "{{ channel_creation_with_version.stdout }}" 125 | 126 | - name: Save channel ids for last connection 127 | shell: | 128 | hermes --json query connection channels --chain {{ chain_ids[0] }} --connection {{ connection_id.stdout }} | jq -r '.result' > /home/{{ hermes_user }}/{{ chain_ids[0] }}-{{ connection_id.stdout }}.txt 129 | hermes --json query connection channels --chain {{ chain_ids[1] }} --connection {{ connection_id.stdout }} | jq -r '.result' > /home/{{ hermes_user }}/{{ chain_ids[1] }}-{{ connection_id.stdout }}.txt 130 | environment: 131 | PATH: "/home/{{hermes_user}}/bin:{{ ansible_env.PATH }}" 132 | become_user: hermes 133 | -------------------------------------------------------------------------------- /roles/node/templates/ansible_vars.json.j2: -------------------------------------------------------------------------------- 1 | { 2 | "app.toml": { 3 | "minimum-gas-prices": {{ minimum_gas_prices | to_json }}, 4 | "pruning": {{ pruning | to_json }}, 5 | "pruning-keep-recent": {{ pruning_keep_recent | to_json }}, 6 | "pruning-keep-every": {{ pruning_keep_every | to_json }}, 7 | "pruning-interval": {{ pruning_interval | to_json }}, 8 | "halt-height": {{ halt_height | to_json }}, 9 | "halt-time": {{ halt_time | to_json }}, 10 | "min-retain-blocks": {{ min_retain_blocks | to_json }}, 11 | "inter-block-cache": {{ inter_block_cache | to_json }}, 12 | "index-events": {{ index_events | to_json }}, 13 | "telemetry.service-name": {{ telemetry_service_name | to_json }}, 14 | "telemetry.enabled": {{ telemetry_enabled | to_json }}, 15 | "telemetry.enable-hostname": {{ telemetry_enable_hostname | to_json }}, 16 | "telemetry.enable-hostname-label": {{ telemetry_enable_hostname_label | to_json }}, 17 | "telemetry.enable-service-label": {{ telemetry_enable_service_label | to_json }}, 18 | "telemetry.prometheus-retention-time": {{ prometheus_retention_time | to_json }}, 19 | "telemetry.global-labels": {{ telemetry_global_labels | to_json }}, 20 | "api.enable": {{ api_enabled | to_json }}, 21 | "api.swagger": {{ api_swagger | to_json }}, 22 | "api.address": {{ api_address | to_json }}, 23 | "api.max-open-connections": {{ api_max_open_connections | to_json }}, 24 | "api.rpc-read-timeout": {{ api_rpc_read_timeout | to_json }}, 25 | "api.rpc-write-timeout": {{ api_rpc_write_timeout | to_json }}, 26 | "api.rpc-max-body-bytes": {{ api_rpc_max_body_bytes | to_json }}, 27 | "api.enabled-unsafe-cors": {{ api_enabled_unsafe_cors | to_json }}, 28 | "grpc.enable": {{ grpc_enabled | to_json }}, 29 | "grpc.address": "0.0.0.0:{{ grpc_port }}", 30 | "grpc-web.enable": {{ grpc_web_enabled | to_json }}, 31 | "grpc-web.address": "0.0.0.0:{{ grpc_web_port }}", 32 | "grpc-web.enable-unsafe-cors": {{ grpc_web_enable_unsafe_cors | to_json }}, 33 | "state-sync.snapshot-interval": {{ statesync_snapshot_interval | to_json }}, 34 | "state-sync.snapshot-keep-recent": {{ statesync_snapshot_keep_recent | to_json }} 35 | }, 36 | "config.toml": { 37 | "proxy_app": {{ config_proxy_app | to_json }}, 38 | "moniker": {{ chain_moniker | to_json }}, 39 | {% if major_version|int >= 8 %} 40 | "blocksync.enable": {{ fast_sync | to_json }}, 41 | "blocksync.version": {{ fastsync_version | to_json }}, 42 | {% else %} 43 | "fast_sync": {{ fast_sync | to_json }}, 44 | "fastsync.version": {{ fastsync_version | to_json }}, 45 | {% endif %} 46 | "genesis_file": {{ config_genesis_file | to_json }}, 47 | "priv_validator_key_file": {{ config_priv_validator_key_file | to_json }}, 48 | "priv_validator_state_file": {{ config_priv_validator_state_file | to_json }}, 49 | "priv_validator_laddr": {{ config_priv_validator_laddr | to_json }}, 50 | "node_key_file": {{ config_node_key_file | to_json }}, 51 | "filter_peers": {{ filter_peers | to_json }}, 52 | "abci": {{ abci | to_json }}, 53 | "rpc.laddr": {{ rpc_laddr | to_json }}, 54 | "rpc.cors_allowed_origins": {{ rpc_cors_allowed_origins | to_json }}, 55 | "rpc.cors_allowed_methods": {{ rpc_cors_allowed_methods | to_json }}, 56 | "rpc.cors_allowed_headers": {{ rpc_cors_allowed_headers | to_json }}, 57 | "rpc.grpc_laddr": {{ grpc_laddr | to_json }}, 58 | "rpc.grpc_max_open_connections": {{ grpc_max_open_connections | to_json }}, 59 | "rpc.unsafe": {{ rpc_unsafe | to_json }}, 60 | "rpc.max_open_connections": {{ rpc_max_open_connections | to_json }}, 61 | "rpc.max_subscription_clients": {{ rpc_max_subscription_clients | to_json }}, 62 | "rpc.max_subscriptions_per_client": {{ rpc_max_subscriptions_per_client | to_json }}, 63 | "rpc.timeout_broadcast_tx_commit": {{ rpc_timeout_broadcast_tx_commit | to_json }}, 64 | "rpc.max_body_bytes": {{ rpc_max_body_bytes | to_json }}, 65 | "rpc.max_header_bytes": {{ rpc_max_header_bytes | to_json }}, 66 | "rpc.tls_cert_file": {{ rpc_tls_cert_file | to_json }}, 67 | "rpc.tls_key_file": {{ rpc_tls_key_file | to_json }}, 68 | "rpc.pprof_laddr": {{ rpc_pprof_laddr | to_json }}, 69 | "p2p.laddr": {{ p2p_laddr | to_json }}, 70 | "p2p.external_address": {{ p2p_external_address | to_json }}, 71 | "p2p.seeds": {{ p2p_seeds | to_json }}, 72 | "p2p.persistent_peers": {{ p2p_persistent_peers | to_json }}, 73 | "p2p.upnp": {{ p2p_upnp | to_json }}, 74 | "p2p.addr_book_file": {{ p2p_addr_book_file | to_json }}, 75 | "p2p.addr_book_strict": {{ p2p_addr_book_strict | to_json }}, 76 | "p2p.max_num_inbound_peers": {{ p2p_max_num_inbound_peers | to_json }}, 77 | "p2p.max_num_outbound_peers": {{ p2p_max_num_outbound_peers | to_json }}, 78 | "p2p.unconditional_peer_ids": {{ p2p_unconditional_peer_ids | to_json }}, 79 | "p2p.pex": {{ p2p_pex | to_json }}, 80 | "p2p.seed_mode": {{ p2p_seed_mode | to_json }}, 81 | "p2p.private_peer_ids": {{ p2p_private_peer_ids | to_json }}, 82 | "p2p.allow_duplicate_ip": {{ p2p_allow_duplicate_ip | to_json }}, 83 | "p2p.handshake_timeout": {{ p2p_handshake_timeout | to_json }}, 84 | "p2p.dial_timeout": {{ p2p_dial_timeout | to_json }}, 85 | "statesync.enable": {{ statesync_enabled | to_json }}, 86 | "statesync.rpc_servers": {{ statesync_rpc_servers | to_json }}, 87 | "statesync.trust_height": {{ statesync_trust_height | to_json }}, 88 | "statesync.trust_hash": {{ statesync_trust_hash | to_json }}, 89 | "statesync.trust_period": {{ statesync_trust_period | to_json }}, 90 | "statesync.discovery_time": {{ statesync_discovery_time | to_json }}, 91 | "statesync.chunk_request_timeout": {{ statesync_chunk_request_timeout | to_json }}, 92 | "statesync.chunk_fetchers": {{ statesync_chunk_fetchers | to_json }}, 93 | "tx_index.indexer": {{ config_indexer | to_json }}, 94 | "instrumentation.prometheus": {{ prometheus_enabled | to_json }}, 95 | "instrumentation.prometheus_listen_addr": {{ prometheus_listen_addr | to_json }}, 96 | "instrumentation.max_open_connections": {{ instrumentation_max_open_connnections | to_json }}, 97 | "instrumentation.namespace": {{ instrumentation_namespace | to_json }} 98 | }, 99 | "client.toml": { 100 | "chain-id": {{ chain_id | to_json }}, 101 | "keyring-backend": {{ client_keyring_backend | to_json }}, 102 | "output": {{ client_output_format | to_json }}, 103 | "node": {{ client_rpc_interface | to_json }}, 104 | "broadcast-mode": {{ client_broadcast_mode | to_json }} 105 | } 106 | } 107 | -------------------------------------------------------------------------------- /roles/configure-panic/files/config_panic_nodes.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | # pylint: skip-file 4 | 5 | import configparser 6 | import sys 7 | import argparse 8 | 9 | # argparse 10 | parser = argparse.ArgumentParser( 11 | description='Configure PANIC user_config_nodes.ini file') 12 | subparser = parser.add_subparsers() 13 | parser.add_argument('--config_file', required=True) 14 | 15 | parser_add = subparser.add_parser('add') 16 | parser_add.add_argument('--node_name', required=True) 17 | parser_add.add_argument('--node_rpc_url', required=True) 18 | parser_add.add_argument('--node_rpc_port', required=True) 19 | parser_add.add_argument('--node_is_validator', required=True) 20 | parser_add.add_argument('--include_in_node_monitor', required=True) 21 | parser_add.add_argument('--include_in_network_monitor', required=True) 22 | parser_add.set_defaults(operation='add') 23 | 24 | parser_del = subparser.add_parser('del') 25 | parser_del.add_argument('--node_name', required=True) 26 | parser_del.set_defaults(operation='del') 27 | 28 | args = parser.parse_args() 29 | 30 | filename = args.config_file 31 | new_node_name = args.node_name 32 | operation = args.operation 33 | 34 | if operation == 'add': 35 | new_node_rpc_url = args.node_rpc_url 36 | new_node_rpc_port = args.node_rpc_port 37 | new_node_is_validator = args.node_is_validator 38 | new_include_in_node_monitor = args.include_in_node_monitor 39 | new_include_in_network_monitor = args.include_in_network_monitor 40 | 41 | node_found = 0 42 | node_count = 0 43 | config = configparser.ConfigParser() 44 | config.read(filename) 45 | 46 | new_config = configparser.ConfigParser() 47 | 48 | 49 | def reorder_nodes(): 50 | reorder_count = 0 51 | for node in config: 52 | try: 53 | if node != 'DEFAULT': 54 | new_node_id = ("node_" + str(reorder_count)) 55 | new_config[new_node_id] = {} 56 | new_config[new_node_id]['node_name'] = config[node]['node_name'] 57 | new_config[new_node_id]['node_rpc_url'] = config[node]['node_rpc_url'] 58 | new_config[new_node_id]['node_is_validator'] = config[node]['node_is_validator'] 59 | new_config[new_node_id]['include_in_node_monitor'] = config[node]['include_in_node_monitor'] 60 | new_config[new_node_id]['include_in_network_monitor'] = config[node]['include_in_network_monitor'] 61 | reorder_count = reorder_count + 1 62 | except: 63 | KeyError 64 | reorder_nodes.reorder_count = reorder_count 65 | return 66 | 67 | 68 | # add and update section 69 | if operation == 'add': 70 | # check if node already exists and update its values and if not add a new entry 71 | for node_key, node in config.items(): 72 | try: 73 | if config[node_key]['node_name'] == new_node_name: 74 | print("Node:", config[node_key]['node_name'], 75 | " already exists in key:", node_key) 76 | print('Updating the values') 77 | config[node_key]['node_rpc_url'] = ( 78 | "http://" + new_node_rpc_url + ":" + new_node_rpc_port) 79 | if new_node_is_validator == 'yes': 80 | config[node_key]['node_is_validator'] = 'true' 81 | else: 82 | config[node_key]['node_is_validator'] = 'false' 83 | 84 | if new_include_in_node_monitor == 'yes': 85 | config[node_key]['include_in_node_monitor'] = 'true' 86 | else: 87 | config[node_key]['include_in_node_monitor'] = 'false' 88 | 89 | if new_include_in_network_monitor == 'yes': 90 | config[node_key]['include_in_network_monitor'] = 'true' 91 | else: 92 | config[node_key]['include_in_network_monitor'] = 'false' 93 | node_found = True 94 | node_count = node_count + 1 95 | except: 96 | KeyError 97 | 98 | # if node_found is set write file and quit else add a new node 99 | if node_found == True: 100 | with open(filename, 'w') as configfile: 101 | config.write(configfile) 102 | print('Updated values in file') 103 | sys.exit(0) 104 | else: 105 | print("Node not found adding to the config") 106 | reorder_nodes() 107 | reorder_count = reorder_nodes.reorder_count 108 | new_node_id = ("node_" + str(reorder_count)) 109 | new_config[new_node_id] = {} 110 | new_config[new_node_id]['node_name'] = new_node_name 111 | new_config[new_node_id]['node_rpc_url'] = ( 112 | "http://" + new_node_rpc_url + ":" + new_node_rpc_port) 113 | if new_node_is_validator == 'yes': 114 | new_config[new_node_id]['node_is_validator'] = 'true' 115 | else: 116 | new_config[new_node_id]['node_is_validator'] = 'false' 117 | 118 | if new_include_in_node_monitor == 'yes': 119 | new_config[new_node_id]['include_in_node_monitor'] = 'true' 120 | else: 121 | new_config[new_node_id]['include_in_node_monitor'] = 'false' 122 | 123 | if new_include_in_network_monitor == 'yes': 124 | new_config[new_node_id]['include_in_network_monitor'] = 'true' 125 | else: 126 | new_config[new_node_id]['include_in_network_monitor'] = 'false' 127 | 128 | with open(filename, 'w') as configfile: 129 | new_config.write(configfile) 130 | print('Added new node to file') 131 | sys.exit(0) 132 | 133 | # delete section 134 | elif operation == 'del': 135 | node_count = 0 136 | del_node_name = new_node_name 137 | for node in config: 138 | try: 139 | if config[node]['node_name'] == del_node_name: 140 | node_found = True 141 | node_num = node_count 142 | node_count = node_count + 1 143 | except: 144 | KeyError 145 | 146 | if node_found != True: 147 | print('Cannot find node:', del_node_name, 'to delete') 148 | sys.exit(1) 149 | else: 150 | print('Found node:', del_node_name, 'deleting...') 151 | node_id = ("node_" + str(node_num)) 152 | config.remove_section(node_id) 153 | reorder_nodes() 154 | with open(filename, 'w') as configfile: 155 | new_config.write(configfile) 156 | sys.exit(0) 157 | -------------------------------------------------------------------------------- /roles/bigdipper/tasks/bdjuno.yml: -------------------------------------------------------------------------------- 1 | --- 2 | 3 | - name: "Checkout BDJuno" 4 | become_user: "{{bigdipper_user}}" 5 | git: 6 | repo: 'https://github.com/forbole/bdjuno.git' 7 | dest: "{{bdjuno_dir}}" 8 | version: chains/evmos/mainnet 9 | update: yes 10 | force: yes 11 | 12 | - name: "Install postgres" 13 | apt: 14 | state: present 15 | pkg: 16 | - postgresql 17 | - postgresql-contrib 18 | 19 | - name: Configure PostgreSQL. Set listen_addresses. 20 | lineinfile: dest=/etc/postgresql/{{ postgresql_version }}/main/postgresql.conf 21 | regexp="listen_addresses =" line="listen_addresses = '*'" state=present 22 | 23 | - name: Configure pg_hba.conf 24 | lineinfile: dest=/etc/postgresql/{{ postgresql_version }}/main/pg_hba.conf 25 | line="host {{ bigdipper_db }} {{ bigdipper_db_user }} {{ hasura_cloud_id }}/32 md5" 26 | 27 | - name: restart postgresql services 28 | systemd: 29 | daemon_reload: true 30 | state: restarted 31 | enabled: true 32 | name: postgresql.service 33 | 34 | - name: Remove old database 35 | become_user: postgres 36 | community.postgresql.postgresql_db: 37 | name: "{{bigdipper_db}}" 38 | state: absent 39 | 40 | - name: Create postgres database 41 | become_user: postgres 42 | community.postgresql.postgresql_db: 43 | name: "{{bigdipper_db}}" 44 | 45 | - name: Configure users on postgres 46 | become_user: postgres 47 | community.postgresql.postgresql_user: 48 | db: "{{bigdipper_db}}" 49 | name: "{{bigdipper_db_user}}" 50 | password: "{{bigdipper_db_password}}" 51 | 52 | - name: Grant user access to database 53 | become_user: postgres 54 | community.postgresql.postgresql_privs: 55 | db: "{{bigdipper_db}}" 56 | privs: ALL 57 | type: database 58 | obj: "{{bigdipper_db}}" 59 | role: "{{bigdipper_db_user}}" 60 | 61 | - name: Find bdjuno schema files 62 | find: 63 | paths: "{{bdjuno_dir}}/database/schema" 64 | register: bdjuno_schemas 65 | 66 | - name: Run postgresql bdjuno setup scripts 67 | community.postgresql.postgresql_script: 68 | db: "{{bigdipper_db}}" 69 | path: "{{ item.path }}" 70 | login_user: "{{bigdipper_db_user}}" 71 | login_password: "{{bigdipper_db_password}}" 72 | login_host: "127.0.0.1" 73 | with_items: "{{ bdjuno_schemas.files | sort(attribute='path') }}" 74 | 75 | - name: "Install BDJuno" 76 | become_user: "{{bigdipper_user}}" 77 | shell: | 78 | export PATH=$PATH:/usr/local/go/bin:/home/{{bigdipper_user}}/go/bin 79 | cd {{bdjuno_dir}} 80 | make install 81 | bdjuno init --home {{bdjuno_home}} --replace 82 | args: 83 | executable: /bin/bash 84 | 85 | # Copy config over from template? 86 | - name: "Generate bdjuno config" 87 | become_user: "{{bigdipper_user}}" 88 | template: 89 | src: bdjuno-config.yaml.j2 90 | dest: "{{bdjuno_home}}/config.yaml" 91 | 92 | # Copy genesis file or download from URL: we want it in {{bdujo_home}}/genesis.json 93 | - name: check if genesis_file is gz or not 94 | when: genesis_file is defined 95 | stat: 96 | path: '{{genesis_file}}' 97 | get_mime: true 98 | delegate_to: localhost 99 | become: false 100 | register: file_type 101 | 102 | - name: File type of {{genesis_file}} 103 | when: genesis_file is defined 104 | debug: 105 | msg: '{{file_type.stat.mimetype}}' 106 | 107 | - name: gzip the file if not zipped 108 | when: 109 | - genesis_file is defined 110 | - file_type.stat.mimetype == "text/plain" 111 | archive: 112 | path: '{{genesis_file}}' 113 | dest: '{{genesis_file}}.gz' 114 | format: gz 115 | delegate_to: localhost 116 | become: false 117 | 118 | - name: set genesis_file to include .gz 119 | when: 120 | - genesis_file is defined 121 | - file_type.stat.mimetype == "text/plain" 122 | set_fact: 123 | genesis_file: '{{ genesis_file }}.gz' 124 | 125 | - name: copy {{genesis_file}} to remote server 126 | when: genesis_file is defined 127 | copy: 128 | src: '{{genesis_file}}' 129 | dest: '{{bigdipper_user_home}}/genesis.json.gz' 130 | owner: '{{bigdipper_user}}' 131 | group: '{{bigdipper_user}}' 132 | 133 | - name: extract {{genesis_file}} to {{bdjuno_home}}/genesis.json 134 | when: genesis_file is defined 135 | shell: | 136 | gunzip -c $HOME/genesis.json.gz > {{bdjuno_home}}/genesis.json 137 | become_user: "{{bigdipper_user}}" 138 | 139 | - name: download genesis file 140 | when: genesis_url is defined 141 | get_url: 142 | url: "{{genesis_url}}" 143 | dest: "{{ bigdipper_user_home }}/genesis.data" 144 | mode: 0644 145 | become_user: "{{bigdipper_user}}" 146 | 147 | - name: Check file type of downloaded genesis file 148 | when: genesis_url is defined 149 | stat: 150 | path: '{{bigdipper_user_home}}/genesis.data' 151 | get_mime: true 152 | register: file_type 153 | 154 | - name: File type of {{bigdipper_user_home}}/genesis.data 155 | when: genesis_url is defined 156 | debug: 157 | msg: '{{file_type.stat.mimetype}}' 158 | 159 | - name: Extract the file if genesis is gzip 160 | when: 161 | - genesis_url is defined 162 | - file_type.stat.mimetype == "application/gzip" 163 | shell: | 164 | gunzip -c $HOME/genesis.data > {{bdjuno_home}}/genesis.json 165 | become_user: "{{bigdipper_user}}" 166 | 167 | - name: Copy non-zipped genesis to genesis config (plain text) 168 | when: 169 | - genesis_url is defined 170 | - file_type.stat.mimetype == "text/plain" 171 | copy: 172 | src: '{{bigdipper_user_home}}/genesis.data' 173 | dest: '{{bdjuno_home}}/genesis.json' 174 | owner: '{{bigdipper_user}}' 175 | group: '{{bigdipper_user}}' 176 | remote_src: true 177 | 178 | - name: Copy non-zipped genesis to genesis config (json) 179 | when: 180 | - genesis_url is defined 181 | - file_type.stat.mimetype == "application/json" 182 | copy: 183 | src: '{{bigdipper_user_home}}/genesis.data' 184 | dest: '{{bdjuno_home}}/genesis.json' 185 | owner: '{{bigdipper_user}}' 186 | group: '{{bigdipper_user}}' 187 | remote_src: true 188 | 189 | - name: "Parse genesis file with bdjuno" 190 | become_user: "{{bigdipper_user}}" 191 | shell: | 192 | export PATH=$PATH:/usr/local/go/bin:/home/{{bigdipper_user}}/go/bin 193 | bdjuno parse genesis-file --home {{bdjuno_home}} --genesis-file-path {{bdjuno_home}}/genesis.json 194 | 195 | - name: "Set up bdjuno systemd service" 196 | template: 197 | src: bdjuno.service.j2 198 | dest: "/etc/systemd/system/{{bdjuno_service_name}}.service" 199 | 200 | - name: "Restart journalctl: the logs must flow" 201 | systemd: 202 | state: restarted 203 | name: systemd-journald 204 | 205 | - name: "Run bdjuno systemd service" 206 | systemd: 207 | daemon_reload: true 208 | state: restarted 209 | enabled: true 210 | name: "{{bdjuno_service_name}}" 211 | -------------------------------------------------------------------------------- /roles/node/defaults/main.yml: -------------------------------------------------------------------------------- 1 | --- 2 | # General settings 3 | chain_binary_name: cascadiad 4 | node_user: ubuntu 5 | node_user_home: "/home/{{node_user}}" 6 | chain_home: "{{node_user_home}}/.cascadiad" 7 | chain_home_clear: false 8 | node_unsafe_reset: false 9 | chain_version: v0.1.1 10 | chain_registry: https://raw.githubusercontent.com/CascadiaFoundation/cascadia-chain/master/chain.json 11 | chain_repository: https://github.com/CascadiaFoundation/cascadia-chain.git 12 | chain_config_repository: https://github.com/CascadiaFoundation/chain-configuration.git 13 | chain_binary_release: "https://github.com/CascadiaFoundation/cascadia-chain/releases/download/{{ chain_version }}/cascadiad-{{ chain_version }}-{{binary_arch_map[ansible_architecture]}}" 14 | chain_binary_source: "build" 15 | chain_bin: "{{ node_user_home }}/go/bin/{{chain_binary_name}}" 16 | node_service_name: "cascadiad" 17 | chain_gov_testing: false 18 | chain_voting_period: 10s 19 | chain_denom: uCC 20 | chain_id: "cosmos-testnet" 21 | chain_repo_dir: "{{ node_user_home }}/cascadia-chain" 22 | chain_config_repo_dir: "{{ node_user_home }}/chain-configuration" 23 | chain_moniker: "{{inventory_hostname}}" 24 | chain_start: true 25 | chain_recover_delegator: false 26 | delegator_account_name: delegator 27 | delegator_account_coins: "1000000000000" 28 | validator_moniker: "{{inventory_hostname}}" 29 | 30 | # Default variables for creating a validator 31 | chain_create_validator: false 32 | chain_recover_validator: false 33 | chain_gentx_validator: "8000000000" 34 | node_keyring: "test" 35 | chain_validator_coins: "1000000000000" 36 | 37 | # Default variables for airdropping tokens 38 | chain_airdrop: false 39 | chain_airdrop_coins: "1000000000" 40 | chain_airdrop_accounts: [] 41 | 42 | # Cosmovisor settings 43 | # TODO: Support arbitrary cosmovisor branches 44 | use_cosmovisor: true 45 | cosmovisor_version: v1.0.0 46 | cosmovisor_repository: github.com/cosmos/cosmos-sdk/cosmovisor/cmd/cosmovisor 47 | cosmovisor_bin: "{{node_user_home}}/go/bin/cosmovisor" 48 | cosmovisor_home: "{{ chain_home }}/cosmovisor" 49 | cosmovisor_service_name: "cosmovisor" 50 | cosmovisor_skip_backup: true 51 | cosmovisor_invariants_flag: "--x-crisis-skip-assert-invariants " 52 | 53 | # Go configuration 54 | go_arch: "{{binary_arch_map[ansible_architecture]}}" 55 | go_version: 1.18.5 56 | 57 | # app.toml 58 | ## app.toml: Base Configuration 59 | minimum_gas_prices: '0{{ chain_denom }}' 60 | pruning: nothing 61 | pruning_keep_recent: '0' 62 | pruning_keep_every: '0' 63 | pruning_interval: '0' 64 | halt_height: '0' 65 | halt_time: '0' 66 | min_retain_blocks: '0' 67 | inter_block_cache: true 68 | index_events: [] 69 | ## app.toml: Telemetry Configuration 70 | telemetry_service_name: '' 71 | telemetry_enabled: false 72 | telemetry_enable_hostname: false 73 | telemetry_enable_hostname_label: false 74 | telemetry_enable_service_label: false 75 | prometheus_retention_time: '0' 76 | telemetry_global_labels: [] 77 | ## app.toml: API Configuration 78 | api_enabled: false 79 | api_swagger: false 80 | api_port: '1317' 81 | api_address: tcp://0.0.0.0:{{ api_port }} 82 | api_max_open_connections: 1000 83 | api_rpc_read_timeout: 10 84 | api_rpc_write_timeout: 0 85 | api_rpc_max_body_bytes: 1000000 86 | api_enabled_unsafe_cors: false 87 | ## app.toml: gRPC Configuration 88 | grpc_enabled: true 89 | grpc_port: 9090 90 | ## app.toml: gRPC Web Configuration 91 | grpc_web_enabled: true 92 | grpc_web_port: 9091 93 | grpc_web_enable_unsafe_cors: false 94 | ## app.toml: State Sync Configuration 95 | statesync_snapshot_interval: 0 96 | statesync_snapshot_keep_recent: 2 97 | 98 | # config.toml 99 | # config.toml: Base Config 100 | config_proxy_app: 'tcp://127.0.0.1:26658' 101 | fast_sync: true 102 | config_genesis_file: 'config/genesis.json' 103 | config_priv_validator_key_file: 'config/priv_validator_key.json' 104 | config_priv_validator_state_file: 'data/priv_validator_state.json' 105 | config_priv_validator_laddr: '' 106 | config_node_key_file: 'config/node_key.json' 107 | filter_peers: false 108 | abci: socket 109 | ## config.toml: RPC Config 110 | rpc_port: 26657 111 | rpc_laddr: tcp://0.0.0.0:{{ rpc_port }} 112 | rpc_cors_allowed_origins: [] 113 | rpc_cors_allowed_methods: ["HEAD", "GET", "POST"] 114 | rpc_cors_allowed_headers: ["Origin", "Accept", "Content-Type", "X-Requested-With", "X-Server-Time"] 115 | grpc_laddr: '' 116 | grpc_max_open_connections: 900 117 | rpc_unsafe: false 118 | rpc_max_open_connections: 900 119 | rpc_max_subscription_clients: 100 120 | rpc_max_subscriptions_per_client: 5 121 | rpc_timeout_broadcast_tx_commit: 10s 122 | rpc_max_body_bytes: 1000000 123 | rpc_max_header_bytes: 1048576 124 | rpc_tls_cert_file: '' 125 | rpc_tls_key_file: '' 126 | rpc_pprof_port: 6060 127 | rpc_pprof_laddr: localhost:{{ rpc_pprof_port }} 128 | ## config.toml: P2P Config 129 | p2p_port: '26656' 130 | p2p_laddr: tcp://0.0.0.0:{{ p2p_port }} 131 | p2p_external_address: '' 132 | p2p_seeds: '' 133 | p2p_persistent_peers: '' 134 | p2p_upnp: false 135 | p2p_addr_book_file: 'config/addrbook.json' 136 | p2p_addr_book_strict: true 137 | p2p_max_num_inbound_peers: 40 138 | p2p_max_num_outbound_peers: 10 139 | p2p_unconditional_peer_ids: '' 140 | p2p_pex: true 141 | p2p_seed_mode: false 142 | p2p_private_peer_ids: false 143 | p2p_allow_duplicate_ip: false 144 | p2p_handshake_timeout: 20s 145 | p2p_dial_timeout: 3s 146 | ## config.toml: State Sync Config 147 | statesync_enabled: false 148 | statesync_rpc_servers: '' 149 | statesync_trust_height: 0 150 | statesync_trust_hash: '' 151 | statesync_trust_period: 168h0m0s 152 | statesync_discovery_time: 15s 153 | statesync_chunk_request_timeout: 10s 154 | statesync_chunk_fetchers: '4' 155 | statesync_auto_populate: true 156 | ## config.toml: Fast Sync Config 157 | fastsync_version: v0 158 | ## config.toml: Transaction Indexer Config 159 | config_indexer: kv 160 | ## config.toml: Instrumentation Config 161 | prometheus_enabled: false 162 | prometheus_listen_addr: :26660 163 | instrumentation_max_open_connnections: 3 164 | instrumentation_namespace: tendermint 165 | 166 | # client.toml 167 | client_keyring_backend: test 168 | client_output_format: text 169 | client_rpc_interface: "tcp://localhost:{{ rpc_port }}" 170 | client_broadcast_mode: sync 171 | 172 | # Faucet settings 173 | faucet_enabled: true 174 | faucet_mnemonic: "" 175 | 176 | # Node Exporter config 177 | node_exporter_port: 9100 178 | 179 | # Prometheus / Grafana defaults 180 | grafana_ssh_url: root@monitor.testnet.com 181 | monitoring_prometheus: false 182 | 183 | # PANIC monitoring 184 | panic_ssh_url: root@monitor.testnet.com 185 | monitoring_panic: false 186 | panic_config_file: /home/panic/panic_cosmos/config/user_config_nodes.ini 187 | panic_is_validator: 'no' 188 | panic_include_in_node_monitor: 'yes' 189 | panic_include_in_network_monitor: 'yes' 190 | 191 | # Reboot after setup 192 | reboot: true 193 | 194 | # Vars with no defaults (to prevent code from running) 195 | # These don't get put into config files 196 | # genesis_url: "" 197 | # genesis_file: "" 198 | # addrbook_file: "" 199 | # addrbook_url: "https://quicksync.io/addrbook.cosmos.json" 200 | # node_key_file: "" 201 | # priv_validator_key_file 202 | 203 | # Architecture mapping 204 | binary_arch_map: 205 | aarch64: "linux-arm64" 206 | x86_64: "linux-amd64" 207 | 208 | # Multi-validator deployment 209 | start_multinode: false 210 | sync_multinode_genesis: false 211 | dynamic_p2p_persistent_peers: false 212 | --------------------------------------------------------------------------------