From a88362022b8587b1059314b59e4afc851c0dba8d Mon Sep 17 00:00:00 2001 From: vivekgsharma Date: Tue, 3 Mar 2026 14:12:32 +0000 Subject: [PATCH 01/30] fix exit before apply --- .github/workflows/create-devnet.yml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.github/workflows/create-devnet.yml b/.github/workflows/create-devnet.yml index c1475573..a93e5504 100644 --- a/.github/workflows/create-devnet.yml +++ b/.github/workflows/create-devnet.yml @@ -257,6 +257,9 @@ jobs: cat "$TFVARS_FILE" - name: Deploy devnet (Terraform + Ansible) + env: + TF_IN_AUTOMATION: "true" + TF_CLI_ARGS_apply: "-auto-approve" run: | echo "============================================" echo "Deploying $NETWORK_NAME" From f06a0e4625853f6b12d36aa38d7a554055edaa42 Mon Sep 17 00:00:00 2001 From: vivekgsharma Date: Tue, 3 Mar 2026 15:23:29 +0000 Subject: [PATCH 02/30] fix main_domain is empty in generated .tfvars --- .github/workflows/create-devnet.yml | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/.github/workflows/create-devnet.yml b/.github/workflows/create-devnet.yml index a93e5504..8d1135ba 100644 --- a/.github/workflows/create-devnet.yml +++ b/.github/workflows/create-devnet.yml @@ -236,9 +236,21 @@ jobs: DISK_SIZE: ${{ github.event.inputs.hpmn_disk_size }} run: | TFVARS_FILE="networks/$NETWORK_NAME.tfvars" + DEFAULT_MAIN_DOMAIN="networks.dash.org" # Read current value from file (empty if not set) CURRENT_SIZE=$(grep -oP 'hpmn_node_disk_size\s*=\s*\K[0-9]+' "$TFVARS_FILE" 2>/dev/null || echo "") + CURRENT_MAIN_DOMAIN=$(grep -oP 'main_domain\s*=\s*"\K[^"]*' "$TFVARS_FILE" 2>/dev/null || echo "") + + # Generated tfvars leaves main_domain empty; ensure ACM DNS names are valid. + if [[ -z "$CURRENT_MAIN_DOMAIN" ]]; then + echo "Setting main_domain to $DEFAULT_MAIN_DOMAIN..." + if grep -q '^main_domain\s*=' "$TFVARS_FILE"; then + sed -i "s|^main_domain\\s*=.*|main_domain = \"$DEFAULT_MAIN_DOMAIN\"|" "$TFVARS_FILE" + else + echo "main_domain = \"$DEFAULT_MAIN_DOMAIN\"" >> "$TFVARS_FILE" + fi + fi if [[ -n "$DISK_SIZE" && "$DISK_SIZE" != "$CURRENT_SIZE" ]]; then if [[ ! "$DISK_SIZE" =~ ^[0-9]+$ ]]; then From 23c40811ecae89b5c83d4e19fe846022617e0242 Mon Sep 17 00:00:00 2001 From: vivekgsharma Date: Tue, 3 Mar 2026 16:23:26 +0000 Subject: [PATCH 03/30] fix : congi repo psuh --- .github/workflows/create-devnet.yml | 21 +++++++++++++++++---- 1 file changed, 17 insertions(+), 4 deletions(-) diff --git a/.github/workflows/create-devnet.yml b/.github/workflows/create-devnet.yml index 8d1135ba..e5f69613 100644 --- a/.github/workflows/create-devnet.yml +++ b/.github/workflows/create-devnet.yml @@ -282,14 +282,27 @@ jobs: ./bin/deploy -f "$NETWORK_NAME" - name: Push configs to dash-network-configs + if: always() run: | # Clone the configs repo to a temp directory git clone git@github.com:dashpay/dash-network-configs.git /tmp/dash-network-configs - # Copy generated config files - cp "networks/$NETWORK_NAME.yml" /tmp/dash-network-configs/ - cp "networks/$NETWORK_NAME.tfvars" /tmp/dash-network-configs/ - cp "networks/$NETWORK_NAME.inventory" /tmp/dash-network-configs/ + # Copy generated config files if present + COPIED=0 + for ext in yml tfvars inventory; do + SRC="networks/$NETWORK_NAME.$ext" + if [[ -f "$SRC" ]]; then + cp "$SRC" /tmp/dash-network-configs/ + COPIED=$((COPIED + 1)) + else + echo "Skipping missing file: $SRC" + fi + done + + if [[ $COPIED -eq 0 ]]; then + echo "No config files found to push" + exit 0 + fi # Commit and push cd /tmp/dash-network-configs From 788758219bbc1ae68e407a17699610409bfb6fc4 Mon Sep 17 00:00:00 2001 From: vivekgsharma Date: Tue, 3 Mar 2026 17:11:10 +0000 Subject: [PATCH 04/30] Harden create-devnet: retry ET repo, fix tfvars main_domain, improve config push --- .github/workflows/create-devnet.yml | 23 ++++++++++++++++++- ansible/roles/eternal_terminal/tasks/main.yml | 4 ++++ .../generateTerraformConfig.js | 2 +- 3 files changed, 27 insertions(+), 2 deletions(-) diff --git a/.github/workflows/create-devnet.yml b/.github/workflows/create-devnet.yml index e5f69613..b7355e40 100644 --- a/.github/workflows/create-devnet.yml +++ b/.github/workflows/create-devnet.yml @@ -124,6 +124,7 @@ jobs: env: DEPLOY_SERVER_KEY: ${{ secrets.DEPLOY_SERVER_KEY }} EVO_APP_DEPLOY_KEY: ${{ secrets.EVO_APP_DEPLOY_KEY }} + EVO_APP_DEPLOY_WRITE_KEY: ${{ secrets.EVO_APP_DEPLOY_WRITE_KEY }} run: | mkdir -p ~/.ssh @@ -139,6 +140,12 @@ jobs: printf '%s\n' "$EVO_APP_DEPLOY_KEY" > ~/.ssh/id_ed25519 chmod 600 ~/.ssh/id_ed25519 + # Optional write key for pushing to configs repo + if [[ -n "$EVO_APP_DEPLOY_WRITE_KEY" ]]; then + printf '%s\n' "$EVO_APP_DEPLOY_WRITE_KEY" > ~/.ssh/id_ed25519_write + chmod 600 ~/.ssh/id_ed25519_write + fi + # SSH config cat > ~/.ssh/config << 'EOL' Host github.com @@ -283,6 +290,8 @@ jobs: - name: Push configs to dash-network-configs if: always() + env: + EVO_APP_DEPLOY_WRITE_KEY: ${{ secrets.EVO_APP_DEPLOY_WRITE_KEY }} run: | # Clone the configs repo to a temp directory git clone git@github.com:dashpay/dash-network-configs.git /tmp/dash-network-configs @@ -310,7 +319,19 @@ jobs: git config user.email "actions@github.com" git add . git commit -m "Add configs for $NETWORK_NAME" || echo "No changes to commit" - git push + + # Use optional write key if configured; otherwise try default key. + if [[ -n "$EVO_APP_DEPLOY_WRITE_KEY" && -f "$HOME/.ssh/id_ed25519_write" ]]; then + GIT_SSH_COMMAND='ssh -i ~/.ssh/id_ed25519_write -o StrictHostKeyChecking=no' git push || { + echo "::warning::Failed to push configs with EVO_APP_DEPLOY_WRITE_KEY" + exit 0 + } + else + git push || { + echo "::warning::Failed to push configs (likely read-only EVO_APP_DEPLOY_KEY). Configure secret EVO_APP_DEPLOY_WRITE_KEY with write access." + exit 0 + } + fi echo "Configs pushed to dash-network-configs repo" diff --git a/ansible/roles/eternal_terminal/tasks/main.yml b/ansible/roles/eternal_terminal/tasks/main.yml index d471e9a8..d18b7b80 100644 --- a/ansible/roles/eternal_terminal/tasks/main.yml +++ b/ansible/roles/eternal_terminal/tasks/main.yml @@ -5,6 +5,10 @@ repo: ppa:jgmath2000/et state: present update_cache: true + register: et_repo + retries: 5 + delay: 20 + until: et_repo is succeeded - name: Install ET ansible.builtin.package: diff --git a/lib/configGenerator/generateTerraformConfig.js b/lib/configGenerator/generateTerraformConfig.js index 90834d31..235a62ed 100644 --- a/lib/configGenerator/generateTerraformConfig.js +++ b/lib/configGenerator/generateTerraformConfig.js @@ -18,7 +18,7 @@ async function generateTerraformConfig( masternode_arm_count: masternodesArmCount, hp_masternode_amd_count: hpMasternodesAmdCount, hp_masternode_arm_count: hpMasternodesArmCount, - main_domain: '""', + main_domain: '"networks.dash.org"', main_host_arch: '"arm64"', create_eip: false, }; From c080f7e9fac4320f8f1fdb2ccb9954078fc33d9e Mon Sep 17 00:00:00 2001 From: vivekgsharma Date: Tue, 3 Mar 2026 18:53:39 +0000 Subject: [PATCH 05/30] [infra] fix destory workfllow --- .github/workflows/destroy-devnet.yml | 3 +++ ansible/roles/dashd/defaults/main.yml | 3 +++ ansible/roles/dashd/tasks/main.yml | 13 ++++++++----- 3 files changed, 14 insertions(+), 5 deletions(-) diff --git a/.github/workflows/destroy-devnet.yml b/.github/workflows/destroy-devnet.yml index a359bafa..d4b7b067 100644 --- a/.github/workflows/destroy-devnet.yml +++ b/.github/workflows/destroy-devnet.yml @@ -190,6 +190,9 @@ jobs: echo "" - name: Destroy devnet + env: + TF_IN_AUTOMATION: "true" + TF_CLI_ARGS_destroy: "-auto-approve" run: | chmod +x ./bin/destroy ./bin/destroy "$NETWORK_NAME" -t="$DESTROY_TARGET" diff --git a/ansible/roles/dashd/defaults/main.yml b/ansible/roles/dashd/defaults/main.yml index b9c52316..db93fb72 100644 --- a/ansible/roles/dashd/defaults/main.yml +++ b/ansible/roles/dashd/defaults/main.yml @@ -16,3 +16,6 @@ dashd_allowprivatenet: '{% if dashd_externalip | ansible.utils.ipaddr("private") dashd_compose_project_name: dashcore dashd_compose_path: '{{ dashd_home }}/{{ dashd_compose_project_name }}' + +# Wallet operations are only enabled on dedicated wallet nodes. +enable_wallet: false diff --git a/ansible/roles/dashd/tasks/main.yml b/ansible/roles/dashd/tasks/main.yml index 43ed00c7..4f43870e 100644 --- a/ansible/roles/dashd/tasks/main.yml +++ b/ansible/roles/dashd/tasks/main.yml @@ -101,7 +101,7 @@ block: | wallet={{ wallet_rpc_wallet_faucet }} wallet={{ wallet_rpc_wallet_mno }} - when: enable_wallet is true and wallet_exists.stat.exists is true + when: (enable_wallet | default(false) | bool) and wallet_exists.stat.exists is true # TODO: why does this always take exactly 30 seconds on first deploy? - name: Start dash core @@ -126,14 +126,14 @@ cmd: dash-cli createwallet {{ wallet_rpc_wallet_faucet }} creates: "{{ dashd_home }}/.dashcore/{{ dash_network_name if dash_network == 'devnet' else 'testnet3' }}/wallets/{{ wallet_rpc_wallet_faucet }}/wallet.dat" register: create_faucet_wallet_result - when: enable_wallet is true + when: enable_wallet | default(false) | bool - name: Create mno wallet ansible.builtin.command: cmd: dash-cli createwallet {{ wallet_rpc_wallet_mno }} creates: "{{ dashd_home }}/.dashcore/{{ dash_network_name if dash_network == 'devnet' else 'testnet3' }}/wallets/{{ wallet_rpc_wallet_mno }}/wallet.dat" register: create_mno_wallet_result - when: enable_wallet is true + when: enable_wallet | default(false) | bool - name: Load wallets on startup ansible.builtin.blockinfile: @@ -142,10 +142,13 @@ block: | wallet={{ wallet_rpc_wallet_faucet }} wallet={{ wallet_rpc_wallet_mno }} - when: create_faucet_wallet_result.changed and create_mno_wallet_result.changed + when: > + (enable_wallet | default(false) | bool) and + (create_faucet_wallet_result is defined and create_faucet_wallet_result.changed) and + (create_mno_wallet_result is defined and create_mno_wallet_result.changed) - name: Import faucet privkey ansible.builtin.command: dash-cli -rpcwallet={{ wallet_rpc_wallet_faucet }} importprivkey {{ faucet_privkey }} register: result - when: enable_wallet is true + when: enable_wallet | default(false) | bool changed_when: result.rc == 0 From ebfe46c82c309e68213e9107097281e4e8b813c3 Mon Sep 17 00:00:00 2001 From: vivekgsharma Date: Tue, 3 Mar 2026 20:54:32 +0000 Subject: [PATCH 06/30] Fix filebeat SSL conditional for newer ansible-core --- ansible/roles/core_filebeat/vars/common.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/ansible/roles/core_filebeat/vars/common.yml b/ansible/roles/core_filebeat/vars/common.yml index 4567afcd..703c44ae 100644 --- a/ansible/roles/core_filebeat/vars/common.yml +++ b/ansible/roles/core_filebeat/vars/common.yml @@ -18,3 +18,5 @@ filebeat_output_elasticsearch_auth: password: "{{ elastic_password }}" filebeat_enable_logging: true filebeat_log_level: info +# Keep SSL key var boolean to satisfy strict conditionals in newer ansible-core. +filebeat_ssl_key_file: false From 153a9faf736519ef07791f416141e6926a513366 Mon Sep 17 00:00:00 2001 From: vivekgsharma Date: Thu, 5 Mar 2026 06:20:16 +0000 Subject: [PATCH 07/30] Fix multifaucet DB wait retry condition for missing stdout --- ansible/roles/multifaucet/tasks/main.yml | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/ansible/roles/multifaucet/tasks/main.yml b/ansible/roles/multifaucet/tasks/main.yml index 57b86178..47a1fefe 100644 --- a/ansible/roles/multifaucet/tasks/main.yml +++ b/ansible/roles/multifaucet/tasks/main.yml @@ -39,7 +39,9 @@ container: multifaucet-db-1 command: mysqladmin ping -u multifaucet --password="multifaucet" register: response - until: response.stdout == "mysqld is alive" + failed_when: false + changed_when: false + until: response.rc == 0 and ('mysqld is alive' in (response.stdout | default(''))) retries: 10 delay: 10 From e456676e316371224ff4e089ee04ac0ca403142b Mon Sep 17 00:00:00 2001 From: vivekgsharma Date: Thu, 5 Mar 2026 07:10:57 +0000 Subject: [PATCH 08/30] Harden multifaucet DB wait condition for variable module response shape --- ansible/roles/multifaucet/tasks/main.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ansible/roles/multifaucet/tasks/main.yml b/ansible/roles/multifaucet/tasks/main.yml index 47a1fefe..11a3b933 100644 --- a/ansible/roles/multifaucet/tasks/main.yml +++ b/ansible/roles/multifaucet/tasks/main.yml @@ -41,7 +41,7 @@ register: response failed_when: false changed_when: false - until: response.rc == 0 and ('mysqld is alive' in (response.stdout | default(''))) + until: "'mysqld is alive' in (response | to_json)" retries: 10 delay: 10 From 2619eb6abf8b3f47f874353fdd235fdaa7ce33bf Mon Sep 17 00:00:00 2001 From: vivekgsharma Date: Thu, 5 Mar 2026 22:37:09 +0000 Subject: [PATCH 09/30] Fix multifaucet DB exec in CI by replacing docker_container_exec with docker exec --- ansible/roles/multifaucet/tasks/main.yml | 42 +++++++++--------------- 1 file changed, 15 insertions(+), 27 deletions(-) diff --git a/ansible/roles/multifaucet/tasks/main.yml b/ansible/roles/multifaucet/tasks/main.yml index 11a3b933..af7af909 100644 --- a/ansible/roles/multifaucet/tasks/main.yml +++ b/ansible/roles/multifaucet/tasks/main.yml @@ -35,44 +35,32 @@ pull: always - name: Wait for database to be available - community.docker.docker_container_exec: - container: multifaucet-db-1 - command: mysqladmin ping -u multifaucet --password="multifaucet" + ansible.builtin.shell: | + docker exec multifaucet-db-1 mysqladmin ping -u multifaucet --password="multifaucet" register: response failed_when: false changed_when: false - until: "'mysqld is alive' in (response | to_json)" - retries: 10 + until: response.rc == 0 and ('mysqld is alive' in (response.stdout | default(''))) + retries: 30 delay: 10 - name: Create promo codes table - community.docker.docker_container_exec: - container: multifaucet-db-1 - command: > - mysql -h localhost -D multifaucet -u multifaucet --password="multifaucet" + ansible.builtin.shell: | + docker exec multifaucet-db-1 mysql -h localhost -D multifaucet -u multifaucet --password="multifaucet" \ -e 'CREATE TABLE IF NOT EXISTS faucet_promo_codes (id int NOT NULL, code varchar(255), minimum_payout int, maximum_payout int, PRIMARY KEY (id));' - name: Load MN promo code - community.docker.docker_container_exec: - container: multifaucet-db-1 - command: > - mysql -h localhost -D multifaucet -u multifaucet --password="multifaucet" - -e 'INSERT IGNORE INTO faucet_promo_codes (id,code,minimum_payout,maximum_payout) - VALUES (1,"masternode",{{ masternode_collaterals.mn }},{{ masternode_collaterals.mn | int + 10 }});' + ansible.builtin.shell: | + docker exec multifaucet-db-1 mysql -h localhost -D multifaucet -u multifaucet --password="multifaucet" \ + -e 'INSERT IGNORE INTO faucet_promo_codes (id,code,minimum_payout,maximum_payout) VALUES (1,"masternode",{{ masternode_collaterals.mn }},{{ masternode_collaterals.mn | int + 10 }});' - name: Load HPMN promo code - community.docker.docker_container_exec: - container: multifaucet-db-1 - command: > - mysql -h localhost -D multifaucet -u multifaucet --password="multifaucet" - -e 'INSERT IGNORE INTO faucet_promo_codes (id,code,minimum_payout,maximum_payout) - VALUES (2,"hp-masternode",{{ masternode_collaterals.hpmn }},{{ masternode_collaterals.hpmn | int + 10 }});' + ansible.builtin.shell: | + docker exec multifaucet-db-1 mysql -h localhost -D multifaucet -u multifaucet --password="multifaucet" \ + -e 'INSERT IGNORE INTO faucet_promo_codes (id,code,minimum_payout,maximum_payout) VALUES (2,"hp-masternode",{{ masternode_collaterals.hpmn }},{{ masternode_collaterals.hpmn | int + 10 }});' when: dash_network == "devnet" - name: Load platform promo code - community.docker.docker_container_exec: - container: multifaucet-db-1 - command: > - mysql -h localhost -D multifaucet -u multifaucet --password="multifaucet" - -e 'INSERT IGNORE INTO faucet_promo_codes (id,code,minimum_payout,maximum_payout) - VALUES (3,"platform",50,55);' + ansible.builtin.shell: | + docker exec multifaucet-db-1 mysql -h localhost -D multifaucet -u multifaucet --password="multifaucet" \ + -e 'INSERT IGNORE INTO faucet_promo_codes (id,code,minimum_payout,maximum_payout) VALUES (3,"platform",50,55);' From d6d377896fc507199aea315eeac1dc85453683ad Mon Sep 17 00:00:00 2001 From: vivekgsharma Date: Sat, 28 Mar 2026 09:40:02 +0000 Subject: [PATCH 10/30] Fix mn_init iteration for empty/dict mnlist on newer Ansible --- ansible/roles/mn_init/tasks/main.yml | 19 ++++++++++++++----- 1 file changed, 14 insertions(+), 5 deletions(-) diff --git a/ansible/roles/mn_init/tasks/main.yml b/ansible/roles/mn_init/tasks/main.yml index 2ec2d671..b5413c86 100644 --- a/ansible/roles/mn_init/tasks/main.yml +++ b/ansible/roles/mn_init/tasks/main.yml @@ -39,10 +39,19 @@ ansible.builtin.set_fact: unimported_owner_addresses: [] +- name: Build masternode names list from mnlist + ansible.builtin.set_fact: + mn_names: >- + {{ + (mnlist | dict2items | map(attribute='key') | list) + if (mnlist is mapping) + else [] + }} + - name: Get list of info on owner addresses to be imported ansible.builtin.command: cmd: 'dash-cli -rpcwallet={{ wallet_rpc_wallet_mno }} getaddressinfo {{ mnlist[item].owner.address }}' - with_items: '{{ mnlist }}' + with_items: '{{ mn_names }}' register: owner_address_info changed_when: owner_address_info.rc == 0 @@ -63,7 +72,7 @@ - name: Get list of info on collateral addresses to be imported ansible.builtin.command: cmd: 'dash-cli -rpcwallet={{ wallet_rpc_wallet_mno }} getaddressinfo {{ mnlist[item].collateral.address }}' - with_items: '{{ mnlist }}' + with_items: '{{ mn_names }}' register: collateral_address_info changed_when: collateral_address_info.rc == 0 @@ -113,7 +122,7 @@ ansible.builtin.set_fact: registered_masternode_names: '{{ registered_masternode_names + [item] }}' when: get_protx_list_result.stdout | from_json | json_query("[?state.ownerAddress=='" + mnlist[item].owner.address + "']") - with_items: '{{ mnlist }}' + with_items: '{{ mn_names }}' - name: Registered masternodes list ansible.builtin.debug: @@ -123,7 +132,7 @@ - name: Determine new masternodes ansible.builtin.set_fact: - new_masternode_names: "{{ mnlist | difference(registered_masternode_names) }}" + new_masternode_names: "{{ mn_names | difference(registered_masternode_names) }}" - name: New masternodes list ansible.builtin.debug: @@ -179,7 +188,7 @@ - name: Populate fee payment targets ansible.builtin.set_fact: fee_target_addresses: "{{ fee_target_addresses + [mnlist[item].collateral.address] }}" - with_items: '{{ mnlist }}' + with_items: '{{ mn_names }}' - name: Check if address contains a suitable fee utxo ansible.builtin.command: > From 20f92a4d231e8c6105596bf5bc8ec162d77a3303 Mon Sep 17 00:00:00 2001 From: vivekgsharma Date: Sat, 28 Mar 2026 11:46:25 +0000 Subject: [PATCH 11/30] Add devnet resume mode and guard mn_protx_config loops --- .github/workflows/create-devnet.yml | 39 +++++++++++++++++++- ansible/roles/mn_protx_config/tasks/main.yml | 11 +++++- 2 files changed, 48 insertions(+), 2 deletions(-) diff --git a/.github/workflows/create-devnet.yml b/.github/workflows/create-devnet.yml index b7355e40..22825f5d 100644 --- a/.github/workflows/create-devnet.yml +++ b/.github/workflows/create-devnet.yml @@ -175,7 +175,39 @@ jobs: TERRAFORM_DYNAMODB_TABLE=$TERRAFORM_DYNAMODB_TABLE EOF + - name: Check for existing devnet configs + id: existing_configs + run: | + git clone git@github.com:dashpay/dash-network-configs.git /tmp/dash-network-configs-source + + FOUND=0 + MISSING=0 + for ext in yml tfvars inventory; do + SRC="/tmp/dash-network-configs-source/$NETWORK_NAME.$ext" + if [[ -f "$SRC" ]]; then + FOUND=$((FOUND + 1)) + else + MISSING=$((MISSING + 1)) + fi + done + + if [[ $FOUND -eq 3 ]]; then + echo "resume_mode=true" >> "$GITHUB_OUTPUT" + echo "Found existing config set for $NETWORK_NAME. Reusing config repo files and skipping Terraform." + cp "/tmp/dash-network-configs-source/$NETWORK_NAME.yml" networks/ + cp "/tmp/dash-network-configs-source/$NETWORK_NAME.tfvars" networks/ + cp "/tmp/dash-network-configs-source/$NETWORK_NAME.inventory" networks/ + elif [[ $FOUND -eq 0 ]]; then + echo "resume_mode=false" >> "$GITHUB_OUTPUT" + echo "No existing config set found for $NETWORK_NAME. Running full create flow." + else + echo "Error: Partial config set found for $NETWORK_NAME in dash-network-configs." + ls -la /tmp/dash-network-configs-source/$NETWORK_NAME.* 2>/dev/null || true + exit 1 + fi + - name: Generate network configs + if: steps.existing_configs.outputs.resume_mode != 'true' env: MN_AMD: ${{ github.event.inputs.masternodes_amd_count }} MN_ARM: ${{ github.event.inputs.masternodes_arm_count }} @@ -286,7 +318,12 @@ jobs: chmod +x ./bin/deploy # GitHub Actions checks out a detached HEAD; bypass branch safety check. - ./bin/deploy -f "$NETWORK_NAME" + if [[ "${{ steps.existing_configs.outputs.resume_mode }}" == "true" ]]; then + echo "Resume mode enabled. Skipping Terraform and re-running provisioning only." + ./bin/deploy -p -f "$NETWORK_NAME" + else + ./bin/deploy -f "$NETWORK_NAME" + fi - name: Push configs to dash-network-configs if: always() diff --git a/ansible/roles/mn_protx_config/tasks/main.yml b/ansible/roles/mn_protx_config/tasks/main.yml index 475e97d0..39a97c12 100644 --- a/ansible/roles/mn_protx_config/tasks/main.yml +++ b/ansible/roles/mn_protx_config/tasks/main.yml @@ -4,6 +4,15 @@ ansible.builtin.set_fact: registered_masternode_names: [] +- name: Build masternode names list from mnlist + ansible.builtin.set_fact: + mn_names: >- + {{ + (mnlist | dict2items | map(attribute='key') | list) + if (mnlist is mapping) + else [] + }} + - name: Get list of ProTx transactions from the wallet ansible.builtin.command: dash-cli -rpcwallet={{ wallet_rpc_wallet_mno }} protx list wallet true register: get_protx_list_result @@ -13,7 +22,7 @@ ansible.builtin.set_fact: registered_masternode_names: "{{ registered_masternode_names + [item] }}" when: get_protx_list_result.stdout | from_json | json_query("[?state.ownerAddress=='" + mnlist[item].owner.address + "']") - with_items: '{{ mnlist }}' + with_items: '{{ mn_names }}' - name: Set empty outer scope variable for protx list ansible.builtin.set_fact: From 3ab4b345b0f2ba88aa167285809507dd9dbc4c82 Mon Sep 17 00:00:00 2001 From: vivekgsharma Date: Sat, 28 Mar 2026 14:45:14 +0000 Subject: [PATCH 12/30] Make masternode role conditionals unambiguously boolean --- ansible/roles/mn_init/tasks/main.yml | 9 +++------ ansible/roles/mn_protx_config/tasks/main.yml | 2 +- 2 files changed, 4 insertions(+), 7 deletions(-) diff --git a/ansible/roles/mn_init/tasks/main.yml b/ansible/roles/mn_init/tasks/main.yml index b5413c86..24f02faa 100644 --- a/ansible/roles/mn_init/tasks/main.yml +++ b/ansible/roles/mn_init/tasks/main.yml @@ -121,7 +121,7 @@ - name: Get names of registered masternodes ansible.builtin.set_fact: registered_masternode_names: '{{ registered_masternode_names + [item] }}' - when: get_protx_list_result.stdout | from_json | json_query("[?state.ownerAddress=='" + mnlist[item].owner.address + "']") + when: ((get_protx_list_result.stdout | from_json | json_query("[?state.ownerAddress=='" + mnlist[item].owner.address + "']")) | length | int) > 0 with_items: '{{ mn_names }}' - name: Registered masternodes list @@ -151,7 +151,7 @@ - name: Get names of banned masternodes ansible.builtin.set_fact: banned_masternode_names: '{{ banned_masternode_names + [item] }}' - when: banned_masternodes_list | json_query("[?state.ownerAddress=='" + mnlist[item].owner.address + "']") + when: ((banned_masternodes_list | json_query("[?state.ownerAddress=='" + mnlist[item].owner.address + "']")) | length | int) > 0 with_items: '{{ registered_masternode_names }}' - name: Banned masternodes list @@ -167,10 +167,7 @@ - name: Get names of misconfigured masternodes ansible.builtin.set_fact: misconfigured_masternode_names: '{{ misconfigured_masternode_names + [item] }}' - when: > - get_protx_list_result.stdout | from_json | - json_query("[?state.ownerAddress=='" + mnlist[item].owner.address + "']") | - json_query("[?state.service!='" + hostvars[item].public_ip + ":" + dashd_port | string + "']") + when: ((get_protx_list_result.stdout | from_json | json_query("[?state.ownerAddress=='" + mnlist[item].owner.address + "']") | json_query("[?state.service!='" + hostvars[item].public_ip + ":" + dashd_port | string + "']")) | length | int) > 0 with_items: '{{ registered_masternode_names }}' # We should probably subtract the banned masternodes from this list so we don't unban twice diff --git a/ansible/roles/mn_protx_config/tasks/main.yml b/ansible/roles/mn_protx_config/tasks/main.yml index 39a97c12..cc3c17b7 100644 --- a/ansible/roles/mn_protx_config/tasks/main.yml +++ b/ansible/roles/mn_protx_config/tasks/main.yml @@ -21,7 +21,7 @@ - name: Get names of registered masternodes ansible.builtin.set_fact: registered_masternode_names: "{{ registered_masternode_names + [item] }}" - when: get_protx_list_result.stdout | from_json | json_query("[?state.ownerAddress=='" + mnlist[item].owner.address + "']") + when: ((get_protx_list_result.stdout | from_json | json_query("[?state.ownerAddress=='" + mnlist[item].owner.address + "']")) | length | int) > 0 with_items: '{{ mn_names }}' - name: Set empty outer scope variable for protx list From 58ac3a0d8f7b02a6d58e95c8317b018bb6d5e243 Mon Sep 17 00:00:00 2001 From: vivekgsharma Date: Sat, 28 Mar 2026 15:44:55 +0000 Subject: [PATCH 13/30] small fix --- .github/workflows/create-devnet.yml | 11 +++++++++-- ansible/roles/mn_find_collateral/tasks/main.yml | 2 +- 2 files changed, 10 insertions(+), 3 deletions(-) diff --git a/.github/workflows/create-devnet.yml b/.github/workflows/create-devnet.yml index 22825f5d..d23feda6 100644 --- a/.github/workflows/create-devnet.yml +++ b/.github/workflows/create-devnet.yml @@ -12,6 +12,11 @@ on: required: true type: string default: "2.0.0-rc.16" + deploy_tags: + description: "Ansible tags to run. Use full_deploy for full flow, or a narrower tag such as unban_hp_masternodes to resume faster." + required: true + type: string + default: "full_deploy" # Advanced options - sane defaults, only change if you know what you're doing hp_masternodes_arm_count: description: "Advanced: Number of ARM HP masternodes" @@ -311,18 +316,20 @@ jobs: env: TF_IN_AUTOMATION: "true" TF_CLI_ARGS_apply: "-auto-approve" + DEPLOY_TAGS: ${{ github.event.inputs.deploy_tags }} run: | echo "============================================" echo "Deploying $NETWORK_NAME" + echo "Ansible tags: $DEPLOY_TAGS" echo "============================================" chmod +x ./bin/deploy # GitHub Actions checks out a detached HEAD; bypass branch safety check. if [[ "${{ steps.existing_configs.outputs.resume_mode }}" == "true" ]]; then echo "Resume mode enabled. Skipping Terraform and re-running provisioning only." - ./bin/deploy -p -f "$NETWORK_NAME" + ./bin/deploy -p -f --tags="$DEPLOY_TAGS" "$NETWORK_NAME" else - ./bin/deploy -f "$NETWORK_NAME" + ./bin/deploy -f --tags="$DEPLOY_TAGS" "$NETWORK_NAME" fi - name: Push configs to dash-network-configs diff --git a/ansible/roles/mn_find_collateral/tasks/main.yml b/ansible/roles/mn_find_collateral/tasks/main.yml index 3bcf4bcb..7eb168a1 100644 --- a/ansible/roles/mn_find_collateral/tasks/main.yml +++ b/ansible/roles/mn_find_collateral/tasks/main.yml @@ -15,7 +15,7 @@ cmd: 'find-collateral.py "-rpcwallet={{ wallet_rpc_wallet_mno }}" {{ masternode.collateral.address }} {{ funding_amount }} {{ find_protx }}' register: r failed_when: false - changed_when: r.rc + changed_when: false - name: Update collateral_ok ansible.builtin.set_fact: From 4169c9bb19cd1ddc592d495892af279054c1c886 Mon Sep 17 00:00:00 2001 From: vivekgsharma Date: Sat, 28 Mar 2026 15:59:00 +0000 Subject: [PATCH 14/30] Temporarily skip early deploy plays to resume HP masternode debugging --- ansible/deploy.yml | 296 ++------------------------------------------- 1 file changed, 8 insertions(+), 288 deletions(-) diff --git a/ansible/deploy.yml b/ansible/deploy.yml index caf71d2d..0e404681 100644 --- a/ansible/deploy.yml +++ b/ansible/deploy.yml @@ -1,293 +1,13 @@ --- -# Bootstrap - -- name: Remove latency on masternodes before deployment starts - hosts: masternodes,hp_masternodes - become: true - roles: - - remove_fake_latency - tags: - - full_deploy - - maintenance - -- name: Set up swap and aws environment vars - hosts: all - gather_facts: true - become: true - pre_tasks: - - name: Check if inside AWS - ansible.builtin.uri: - url: http://169.254.169.254/latest/meta-data - timeout: 2 - register: aws_uri_check - failed_when: false - - name: Set AWS environment variable - ansible.builtin.set_fact: - is_aws_environment: '{{ aws_uri_check.status == 200 }}' - roles: - - role: aws - when: is_aws_environment - - swap - tags: - - full_deploy - - infra_setup - -- name: Setup VPN - hosts: vpn - become: true - roles: - - role: openvpn - when: openvpn_enabled - tags: - - full_deploy - - infra_setup - - vpn - -- name: Setup jq, Python, CWAgent and Docker - hosts: all - become: true - pre_tasks: - - name: Update apt cache and install jq - ansible.builtin.apt: - pkg: - - jq - - unzip - update_cache: true - vars: - pip_package: python3-pip - pip_install_packages: - - name: docker - version: "6.0.1" - - name: docker-compose - version: "1.29.2" - - name: requests - version: "2.31.0" - roles: - - geerlingguy.pip - - role: geerlingguy.docker - vars: - docker_apt_arch: "{{ 'amd64' if ansible_architecture == 'x86_64' else 'arm64' }}" - docker_install_compose: false - docker_users: - - ubuntu - - docker_options - - eternal_terminal - - cwagent - tags: - - full_deploy - - infra_setup - -- name: Configure tcpdump - hosts: all - become: true - roles: - - role: tcpdumpd - when: dashd_network_logging != 0 - tags: - - full_deploy - - infra_setup - -- name: Setup logs - hosts: logs_nodes - become: true - roles: - - elastic_stack - - metricbeat - tags: - - full_deploy - - infra_setup - -- name: Setup load tester - hosts: load_test - become: true - roles: - - role: protobuf_compiler - - role: load_tool - tags: - - full_deploy - - infra_setup - -- name: Setup metrics - hosts: metrics - become: true - roles: - - metrics - - metricbeat - tags: - - full_deploy - - infra_setup - -- name: Set up miners - hosts: miners - become: true - roles: - - role: dash_cli - - role: dashd - tags: - - dashd - - core_filebeat - - metricbeat - tags: - - full_deploy - -- name: Set up mixers - hosts: mixer_nodes - become: true - roles: - - role: dash_cli - - role: dashd - tags: - - dashd - - core_filebeat - - metricbeat - tags: - - full_deploy - -- name: Set up core and tenderdash on seed nodes - hosts: seed_nodes - become: true - pre_tasks: - - name: Set node variables for seed nodes - ansible.builtin.set_fact: - node: "{{ seed_nodes[inventory_hostname] }}" - mode: "seed" - tags: always - when: inventory_hostname in seed_nodes - roles: - - role: dash_cli - - role: dashd - dashd_listen: true - dashd_zmq: true - dashd_indexes: true - tags: - - dashd - - role: tenderdash - - core_filebeat - - metricbeat - tags: - - full_deploy - - update_seed_nodes - -- name: Set up core on masternodes - hosts: masternodes - become: true - pre_tasks: - - name: Check inventory for masternodes - ansible.builtin.set_fact: - masternode: "{{ masternodes[inventory_hostname] }}" - tags: always - when: inventory_hostname in masternodes - - name: Fail if no masternodes present - ansible.builtin.fail: - msg: Masternode not defined in network config - when: masternode is not defined - roles: - - role: dash_cli - - role: dashd - dashd_listen: true - dashd_zmq: true - dashd_indexes: true - tags: - - dashd - - mn_status_report - - core_filebeat - - metricbeat - tags: - - full_deploy - - core_update - - update_masternodes - - -# Start network - -- name: Generate first block to leave IBD mode - hosts: seed-1 - become: true - roles: - - role: generate_firstblock - when: dash_network == "devnet" or dash_network == "regtest" - tags: - - full_deploy - -- name: Start miner - hosts: miners - become: true - roles: - - role: dashd_generate_miner - when: dash_network != "mainnet" - tags: - - full_deploy - -- name: Setup faucet and insight - hosts: web - become: true - roles: - - multifaucet - - role: dash_cli - - role: dashd - dashd_indexes: true - dashd_zmq: true - dashd_listen: true - - insight - - role: status_dashboard - when: dash_network == "devnet" - - core_filebeat - - metricbeat - tags: - - full_deploy - - web - -- name: Deploy status monitoring to masternodes - hosts: masternodes,hp_masternodes - become: true - gather_facts: false - strategy: free - roles: - - status_monitoring - tags: - - full_deploy - - dashmate_deploy - - status_dashboard - -- name: Set up wallets - hosts: wallet_nodes - become: true - roles: - - role: dash_cli - - role: dashd - dashd_indexes: true - dashd_zmq: true - enable_wallet: true - tags: - - dashd - - core_filebeat - - metricbeat - tags: - - full_deploy - - core_update - -# Register masternodes and set sporks - -- name: Register masternodes - hosts: wallet_nodes - become: true - roles: - - role: mn_init - mnlist: "{{ masternodes }}" - funding_amount: "{{ masternode_collaterals.mn | int }}" - tags: - - full_deploy - - unban_masternodes - -- name: Update inventory with protx values - hosts: wallet_nodes - roles: - - role: mn_protx_config - mnlist: "{{ masternodes }}" - tags: - - full_deploy - - unban_masternodes +# TEMPORARY DEBUG MODE +# The plays above "Register HP masternodes" already completed on the current +# devnet infrastructure. They are intentionally commented out from this branch's +# active deploy flow so reruns jump directly into the failing HP masternode +# registration path and iterate faster. +# +# Re-enable the normal full deploy flow after the current HP masternode issues +# are resolved by restoring this file from git history. - name: Register HP masternodes hosts: wallet_nodes From 627b4d43b2434bb2aea8d221c0a597c35f34e44e Mon Sep 17 00:00:00 2001 From: vivekgsharma Date: Sat, 28 Mar 2026 19:55:10 +0000 Subject: [PATCH 15/30] Split collateral funding into per-address transactions --- .../tasks/fund_collateral.yml | 25 ++++++++++++++++--- .../roles/mn_fund_collateral/tasks/main.yml | 2 +- 2 files changed, 22 insertions(+), 5 deletions(-) diff --git a/ansible/roles/mn_fund_collateral/tasks/fund_collateral.yml b/ansible/roles/mn_fund_collateral/tasks/fund_collateral.yml index c804ddd8..391429a3 100644 --- a/ansible/roles/mn_fund_collateral/tasks/fund_collateral.yml +++ b/ansible/roles/mn_fund_collateral/tasks/fund_collateral.yml @@ -16,15 +16,32 @@ ansible.builtin.debug: var: payments -- name: Fund listed masternodes with {{ amount ~ ' Dash'}} - ansible.builtin.command: "dash-cli -rpcwallet={{ wallet_rpc_wallet_faucet }} sendmany '' '{{ payments | to_json }}'" +- name: Initialize list of collateral funding txids + ansible.builtin.set_fact: + fund_txids: [] + +- name: Fund listed masternodes with {{ amount ~ ' Dash' }} + ansible.builtin.command: + argv: + - dash-cli + - "-rpcwallet={{ wallet_rpc_wallet_faucet }}" + - sendtoaddress + - "{{ item.key }}" + - "{{ item.value | string }}" register: fund_result - changed_when: fund_result.stdout | length == 64 + changed_when: (fund_result.stdout | default('') | length) == 64 + with_dict: "{{ payments }}" + +- name: Collect collateral funding txids + ansible.builtin.set_fact: + fund_txids: "{{ fund_txids + [item.stdout] }}" + with_items: "{{ fund_result.results }}" + when: (item.stdout | default('') | length) == 64 - name: Produce blocks until funding transaction is confirmed ansible.builtin.include_role: name: generate_blocks vars: generate: confirmations - txid_list: "{{ [fund_result.stdout] }}" + txid_list: "{{ fund_txids }}" tx_source: "{{ wallet_rpc_wallet_faucet }}" diff --git a/ansible/roles/mn_fund_collateral/tasks/main.yml b/ansible/roles/mn_fund_collateral/tasks/main.yml index 485ae39d..917a1b01 100644 --- a/ansible/roles/mn_fund_collateral/tasks/main.yml +++ b/ansible/roles/mn_fund_collateral/tasks/main.yml @@ -49,7 +49,7 @@ ansible.builtin.set_fact: uncollateralized_addresses: "{{ uncollateralized_addresses + [mnlist[item].collateral.address] }}" with_items: '{{ masternode_names }}' - when: not vars["collateral_ok_" + item|replace("-","_")] + when: not (lookup('vars', 'collateral_ok_' + (item | replace('-', '_'))) | default(false) | bool) - name: Fund masternode collaterals ansible.builtin.include_tasks: From 03e610f158a397a0904b4ceda83811346aeebb63 Mon Sep 17 00:00:00 2001 From: vivekgsharma Date: Sat, 28 Mar 2026 20:08:50 +0000 Subject: [PATCH 16/30] Pin CI Ansible to 2.16.3 and restore Ansible roles to v1.0-dev behavior --- .github/workflows/create-devnet.yml | 4 +- .github/workflows/destroy-devnet.yml | 4 +- ansible/deploy.yml | 296 +++++++++++++++++- ansible/roles/core_filebeat/vars/common.yml | 2 - ansible/roles/dashd/defaults/main.yml | 3 - ansible/roles/dashd/tasks/main.yml | 13 +- ansible/roles/eternal_terminal/tasks/main.yml | 4 - .../roles/mn_find_collateral/tasks/main.yml | 2 +- .../tasks/fund_collateral.yml | 25 +- .../roles/mn_fund_collateral/tasks/main.yml | 2 +- ansible/roles/mn_init/tasks/main.yml | 9 +- ansible/roles/mn_protx_config/tasks/main.yml | 13 +- ansible/roles/multifaucet/tasks/main.yml | 44 ++- 13 files changed, 338 insertions(+), 83 deletions(-) diff --git a/.github/workflows/create-devnet.yml b/.github/workflows/create-devnet.yml index d23feda6..5e41e934 100644 --- a/.github/workflows/create-devnet.yml +++ b/.github/workflows/create-devnet.yml @@ -57,7 +57,7 @@ on: jobs: create: name: Create Devnet - runs-on: ubuntu-latest + runs-on: ubuntu-22.04 timeout-minutes: 120 concurrency: group: "devnet-${{ github.event.inputs.devnet_name }}" @@ -117,7 +117,7 @@ jobs: - name: Install Ansible run: | python3 -m pip install --upgrade pip - python3 -m pip install ansible + python3 -m pip install ansible-core==2.16.3 - name: Install Ansible roles run: | diff --git a/.github/workflows/destroy-devnet.yml b/.github/workflows/destroy-devnet.yml index d4b7b067..6ae35be5 100644 --- a/.github/workflows/destroy-devnet.yml +++ b/.github/workflows/destroy-devnet.yml @@ -20,7 +20,7 @@ on: jobs: destroy: name: Destroy Devnet - runs-on: ubuntu-latest + runs-on: ubuntu-22.04 timeout-minutes: 60 concurrency: group: "devnet-${{ github.event.inputs.devnet_name }}" @@ -77,7 +77,7 @@ jobs: - name: Install Ansible run: | python3 -m pip install --upgrade pip - python3 -m pip install ansible + python3 -m pip install ansible-core==2.16.3 - name: Install Ansible roles run: | diff --git a/ansible/deploy.yml b/ansible/deploy.yml index 0e404681..caf71d2d 100644 --- a/ansible/deploy.yml +++ b/ansible/deploy.yml @@ -1,13 +1,293 @@ --- -# TEMPORARY DEBUG MODE -# The plays above "Register HP masternodes" already completed on the current -# devnet infrastructure. They are intentionally commented out from this branch's -# active deploy flow so reruns jump directly into the failing HP masternode -# registration path and iterate faster. -# -# Re-enable the normal full deploy flow after the current HP masternode issues -# are resolved by restoring this file from git history. +# Bootstrap + +- name: Remove latency on masternodes before deployment starts + hosts: masternodes,hp_masternodes + become: true + roles: + - remove_fake_latency + tags: + - full_deploy + - maintenance + +- name: Set up swap and aws environment vars + hosts: all + gather_facts: true + become: true + pre_tasks: + - name: Check if inside AWS + ansible.builtin.uri: + url: http://169.254.169.254/latest/meta-data + timeout: 2 + register: aws_uri_check + failed_when: false + - name: Set AWS environment variable + ansible.builtin.set_fact: + is_aws_environment: '{{ aws_uri_check.status == 200 }}' + roles: + - role: aws + when: is_aws_environment + - swap + tags: + - full_deploy + - infra_setup + +- name: Setup VPN + hosts: vpn + become: true + roles: + - role: openvpn + when: openvpn_enabled + tags: + - full_deploy + - infra_setup + - vpn + +- name: Setup jq, Python, CWAgent and Docker + hosts: all + become: true + pre_tasks: + - name: Update apt cache and install jq + ansible.builtin.apt: + pkg: + - jq + - unzip + update_cache: true + vars: + pip_package: python3-pip + pip_install_packages: + - name: docker + version: "6.0.1" + - name: docker-compose + version: "1.29.2" + - name: requests + version: "2.31.0" + roles: + - geerlingguy.pip + - role: geerlingguy.docker + vars: + docker_apt_arch: "{{ 'amd64' if ansible_architecture == 'x86_64' else 'arm64' }}" + docker_install_compose: false + docker_users: + - ubuntu + - docker_options + - eternal_terminal + - cwagent + tags: + - full_deploy + - infra_setup + +- name: Configure tcpdump + hosts: all + become: true + roles: + - role: tcpdumpd + when: dashd_network_logging != 0 + tags: + - full_deploy + - infra_setup + +- name: Setup logs + hosts: logs_nodes + become: true + roles: + - elastic_stack + - metricbeat + tags: + - full_deploy + - infra_setup + +- name: Setup load tester + hosts: load_test + become: true + roles: + - role: protobuf_compiler + - role: load_tool + tags: + - full_deploy + - infra_setup + +- name: Setup metrics + hosts: metrics + become: true + roles: + - metrics + - metricbeat + tags: + - full_deploy + - infra_setup + +- name: Set up miners + hosts: miners + become: true + roles: + - role: dash_cli + - role: dashd + tags: + - dashd + - core_filebeat + - metricbeat + tags: + - full_deploy + +- name: Set up mixers + hosts: mixer_nodes + become: true + roles: + - role: dash_cli + - role: dashd + tags: + - dashd + - core_filebeat + - metricbeat + tags: + - full_deploy + +- name: Set up core and tenderdash on seed nodes + hosts: seed_nodes + become: true + pre_tasks: + - name: Set node variables for seed nodes + ansible.builtin.set_fact: + node: "{{ seed_nodes[inventory_hostname] }}" + mode: "seed" + tags: always + when: inventory_hostname in seed_nodes + roles: + - role: dash_cli + - role: dashd + dashd_listen: true + dashd_zmq: true + dashd_indexes: true + tags: + - dashd + - role: tenderdash + - core_filebeat + - metricbeat + tags: + - full_deploy + - update_seed_nodes + +- name: Set up core on masternodes + hosts: masternodes + become: true + pre_tasks: + - name: Check inventory for masternodes + ansible.builtin.set_fact: + masternode: "{{ masternodes[inventory_hostname] }}" + tags: always + when: inventory_hostname in masternodes + - name: Fail if no masternodes present + ansible.builtin.fail: + msg: Masternode not defined in network config + when: masternode is not defined + roles: + - role: dash_cli + - role: dashd + dashd_listen: true + dashd_zmq: true + dashd_indexes: true + tags: + - dashd + - mn_status_report + - core_filebeat + - metricbeat + tags: + - full_deploy + - core_update + - update_masternodes + + +# Start network + +- name: Generate first block to leave IBD mode + hosts: seed-1 + become: true + roles: + - role: generate_firstblock + when: dash_network == "devnet" or dash_network == "regtest" + tags: + - full_deploy + +- name: Start miner + hosts: miners + become: true + roles: + - role: dashd_generate_miner + when: dash_network != "mainnet" + tags: + - full_deploy + +- name: Setup faucet and insight + hosts: web + become: true + roles: + - multifaucet + - role: dash_cli + - role: dashd + dashd_indexes: true + dashd_zmq: true + dashd_listen: true + - insight + - role: status_dashboard + when: dash_network == "devnet" + - core_filebeat + - metricbeat + tags: + - full_deploy + - web + +- name: Deploy status monitoring to masternodes + hosts: masternodes,hp_masternodes + become: true + gather_facts: false + strategy: free + roles: + - status_monitoring + tags: + - full_deploy + - dashmate_deploy + - status_dashboard + +- name: Set up wallets + hosts: wallet_nodes + become: true + roles: + - role: dash_cli + - role: dashd + dashd_indexes: true + dashd_zmq: true + enable_wallet: true + tags: + - dashd + - core_filebeat + - metricbeat + tags: + - full_deploy + - core_update + +# Register masternodes and set sporks + +- name: Register masternodes + hosts: wallet_nodes + become: true + roles: + - role: mn_init + mnlist: "{{ masternodes }}" + funding_amount: "{{ masternode_collaterals.mn | int }}" + tags: + - full_deploy + - unban_masternodes + +- name: Update inventory with protx values + hosts: wallet_nodes + roles: + - role: mn_protx_config + mnlist: "{{ masternodes }}" + tags: + - full_deploy + - unban_masternodes - name: Register HP masternodes hosts: wallet_nodes diff --git a/ansible/roles/core_filebeat/vars/common.yml b/ansible/roles/core_filebeat/vars/common.yml index 703c44ae..4567afcd 100644 --- a/ansible/roles/core_filebeat/vars/common.yml +++ b/ansible/roles/core_filebeat/vars/common.yml @@ -18,5 +18,3 @@ filebeat_output_elasticsearch_auth: password: "{{ elastic_password }}" filebeat_enable_logging: true filebeat_log_level: info -# Keep SSL key var boolean to satisfy strict conditionals in newer ansible-core. -filebeat_ssl_key_file: false diff --git a/ansible/roles/dashd/defaults/main.yml b/ansible/roles/dashd/defaults/main.yml index db93fb72..b9c52316 100644 --- a/ansible/roles/dashd/defaults/main.yml +++ b/ansible/roles/dashd/defaults/main.yml @@ -16,6 +16,3 @@ dashd_allowprivatenet: '{% if dashd_externalip | ansible.utils.ipaddr("private") dashd_compose_project_name: dashcore dashd_compose_path: '{{ dashd_home }}/{{ dashd_compose_project_name }}' - -# Wallet operations are only enabled on dedicated wallet nodes. -enable_wallet: false diff --git a/ansible/roles/dashd/tasks/main.yml b/ansible/roles/dashd/tasks/main.yml index 4f43870e..43ed00c7 100644 --- a/ansible/roles/dashd/tasks/main.yml +++ b/ansible/roles/dashd/tasks/main.yml @@ -101,7 +101,7 @@ block: | wallet={{ wallet_rpc_wallet_faucet }} wallet={{ wallet_rpc_wallet_mno }} - when: (enable_wallet | default(false) | bool) and wallet_exists.stat.exists is true + when: enable_wallet is true and wallet_exists.stat.exists is true # TODO: why does this always take exactly 30 seconds on first deploy? - name: Start dash core @@ -126,14 +126,14 @@ cmd: dash-cli createwallet {{ wallet_rpc_wallet_faucet }} creates: "{{ dashd_home }}/.dashcore/{{ dash_network_name if dash_network == 'devnet' else 'testnet3' }}/wallets/{{ wallet_rpc_wallet_faucet }}/wallet.dat" register: create_faucet_wallet_result - when: enable_wallet | default(false) | bool + when: enable_wallet is true - name: Create mno wallet ansible.builtin.command: cmd: dash-cli createwallet {{ wallet_rpc_wallet_mno }} creates: "{{ dashd_home }}/.dashcore/{{ dash_network_name if dash_network == 'devnet' else 'testnet3' }}/wallets/{{ wallet_rpc_wallet_mno }}/wallet.dat" register: create_mno_wallet_result - when: enable_wallet | default(false) | bool + when: enable_wallet is true - name: Load wallets on startup ansible.builtin.blockinfile: @@ -142,13 +142,10 @@ block: | wallet={{ wallet_rpc_wallet_faucet }} wallet={{ wallet_rpc_wallet_mno }} - when: > - (enable_wallet | default(false) | bool) and - (create_faucet_wallet_result is defined and create_faucet_wallet_result.changed) and - (create_mno_wallet_result is defined and create_mno_wallet_result.changed) + when: create_faucet_wallet_result.changed and create_mno_wallet_result.changed - name: Import faucet privkey ansible.builtin.command: dash-cli -rpcwallet={{ wallet_rpc_wallet_faucet }} importprivkey {{ faucet_privkey }} register: result - when: enable_wallet | default(false) | bool + when: enable_wallet is true changed_when: result.rc == 0 diff --git a/ansible/roles/eternal_terminal/tasks/main.yml b/ansible/roles/eternal_terminal/tasks/main.yml index d18b7b80..d471e9a8 100644 --- a/ansible/roles/eternal_terminal/tasks/main.yml +++ b/ansible/roles/eternal_terminal/tasks/main.yml @@ -5,10 +5,6 @@ repo: ppa:jgmath2000/et state: present update_cache: true - register: et_repo - retries: 5 - delay: 20 - until: et_repo is succeeded - name: Install ET ansible.builtin.package: diff --git a/ansible/roles/mn_find_collateral/tasks/main.yml b/ansible/roles/mn_find_collateral/tasks/main.yml index 7eb168a1..3bcf4bcb 100644 --- a/ansible/roles/mn_find_collateral/tasks/main.yml +++ b/ansible/roles/mn_find_collateral/tasks/main.yml @@ -15,7 +15,7 @@ cmd: 'find-collateral.py "-rpcwallet={{ wallet_rpc_wallet_mno }}" {{ masternode.collateral.address }} {{ funding_amount }} {{ find_protx }}' register: r failed_when: false - changed_when: false + changed_when: r.rc - name: Update collateral_ok ansible.builtin.set_fact: diff --git a/ansible/roles/mn_fund_collateral/tasks/fund_collateral.yml b/ansible/roles/mn_fund_collateral/tasks/fund_collateral.yml index 391429a3..c804ddd8 100644 --- a/ansible/roles/mn_fund_collateral/tasks/fund_collateral.yml +++ b/ansible/roles/mn_fund_collateral/tasks/fund_collateral.yml @@ -16,32 +16,15 @@ ansible.builtin.debug: var: payments -- name: Initialize list of collateral funding txids - ansible.builtin.set_fact: - fund_txids: [] - -- name: Fund listed masternodes with {{ amount ~ ' Dash' }} - ansible.builtin.command: - argv: - - dash-cli - - "-rpcwallet={{ wallet_rpc_wallet_faucet }}" - - sendtoaddress - - "{{ item.key }}" - - "{{ item.value | string }}" +- name: Fund listed masternodes with {{ amount ~ ' Dash'}} + ansible.builtin.command: "dash-cli -rpcwallet={{ wallet_rpc_wallet_faucet }} sendmany '' '{{ payments | to_json }}'" register: fund_result - changed_when: (fund_result.stdout | default('') | length) == 64 - with_dict: "{{ payments }}" - -- name: Collect collateral funding txids - ansible.builtin.set_fact: - fund_txids: "{{ fund_txids + [item.stdout] }}" - with_items: "{{ fund_result.results }}" - when: (item.stdout | default('') | length) == 64 + changed_when: fund_result.stdout | length == 64 - name: Produce blocks until funding transaction is confirmed ansible.builtin.include_role: name: generate_blocks vars: generate: confirmations - txid_list: "{{ fund_txids }}" + txid_list: "{{ [fund_result.stdout] }}" tx_source: "{{ wallet_rpc_wallet_faucet }}" diff --git a/ansible/roles/mn_fund_collateral/tasks/main.yml b/ansible/roles/mn_fund_collateral/tasks/main.yml index 917a1b01..485ae39d 100644 --- a/ansible/roles/mn_fund_collateral/tasks/main.yml +++ b/ansible/roles/mn_fund_collateral/tasks/main.yml @@ -49,7 +49,7 @@ ansible.builtin.set_fact: uncollateralized_addresses: "{{ uncollateralized_addresses + [mnlist[item].collateral.address] }}" with_items: '{{ masternode_names }}' - when: not (lookup('vars', 'collateral_ok_' + (item | replace('-', '_'))) | default(false) | bool) + when: not vars["collateral_ok_" + item|replace("-","_")] - name: Fund masternode collaterals ansible.builtin.include_tasks: diff --git a/ansible/roles/mn_init/tasks/main.yml b/ansible/roles/mn_init/tasks/main.yml index 24f02faa..b5413c86 100644 --- a/ansible/roles/mn_init/tasks/main.yml +++ b/ansible/roles/mn_init/tasks/main.yml @@ -121,7 +121,7 @@ - name: Get names of registered masternodes ansible.builtin.set_fact: registered_masternode_names: '{{ registered_masternode_names + [item] }}' - when: ((get_protx_list_result.stdout | from_json | json_query("[?state.ownerAddress=='" + mnlist[item].owner.address + "']")) | length | int) > 0 + when: get_protx_list_result.stdout | from_json | json_query("[?state.ownerAddress=='" + mnlist[item].owner.address + "']") with_items: '{{ mn_names }}' - name: Registered masternodes list @@ -151,7 +151,7 @@ - name: Get names of banned masternodes ansible.builtin.set_fact: banned_masternode_names: '{{ banned_masternode_names + [item] }}' - when: ((banned_masternodes_list | json_query("[?state.ownerAddress=='" + mnlist[item].owner.address + "']")) | length | int) > 0 + when: banned_masternodes_list | json_query("[?state.ownerAddress=='" + mnlist[item].owner.address + "']") with_items: '{{ registered_masternode_names }}' - name: Banned masternodes list @@ -167,7 +167,10 @@ - name: Get names of misconfigured masternodes ansible.builtin.set_fact: misconfigured_masternode_names: '{{ misconfigured_masternode_names + [item] }}' - when: ((get_protx_list_result.stdout | from_json | json_query("[?state.ownerAddress=='" + mnlist[item].owner.address + "']") | json_query("[?state.service!='" + hostvars[item].public_ip + ":" + dashd_port | string + "']")) | length | int) > 0 + when: > + get_protx_list_result.stdout | from_json | + json_query("[?state.ownerAddress=='" + mnlist[item].owner.address + "']") | + json_query("[?state.service!='" + hostvars[item].public_ip + ":" + dashd_port | string + "']") with_items: '{{ registered_masternode_names }}' # We should probably subtract the banned masternodes from this list so we don't unban twice diff --git a/ansible/roles/mn_protx_config/tasks/main.yml b/ansible/roles/mn_protx_config/tasks/main.yml index cc3c17b7..475e97d0 100644 --- a/ansible/roles/mn_protx_config/tasks/main.yml +++ b/ansible/roles/mn_protx_config/tasks/main.yml @@ -4,15 +4,6 @@ ansible.builtin.set_fact: registered_masternode_names: [] -- name: Build masternode names list from mnlist - ansible.builtin.set_fact: - mn_names: >- - {{ - (mnlist | dict2items | map(attribute='key') | list) - if (mnlist is mapping) - else [] - }} - - name: Get list of ProTx transactions from the wallet ansible.builtin.command: dash-cli -rpcwallet={{ wallet_rpc_wallet_mno }} protx list wallet true register: get_protx_list_result @@ -21,8 +12,8 @@ - name: Get names of registered masternodes ansible.builtin.set_fact: registered_masternode_names: "{{ registered_masternode_names + [item] }}" - when: ((get_protx_list_result.stdout | from_json | json_query("[?state.ownerAddress=='" + mnlist[item].owner.address + "']")) | length | int) > 0 - with_items: '{{ mn_names }}' + when: get_protx_list_result.stdout | from_json | json_query("[?state.ownerAddress=='" + mnlist[item].owner.address + "']") + with_items: '{{ mnlist }}' - name: Set empty outer scope variable for protx list ansible.builtin.set_fact: diff --git a/ansible/roles/multifaucet/tasks/main.yml b/ansible/roles/multifaucet/tasks/main.yml index af7af909..57b86178 100644 --- a/ansible/roles/multifaucet/tasks/main.yml +++ b/ansible/roles/multifaucet/tasks/main.yml @@ -35,32 +35,42 @@ pull: always - name: Wait for database to be available - ansible.builtin.shell: | - docker exec multifaucet-db-1 mysqladmin ping -u multifaucet --password="multifaucet" + community.docker.docker_container_exec: + container: multifaucet-db-1 + command: mysqladmin ping -u multifaucet --password="multifaucet" register: response - failed_when: false - changed_when: false - until: response.rc == 0 and ('mysqld is alive' in (response.stdout | default(''))) - retries: 30 + until: response.stdout == "mysqld is alive" + retries: 10 delay: 10 - name: Create promo codes table - ansible.builtin.shell: | - docker exec multifaucet-db-1 mysql -h localhost -D multifaucet -u multifaucet --password="multifaucet" \ + community.docker.docker_container_exec: + container: multifaucet-db-1 + command: > + mysql -h localhost -D multifaucet -u multifaucet --password="multifaucet" -e 'CREATE TABLE IF NOT EXISTS faucet_promo_codes (id int NOT NULL, code varchar(255), minimum_payout int, maximum_payout int, PRIMARY KEY (id));' - name: Load MN promo code - ansible.builtin.shell: | - docker exec multifaucet-db-1 mysql -h localhost -D multifaucet -u multifaucet --password="multifaucet" \ - -e 'INSERT IGNORE INTO faucet_promo_codes (id,code,minimum_payout,maximum_payout) VALUES (1,"masternode",{{ masternode_collaterals.mn }},{{ masternode_collaterals.mn | int + 10 }});' + community.docker.docker_container_exec: + container: multifaucet-db-1 + command: > + mysql -h localhost -D multifaucet -u multifaucet --password="multifaucet" + -e 'INSERT IGNORE INTO faucet_promo_codes (id,code,minimum_payout,maximum_payout) + VALUES (1,"masternode",{{ masternode_collaterals.mn }},{{ masternode_collaterals.mn | int + 10 }});' - name: Load HPMN promo code - ansible.builtin.shell: | - docker exec multifaucet-db-1 mysql -h localhost -D multifaucet -u multifaucet --password="multifaucet" \ - -e 'INSERT IGNORE INTO faucet_promo_codes (id,code,minimum_payout,maximum_payout) VALUES (2,"hp-masternode",{{ masternode_collaterals.hpmn }},{{ masternode_collaterals.hpmn | int + 10 }});' + community.docker.docker_container_exec: + container: multifaucet-db-1 + command: > + mysql -h localhost -D multifaucet -u multifaucet --password="multifaucet" + -e 'INSERT IGNORE INTO faucet_promo_codes (id,code,minimum_payout,maximum_payout) + VALUES (2,"hp-masternode",{{ masternode_collaterals.hpmn }},{{ masternode_collaterals.hpmn | int + 10 }});' when: dash_network == "devnet" - name: Load platform promo code - ansible.builtin.shell: | - docker exec multifaucet-db-1 mysql -h localhost -D multifaucet -u multifaucet --password="multifaucet" \ - -e 'INSERT IGNORE INTO faucet_promo_codes (id,code,minimum_payout,maximum_payout) VALUES (3,"platform",50,55);' + community.docker.docker_container_exec: + container: multifaucet-db-1 + command: > + mysql -h localhost -D multifaucet -u multifaucet --password="multifaucet" + -e 'INSERT IGNORE INTO faucet_promo_codes (id,code,minimum_payout,maximum_payout) + VALUES (3,"platform",50,55);' From 423874a580ca9703979d3ea16e8a8a09764e5aba Mon Sep 17 00:00:00 2001 From: vivekgsharma Date: Sat, 28 Mar 2026 20:33:16 +0000 Subject: [PATCH 17/30] Install jmespath in CI and temporarily resume deploy from masternode registration --- .github/workflows/create-devnet.yml | 2 +- .github/workflows/destroy-devnet.yml | 2 +- ansible/deploy.yml | 269 +-------------------------- 3 files changed, 5 insertions(+), 268 deletions(-) diff --git a/.github/workflows/create-devnet.yml b/.github/workflows/create-devnet.yml index 5e41e934..1df3d0f0 100644 --- a/.github/workflows/create-devnet.yml +++ b/.github/workflows/create-devnet.yml @@ -117,7 +117,7 @@ jobs: - name: Install Ansible run: | python3 -m pip install --upgrade pip - python3 -m pip install ansible-core==2.16.3 + python3 -m pip install ansible-core==2.16.3 jmespath - name: Install Ansible roles run: | diff --git a/.github/workflows/destroy-devnet.yml b/.github/workflows/destroy-devnet.yml index 6ae35be5..2be8c696 100644 --- a/.github/workflows/destroy-devnet.yml +++ b/.github/workflows/destroy-devnet.yml @@ -77,7 +77,7 @@ jobs: - name: Install Ansible run: | python3 -m pip install --upgrade pip - python3 -m pip install ansible-core==2.16.3 + python3 -m pip install ansible-core==2.16.3 jmespath - name: Install Ansible roles run: | diff --git a/ansible/deploy.yml b/ansible/deploy.yml index caf71d2d..850825d2 100644 --- a/ansible/deploy.yml +++ b/ansible/deploy.yml @@ -1,271 +1,8 @@ --- -# Bootstrap - -- name: Remove latency on masternodes before deployment starts - hosts: masternodes,hp_masternodes - become: true - roles: - - remove_fake_latency - tags: - - full_deploy - - maintenance - -- name: Set up swap and aws environment vars - hosts: all - gather_facts: true - become: true - pre_tasks: - - name: Check if inside AWS - ansible.builtin.uri: - url: http://169.254.169.254/latest/meta-data - timeout: 2 - register: aws_uri_check - failed_when: false - - name: Set AWS environment variable - ansible.builtin.set_fact: - is_aws_environment: '{{ aws_uri_check.status == 200 }}' - roles: - - role: aws - when: is_aws_environment - - swap - tags: - - full_deploy - - infra_setup - -- name: Setup VPN - hosts: vpn - become: true - roles: - - role: openvpn - when: openvpn_enabled - tags: - - full_deploy - - infra_setup - - vpn - -- name: Setup jq, Python, CWAgent and Docker - hosts: all - become: true - pre_tasks: - - name: Update apt cache and install jq - ansible.builtin.apt: - pkg: - - jq - - unzip - update_cache: true - vars: - pip_package: python3-pip - pip_install_packages: - - name: docker - version: "6.0.1" - - name: docker-compose - version: "1.29.2" - - name: requests - version: "2.31.0" - roles: - - geerlingguy.pip - - role: geerlingguy.docker - vars: - docker_apt_arch: "{{ 'amd64' if ansible_architecture == 'x86_64' else 'arm64' }}" - docker_install_compose: false - docker_users: - - ubuntu - - docker_options - - eternal_terminal - - cwagent - tags: - - full_deploy - - infra_setup - -- name: Configure tcpdump - hosts: all - become: true - roles: - - role: tcpdumpd - when: dashd_network_logging != 0 - tags: - - full_deploy - - infra_setup - -- name: Setup logs - hosts: logs_nodes - become: true - roles: - - elastic_stack - - metricbeat - tags: - - full_deploy - - infra_setup - -- name: Setup load tester - hosts: load_test - become: true - roles: - - role: protobuf_compiler - - role: load_tool - tags: - - full_deploy - - infra_setup - -- name: Setup metrics - hosts: metrics - become: true - roles: - - metrics - - metricbeat - tags: - - full_deploy - - infra_setup - -- name: Set up miners - hosts: miners - become: true - roles: - - role: dash_cli - - role: dashd - tags: - - dashd - - core_filebeat - - metricbeat - tags: - - full_deploy - -- name: Set up mixers - hosts: mixer_nodes - become: true - roles: - - role: dash_cli - - role: dashd - tags: - - dashd - - core_filebeat - - metricbeat - tags: - - full_deploy - -- name: Set up core and tenderdash on seed nodes - hosts: seed_nodes - become: true - pre_tasks: - - name: Set node variables for seed nodes - ansible.builtin.set_fact: - node: "{{ seed_nodes[inventory_hostname] }}" - mode: "seed" - tags: always - when: inventory_hostname in seed_nodes - roles: - - role: dash_cli - - role: dashd - dashd_listen: true - dashd_zmq: true - dashd_indexes: true - tags: - - dashd - - role: tenderdash - - core_filebeat - - metricbeat - tags: - - full_deploy - - update_seed_nodes - -- name: Set up core on masternodes - hosts: masternodes - become: true - pre_tasks: - - name: Check inventory for masternodes - ansible.builtin.set_fact: - masternode: "{{ masternodes[inventory_hostname] }}" - tags: always - when: inventory_hostname in masternodes - - name: Fail if no masternodes present - ansible.builtin.fail: - msg: Masternode not defined in network config - when: masternode is not defined - roles: - - role: dash_cli - - role: dashd - dashd_listen: true - dashd_zmq: true - dashd_indexes: true - tags: - - dashd - - mn_status_report - - core_filebeat - - metricbeat - tags: - - full_deploy - - core_update - - update_masternodes - - -# Start network - -- name: Generate first block to leave IBD mode - hosts: seed-1 - become: true - roles: - - role: generate_firstblock - when: dash_network == "devnet" or dash_network == "regtest" - tags: - - full_deploy - -- name: Start miner - hosts: miners - become: true - roles: - - role: dashd_generate_miner - when: dash_network != "mainnet" - tags: - - full_deploy - -- name: Setup faucet and insight - hosts: web - become: true - roles: - - multifaucet - - role: dash_cli - - role: dashd - dashd_indexes: true - dashd_zmq: true - dashd_listen: true - - insight - - role: status_dashboard - when: dash_network == "devnet" - - core_filebeat - - metricbeat - tags: - - full_deploy - - web - -- name: Deploy status monitoring to masternodes - hosts: masternodes,hp_masternodes - become: true - gather_facts: false - strategy: free - roles: - - status_monitoring - tags: - - full_deploy - - dashmate_deploy - - status_dashboard - -- name: Set up wallets - hosts: wallet_nodes - become: true - roles: - - role: dash_cli - - role: dashd - dashd_indexes: true - dashd_zmq: true - enable_wallet: true - tags: - - dashd - - core_filebeat - - metricbeat - tags: - - full_deploy - - core_update +# TEMPORARY DEBUG MODE +# Early bootstrap/setup plays are intentionally skipped to speed up CI iteration. +# Restore the full playbook after the masternode registration issues are resolved. # Register masternodes and set sporks From 1b8362ac610dc71950d3d28e2743b6f6ed183ae1 Mon Sep 17 00:00:00 2001 From: vivekgsharma Date: Sat, 28 Mar 2026 20:50:48 +0000 Subject: [PATCH 18/30] Fix EHF spork activation handling and align with v3 --- ansible/roles/activate_dashd_sporks/tasks/main.yml | 5 +++-- ansible/roles/generate_blocks/tasks/main.yml | 2 +- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/ansible/roles/activate_dashd_sporks/tasks/main.yml b/ansible/roles/activate_dashd_sporks/tasks/main.yml index bb299dd6..54c0650f 100644 --- a/ansible/roles/activate_dashd_sporks/tasks/main.yml +++ b/ansible/roles/activate_dashd_sporks/tasks/main.yml @@ -28,7 +28,8 @@ - SPORK_17_QUORUM_DKG_ENABLED - SPORK_19_CHAINLOCKS_ENABLED - SPORK_21_QUORUM_ALL_CONNECTED - when: not (active_sporks.stdout | from_json)[item] + - SPORK_24_TEST_EHF + when: not ((active_sporks.stdout | from_json).get(item, false)) changed_when: spork_update.stdout == "success" - name: Activate EHF @@ -37,4 +38,4 @@ vars: generate: spork_activation spork_name: SPORK_24_TEST_EHF - when: not (active_sporks.stdout | from_json)["SPORK_24_TEST_EHF"] + when: not ((active_sporks.stdout | from_json).get("SPORK_24_TEST_EHF", false)) diff --git a/ansible/roles/generate_blocks/tasks/main.yml b/ansible/roles/generate_blocks/tasks/main.yml index 650a4a1a..e95890a0 100644 --- a/ansible/roles/generate_blocks/tasks/main.yml +++ b/ansible/roles/generate_blocks/tasks/main.yml @@ -70,7 +70,7 @@ ansible.builtin.command: dash-cli spork active when: generate == 'spork_activation' register: active_sporks - until: (active_sporks.stdout | from_json)[spork_name] + until: (active_sporks.stdout | from_json).get(spork_name, false) retries: 200 delay: 10 changed_when: active_sporks.rc == 0 From 6f0771b08e4ba7b3d1900f853275046f0a104c84 Mon Sep 17 00:00:00 2001 From: vivekgsharma Date: Sat, 28 Mar 2026 20:52:18 +0000 Subject: [PATCH 19/30] Fix EHF spork activation and temporarily resume deploy from sporks --- ansible/deploy.yml | 65 ++-------------------------------------------- 1 file changed, 2 insertions(+), 63 deletions(-) diff --git a/ansible/deploy.yml b/ansible/deploy.yml index 850825d2..7ff788ee 100644 --- a/ansible/deploy.yml +++ b/ansible/deploy.yml @@ -1,69 +1,8 @@ --- # TEMPORARY DEBUG MODE -# Early bootstrap/setup plays are intentionally skipped to speed up CI iteration. -# Restore the full playbook after the masternode registration issues are resolved. - -# Register masternodes and set sporks - -- name: Register masternodes - hosts: wallet_nodes - become: true - roles: - - role: mn_init - mnlist: "{{ masternodes }}" - funding_amount: "{{ masternode_collaterals.mn | int }}" - tags: - - full_deploy - - unban_masternodes - -- name: Update inventory with protx values - hosts: wallet_nodes - roles: - - role: mn_protx_config - mnlist: "{{ masternodes }}" - tags: - - full_deploy - - unban_masternodes - -- name: Register HP masternodes - hosts: wallet_nodes - become: true - roles: - - role: mn_init - mnlist: "{{ hp_masternodes }}" - funding_amount: "{{ masternode_collaterals.hpmn | int }}" - tags: - - full_deploy - - unban_hp_masternodes - -- name: Update inventory with HPMN protx values - hosts: wallet_nodes - roles: - - role: mn_protx_config - mnlist: "{{ hp_masternodes }}" - tags: - - full_deploy - - unban_hp_masternodes - - -- name: Fund load tester nodes - hosts: wallet_nodes - become: true - tasks: - - name: Extract load tester addresses - ansible.builtin.set_fact: - load_tester_addresses: "{{ load_testers.values() | map(attribute='wallet.address') | list }}" - when: load_testers is defined and load_testers | length > 0 - - - name: Include funding for load testers - ansible.builtin.include_tasks: ./roles/mn_fund_collateral/tasks/fund_collateral.yml - vars: - payment_targets: "{{ load_tester_addresses }}" - amount: "{{ load_tester_wallet_amount }}" - when: load_testers is defined and load_testers | length > 0 - tags: - - full_deploy +# Early plays already passed in CI and are skipped to speed up iteration. +# Current resume point: Activate sporks. Restore the full playbook after debugging. - name: Activate sporks hosts: wallet_nodes From e6b2011bcc3173bae993e74d82f8e1d1caba2157 Mon Sep 17 00:00:00 2001 From: vivekgsharma Date: Sat, 28 Mar 2026 20:55:16 +0000 Subject: [PATCH 20/30] Skip unsupported EHF spork activation --- ansible/roles/activate_dashd_sporks/tasks/main.yml | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/ansible/roles/activate_dashd_sporks/tasks/main.yml b/ansible/roles/activate_dashd_sporks/tasks/main.yml index 54c0650f..2287dc2d 100644 --- a/ansible/roles/activate_dashd_sporks/tasks/main.yml +++ b/ansible/roles/activate_dashd_sporks/tasks/main.yml @@ -28,7 +28,6 @@ - SPORK_17_QUORUM_DKG_ENABLED - SPORK_19_CHAINLOCKS_ENABLED - SPORK_21_QUORUM_ALL_CONNECTED - - SPORK_24_TEST_EHF when: not ((active_sporks.stdout | from_json).get(item, false)) changed_when: spork_update.stdout == "success" @@ -38,4 +37,6 @@ vars: generate: spork_activation spork_name: SPORK_24_TEST_EHF - when: not ((active_sporks.stdout | from_json).get("SPORK_24_TEST_EHF", false)) + when: + - "'SPORK_24_TEST_EHF' in (active_sporks.stdout | from_json)" + - not ((active_sporks.stdout | from_json).get("SPORK_24_TEST_EHF", false)) From 920b004e84cab4c1429ffe9da46e5acac82986cf Mon Sep 17 00:00:00 2001 From: vivekgsharma Date: Sat, 28 Mar 2026 21:01:02 +0000 Subject: [PATCH 21/30] Use explicit Dashmate config selection on HP nodes --- ansible/roles/dashmate/tasks/main.yml | 22 +++++++++++----------- ansible/roles/dashmate/tasks/set_vars.yml | 1 + 2 files changed, 12 insertions(+), 11 deletions(-) diff --git a/ansible/roles/dashmate/tasks/main.yml b/ansible/roles/dashmate/tasks/main.yml index 3bb030f3..4215e30a 100644 --- a/ansible/roles/dashmate/tasks/main.yml +++ b/ansible/roles/dashmate/tasks/main.yml @@ -252,7 +252,7 @@ # This check will return an error code if config is missing, config schema is invalid or default config is not yet set - name: Check state of dashmate config - ansible.builtin.command: "{{ dashmate_cmd }} config" + ansible.builtin.command: "{{ dashmate_runtime_cmd }} config" become: true become_user: dashmate args: @@ -263,7 +263,7 @@ when: not (skip_dashmate_image_update | default(false)) - name: Get ZeroSSL certificate ID from config - ansible.builtin.command: "{{ dashmate_cmd }} config get platform.gateway.ssl.providerConfigs.zerossl.id" + ansible.builtin.command: "{{ dashmate_runtime_cmd }} config get platform.gateway.ssl.providerConfigs.zerossl.id" become: true become_user: dashmate args: @@ -289,7 +289,7 @@ # Fast mode: Get ZeroSSL certificate ID from existing config if available - name: Get ZeroSSL certificate ID from config (fast mode) - ansible.builtin.command: "{{ dashmate_cmd }} config get platform.gateway.ssl.providerConfigs.zerossl.id" + ansible.builtin.command: "{{ dashmate_runtime_cmd }} config get platform.gateway.ssl.providerConfigs.zerossl.id" become: true become_user: dashmate args: @@ -434,7 +434,7 @@ # .dashmate directory already created in early permission fixes section - name: Render service configs - ansible.builtin.command: "{{ dashmate_cmd }} config render" + ansible.builtin.command: "{{ dashmate_runtime_cmd }} config render" become: true become_user: dashmate args: @@ -498,7 +498,7 @@ register: env_file_stat - name: Export current dashmate config - ansible.builtin.command: "{{ dashmate_cmd }} config envs" + ansible.builtin.command: "{{ dashmate_runtime_cmd }} config envs" become: true become_user: dashmate args: @@ -524,7 +524,7 @@ skip_image_update: "{{ skip_dashmate_image_update | default(false) }}" - name: Update dashmate images - ansible.builtin.command: "{{ dashmate_cmd }} update --format=json" + ansible.builtin.command: "{{ dashmate_runtime_cmd }} update --format=json" become: true become_user: dashmate register: dashmate_update @@ -538,7 +538,7 @@ # ============================================================================ - name: Get service statuses - ansible.builtin.command: "{{ dashmate_cmd }} status services --format=json" + ansible.builtin.command: "{{ dashmate_runtime_cmd }} status services --format=json" become: true become_user: dashmate changed_when: dashmate_services_status.rc == 0 @@ -594,7 +594,7 @@ # Start all if everything is stopped (not started yet) - name: Start all dashmate services - ansible.builtin.command: "{{ dashmate_cmd }} start --verbose" + ansible.builtin.command: "{{ dashmate_runtime_cmd }} start --verbose" become: true become_user: dashmate args: @@ -611,7 +611,7 @@ # Fast deployment: each node restarts itself independently - name: Restart dashmate services (fast mode - individual restart) - ansible.builtin.command: "{{ dashmate_cmd }} restart --safe --verbose{{ '' if needs_core_restart | default(false) else ' --platform' }}" + ansible.builtin.command: "{{ dashmate_runtime_cmd }} restart --safe --verbose{{ '' if needs_core_restart | default(false) else ' --platform' }}" become: true become_user: dashmate args: @@ -674,7 +674,7 @@ # Force start is equivalent to `docker compose up` and will replace services that have changed - name: Start not started services and replace updated services - ansible.builtin.command: "{{ dashmate_cmd }} start --force --verbose{{ '' if needs_core_restart | default(false) else ' --platform' }}" + ansible.builtin.command: "{{ dashmate_runtime_cmd }} start --force --verbose{{ '' if needs_core_restart | default(false) else ' --platform' }}" become: true become_user: dashmate args: @@ -687,7 +687,7 @@ changed_when: dashmate_force_start.rc == 0 - name: Disable dashmate helper build - ansible.builtin.command: "{{ dashmate_cmd }} config set dashmate.helper.docker.build.enabled false" + ansible.builtin.command: "{{ dashmate_runtime_cmd }} config set dashmate.helper.docker.build.enabled false" become: true become_user: dashmate register: build_dashmate_helper diff --git a/ansible/roles/dashmate/tasks/set_vars.yml b/ansible/roles/dashmate/tasks/set_vars.yml index 076437c0..6a506142 100644 --- a/ansible/roles/dashmate/tasks/set_vars.yml +++ b/ansible/roles/dashmate/tasks/set_vars.yml @@ -9,3 +9,4 @@ ansible.builtin.set_fact: dashmate_cmd: "{{ 'yarn dashmate' if dashmate_branch is defined else 'dashmate' }}" dashmate_cwd: "{{ dashmate_source_dir if dashmate_branch is defined else dashmate_home }}" + dashmate_runtime_cmd: "{{ ('yarn dashmate' if dashmate_branch is defined else 'dashmate') ~ ' --config=' ~ dash_network_name }}" From 636236c86d9011b1f9deb67614c5b09a6f54a572 Mon Sep 17 00:00:00 2001 From: vivekgsharma Date: Sat, 28 Mar 2026 21:18:10 +0000 Subject: [PATCH 22/30] Run dashmate commands with dashmate HOME like v1.0-dev --- ansible/roles/dashmate/tasks/build.yml | 7 ++++ .../roles/dashmate/tasks/destroy_platform.yml | 1 + ansible/roles/dashmate/tasks/main.yml | 34 +++++++++++++------ ansible/roles/dashmate/tasks/quick_update.yml | 2 ++ ansible/roles/dashmate/tasks/reindex.yml | 1 + .../roles/dashmate/tasks/rolling_restart.yml | 1 + ansible/roles/dashmate/tasks/set_vars.yml | 1 - .../roles/dashmate/tasks/ssl/letsencrypt.yml | 1 + ansible/roles/dashmate/tasks/ssl/zerossl.yml | 3 ++ 9 files changed, 39 insertions(+), 12 deletions(-) diff --git a/ansible/roles/dashmate/tasks/build.yml b/ansible/roles/dashmate/tasks/build.yml index b7b67325..25436b07 100644 --- a/ansible/roles/dashmate/tasks/build.yml +++ b/ansible/roles/dashmate/tasks/build.yml @@ -52,6 +52,7 @@ ansible.builtin.command: '{{ dashmate_home }}/rustup.sh -y' become: true become_user: dashmate + become_flags: '-H' when: - rustup.changed - dashmate_platform_enable @@ -73,6 +74,7 @@ cargo install wasm-bindgen-cli@0.2.86 become: true become_user: dashmate + become_flags: '-H' args: executable: /bin/bash changed_when: true @@ -110,6 +112,7 @@ - name: Clone dashmate source become: true become_user: dashmate + become_flags: '-H' ansible.builtin.git: repo: 'https://github.com/dashpay/platform' dest: '{{ dashmate_source_dir }}' @@ -132,6 +135,7 @@ ansible.builtin.command: yarn install become: true become_user: dashmate + become_flags: '-H' args: chdir: '{{ dashmate_source_dir }}' creates: '{{ dashmate_source_dir }}/.yarn/unplugged' @@ -148,6 +152,7 @@ yarn workspace dash build become: true become_user: dashmate + become_flags: '-H' args: chdir: '{{ dashmate_source_dir }}' executable: /bin/bash @@ -158,6 +163,7 @@ ansible.builtin.command: "{{ dashmate_cmd }} config" become: true become_user: dashmate + become_flags: '-H' args: chdir: '{{ dashmate_cwd }}' register: dashmate_config_result @@ -168,6 +174,7 @@ ansible.builtin.command: yarn dashmate config set dashmate.helper.docker.build.enabled true become: true become_user: dashmate + become_flags: '-H' register: build_dashmate_helper args: chdir: '{{ dashmate_source_dir }}' diff --git a/ansible/roles/dashmate/tasks/destroy_platform.yml b/ansible/roles/dashmate/tasks/destroy_platform.yml index 9a8d3442..ade6268a 100644 --- a/ansible/roles/dashmate/tasks/destroy_platform.yml +++ b/ansible/roles/dashmate/tasks/destroy_platform.yml @@ -7,6 +7,7 @@ ansible.builtin.command: "{{ dashmate_cmd }} reset --platform --force --hard" become: true become_user: dashmate + become_flags: '-H' args: chdir: '{{ dashmate_cwd }}' register: dashmate_reset diff --git a/ansible/roles/dashmate/tasks/main.yml b/ansible/roles/dashmate/tasks/main.yml index 4215e30a..5268e613 100644 --- a/ansible/roles/dashmate/tasks/main.yml +++ b/ansible/roles/dashmate/tasks/main.yml @@ -22,6 +22,7 @@ ansible.builtin.command: "{{ dashmate_cmd }} --version" become: true become_user: dashmate + become_flags: '-H' args: chdir: '{{ dashmate_cwd }}' register: current_dashmate_version @@ -252,9 +253,10 @@ # This check will return an error code if config is missing, config schema is invalid or default config is not yet set - name: Check state of dashmate config - ansible.builtin.command: "{{ dashmate_runtime_cmd }} config" + ansible.builtin.command: "{{ dashmate_cmd }} config" become: true become_user: dashmate + become_flags: '-H' args: chdir: '{{ dashmate_cwd }}' register: dashmate_config_result @@ -263,9 +265,10 @@ when: not (skip_dashmate_image_update | default(false)) - name: Get ZeroSSL certificate ID from config - ansible.builtin.command: "{{ dashmate_runtime_cmd }} config get platform.gateway.ssl.providerConfigs.zerossl.id" + ansible.builtin.command: "{{ dashmate_cmd }} config get platform.gateway.ssl.providerConfigs.zerossl.id" become: true become_user: dashmate + become_flags: '-H' args: chdir: '{{ dashmate_cwd }}' register: dashmate_zerossl_id_result @@ -289,9 +292,10 @@ # Fast mode: Get ZeroSSL certificate ID from existing config if available - name: Get ZeroSSL certificate ID from config (fast mode) - ansible.builtin.command: "{{ dashmate_runtime_cmd }} config get platform.gateway.ssl.providerConfigs.zerossl.id" + ansible.builtin.command: "{{ dashmate_cmd }} config get platform.gateway.ssl.providerConfigs.zerossl.id" become: true become_user: dashmate + become_flags: '-H' args: chdir: '{{ dashmate_cwd }}' register: dashmate_zerossl_id_result_fast @@ -434,9 +438,10 @@ # .dashmate directory already created in early permission fixes section - name: Render service configs - ansible.builtin.command: "{{ dashmate_runtime_cmd }} config render" + ansible.builtin.command: "{{ dashmate_cmd }} config render" become: true become_user: dashmate + become_flags: '-H' args: chdir: '{{ dashmate_cwd }}' register: dashmate_render_configs_result @@ -498,9 +503,10 @@ register: env_file_stat - name: Export current dashmate config - ansible.builtin.command: "{{ dashmate_runtime_cmd }} config envs" + ansible.builtin.command: "{{ dashmate_cmd }} config envs" become: true become_user: dashmate + become_flags: '-H' args: chdir: '{{ dashmate_cwd }}' register: dashmate_envs_output @@ -524,9 +530,10 @@ skip_image_update: "{{ skip_dashmate_image_update | default(false) }}" - name: Update dashmate images - ansible.builtin.command: "{{ dashmate_runtime_cmd }} update --format=json" + ansible.builtin.command: "{{ dashmate_cmd }} update --format=json" become: true become_user: dashmate + become_flags: '-H' register: dashmate_update args: chdir: '{{ dashmate_cwd }}' @@ -538,9 +545,10 @@ # ============================================================================ - name: Get service statuses - ansible.builtin.command: "{{ dashmate_runtime_cmd }} status services --format=json" + ansible.builtin.command: "{{ dashmate_cmd }} status services --format=json" become: true become_user: dashmate + become_flags: '-H' changed_when: dashmate_services_status.rc == 0 args: chdir: '{{ dashmate_cwd }}' @@ -594,9 +602,10 @@ # Start all if everything is stopped (not started yet) - name: Start all dashmate services - ansible.builtin.command: "{{ dashmate_runtime_cmd }} start --verbose" + ansible.builtin.command: "{{ dashmate_cmd }} start --verbose" become: true become_user: dashmate + become_flags: '-H' args: chdir: '{{ dashmate_cwd }}' register: dashmate_start_all @@ -611,9 +620,10 @@ # Fast deployment: each node restarts itself independently - name: Restart dashmate services (fast mode - individual restart) - ansible.builtin.command: "{{ dashmate_runtime_cmd }} restart --safe --verbose{{ '' if needs_core_restart | default(false) else ' --platform' }}" + ansible.builtin.command: "{{ dashmate_cmd }} restart --safe --verbose{{ '' if needs_core_restart | default(false) else ' --platform' }}" become: true become_user: dashmate + become_flags: '-H' args: chdir: '{{ dashmate_cwd }}' register: dashmate_restart_all @@ -674,9 +684,10 @@ # Force start is equivalent to `docker compose up` and will replace services that have changed - name: Start not started services and replace updated services - ansible.builtin.command: "{{ dashmate_runtime_cmd }} start --force --verbose{{ '' if needs_core_restart | default(false) else ' --platform' }}" + ansible.builtin.command: "{{ dashmate_cmd }} start --force --verbose{{ '' if needs_core_restart | default(false) else ' --platform' }}" become: true become_user: dashmate + become_flags: '-H' args: chdir: '{{ dashmate_cwd }}' register: dashmate_force_start @@ -687,9 +698,10 @@ changed_when: dashmate_force_start.rc == 0 - name: Disable dashmate helper build - ansible.builtin.command: "{{ dashmate_runtime_cmd }} config set dashmate.helper.docker.build.enabled false" + ansible.builtin.command: "{{ dashmate_cmd }} config set dashmate.helper.docker.build.enabled false" become: true become_user: dashmate + become_flags: '-H' register: build_dashmate_helper args: chdir: '{{ dashmate_cwd }}' diff --git a/ansible/roles/dashmate/tasks/quick_update.yml b/ansible/roles/dashmate/tasks/quick_update.yml index 4b2589ae..52684572 100644 --- a/ansible/roles/dashmate/tasks/quick_update.yml +++ b/ansible/roles/dashmate/tasks/quick_update.yml @@ -14,6 +14,7 @@ ansible.builtin.command: "{{ dashmate_cmd }} --version" become: true become_user: dashmate + become_flags: '-H' args: chdir: '{{ dashmate_cwd }}' register: current_dashmate_version @@ -44,6 +45,7 @@ ansible.builtin.command: "{{ dashmate_cmd }} restart --verbose" become: true become_user: dashmate + become_flags: '-H' args: chdir: '{{ dashmate_cwd }}' register: dashmate_restart diff --git a/ansible/roles/dashmate/tasks/reindex.yml b/ansible/roles/dashmate/tasks/reindex.yml index 673a486e..47f9f087 100644 --- a/ansible/roles/dashmate/tasks/reindex.yml +++ b/ansible/roles/dashmate/tasks/reindex.yml @@ -6,6 +6,7 @@ ansible.builtin.command: "{{ dashmate_cmd }} reindex -d --force" become: true become_user: dashmate + become_flags: '-H' args: chdir: '{{ dashmate_cwd }}' register: dashmate_reindex diff --git a/ansible/roles/dashmate/tasks/rolling_restart.yml b/ansible/roles/dashmate/tasks/rolling_restart.yml index 9fb93b59..e215872f 100644 --- a/ansible/roles/dashmate/tasks/rolling_restart.yml +++ b/ansible/roles/dashmate/tasks/rolling_restart.yml @@ -4,6 +4,7 @@ ansible.builtin.command: "{{ dashmate_cmd }} restart --safe --verbose{{ '' if needs_core_restart | default(false) else ' --platform' }}" become: true become_user: dashmate + become_flags: '-H' args: chdir: '{{ dashmate_cwd }}' register: dashmate_restart_all diff --git a/ansible/roles/dashmate/tasks/set_vars.yml b/ansible/roles/dashmate/tasks/set_vars.yml index 6a506142..076437c0 100644 --- a/ansible/roles/dashmate/tasks/set_vars.yml +++ b/ansible/roles/dashmate/tasks/set_vars.yml @@ -9,4 +9,3 @@ ansible.builtin.set_fact: dashmate_cmd: "{{ 'yarn dashmate' if dashmate_branch is defined else 'dashmate' }}" dashmate_cwd: "{{ dashmate_source_dir if dashmate_branch is defined else dashmate_home }}" - dashmate_runtime_cmd: "{{ ('yarn dashmate' if dashmate_branch is defined else 'dashmate') ~ ' --config=' ~ dash_network_name }}" diff --git a/ansible/roles/dashmate/tasks/ssl/letsencrypt.yml b/ansible/roles/dashmate/tasks/ssl/letsencrypt.yml index 4e23733f..03295812 100644 --- a/ansible/roles/dashmate/tasks/ssl/letsencrypt.yml +++ b/ansible/roles/dashmate/tasks/ssl/letsencrypt.yml @@ -16,6 +16,7 @@ ansible.builtin.command: "{{ dashmate_cmd }} ssl obtain --provider letsencrypt --verbose --no-retry" become: true become_user: dashmate + become_flags: '-H' args: chdir: '{{ dashmate_cwd }}' register: dashmate_letsencrypt_obtain diff --git a/ansible/roles/dashmate/tasks/ssl/zerossl.yml b/ansible/roles/dashmate/tasks/ssl/zerossl.yml index 607880a4..97551856 100644 --- a/ansible/roles/dashmate/tasks/ssl/zerossl.yml +++ b/ansible/roles/dashmate/tasks/ssl/zerossl.yml @@ -29,6 +29,7 @@ ansible.builtin.command: "{{ dashmate_cmd }} config set {{ dashmate_zerossl_config_path }}.id {{ dashmate_zerossl_ssm_certificate_id }}" become: true become_user: dashmate + become_flags: '-H' args: chdir: '{{ dashmate_cwd }}' register: dashmate_zerossl_id @@ -70,6 +71,7 @@ ansible.builtin.command: "{{ dashmate_cmd }} ssl obtain --verbose --no-retry" become: true become_user: dashmate + become_flags: '-H' args: chdir: '{{ dashmate_cwd }}' register: dashmate_obtain @@ -84,6 +86,7 @@ ansible.builtin.command: "{{ dashmate_cmd }} config get {{ dashmate_zerossl_config_path }}.id" become: true become_user: dashmate + become_flags: '-H' args: chdir: '{{ dashmate_cwd }}' register: dashmate_zerossl_id From 6e5cb5e922cfaa42ea7da701b2546fd1f8e13483 Mon Sep 17 00:00:00 2001 From: vivekgsharma Date: Sat, 28 Mar 2026 21:43:57 +0000 Subject: [PATCH 23/30] Fix empty quorum-list RPC password in generated Dashmate config --- ansible/deploy.yml | 21 ++----------------- .../roles/dashmate/templates/dashmate.json.j2 | 2 +- lib/configGenerator/generateAnsibleConfig.js | 1 + 3 files changed, 4 insertions(+), 20 deletions(-) diff --git a/ansible/deploy.yml b/ansible/deploy.yml index 7ff788ee..9ffb9767 100644 --- a/ansible/deploy.yml +++ b/ansible/deploy.yml @@ -2,25 +2,8 @@ # TEMPORARY DEBUG MODE # Early plays already passed in CI and are skipped to speed up iteration. -# Current resume point: Activate sporks. Restore the full playbook after debugging. - -- name: Activate sporks - hosts: wallet_nodes - become: true - roles: - - role: activate_dashd_sporks - when: dash_network != "mainnet" and dash_network != "testnet" - delegate_to: '{{ play_hosts | first }}' - tags: - - full_deploy - -# todo: partially working code causes errors in deploy, comment out for now and fix later -# - name: Create governance proposals -# hosts: wallet_nodes -# become: true -# roles: -# - role: generate_proposals -# when: governance_proposal_count > 0 +# Current resume point: Set up core and platform on HP masternodes. +# Restore the full playbook after debugging. - name: Set up core and platform on HP masternodes hosts: hp_masternodes diff --git a/ansible/roles/dashmate/templates/dashmate.json.j2 b/ansible/roles/dashmate/templates/dashmate.json.j2 index c3c57163..8cfcfc93 100644 --- a/ansible/roles/dashmate/templates/dashmate.json.j2 +++ b/ansible/roles/dashmate/templates/dashmate.json.j2 @@ -60,7 +60,7 @@ "lowPriority": false }, "quorum_list": { - "password": "{{ dashmate_core_rpc_quorum_list_password | default(dashmate_core_rpc_dashmate_password) }}", + "password": "{{ dashmate_core_rpc_quorum_list_password | default(dashmate_core_rpc_dashmate_password, true) }}", "whitelist": [ "quorum", "masternode", "getblockcount" ], diff --git a/lib/configGenerator/generateAnsibleConfig.js b/lib/configGenerator/generateAnsibleConfig.js index 4143da2c..46926504 100644 --- a/lib/configGenerator/generateAnsibleConfig.js +++ b/lib/configGenerator/generateAnsibleConfig.js @@ -155,6 +155,7 @@ async function generateAnsibleConfig( config.dashmate_core_rpc_dashmate_password = crypto.randomBytes(32) .toString('base64').slice(0, 32); + config.dashmate_core_rpc_quorum_list_password = config.dashmate_core_rpc_dashmate_password; config.dashmate_core_rpc_dapi_password = crypto.randomBytes(32) .toString('base64').slice(0, 32); config.dashmate_core_rpc_drive_consensus_password = crypto.randomBytes(32) From bf599edbde9552ca35577921b7aa90ce625c5b15 Mon Sep 17 00:00:00 2001 From: vivekgsharma Date: Sat, 28 Mar 2026 21:59:12 +0000 Subject: [PATCH 24/30] Retry dashmate letsencrypt obtain on transient ACME failures --- ansible/roles/dashmate/tasks/ssl/letsencrypt.yml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/ansible/roles/dashmate/tasks/ssl/letsencrypt.yml b/ansible/roles/dashmate/tasks/ssl/letsencrypt.yml index 03295812..1eab18f0 100644 --- a/ansible/roles/dashmate/tasks/ssl/letsencrypt.yml +++ b/ansible/roles/dashmate/tasks/ssl/letsencrypt.yml @@ -21,3 +21,6 @@ chdir: '{{ dashmate_cwd }}' register: dashmate_letsencrypt_obtain changed_when: dashmate_letsencrypt_obtain.rc == 0 + retries: 3 + delay: 20 + until: dashmate_letsencrypt_obtain.rc == 0 From 08fbc954f14d4b2eb48da76b8bfd19d00b7293a7 Mon Sep 17 00:00:00 2001 From: vivekgsharma Date: Mon, 30 Mar 2026 09:42:17 +0000 Subject: [PATCH 25/30] Restore full deploy playbook after CI debugging --- ansible/deploy.yml | 349 ++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 345 insertions(+), 4 deletions(-) diff --git a/ansible/deploy.yml b/ansible/deploy.yml index 9ffb9767..caf71d2d 100644 --- a/ansible/deploy.yml +++ b/ansible/deploy.yml @@ -1,9 +1,350 @@ --- -# TEMPORARY DEBUG MODE -# Early plays already passed in CI and are skipped to speed up iteration. -# Current resume point: Set up core and platform on HP masternodes. -# Restore the full playbook after debugging. +# Bootstrap + +- name: Remove latency on masternodes before deployment starts + hosts: masternodes,hp_masternodes + become: true + roles: + - remove_fake_latency + tags: + - full_deploy + - maintenance + +- name: Set up swap and aws environment vars + hosts: all + gather_facts: true + become: true + pre_tasks: + - name: Check if inside AWS + ansible.builtin.uri: + url: http://169.254.169.254/latest/meta-data + timeout: 2 + register: aws_uri_check + failed_when: false + - name: Set AWS environment variable + ansible.builtin.set_fact: + is_aws_environment: '{{ aws_uri_check.status == 200 }}' + roles: + - role: aws + when: is_aws_environment + - swap + tags: + - full_deploy + - infra_setup + +- name: Setup VPN + hosts: vpn + become: true + roles: + - role: openvpn + when: openvpn_enabled + tags: + - full_deploy + - infra_setup + - vpn + +- name: Setup jq, Python, CWAgent and Docker + hosts: all + become: true + pre_tasks: + - name: Update apt cache and install jq + ansible.builtin.apt: + pkg: + - jq + - unzip + update_cache: true + vars: + pip_package: python3-pip + pip_install_packages: + - name: docker + version: "6.0.1" + - name: docker-compose + version: "1.29.2" + - name: requests + version: "2.31.0" + roles: + - geerlingguy.pip + - role: geerlingguy.docker + vars: + docker_apt_arch: "{{ 'amd64' if ansible_architecture == 'x86_64' else 'arm64' }}" + docker_install_compose: false + docker_users: + - ubuntu + - docker_options + - eternal_terminal + - cwagent + tags: + - full_deploy + - infra_setup + +- name: Configure tcpdump + hosts: all + become: true + roles: + - role: tcpdumpd + when: dashd_network_logging != 0 + tags: + - full_deploy + - infra_setup + +- name: Setup logs + hosts: logs_nodes + become: true + roles: + - elastic_stack + - metricbeat + tags: + - full_deploy + - infra_setup + +- name: Setup load tester + hosts: load_test + become: true + roles: + - role: protobuf_compiler + - role: load_tool + tags: + - full_deploy + - infra_setup + +- name: Setup metrics + hosts: metrics + become: true + roles: + - metrics + - metricbeat + tags: + - full_deploy + - infra_setup + +- name: Set up miners + hosts: miners + become: true + roles: + - role: dash_cli + - role: dashd + tags: + - dashd + - core_filebeat + - metricbeat + tags: + - full_deploy + +- name: Set up mixers + hosts: mixer_nodes + become: true + roles: + - role: dash_cli + - role: dashd + tags: + - dashd + - core_filebeat + - metricbeat + tags: + - full_deploy + +- name: Set up core and tenderdash on seed nodes + hosts: seed_nodes + become: true + pre_tasks: + - name: Set node variables for seed nodes + ansible.builtin.set_fact: + node: "{{ seed_nodes[inventory_hostname] }}" + mode: "seed" + tags: always + when: inventory_hostname in seed_nodes + roles: + - role: dash_cli + - role: dashd + dashd_listen: true + dashd_zmq: true + dashd_indexes: true + tags: + - dashd + - role: tenderdash + - core_filebeat + - metricbeat + tags: + - full_deploy + - update_seed_nodes + +- name: Set up core on masternodes + hosts: masternodes + become: true + pre_tasks: + - name: Check inventory for masternodes + ansible.builtin.set_fact: + masternode: "{{ masternodes[inventory_hostname] }}" + tags: always + when: inventory_hostname in masternodes + - name: Fail if no masternodes present + ansible.builtin.fail: + msg: Masternode not defined in network config + when: masternode is not defined + roles: + - role: dash_cli + - role: dashd + dashd_listen: true + dashd_zmq: true + dashd_indexes: true + tags: + - dashd + - mn_status_report + - core_filebeat + - metricbeat + tags: + - full_deploy + - core_update + - update_masternodes + + +# Start network + +- name: Generate first block to leave IBD mode + hosts: seed-1 + become: true + roles: + - role: generate_firstblock + when: dash_network == "devnet" or dash_network == "regtest" + tags: + - full_deploy + +- name: Start miner + hosts: miners + become: true + roles: + - role: dashd_generate_miner + when: dash_network != "mainnet" + tags: + - full_deploy + +- name: Setup faucet and insight + hosts: web + become: true + roles: + - multifaucet + - role: dash_cli + - role: dashd + dashd_indexes: true + dashd_zmq: true + dashd_listen: true + - insight + - role: status_dashboard + when: dash_network == "devnet" + - core_filebeat + - metricbeat + tags: + - full_deploy + - web + +- name: Deploy status monitoring to masternodes + hosts: masternodes,hp_masternodes + become: true + gather_facts: false + strategy: free + roles: + - status_monitoring + tags: + - full_deploy + - dashmate_deploy + - status_dashboard + +- name: Set up wallets + hosts: wallet_nodes + become: true + roles: + - role: dash_cli + - role: dashd + dashd_indexes: true + dashd_zmq: true + enable_wallet: true + tags: + - dashd + - core_filebeat + - metricbeat + tags: + - full_deploy + - core_update + +# Register masternodes and set sporks + +- name: Register masternodes + hosts: wallet_nodes + become: true + roles: + - role: mn_init + mnlist: "{{ masternodes }}" + funding_amount: "{{ masternode_collaterals.mn | int }}" + tags: + - full_deploy + - unban_masternodes + +- name: Update inventory with protx values + hosts: wallet_nodes + roles: + - role: mn_protx_config + mnlist: "{{ masternodes }}" + tags: + - full_deploy + - unban_masternodes + +- name: Register HP masternodes + hosts: wallet_nodes + become: true + roles: + - role: mn_init + mnlist: "{{ hp_masternodes }}" + funding_amount: "{{ masternode_collaterals.hpmn | int }}" + tags: + - full_deploy + - unban_hp_masternodes + +- name: Update inventory with HPMN protx values + hosts: wallet_nodes + roles: + - role: mn_protx_config + mnlist: "{{ hp_masternodes }}" + tags: + - full_deploy + - unban_hp_masternodes + + +- name: Fund load tester nodes + hosts: wallet_nodes + become: true + tasks: + - name: Extract load tester addresses + ansible.builtin.set_fact: + load_tester_addresses: "{{ load_testers.values() | map(attribute='wallet.address') | list }}" + when: load_testers is defined and load_testers | length > 0 + + - name: Include funding for load testers + ansible.builtin.include_tasks: ./roles/mn_fund_collateral/tasks/fund_collateral.yml + vars: + payment_targets: "{{ load_tester_addresses }}" + amount: "{{ load_tester_wallet_amount }}" + when: load_testers is defined and load_testers | length > 0 + tags: + - full_deploy + +- name: Activate sporks + hosts: wallet_nodes + become: true + roles: + - role: activate_dashd_sporks + when: dash_network != "mainnet" and dash_network != "testnet" + delegate_to: '{{ play_hosts | first }}' + tags: + - full_deploy + +# todo: partially working code causes errors in deploy, comment out for now and fix later +# - name: Create governance proposals +# hosts: wallet_nodes +# become: true +# roles: +# - role: generate_proposals +# when: governance_proposal_count > 0 - name: Set up core and platform on HP masternodes hosts: hp_masternodes From 2c895a614efea84fdecbd0d2d6b5a39fb130a460 Mon Sep 17 00:00:00 2001 From: vivekgsharma Date: Mon, 30 Mar 2026 09:56:48 +0000 Subject: [PATCH 26/30] Use write key fallback when removing devnet configs --- .github/workflows/destroy-devnet.yml | 23 ++++++++++++++++++++++- 1 file changed, 22 insertions(+), 1 deletion(-) diff --git a/.github/workflows/destroy-devnet.yml b/.github/workflows/destroy-devnet.yml index 2be8c696..43fb7f96 100644 --- a/.github/workflows/destroy-devnet.yml +++ b/.github/workflows/destroy-devnet.yml @@ -89,6 +89,7 @@ jobs: env: DEPLOY_SERVER_KEY: ${{ secrets.DEPLOY_SERVER_KEY }} EVO_APP_DEPLOY_KEY: ${{ secrets.EVO_APP_DEPLOY_KEY }} + EVO_APP_DEPLOY_WRITE_KEY: ${{ secrets.EVO_APP_DEPLOY_WRITE_KEY }} run: | mkdir -p ~/.ssh @@ -104,6 +105,12 @@ jobs: printf '%s\n' "$EVO_APP_DEPLOY_KEY" > ~/.ssh/id_ed25519 chmod 600 ~/.ssh/id_ed25519 + # Optional write key for pushing to configs repo + if [[ -n "$EVO_APP_DEPLOY_WRITE_KEY" ]]; then + printf '%s\n' "$EVO_APP_DEPLOY_WRITE_KEY" > ~/.ssh/id_ed25519_write + chmod 600 ~/.ssh/id_ed25519_write + fi + # SSH config cat > ~/.ssh/config << 'EOL' Host github.com @@ -199,6 +206,8 @@ jobs: - name: Remove configs from dash-network-configs if: github.event.inputs.destroy_target == 'all' + env: + EVO_APP_DEPLOY_WRITE_KEY: ${{ secrets.EVO_APP_DEPLOY_WRITE_KEY }} run: | cd /tmp/dash-network-configs git config user.name "GitHub Actions" @@ -210,7 +219,19 @@ jobs: git rm "$NETWORK_NAME.inventory" 2>/dev/null || true git commit -m "Remove configs for $NETWORK_NAME (destroyed)" || echo "No changes to commit" - git push + + # Use optional write key if configured; otherwise try default key. + if [[ -n "$EVO_APP_DEPLOY_WRITE_KEY" && -f "$HOME/.ssh/id_ed25519_write" ]]; then + GIT_SSH_COMMAND='ssh -i ~/.ssh/id_ed25519_write -o StrictHostKeyChecking=no' git push || { + echo "::warning::Failed to push config removal with EVO_APP_DEPLOY_WRITE_KEY" + exit 0 + } + else + git push || { + echo "::warning::Failed to push config removal (likely read-only EVO_APP_DEPLOY_KEY). Configure secret EVO_APP_DEPLOY_WRITE_KEY with write access." + exit 0 + } + fi echo "Configs removed from dash-network-configs repo" From 01ec6ac3c3a184857fa5a99667f5df95a9a8d17e Mon Sep 17 00:00:00 2001 From: vivekgsharma Date: Mon, 30 Mar 2026 10:53:44 +0000 Subject: [PATCH 27/30] Split fee and collateral funding paths for masternode registration --- ansible/deploy.yml | 268 +----------------- .../tasks/fund_collateral.yml | 16 +- ansible/roles/mn_init/tasks/main.yml | 25 +- 3 files changed, 28 insertions(+), 281 deletions(-) diff --git a/ansible/deploy.yml b/ansible/deploy.yml index caf71d2d..69435b9d 100644 --- a/ansible/deploy.yml +++ b/ansible/deploy.yml @@ -1,272 +1,6 @@ --- -# Bootstrap - -- name: Remove latency on masternodes before deployment starts - hosts: masternodes,hp_masternodes - become: true - roles: - - remove_fake_latency - tags: - - full_deploy - - maintenance - -- name: Set up swap and aws environment vars - hosts: all - gather_facts: true - become: true - pre_tasks: - - name: Check if inside AWS - ansible.builtin.uri: - url: http://169.254.169.254/latest/meta-data - timeout: 2 - register: aws_uri_check - failed_when: false - - name: Set AWS environment variable - ansible.builtin.set_fact: - is_aws_environment: '{{ aws_uri_check.status == 200 }}' - roles: - - role: aws - when: is_aws_environment - - swap - tags: - - full_deploy - - infra_setup - -- name: Setup VPN - hosts: vpn - become: true - roles: - - role: openvpn - when: openvpn_enabled - tags: - - full_deploy - - infra_setup - - vpn - -- name: Setup jq, Python, CWAgent and Docker - hosts: all - become: true - pre_tasks: - - name: Update apt cache and install jq - ansible.builtin.apt: - pkg: - - jq - - unzip - update_cache: true - vars: - pip_package: python3-pip - pip_install_packages: - - name: docker - version: "6.0.1" - - name: docker-compose - version: "1.29.2" - - name: requests - version: "2.31.0" - roles: - - geerlingguy.pip - - role: geerlingguy.docker - vars: - docker_apt_arch: "{{ 'amd64' if ansible_architecture == 'x86_64' else 'arm64' }}" - docker_install_compose: false - docker_users: - - ubuntu - - docker_options - - eternal_terminal - - cwagent - tags: - - full_deploy - - infra_setup - -- name: Configure tcpdump - hosts: all - become: true - roles: - - role: tcpdumpd - when: dashd_network_logging != 0 - tags: - - full_deploy - - infra_setup - -- name: Setup logs - hosts: logs_nodes - become: true - roles: - - elastic_stack - - metricbeat - tags: - - full_deploy - - infra_setup - -- name: Setup load tester - hosts: load_test - become: true - roles: - - role: protobuf_compiler - - role: load_tool - tags: - - full_deploy - - infra_setup - -- name: Setup metrics - hosts: metrics - become: true - roles: - - metrics - - metricbeat - tags: - - full_deploy - - infra_setup - -- name: Set up miners - hosts: miners - become: true - roles: - - role: dash_cli - - role: dashd - tags: - - dashd - - core_filebeat - - metricbeat - tags: - - full_deploy - -- name: Set up mixers - hosts: mixer_nodes - become: true - roles: - - role: dash_cli - - role: dashd - tags: - - dashd - - core_filebeat - - metricbeat - tags: - - full_deploy - -- name: Set up core and tenderdash on seed nodes - hosts: seed_nodes - become: true - pre_tasks: - - name: Set node variables for seed nodes - ansible.builtin.set_fact: - node: "{{ seed_nodes[inventory_hostname] }}" - mode: "seed" - tags: always - when: inventory_hostname in seed_nodes - roles: - - role: dash_cli - - role: dashd - dashd_listen: true - dashd_zmq: true - dashd_indexes: true - tags: - - dashd - - role: tenderdash - - core_filebeat - - metricbeat - tags: - - full_deploy - - update_seed_nodes - -- name: Set up core on masternodes - hosts: masternodes - become: true - pre_tasks: - - name: Check inventory for masternodes - ansible.builtin.set_fact: - masternode: "{{ masternodes[inventory_hostname] }}" - tags: always - when: inventory_hostname in masternodes - - name: Fail if no masternodes present - ansible.builtin.fail: - msg: Masternode not defined in network config - when: masternode is not defined - roles: - - role: dash_cli - - role: dashd - dashd_listen: true - dashd_zmq: true - dashd_indexes: true - tags: - - dashd - - mn_status_report - - core_filebeat - - metricbeat - tags: - - full_deploy - - core_update - - update_masternodes - - -# Start network - -- name: Generate first block to leave IBD mode - hosts: seed-1 - become: true - roles: - - role: generate_firstblock - when: dash_network == "devnet" or dash_network == "regtest" - tags: - - full_deploy - -- name: Start miner - hosts: miners - become: true - roles: - - role: dashd_generate_miner - when: dash_network != "mainnet" - tags: - - full_deploy - -- name: Setup faucet and insight - hosts: web - become: true - roles: - - multifaucet - - role: dash_cli - - role: dashd - dashd_indexes: true - dashd_zmq: true - dashd_listen: true - - insight - - role: status_dashboard - when: dash_network == "devnet" - - core_filebeat - - metricbeat - tags: - - full_deploy - - web - -- name: Deploy status monitoring to masternodes - hosts: masternodes,hp_masternodes - become: true - gather_facts: false - strategy: free - roles: - - status_monitoring - tags: - - full_deploy - - dashmate_deploy - - status_dashboard - -- name: Set up wallets - hosts: wallet_nodes - become: true - roles: - - role: dash_cli - - role: dashd - dashd_indexes: true - dashd_zmq: true - enable_wallet: true - tags: - - dashd - - core_filebeat - - metricbeat - tags: - - full_deploy - - core_update - +# TEMPORARY DEBUG MODE: resume from masternode registration # Register masternodes and set sporks - name: Register masternodes diff --git a/ansible/roles/mn_fund_collateral/tasks/fund_collateral.yml b/ansible/roles/mn_fund_collateral/tasks/fund_collateral.yml index c804ddd8..1059ba3b 100644 --- a/ansible/roles/mn_fund_collateral/tasks/fund_collateral.yml +++ b/ansible/roles/mn_fund_collateral/tasks/fund_collateral.yml @@ -17,14 +17,8 @@ var: payments - name: Fund listed masternodes with {{ amount ~ ' Dash'}} - ansible.builtin.command: "dash-cli -rpcwallet={{ wallet_rpc_wallet_faucet }} sendmany '' '{{ payments | to_json }}'" - register: fund_result - changed_when: fund_result.stdout | length == 64 - -- name: Produce blocks until funding transaction is confirmed - ansible.builtin.include_role: - name: generate_blocks - vars: - generate: confirmations - txid_list: "{{ [fund_result.stdout] }}" - tx_source: "{{ wallet_rpc_wallet_faucet }}" + ansible.builtin.include_tasks: "{{ playbook_dir }}/roles/mn_fund_collateral/tasks/fund_one_collateral.yml" + with_items: + - '{{ payment_targets }}' + loop_control: + loop_var: payment_target diff --git a/ansible/roles/mn_init/tasks/main.yml b/ansible/roles/mn_init/tasks/main.yml index b5413c86..9a8ff529 100644 --- a/ansible/roles/mn_init/tasks/main.yml +++ b/ansible/roles/mn_init/tasks/main.yml @@ -203,11 +203,30 @@ ansible.builtin.set_fact: fee_missing_addresses: "{{ fee_target_addresses | difference(funded_addresses.stdout) }}" +- name: Initialize fee payments + ansible.builtin.set_fact: + fee_payments: {} + when: fee_missing_addresses | length > 0 + +- name: Populate fee payments + ansible.builtin.set_fact: + fee_payments: "{{ fee_payments | combine({item: 1}) }}" + with_items: '{{ fee_missing_addresses }}' + when: fee_missing_addresses | length > 0 + - name: Fund 1 coin for ProTx fee - ansible.builtin.include_tasks: ./roles/mn_fund_collateral/tasks/fund_collateral.yml + ansible.builtin.command: "dash-cli -rpcwallet={{ wallet_rpc_wallet_faucet }} sendmany '' '{{ fee_payments | to_json }}'" + register: fee_fund_result + changed_when: fee_fund_result.stdout | length == 64 + when: fee_missing_addresses | length > 0 + +- name: Produce blocks until fee funding transaction is confirmed + ansible.builtin.include_role: + name: generate_blocks vars: - amount: 1 - payment_targets: '{{ fee_missing_addresses }}' + generate: confirmations + txid_list: "{{ [fee_fund_result.stdout] }}" + tx_source: "{{ wallet_rpc_wallet_faucet }}" when: fee_missing_addresses | length > 0 # Take action From 329878c47781adf9857edde7c7c0d396fa1ff571 Mon Sep 17 00:00:00 2001 From: vivekgsharma Date: Mon, 30 Mar 2026 11:07:36 +0000 Subject: [PATCH 28/30] Restore masternode funding roles to v1.0-dev behavior --- .../tasks/fund_collateral.yml | 16 ++++++++---- ansible/roles/mn_init/tasks/main.yml | 25 +++---------------- 2 files changed, 14 insertions(+), 27 deletions(-) diff --git a/ansible/roles/mn_fund_collateral/tasks/fund_collateral.yml b/ansible/roles/mn_fund_collateral/tasks/fund_collateral.yml index 1059ba3b..c804ddd8 100644 --- a/ansible/roles/mn_fund_collateral/tasks/fund_collateral.yml +++ b/ansible/roles/mn_fund_collateral/tasks/fund_collateral.yml @@ -17,8 +17,14 @@ var: payments - name: Fund listed masternodes with {{ amount ~ ' Dash'}} - ansible.builtin.include_tasks: "{{ playbook_dir }}/roles/mn_fund_collateral/tasks/fund_one_collateral.yml" - with_items: - - '{{ payment_targets }}' - loop_control: - loop_var: payment_target + ansible.builtin.command: "dash-cli -rpcwallet={{ wallet_rpc_wallet_faucet }} sendmany '' '{{ payments | to_json }}'" + register: fund_result + changed_when: fund_result.stdout | length == 64 + +- name: Produce blocks until funding transaction is confirmed + ansible.builtin.include_role: + name: generate_blocks + vars: + generate: confirmations + txid_list: "{{ [fund_result.stdout] }}" + tx_source: "{{ wallet_rpc_wallet_faucet }}" diff --git a/ansible/roles/mn_init/tasks/main.yml b/ansible/roles/mn_init/tasks/main.yml index 9a8ff529..b5413c86 100644 --- a/ansible/roles/mn_init/tasks/main.yml +++ b/ansible/roles/mn_init/tasks/main.yml @@ -203,30 +203,11 @@ ansible.builtin.set_fact: fee_missing_addresses: "{{ fee_target_addresses | difference(funded_addresses.stdout) }}" -- name: Initialize fee payments - ansible.builtin.set_fact: - fee_payments: {} - when: fee_missing_addresses | length > 0 - -- name: Populate fee payments - ansible.builtin.set_fact: - fee_payments: "{{ fee_payments | combine({item: 1}) }}" - with_items: '{{ fee_missing_addresses }}' - when: fee_missing_addresses | length > 0 - - name: Fund 1 coin for ProTx fee - ansible.builtin.command: "dash-cli -rpcwallet={{ wallet_rpc_wallet_faucet }} sendmany '' '{{ fee_payments | to_json }}'" - register: fee_fund_result - changed_when: fee_fund_result.stdout | length == 64 - when: fee_missing_addresses | length > 0 - -- name: Produce blocks until fee funding transaction is confirmed - ansible.builtin.include_role: - name: generate_blocks + ansible.builtin.include_tasks: ./roles/mn_fund_collateral/tasks/fund_collateral.yml vars: - generate: confirmations - txid_list: "{{ [fee_fund_result.stdout] }}" - tx_source: "{{ wallet_rpc_wallet_faucet }}" + amount: 1 + payment_targets: '{{ fee_missing_addresses }}' when: fee_missing_addresses | length > 0 # Take action From 00fceb3c63a22755ecfa01dff34fa757da7bed11 Mon Sep 17 00:00:00 2001 From: vivekgsharma Date: Mon, 30 Mar 2026 11:19:42 +0000 Subject: [PATCH 29/30] Fund HPMN collaterals one at a time to avoid oversized transactions --- .../tasks/fund_collateral.yml | 16 ++++-------- .../tasks/fund_one_collateral.yml | 16 ++++++++++++ ansible/roles/mn_init/tasks/main.yml | 25 ++++++++++++++++--- 3 files changed, 43 insertions(+), 14 deletions(-) create mode 100644 ansible/roles/mn_fund_collateral/tasks/fund_one_collateral.yml diff --git a/ansible/roles/mn_fund_collateral/tasks/fund_collateral.yml b/ansible/roles/mn_fund_collateral/tasks/fund_collateral.yml index c804ddd8..1059ba3b 100644 --- a/ansible/roles/mn_fund_collateral/tasks/fund_collateral.yml +++ b/ansible/roles/mn_fund_collateral/tasks/fund_collateral.yml @@ -17,14 +17,8 @@ var: payments - name: Fund listed masternodes with {{ amount ~ ' Dash'}} - ansible.builtin.command: "dash-cli -rpcwallet={{ wallet_rpc_wallet_faucet }} sendmany '' '{{ payments | to_json }}'" - register: fund_result - changed_when: fund_result.stdout | length == 64 - -- name: Produce blocks until funding transaction is confirmed - ansible.builtin.include_role: - name: generate_blocks - vars: - generate: confirmations - txid_list: "{{ [fund_result.stdout] }}" - tx_source: "{{ wallet_rpc_wallet_faucet }}" + ansible.builtin.include_tasks: "{{ playbook_dir }}/roles/mn_fund_collateral/tasks/fund_one_collateral.yml" + with_items: + - '{{ payment_targets }}' + loop_control: + loop_var: payment_target diff --git a/ansible/roles/mn_fund_collateral/tasks/fund_one_collateral.yml b/ansible/roles/mn_fund_collateral/tasks/fund_one_collateral.yml new file mode 100644 index 00000000..294a2004 --- /dev/null +++ b/ansible/roles/mn_fund_collateral/tasks/fund_one_collateral.yml @@ -0,0 +1,16 @@ +--- + +- name: Fund collateral address {{ payment_target }} with {{ amount }} Dash + ansible.builtin.command: > + dash-cli -rpcwallet={{ wallet_rpc_wallet_faucet }} sendtoaddress {{ payment_target }} {{ amount }} + register: fund_result + changed_when: fund_result.stdout | length == 64 + +- name: Produce blocks until funding transaction for {{ payment_target }} is confirmed + ansible.builtin.include_role: + name: generate_blocks + vars: + generate: confirmations + txid_list: "{{ [fund_result.stdout] }}" + tx_source: "{{ wallet_rpc_wallet_faucet }}" + when: fund_result.stdout is defined and fund_result.stdout | length > 0 diff --git a/ansible/roles/mn_init/tasks/main.yml b/ansible/roles/mn_init/tasks/main.yml index b5413c86..9a8ff529 100644 --- a/ansible/roles/mn_init/tasks/main.yml +++ b/ansible/roles/mn_init/tasks/main.yml @@ -203,11 +203,30 @@ ansible.builtin.set_fact: fee_missing_addresses: "{{ fee_target_addresses | difference(funded_addresses.stdout) }}" +- name: Initialize fee payments + ansible.builtin.set_fact: + fee_payments: {} + when: fee_missing_addresses | length > 0 + +- name: Populate fee payments + ansible.builtin.set_fact: + fee_payments: "{{ fee_payments | combine({item: 1}) }}" + with_items: '{{ fee_missing_addresses }}' + when: fee_missing_addresses | length > 0 + - name: Fund 1 coin for ProTx fee - ansible.builtin.include_tasks: ./roles/mn_fund_collateral/tasks/fund_collateral.yml + ansible.builtin.command: "dash-cli -rpcwallet={{ wallet_rpc_wallet_faucet }} sendmany '' '{{ fee_payments | to_json }}'" + register: fee_fund_result + changed_when: fee_fund_result.stdout | length == 64 + when: fee_missing_addresses | length > 0 + +- name: Produce blocks until fee funding transaction is confirmed + ansible.builtin.include_role: + name: generate_blocks vars: - amount: 1 - payment_targets: '{{ fee_missing_addresses }}' + generate: confirmations + txid_list: "{{ [fee_fund_result.stdout] }}" + tx_source: "{{ wallet_rpc_wallet_faucet }}" when: fee_missing_addresses | length > 0 # Take action From 4afc26aabb36dd34cc9a069035ffffedccd171a7 Mon Sep 17 00:00:00 2001 From: vivekgsharma Date: Mon, 30 Mar 2026 12:02:29 +0000 Subject: [PATCH 30/30] Use explicit Dashmate config selection for HP node setup --- ansible/deploy.yml | 72 +------------------ ansible/roles/dashmate/tasks/main.yml | 16 ++--- ansible/roles/dashmate/tasks/set_vars.yml | 1 + .../roles/dashmate/tasks/ssl/letsencrypt.yml | 2 +- ansible/roles/dashmate/tasks/ssl/zerossl.yml | 6 +- 5 files changed, 14 insertions(+), 83 deletions(-) diff --git a/ansible/deploy.yml b/ansible/deploy.yml index 69435b9d..b68a9852 100644 --- a/ansible/deploy.yml +++ b/ansible/deploy.yml @@ -1,76 +1,6 @@ --- -# TEMPORARY DEBUG MODE: resume from masternode registration -# Register masternodes and set sporks - -- name: Register masternodes - hosts: wallet_nodes - become: true - roles: - - role: mn_init - mnlist: "{{ masternodes }}" - funding_amount: "{{ masternode_collaterals.mn | int }}" - tags: - - full_deploy - - unban_masternodes - -- name: Update inventory with protx values - hosts: wallet_nodes - roles: - - role: mn_protx_config - mnlist: "{{ masternodes }}" - tags: - - full_deploy - - unban_masternodes - -- name: Register HP masternodes - hosts: wallet_nodes - become: true - roles: - - role: mn_init - mnlist: "{{ hp_masternodes }}" - funding_amount: "{{ masternode_collaterals.hpmn | int }}" - tags: - - full_deploy - - unban_hp_masternodes - -- name: Update inventory with HPMN protx values - hosts: wallet_nodes - roles: - - role: mn_protx_config - mnlist: "{{ hp_masternodes }}" - tags: - - full_deploy - - unban_hp_masternodes - - -- name: Fund load tester nodes - hosts: wallet_nodes - become: true - tasks: - - name: Extract load tester addresses - ansible.builtin.set_fact: - load_tester_addresses: "{{ load_testers.values() | map(attribute='wallet.address') | list }}" - when: load_testers is defined and load_testers | length > 0 - - - name: Include funding for load testers - ansible.builtin.include_tasks: ./roles/mn_fund_collateral/tasks/fund_collateral.yml - vars: - payment_targets: "{{ load_tester_addresses }}" - amount: "{{ load_tester_wallet_amount }}" - when: load_testers is defined and load_testers | length > 0 - tags: - - full_deploy - -- name: Activate sporks - hosts: wallet_nodes - become: true - roles: - - role: activate_dashd_sporks - when: dash_network != "mainnet" and dash_network != "testnet" - delegate_to: '{{ play_hosts | first }}' - tags: - - full_deploy +# TEMPORARY DEBUG MODE: resume from HP Dashmate setup # todo: partially working code causes errors in deploy, comment out for now and fix later # - name: Create governance proposals diff --git a/ansible/roles/dashmate/tasks/main.yml b/ansible/roles/dashmate/tasks/main.yml index 5268e613..a3d9e9ec 100644 --- a/ansible/roles/dashmate/tasks/main.yml +++ b/ansible/roles/dashmate/tasks/main.yml @@ -438,7 +438,7 @@ # .dashmate directory already created in early permission fixes section - name: Render service configs - ansible.builtin.command: "{{ dashmate_cmd }} config render" + ansible.builtin.command: "{{ dashmate_cmd }} config render {{ dashmate_config_arg }}" become: true become_user: dashmate become_flags: '-H' @@ -503,7 +503,7 @@ register: env_file_stat - name: Export current dashmate config - ansible.builtin.command: "{{ dashmate_cmd }} config envs" + ansible.builtin.command: "{{ dashmate_cmd }} config envs {{ dashmate_config_arg }}" become: true become_user: dashmate become_flags: '-H' @@ -530,7 +530,7 @@ skip_image_update: "{{ skip_dashmate_image_update | default(false) }}" - name: Update dashmate images - ansible.builtin.command: "{{ dashmate_cmd }} update --format=json" + ansible.builtin.command: "{{ dashmate_cmd }} update --format=json {{ dashmate_config_arg }}" become: true become_user: dashmate become_flags: '-H' @@ -545,7 +545,7 @@ # ============================================================================ - name: Get service statuses - ansible.builtin.command: "{{ dashmate_cmd }} status services --format=json" + ansible.builtin.command: "{{ dashmate_cmd }} status services --format=json {{ dashmate_config_arg }}" become: true become_user: dashmate become_flags: '-H' @@ -602,7 +602,7 @@ # Start all if everything is stopped (not started yet) - name: Start all dashmate services - ansible.builtin.command: "{{ dashmate_cmd }} start --verbose" + ansible.builtin.command: "{{ dashmate_cmd }} start --verbose {{ dashmate_config_arg }}" become: true become_user: dashmate become_flags: '-H' @@ -620,7 +620,7 @@ # Fast deployment: each node restarts itself independently - name: Restart dashmate services (fast mode - individual restart) - ansible.builtin.command: "{{ dashmate_cmd }} restart --safe --verbose{{ '' if needs_core_restart | default(false) else ' --platform' }}" + ansible.builtin.command: "{{ dashmate_cmd }} restart --safe --verbose{{ '' if needs_core_restart | default(false) else ' --platform' }} {{ dashmate_config_arg }}" become: true become_user: dashmate become_flags: '-H' @@ -684,7 +684,7 @@ # Force start is equivalent to `docker compose up` and will replace services that have changed - name: Start not started services and replace updated services - ansible.builtin.command: "{{ dashmate_cmd }} start --force --verbose{{ '' if needs_core_restart | default(false) else ' --platform' }}" + ansible.builtin.command: "{{ dashmate_cmd }} start --force --verbose{{ '' if needs_core_restart | default(false) else ' --platform' }} {{ dashmate_config_arg }}" become: true become_user: dashmate become_flags: '-H' @@ -698,7 +698,7 @@ changed_when: dashmate_force_start.rc == 0 - name: Disable dashmate helper build - ansible.builtin.command: "{{ dashmate_cmd }} config set dashmate.helper.docker.build.enabled false" + ansible.builtin.command: "{{ dashmate_cmd }} config set dashmate.helper.docker.build.enabled false {{ dashmate_config_arg }}" become: true become_user: dashmate become_flags: '-H' diff --git a/ansible/roles/dashmate/tasks/set_vars.yml b/ansible/roles/dashmate/tasks/set_vars.yml index 076437c0..76692a64 100644 --- a/ansible/roles/dashmate/tasks/set_vars.yml +++ b/ansible/roles/dashmate/tasks/set_vars.yml @@ -9,3 +9,4 @@ ansible.builtin.set_fact: dashmate_cmd: "{{ 'yarn dashmate' if dashmate_branch is defined else 'dashmate' }}" dashmate_cwd: "{{ dashmate_source_dir if dashmate_branch is defined else dashmate_home }}" + dashmate_config_arg: "--config={{ dash_network_name }}" diff --git a/ansible/roles/dashmate/tasks/ssl/letsencrypt.yml b/ansible/roles/dashmate/tasks/ssl/letsencrypt.yml index 1eab18f0..c3a0c66b 100644 --- a/ansible/roles/dashmate/tasks/ssl/letsencrypt.yml +++ b/ansible/roles/dashmate/tasks/ssl/letsencrypt.yml @@ -13,7 +13,7 @@ mode: "0750" - name: Obtain Let's Encrypt certificate for DAPI - ansible.builtin.command: "{{ dashmate_cmd }} ssl obtain --provider letsencrypt --verbose --no-retry" + ansible.builtin.command: "{{ dashmate_cmd }} ssl obtain --provider letsencrypt --verbose --no-retry {{ dashmate_config_arg }}" become: true become_user: dashmate become_flags: '-H' diff --git a/ansible/roles/dashmate/tasks/ssl/zerossl.yml b/ansible/roles/dashmate/tasks/ssl/zerossl.yml index 97551856..ffcf400a 100644 --- a/ansible/roles/dashmate/tasks/ssl/zerossl.yml +++ b/ansible/roles/dashmate/tasks/ssl/zerossl.yml @@ -26,7 +26,7 @@ dashmate_zerossl_ssm_certificate_id: "{{ lookup('aws_ssm', '{{ dashmate_zerossl_ssm_path }}-id', on_missing='skip') }}" - name: Set ZeroSSL certificate ID to dashmate config from SSM if not set - ansible.builtin.command: "{{ dashmate_cmd }} config set {{ dashmate_zerossl_config_path }}.id {{ dashmate_zerossl_ssm_certificate_id }}" + ansible.builtin.command: "{{ dashmate_cmd }} config set {{ dashmate_zerossl_config_path }}.id {{ dashmate_zerossl_ssm_certificate_id }} {{ dashmate_config_arg }}" become: true become_user: dashmate become_flags: '-H' @@ -68,7 +68,7 @@ register: zero_ssl_bundle_file - name: Obtain ZeroSSL certificate for DAPI - ansible.builtin.command: "{{ dashmate_cmd }} ssl obtain --verbose --no-retry" + ansible.builtin.command: "{{ dashmate_cmd }} ssl obtain --verbose --no-retry {{ dashmate_config_arg }}" become: true become_user: dashmate become_flags: '-H' @@ -83,7 +83,7 @@ # Save new ZeroSSL information to SSM - name: Get new ZeroSSL certificate ID from dashmate config - ansible.builtin.command: "{{ dashmate_cmd }} config get {{ dashmate_zerossl_config_path }}.id" + ansible.builtin.command: "{{ dashmate_cmd }} config get {{ dashmate_zerossl_config_path }}.id {{ dashmate_config_arg }}" become: true become_user: dashmate become_flags: '-H'